Version Description
- Fix - Do not allow birth date older than 100 years for PUI. #743
- Fix - Store the customer id for vaulted payment method in usermeta to not lose vaulted methods after the invoice prefix change. #698
- Fix - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
- Fix - Voiding authorization at PayPal did not update the status/order notes. #712
- Fix - PayPal scripts were loading on pages without smart buttons or Pay Later messaging. #750
- Fix - Do not show links for unavailable gateways settings pages. #753
- Fix - The smart buttons were not loaded on single product page if a subscription product exists in the cart. #703
- Fix - DCC was causing other gateways to disappear after checkout validation error. #757
- Fix - Buttons not loading on single product page with default settings when product is in cart. #777
- Enhancement - Improve Checkout Field Validation Message. #739
- Enhancement - Handle PAYER_ACTION_REQUIRED error. #759
Download this release
Release Info
Developer | automattic |
Plugin | WooCommerce PayPal Payments |
Version | 1.9.2 |
Comparing to | |
See all releases |
Code changes from version 1.9.1 to 1.9.2
- changelog.txt +13 -0
- modules/ppcp-api-client/services.php +54 -0
- modules/ppcp-api-client/src/Endpoint/IdentityToken.php +1 -1
- modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php +48 -1
- modules/ppcp-api-client/src/Entity/Payer.php +36 -19
- modules/ppcp-api-client/src/Exception/PayPalApiException.php +0 -9
- modules/ppcp-api-client/src/Factory/AmountFactory.php +2 -1
- modules/ppcp-api-client/src/Repository/CustomerRepository.php +1 -1
- modules/ppcp-button/assets/js/button.js +1 -1
- modules/ppcp-button/resources/js/button.js +40 -6
- modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +5 -2
- modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +1 -3
- modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +13 -4
- modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js +7 -3
- modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +1 -3
- modules/ppcp-button/resources/js/modules/Helper/CheckoutMethodState.js +2 -0
- modules/ppcp-button/resources/js/modules/Renderer/Renderer.js +75 -12
- modules/ppcp-button/services.php +1 -0
- modules/ppcp-button/src/Assets/SmartButton.php +109 -56
- modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +39 -4
- modules/ppcp-session/src/Cancellation/CancelController.php +4 -0
- modules/ppcp-subscription/services.php +5 -1
- modules/ppcp-subscription/src/RenewalHandler.php +81 -15
- modules/ppcp-vaulting/src/PaymentTokenChecker.php +2 -1
- modules/ppcp-wc-gateway/assets/images/oxxo.svg +18 -0
- modules/ppcp-wc-gateway/assets/js/oxxo.js +1 -0
- modules/ppcp-wc-gateway/resources/js/oxxo.js +18 -0
- modules/ppcp-wc-gateway/services.php +209 -63
- modules/ppcp-wc-gateway/src/CardBillingMode.php +19 -0
- modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +14 -20
- modules/ppcp-wc-gateway/src/Endpoint/ReturnUrlEndpoint.php +8 -2
- modules/ppcp-wc-gateway/src/Exception/GatewayGenericException.php +32 -0
- modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php +364 -0
- modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +180 -33
- modules/ppcp-wc-gateway/src/Gateway/GatewaySettingsRendererTrait.php +37 -0
- modules/ppcp-wc-gateway/src/Gateway/Messages.php +27 -0
- modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXO.php +223 -0
- modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOEndpoint.php +156 -0
- modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php +210 -0
- modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +166 -106
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +14 -3
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +13 -4
- modules/ppcp-wc-gateway/src/Gateway/ProcessPaymentTrait.php +71 -279
- modules/ppcp-wc-gateway/src/Helper/CheckoutHelper.php +131 -0
- modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php +9 -90
- modules/ppcp-wc-gateway/src/Notice/{DccWithoutPayPalAdminNotice.php → GatewayWithoutPayPalAdminNotice.php} +47 -9
- modules/ppcp-wc-gateway/src/Settings/PageMatcherTrait.php +2 -0
- modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +17 -27
- modules/ppcp-wc-gateway/src/WCGatewayModule.php +34 -6
- modules/ppcp-wc-gateway/webpack.config.js +1 -0
- modules/ppcp-webhooks/services.php +3 -0
- modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +2 -1
- modules/ppcp-webhooks/src/Handler/PaymentCapturePending.php +122 -0
- modules/ppcp-webhooks/src/Handler/PaymentCaptureRefunded.php +1 -1
- modules/ppcp-webhooks/src/Handler/PaymentCaptureReversed.php +6 -1
- readme.txt +14 -1
- vendor/autoload.php +1 -1
- vendor/composer/autoload_real.php +7 -7
- vendor/composer/autoload_static.php +4 -4
- woocommerce-paypal-payments.php +4 -2
changelog.txt
CHANGED
@@ -1,5 +1,18 @@
|
|
1 |
*** Changelog ***
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
= 1.9.1 - 2022-07-25 =
|
4 |
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
5 |
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
1 |
*** Changelog ***
|
2 |
|
3 |
+
= 1.9.2 - 2022-08-09 =
|
4 |
+
* Fix - Do not allow birth date older than 100 years for PUI. #743
|
5 |
+
* Fix - Store the customer id for vaulted payment method in usermeta to not lose vaulted methods after the invoice prefix change. #698
|
6 |
+
* Fix - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
|
7 |
+
* Fix - Voiding authorization at PayPal did not update the status/order notes. #712
|
8 |
+
* Fix - PayPal scripts were loading on pages without smart buttons or Pay Later messaging. #750
|
9 |
+
* Fix - Do not show links for unavailable gateways settings pages. #753
|
10 |
+
* Fix - The smart buttons were not loaded on single product page if a subscription product exists in the cart. #703
|
11 |
+
* Fix - DCC was causing other gateways to disappear after checkout validation error. #757
|
12 |
+
* Fix - Buttons not loading on single product page with default settings when product is in cart. #777
|
13 |
+
* Enhancement - Improve Checkout Field Validation Message. #739
|
14 |
+
* Enhancement - Handle PAYER_ACTION_REQUIRED error. #759
|
15 |
+
|
16 |
= 1.9.1 - 2022-07-25 =
|
17 |
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
18 |
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
modules/ppcp-api-client/services.php
CHANGED
@@ -400,6 +400,60 @@ return array(
|
|
400 |
);
|
401 |
},
|
402 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
403 |
/**
|
404 |
* Currencies supported by PayPal.
|
405 |
*
|
400 |
);
|
401 |
},
|
402 |
|
403 |
+
|
404 |
+
'api.shop.is-latin-america' => static function ( ContainerInterface $container ): bool {
|
405 |
+
return in_array(
|
406 |
+
$container->get( 'api.shop.country' ),
|
407 |
+
array(
|
408 |
+
'AI',
|
409 |
+
'AG',
|
410 |
+
'AR',
|
411 |
+
'AW',
|
412 |
+
'BS',
|
413 |
+
'BB',
|
414 |
+
'BZ',
|
415 |
+
'BM',
|
416 |
+
'BO',
|
417 |
+
'BR',
|
418 |
+
'VG',
|
419 |
+
'KY',
|
420 |
+
'CL',
|
421 |
+
'CO',
|
422 |
+
'CR',
|
423 |
+
'DM',
|
424 |
+
'DO',
|
425 |
+
'EC',
|
426 |
+
'SV',
|
427 |
+
'FK',
|
428 |
+
'GF',
|
429 |
+
'GD',
|
430 |
+
'GP',
|
431 |
+
'GT',
|
432 |
+
'GY',
|
433 |
+
'HN',
|
434 |
+
'JM',
|
435 |
+
'MQ',
|
436 |
+
'MX',
|
437 |
+
'MS',
|
438 |
+
'AN',
|
439 |
+
'NI',
|
440 |
+
'PA',
|
441 |
+
'PY',
|
442 |
+
'PE',
|
443 |
+
'KN',
|
444 |
+
'LC',
|
445 |
+
'PM',
|
446 |
+
'VC',
|
447 |
+
'SR',
|
448 |
+
'TT',
|
449 |
+
'TC',
|
450 |
+
'UY',
|
451 |
+
'VE',
|
452 |
+
),
|
453 |
+
true
|
454 |
+
);
|
455 |
+
},
|
456 |
+
|
457 |
/**
|
458 |
* Currencies supported by PayPal.
|
459 |
*
|
modules/ppcp-api-client/src/Endpoint/IdentityToken.php
CHANGED
@@ -106,7 +106,7 @@ class IdentityToken {
|
|
106 |
&& defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION
|
107 |
) {
|
108 |
$customer_id = $this->customer_repository->customer_id_for_user( ( $user_id ) );
|
109 |
-
|
110 |
$args['body'] = wp_json_encode(
|
111 |
array(
|
112 |
'customer_id' => $customer_id,
|
106 |
&& defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION
|
107 |
) {
|
108 |
$customer_id = $this->customer_repository->customer_id_for_user( ( $user_id ) );
|
109 |
+
update_user_meta( $user_id, 'ppcp_customer_id', $customer_id );
|
110 |
$args['body'] = wp_json_encode(
|
111 |
array(
|
112 |
'customer_id' => $customer_id,
|
modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php
CHANGED
@@ -9,6 +9,7 @@ declare(strict_types=1);
|
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
11 |
|
|
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
13 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
14 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
|
@@ -28,6 +29,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository
|
|
28 |
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
29 |
use Psr\Log\LoggerInterface;
|
30 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
|
|
31 |
|
32 |
/**
|
33 |
* Class OrderEndpoint
|
@@ -192,7 +194,7 @@ class OrderEndpoint {
|
|
192 |
'application_context' => $this->application_context_repository
|
193 |
->current_context( $shipping_preference )->to_array(),
|
194 |
);
|
195 |
-
if ( $payer && ! empty( $payer->email_address() )
|
196 |
$data['payer'] = $payer->to_array();
|
197 |
}
|
198 |
if ( $payment_token ) {
|
@@ -564,4 +566,49 @@ class OrderEndpoint {
|
|
564 |
$new_order = $this->order( $order_to_update->id() );
|
565 |
return $new_order;
|
566 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
567 |
}
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
11 |
|
12 |
+
use stdClass;
|
13 |
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
14 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
|
29 |
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
30 |
use Psr\Log\LoggerInterface;
|
31 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
32 |
+
use WP_Error;
|
33 |
|
34 |
/**
|
35 |
* Class OrderEndpoint
|
194 |
'application_context' => $this->application_context_repository
|
195 |
->current_context( $shipping_preference )->to_array(),
|
196 |
);
|
197 |
+
if ( $payer && ! empty( $payer->email_address() ) ) {
|
198 |
$data['payer'] = $payer->to_array();
|
199 |
}
|
200 |
if ( $payment_token ) {
|
566 |
$new_order = $this->order( $order_to_update->id() );
|
567 |
return $new_order;
|
568 |
}
|
569 |
+
|
570 |
+
/**
|
571 |
+
* Confirms payment source.
|
572 |
+
*
|
573 |
+
* @param string $id The PayPal order ID.
|
574 |
+
* @param array $payment_source The payment source.
|
575 |
+
* @return stdClass
|
576 |
+
* @throws PayPalApiException If the request fails.
|
577 |
+
* @throws RuntimeException If something unexpected happens.
|
578 |
+
*/
|
579 |
+
public function confirm_payment_source( string $id, array $payment_source ): stdClass {
|
580 |
+
$bearer = $this->bearer->bearer();
|
581 |
+
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id . '/confirm-payment-source';
|
582 |
+
|
583 |
+
$data = array(
|
584 |
+
'payment_source' => $payment_source,
|
585 |
+
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
586 |
+
'application_context' => array(
|
587 |
+
'locale' => 'es-MX',
|
588 |
+
),
|
589 |
+
);
|
590 |
+
|
591 |
+
$args = array(
|
592 |
+
'method' => 'POST',
|
593 |
+
'headers' => array(
|
594 |
+
'Authorization' => 'Bearer ' . $bearer->token(),
|
595 |
+
'Content-Type' => 'application/json',
|
596 |
+
'Prefer' => 'return=representation',
|
597 |
+
),
|
598 |
+
'body' => wp_json_encode( $data ),
|
599 |
+
);
|
600 |
+
|
601 |
+
$response = $this->request( $url, $args );
|
602 |
+
if ( $response instanceof WP_Error ) {
|
603 |
+
throw new RuntimeException( $response->get_error_message() );
|
604 |
+
}
|
605 |
+
|
606 |
+
$json = json_decode( $response['body'] );
|
607 |
+
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
608 |
+
if ( 200 !== $status_code ) {
|
609 |
+
throw new PayPalApiException( $json, $status_code );
|
610 |
+
}
|
611 |
+
|
612 |
+
return $json;
|
613 |
+
}
|
614 |
}
|
modules/ppcp-api-client/src/Entity/Payer.php
CHANGED
@@ -18,7 +18,7 @@ class Payer {
|
|
18 |
/**
|
19 |
* The name.
|
20 |
*
|
21 |
-
* @var PayerName
|
22 |
*/
|
23 |
private $name;
|
24 |
|
@@ -46,7 +46,7 @@ class Payer {
|
|
46 |
/**
|
47 |
* The address.
|
48 |
*
|
49 |
-
* @var Address
|
50 |
*/
|
51 |
private $address;
|
52 |
|
@@ -67,7 +67,7 @@ class Payer {
|
|
67 |
/**
|
68 |
* Payer constructor.
|
69 |
*
|
70 |
-
* @param PayerName
|
71 |
* @param string $email_address The email.
|
72 |
* @param string $payer_id The payer id.
|
73 |
* @param Address|null $address The address.
|
@@ -76,7 +76,7 @@ class Payer {
|
|
76 |
* @param PayerTaxInfo|null $tax_info The tax info.
|
77 |
*/
|
78 |
public function __construct(
|
79 |
-
PayerName $name,
|
80 |
string $email_address,
|
81 |
string $payer_id,
|
82 |
Address $address = null,
|
@@ -97,12 +97,21 @@ class Payer {
|
|
97 |
/**
|
98 |
* Returns the name.
|
99 |
*
|
100 |
-
* @return PayerName
|
101 |
*/
|
102 |
-
public function name(): PayerName {
|
103 |
return $this->name;
|
104 |
}
|
105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
/**
|
107 |
* Returns the email address.
|
108 |
*
|
@@ -139,6 +148,15 @@ class Payer {
|
|
139 |
return $this->address;
|
140 |
}
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
/**
|
143 |
* Returns the phone.
|
144 |
*
|
@@ -164,27 +182,26 @@ class Payer {
|
|
164 |
*/
|
165 |
public function to_array() {
|
166 |
$payer = array(
|
167 |
-
'name' => $this->name()->to_array(),
|
168 |
'email_address' => $this->email_address(),
|
169 |
);
|
170 |
-
if ( $this->
|
|
|
|
|
|
|
171 |
$payer['address'] = $this->address->to_array();
|
172 |
-
if ( 2 !== strlen( $this->address()->country_code() ) ) {
|
173 |
-
unset( $payer['address'] );
|
174 |
-
}
|
175 |
}
|
176 |
-
if ( $this->payer_id
|
177 |
-
$payer['payer_id'] = $this->payer_id
|
178 |
}
|
179 |
|
180 |
-
if ( $this->phone
|
181 |
-
$payer['phone'] = $this->phone
|
182 |
}
|
183 |
-
if ( $this->tax_info
|
184 |
-
$payer['tax_info'] = $this->tax_info
|
185 |
}
|
186 |
-
if ( $this->birthdate
|
187 |
-
$payer['birth_date'] = $this->birthdate
|
188 |
}
|
189 |
return $payer;
|
190 |
}
|
18 |
/**
|
19 |
* The name.
|
20 |
*
|
21 |
+
* @var PayerName|null
|
22 |
*/
|
23 |
private $name;
|
24 |
|
46 |
/**
|
47 |
* The address.
|
48 |
*
|
49 |
+
* @var Address|null
|
50 |
*/
|
51 |
private $address;
|
52 |
|
67 |
/**
|
68 |
* Payer constructor.
|
69 |
*
|
70 |
+
* @param PayerName|null $name The name.
|
71 |
* @param string $email_address The email.
|
72 |
* @param string $payer_id The payer id.
|
73 |
* @param Address|null $address The address.
|
76 |
* @param PayerTaxInfo|null $tax_info The tax info.
|
77 |
*/
|
78 |
public function __construct(
|
79 |
+
?PayerName $name,
|
80 |
string $email_address,
|
81 |
string $payer_id,
|
82 |
Address $address = null,
|
97 |
/**
|
98 |
* Returns the name.
|
99 |
*
|
100 |
+
* @return PayerName|null
|
101 |
*/
|
102 |
+
public function name(): ?PayerName {
|
103 |
return $this->name;
|
104 |
}
|
105 |
|
106 |
+
/**
|
107 |
+
* Sets the name.
|
108 |
+
*
|
109 |
+
* @param PayerName|null $name The value.
|
110 |
+
*/
|
111 |
+
public function set_name( ?PayerName $name ): void {
|
112 |
+
$this->name = $name;
|
113 |
+
}
|
114 |
+
|
115 |
/**
|
116 |
* Returns the email address.
|
117 |
*
|
148 |
return $this->address;
|
149 |
}
|
150 |
|
151 |
+
/**
|
152 |
+
* Sets the address.
|
153 |
+
*
|
154 |
+
* @param Address|null $address The value.
|
155 |
+
*/
|
156 |
+
public function set_address( ?Address $address ): void {
|
157 |
+
$this->address = $address;
|
158 |
+
}
|
159 |
+
|
160 |
/**
|
161 |
* Returns the phone.
|
162 |
*
|
182 |
*/
|
183 |
public function to_array() {
|
184 |
$payer = array(
|
|
|
185 |
'email_address' => $this->email_address(),
|
186 |
);
|
187 |
+
if ( $this->name ) {
|
188 |
+
$payer['name'] = $this->name->to_array();
|
189 |
+
}
|
190 |
+
if ( $this->address && 2 === strlen( $this->address->country_code() ) ) {
|
191 |
$payer['address'] = $this->address->to_array();
|
|
|
|
|
|
|
192 |
}
|
193 |
+
if ( $this->payer_id ) {
|
194 |
+
$payer['payer_id'] = $this->payer_id;
|
195 |
}
|
196 |
|
197 |
+
if ( $this->phone ) {
|
198 |
+
$payer['phone'] = $this->phone->to_array();
|
199 |
}
|
200 |
+
if ( $this->tax_info ) {
|
201 |
+
$payer['tax_info'] = $this->tax_info->to_array();
|
202 |
}
|
203 |
+
if ( $this->birthdate ) {
|
204 |
+
$payer['birth_date'] = $this->birthdate->format( 'Y-m-d' );
|
205 |
}
|
206 |
return $payer;
|
207 |
}
|
modules/ppcp-api-client/src/Exception/PayPalApiException.php
CHANGED
@@ -111,15 +111,6 @@ class PayPalApiException extends RuntimeException {
|
|
111 |
return false;
|
112 |
}
|
113 |
|
114 |
-
/**
|
115 |
-
* Returns response issues.
|
116 |
-
*
|
117 |
-
* @return array
|
118 |
-
*/
|
119 |
-
public function issues(): array {
|
120 |
-
return $this->response->issues ?? array();
|
121 |
-
}
|
122 |
-
|
123 |
/**
|
124 |
* The HTTP status code.
|
125 |
*
|
111 |
return false;
|
112 |
}
|
113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
/**
|
115 |
* The HTTP status code.
|
116 |
*
|
modules/ppcp-api-client/src/Factory/AmountFactory.php
CHANGED
@@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
17 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
|
|
18 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
19 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
20 |
|
@@ -132,7 +133,7 @@ class AmountFactory {
|
|
132 |
|
133 |
$total_value = (float) $order->get_total();
|
134 |
if ( (
|
135 |
-
|
136 |
|| ( PayPalGateway::ID === $order->get_payment_method() && 'card' === $order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
137 |
)
|
138 |
&& $this->is_free_trial_order( $order )
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
17 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
18 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
19 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
20 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
21 |
|
133 |
|
134 |
$total_value = (float) $order->get_total();
|
135 |
if ( (
|
136 |
+
in_array( $order->get_payment_method(), array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
137 |
|| ( PayPalGateway::ID === $order->get_payment_method() && 'card' === $order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
138 |
)
|
139 |
&& $this->is_free_trial_order( $order )
|
modules/ppcp-api-client/src/Repository/CustomerRepository.php
CHANGED
@@ -57,6 +57,6 @@ class CustomerRepository {
|
|
57 |
return $guest_customer_id;
|
58 |
}
|
59 |
|
60 |
-
return $this->prefix . (string) $user_id;
|
61 |
}
|
62 |
}
|
57 |
return $guest_customer_id;
|
58 |
}
|
59 |
|
60 |
+
return get_user_meta( $user_id, 'ppcp_customer_id', true ) ?: $this->prefix . (string) $user_id;
|
61 |
}
|
62 |
}
|
modules/ppcp-button/assets/js/button.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
(()=>{"use strict";var __webpack_modules__={536:()=>{eval("\n;// CONCATENATED MODULE: ./resources/js/modules/ErrorHandler.js\nclass ErrorHandler {\n constructor(genericErrorText) {\n this.genericErrorText = genericErrorText;\n this.wrapper = document.querySelector('.woocommerce-notices-wrapper');\n this.messagesList = document.querySelector('ul.woocommerce-error');\n }\n\n genericError() {\n if (this.wrapper.classList.contains('ppcp-persist')) {\n return;\n }\n\n this.clear();\n this.message(this.genericErrorText);\n }\n\n appendPreparedErrorMessageElement(errorMessageElement) {\n if (this.messagesList === null) {\n this.prepareMessagesList();\n }\n\n this.messagesList.replaceWith(errorMessageElement);\n }\n\n message(text, persist = false) {\n if (!typeof String || text.length === 0) {\n throw new Error('A new message text must be a non-empty string.');\n }\n\n if (this.messagesList === null) {\n this.prepareMessagesList();\n }\n\n if (persist) {\n this.wrapper.classList.add('ppcp-persist');\n } else {\n this.wrapper.classList.remove('ppcp-persist');\n }\n\n let messageNode = this.prepareMessagesListItem(text);\n this.messagesList.appendChild(messageNode);\n jQuery.scroll_to_notices(jQuery('.woocommerce-notices-wrapper'));\n }\n\n prepareMessagesList() {\n if (this.messagesList === null) {\n this.messagesList = document.createElement('ul');\n this.messagesList.setAttribute('class', 'woocommerce-error');\n this.messagesList.setAttribute('role', 'alert');\n this.wrapper.appendChild(this.messagesList);\n }\n }\n\n prepareMessagesListItem(message) {\n const li = document.createElement('li');\n li.innerHTML = message;\n return li;\n }\n\n sanitize(text) {\n const textarea = document.createElement('textarea');\n textarea.innerHTML = text;\n return textarea.value.replace('Error: ', '');\n }\n\n clear() {\n if (this.messagesList === null) {\n return;\n }\n\n this.messagesList.innerHTML = '';\n }\n\n}\n\n/* harmony default export */ const modules_ErrorHandler = (ErrorHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/OnApproveHandler/onApproveForContinue.js\nconst onApprove = (context, errorHandler) => {\n return (data, actions) => {\n return fetch(context.config.ajax.approve_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: context.config.ajax.approve_order.nonce,\n order_id: data.orderID,\n funding_source: window.ppcpFundingSource\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n if (!data.success) {\n errorHandler.genericError();\n return actions.restart().catch(err => {\n errorHandler.genericError();\n });\n }\n\n location.href = context.config.redirect;\n });\n };\n};\n\n/* harmony default export */ const onApproveForContinue = (onApprove);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/PayerData.js\nconst payerData = () => {\n const payer = PayPalCommerceGateway.payer;\n\n if (!payer) {\n return null;\n }\n\n const phone = document.querySelector('#billing_phone') || typeof payer.phone !== 'undefined' ? {\n phone_type: \"HOME\",\n phone_number: {\n national_number: document.querySelector('#billing_phone') ? document.querySelector('#billing_phone').value : payer.phone.phone_number.national_number\n }\n } : null;\n const payerData = {\n email_address: document.querySelector('#billing_email') ? document.querySelector('#billing_email').value : payer.email_address,\n name: {\n surname: document.querySelector('#billing_last_name') ? document.querySelector('#billing_last_name').value : payer.name.surname,\n given_name: document.querySelector('#billing_first_name') ? document.querySelector('#billing_first_name').value : payer.name.given_name\n },\n address: {\n country_code: document.querySelector('#billing_country') ? document.querySelector('#billing_country').value : payer.address.country_code,\n address_line_1: document.querySelector('#billing_address_1') ? document.querySelector('#billing_address_1').value : payer.address.address_line_1,\n address_line_2: document.querySelector('#billing_address_2') ? document.querySelector('#billing_address_2').value : payer.address.address_line_2,\n admin_area_1: document.querySelector('#billing_state') ? document.querySelector('#billing_state').value : payer.address.admin_area_1,\n admin_area_2: document.querySelector('#billing_city') ? document.querySelector('#billing_city').value : payer.address.admin_area_2,\n postal_code: document.querySelector('#billing_postcode') ? document.querySelector('#billing_postcode').value : payer.address.postal_code\n }\n };\n\n if (phone) {\n payerData.phone = phone;\n }\n\n return payerData;\n};\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/CheckoutMethodState.js\nconst PaymentMethods = {\n PAYPAL: 'ppcp-gateway',\n CARDS: 'ppcp-credit-card-gateway'\n};\nconst ORDER_BUTTON_SELECTOR = '#place_order';\nconst getCurrentPaymentMethod = () => {\n const el = document.querySelector('input[name=\"payment_method\"]:checked');\n\n if (!el) {\n return null;\n }\n\n return el.value;\n};\nconst isSavedCardSelected = () => {\n const savedCardList = document.querySelector('#saved-credit-card');\n return savedCardList && savedCardList.value !== '';\n};\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/CartActionHandler.js\n\n\n\n\nclass CartActionHandler {\n constructor(config, errorHandler) {\n this.config = config;\n this.errorHandler = errorHandler;\n }\n\n configuration() {\n const createOrder = (data, actions) => {\n const payer = payerData();\n const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : '';\n return fetch(this.config.ajax.create_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.create_order.nonce,\n purchase_units: [],\n payment_method: PaymentMethods.PAYPAL,\n funding_source: window.ppcpFundingSource,\n bn_code: bnCode,\n payer,\n context: this.config.context\n })\n }).then(function (res) {\n return res.json();\n }).then(function (data) {\n if (!data.success) {\n console.error(data);\n throw Error(data.data.message);\n }\n\n return data.data.id;\n });\n };\n\n return {\n createOrder,\n onApprove: onApproveForContinue(this, this.errorHandler),\n onError: error => {\n this.errorHandler.genericError();\n }\n };\n }\n\n}\n\n/* harmony default export */ const ActionHandler_CartActionHandler = (CartActionHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/MiniCartBootstap.js\n\n\n\nclass MiniCartBootstap {\n constructor(gateway, renderer) {\n this.gateway = gateway;\n this.renderer = renderer;\n this.actionHandler = null;\n }\n\n init() {\n this.actionHandler = new ActionHandler_CartActionHandler(PayPalCommerceGateway, new modules_ErrorHandler(this.gateway.labels.error.generic));\n this.render();\n jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => {\n this.render();\n });\n }\n\n shouldRender() {\n return document.querySelector(this.gateway.button.mini_cart_wrapper) !== null || document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !== null;\n }\n\n render() {\n if (!this.shouldRender()) {\n return;\n }\n\n this.renderer.render(this.gateway.button.mini_cart_wrapper, this.gateway.hosted_fields.mini_cart_wrapper, this.actionHandler.configuration());\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_MiniCartBootstap = (MiniCartBootstap);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/UpdateCart.js\n\n\nclass UpdateCart {\n constructor(endpoint, nonce) {\n this.endpoint = endpoint;\n this.nonce = nonce;\n }\n /**\n *\n * @param onResolve\n * @param {Product[]} products\n * @returns {Promise<unknown>}\n */\n\n\n update(onResolve, products) {\n return new Promise((resolve, reject) => {\n fetch(this.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.nonce,\n products\n })\n }).then(result => {\n return result.json();\n }).then(result => {\n if (!result.success) {\n reject(result.data);\n return;\n }\n\n const resolved = onResolve(result.data);\n resolve(resolved);\n });\n });\n }\n\n}\n\n/* harmony default export */ const Helper_UpdateCart = (UpdateCart);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/ButtonsToggleListener.js\n/**\n * When you can't add something to the cart, the PayPal buttons should not show.\n * Therefore we listen for changes on the add to cart button and show/hide the buttons accordingly.\n */\nclass ButtonsToggleListener {\n constructor(element, showCallback, hideCallback) {\n this.element = element;\n this.showCallback = showCallback;\n this.hideCallback = hideCallback;\n this.observer = null;\n }\n\n init() {\n const config = {\n attributes: true\n };\n\n const callback = () => {\n if (this.element.classList.contains('disabled')) {\n this.hideCallback();\n return;\n }\n\n this.showCallback();\n };\n\n this.observer = new MutationObserver(callback);\n this.observer.observe(this.element, config);\n callback();\n }\n\n disconnect() {\n this.observer.disconnect();\n }\n\n}\n\n/* harmony default export */ const Helper_ButtonsToggleListener = (ButtonsToggleListener);\n;// CONCATENATED MODULE: ./resources/js/modules/Entity/Product.js\nclass Product {\n constructor(id, quantity, variations) {\n this.id = id;\n this.quantity = quantity;\n this.variations = variations;\n }\n\n data() {\n return {\n id: this.id,\n quantity: this.quantity,\n variations: this.variations\n };\n }\n\n}\n\n/* harmony default export */ const Entity_Product = (Product);\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/SingleProductActionHandler.js\n\n\n\n\n\n\nclass SingleProductActionHandler {\n constructor(config, updateCart, showButtonCallback, hideButtonCallback, formElement, errorHandler) {\n this.config = config;\n this.updateCart = updateCart;\n this.showButtonCallback = showButtonCallback;\n this.hideButtonCallback = hideButtonCallback;\n this.formElement = formElement;\n this.errorHandler = errorHandler;\n }\n\n configuration() {\n if (this.hasVariations()) {\n const observer = new Helper_ButtonsToggleListener(this.formElement.querySelector('.single_add_to_cart_button'), this.showButtonCallback, this.hideButtonCallback);\n observer.init();\n }\n\n return {\n createOrder: this.createOrder(),\n onApprove: onApproveForContinue(this, this.errorHandler),\n onError: error => {\n this.errorHandler.genericError();\n }\n };\n }\n\n createOrder() {\n var getProducts = null;\n\n if (!this.isGroupedProduct()) {\n getProducts = () => {\n const id = document.querySelector('[name=\"add-to-cart\"]').value;\n const qty = document.querySelector('[name=\"quantity\"]').value;\n const variations = this.variations();\n return [new Entity_Product(id, qty, variations)];\n };\n } else {\n getProducts = () => {\n const products = [];\n this.formElement.querySelectorAll('input[type=\"number\"]').forEach(element => {\n if (!element.value) {\n return;\n }\n\n const elementName = element.getAttribute('name').match(/quantity\\[([\\d]*)\\]/);\n\n if (elementName.length !== 2) {\n return;\n }\n\n const id = parseInt(elementName[1]);\n const quantity = parseInt(element.value);\n products.push(new Entity_Product(id, quantity, null));\n });\n return products;\n };\n }\n\n const createOrder = (data, actions) => {\n this.errorHandler.clear();\n\n const onResolve = purchase_units => {\n const payer = payerData();\n const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : '';\n return fetch(this.config.ajax.create_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.create_order.nonce,\n purchase_units,\n payer,\n bn_code: bnCode,\n payment_method: PaymentMethods.PAYPAL,\n funding_source: window.ppcpFundingSource,\n context: this.config.context\n })\n }).then(function (res) {\n return res.json();\n }).then(function (data) {\n if (!data.success) {\n console.error(data);\n throw Error(data.data.message);\n }\n\n return data.data.id;\n });\n };\n\n const promise = this.updateCart.update(onResolve, getProducts());\n return promise;\n };\n\n return createOrder;\n }\n\n variations() {\n if (!this.hasVariations()) {\n return null;\n }\n\n const attributes = [...this.formElement.querySelectorAll(\"[name^='attribute_']\")].map(element => {\n return {\n value: element.value,\n name: element.name\n };\n });\n return attributes;\n }\n\n hasVariations() {\n return this.formElement.classList.contains('variations_form');\n }\n\n isGroupedProduct() {\n return this.formElement.classList.contains('grouped_form');\n }\n\n}\n\n/* harmony default export */ const ActionHandler_SingleProductActionHandler = (SingleProductActionHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/SingleProductBootstap.js\n\n\n\n\nclass SingleProductBootstap {\n constructor(gateway, renderer, messages) {\n this.gateway = gateway;\n this.renderer = renderer;\n this.messages = messages;\n }\n\n handleChange() {\n if (!this.shouldRender()) {\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\n this.renderer.hideButtons(this.gateway.button.wrapper);\n this.messages.hideMessages();\n return;\n }\n\n this.render();\n }\n\n init() {\n document.querySelector('form.cart').addEventListener('change', this.handleChange.bind(this));\n\n if (!this.shouldRender()) {\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\n this.messages.hideMessages();\n return;\n }\n\n this.render();\n }\n\n shouldRender() {\n return document.querySelector('form.cart') !== null && !this.priceAmountIsZero();\n }\n\n priceAmount() {\n let priceText = \"0\";\n\n if (document.querySelector('form.cart ins .woocommerce-Price-amount')) {\n priceText = document.querySelector('form.cart ins .woocommerce-Price-amount').innerText;\n } else if (document.querySelector('form.cart .woocommerce-Price-amount')) {\n priceText = document.querySelector('form.cart .woocommerce-Price-amount').innerText;\n } else if (document.querySelector('.product .woocommerce-Price-amount')) {\n priceText = document.querySelector('.product .woocommerce-Price-amount').innerText;\n }\n\n priceText = priceText.replace(/,/g, '.');\n return parseFloat(priceText.replace(/([^\\d,\\.\\s]*)/g, ''));\n }\n\n priceAmountIsZero() {\n return this.priceAmount() === 0;\n }\n\n render() {\n const actionHandler = new ActionHandler_SingleProductActionHandler(this.gateway, new Helper_UpdateCart(this.gateway.ajax.change_cart.endpoint, this.gateway.ajax.change_cart.nonce), () => {\n this.renderer.showButtons(this.gateway.button.wrapper);\n this.renderer.showButtons(this.gateway.hosted_fields.wrapper);\n this.messages.renderWithAmount(this.priceAmount());\n }, () => {\n this.renderer.hideButtons(this.gateway.button.wrapper);\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\n this.messages.hideMessages();\n }, document.querySelector('form.cart'), new modules_ErrorHandler(this.gateway.labels.error.generic));\n this.renderer.render(this.gateway.button.wrapper, this.gateway.hosted_fields.wrapper, actionHandler.configuration());\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_SingleProductBootstap = (SingleProductBootstap);\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/CartBootstap.js\n\n\n\nclass CartBootstrap {\n constructor(gateway, renderer) {\n this.gateway = gateway;\n this.renderer = renderer;\n }\n\n init() {\n if (!this.shouldRender()) {\n return;\n }\n\n this.render();\n jQuery(document.body).on('updated_cart_totals updated_checkout', () => {\n this.render();\n });\n }\n\n shouldRender() {\n return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;\n }\n\n render() {\n const actionHandler = new ActionHandler_CartActionHandler(PayPalCommerceGateway, new modules_ErrorHandler(this.gateway.labels.error.generic));\n this.renderer.render(this.gateway.button.wrapper, this.gateway.hosted_fields.wrapper, actionHandler.configuration());\n }\n\n}\n\n/* harmony default export */ const CartBootstap = (CartBootstrap);\n;// CONCATENATED MODULE: ./resources/js/modules/OnApproveHandler/onApproveForPayNow.js\nconst onApproveForPayNow_onApprove = (context, errorHandler, spinner) => {\n return (data, actions) => {\n spinner.block();\n errorHandler.clear();\n return fetch(context.config.ajax.approve_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: context.config.ajax.approve_order.nonce,\n order_id: data.orderID,\n funding_source: window.ppcpFundingSource\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n spinner.unblock();\n\n if (!data.success) {\n if (data.data.code === 100) {\n errorHandler.message(data.data.message);\n } else {\n errorHandler.genericError();\n }\n\n if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {\n return actions.restart();\n }\n\n throw new Error(data.data.message);\n }\n\n document.querySelector('#place_order').click();\n });\n };\n};\n\n/* harmony default export */ const onApproveForPayNow = (onApproveForPayNow_onApprove);\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/CheckoutActionHandler.js\n\n\n\n\nclass CheckoutActionHandler {\n constructor(config, errorHandler, spinner) {\n this.config = config;\n this.errorHandler = errorHandler;\n this.spinner = spinner;\n }\n\n configuration() {\n const spinner = this.spinner;\n\n const createOrder = (data, actions) => {\n const payer = payerData();\n const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : '';\n const errorHandler = this.errorHandler;\n const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';\n const formData = new FormData(document.querySelector(formSelector)); // will not handle fields with multiple values (checkboxes, <select multiple>), but we do not care about this here\n\n const formJsonObj = Object.fromEntries(formData);\n const createaccount = jQuery('#createaccount').is(\":checked\") ? true : false;\n return fetch(this.config.ajax.create_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.create_order.nonce,\n payer,\n bn_code: bnCode,\n context: this.config.context,\n order_id: this.config.order_id,\n payment_method: getCurrentPaymentMethod(),\n funding_source: window.ppcpFundingSource,\n form: formJsonObj,\n createaccount: createaccount\n })\n }).then(function (res) {\n return res.json();\n }).then(function (data) {\n if (!data.success) {\n spinner.unblock(); //handle both messages sent from Woocommerce (data.messages) and this plugin (data.data.message)\n\n if (typeof data.messages !== 'undefined') {\n const domParser = new DOMParser();\n errorHandler.appendPreparedErrorMessageElement(domParser.parseFromString(data.messages, 'text/html').querySelector('ul'));\n } else {\n errorHandler.clear();\n\n if (data.data.details.length > 0) {\n errorHandler.message(data.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);\n } else {\n errorHandler.message(data.data.message, true);\n }\n }\n\n throw new Error(data.data.message);\n }\n\n const input = document.createElement('input');\n input.setAttribute('type', 'hidden');\n input.setAttribute('name', 'ppcp-resume-order');\n input.setAttribute('value', data.data.purchase_units[0].custom_id);\n document.querySelector(formSelector).append(input);\n return data.data.id;\n });\n };\n\n return {\n createOrder,\n onApprove: onApproveForPayNow(this, this.errorHandler, this.spinner),\n onCancel: () => {\n spinner.unblock();\n },\n onError: () => {\n this.errorHandler.genericError();\n spinner.unblock();\n }\n };\n }\n\n}\n\n/* harmony default export */ const ActionHandler_CheckoutActionHandler = (CheckoutActionHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/Hiding.js\nconst getElement = selectorOrElement => {\n if (typeof selectorOrElement === 'string') {\n return document.querySelector(selectorOrElement);\n }\n\n return selectorOrElement;\n};\n\nconst isVisible = element => {\n return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);\n};\nconst setVisible = (selectorOrElement, show, important = false) => {\n const element = getElement(selectorOrElement);\n\n if (!element) {\n return;\n }\n\n const currentValue = element.style.getPropertyValue('display');\n\n if (!show) {\n if (currentValue === 'none') {\n return;\n }\n\n element.style.setProperty('display', 'none', important ? 'important' : '');\n } else {\n if (currentValue === 'none') {\n element.style.removeProperty('display');\n } // still not visible (if something else added display: none in CSS)\n\n\n if (!isVisible(element)) {\n element.style.setProperty('display', 'block');\n }\n }\n};\nconst hide = (selectorOrElement, important = false) => {\n setVisible(selectorOrElement, false, important);\n};\nconst show = selectorOrElement => {\n setVisible(selectorOrElement, true);\n};\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/CheckoutBootstap.js\n\n\n\n\n\nclass CheckoutBootstap {\n constructor(gateway, renderer, messages, spinner) {\n this.gateway = gateway;\n this.renderer = renderer;\n this.messages = messages;\n this.spinner = spinner;\n this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;\n this.buttonChangeObserver = new MutationObserver(el => {\n this.updateUi();\n });\n }\n\n init() {\n this.render(); // Unselect saved card.\n // WC saves form values, so with our current UI it would be a bit weird\n // if the user paid with saved, then after some time tries to pay again,\n // but wants to enter a new card, and to do that they have to choose “Select payment” in the list.\n\n jQuery('#saved-credit-card').val(jQuery('#saved-credit-card option:first').val());\n jQuery(document.body).on('updated_checkout', () => {\n this.render();\n });\n jQuery(document.body).on('updated_checkout payment_method_selected', () => {\n this.updateUi();\n });\n jQuery(document).on('hosted_fields_loaded', () => {\n jQuery('#saved-credit-card').on('change', () => {\n this.updateUi();\n });\n });\n this.updateUi();\n }\n\n shouldRender() {\n if (document.querySelector(this.gateway.button.cancel_wrapper)) {\n return false;\n }\n\n return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;\n }\n\n render() {\n if (!this.shouldRender()) {\n return;\n }\n\n if (document.querySelector(this.gateway.hosted_fields.wrapper + '>div')) {\n document.querySelector(this.gateway.hosted_fields.wrapper + '>div').setAttribute('style', '');\n }\n\n const actionHandler = new ActionHandler_CheckoutActionHandler(PayPalCommerceGateway, new modules_ErrorHandler(this.gateway.labels.error.generic), this.spinner);\n this.renderer.render(this.gateway.button.wrapper, this.gateway.hosted_fields.wrapper, actionHandler.configuration());\n this.buttonChangeObserver.observe(document.querySelector(this.standardOrderButtonSelector), {\n attributes: true\n });\n }\n\n updateUi() {\n const currentPaymentMethod = getCurrentPaymentMethod();\n const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;\n const isCard = currentPaymentMethod === PaymentMethods.CARDS;\n const isSavedCard = isCard && isSavedCardSelected();\n const isNotOurGateway = !isPaypal && !isCard;\n const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;\n const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';\n setVisible(this.standardOrderButtonSelector, isPaypal && isFreeTrial && hasVaultedPaypal || isNotOurGateway || isSavedCard, true);\n setVisible('.ppcp-vaulted-paypal-details', isPaypal);\n setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));\n setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial);\n setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);\n\n if (isPaypal && !isFreeTrial) {\n this.messages.render();\n }\n\n if (isCard) {\n if (isSavedCard) {\n this.disableCreditCardFields();\n } else {\n this.enableCreditCardFields();\n }\n }\n }\n\n disableCreditCardFields() {\n jQuery('label[for=\"ppcp-credit-card-gateway-card-number\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-number').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-expiry\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-expiry').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-cvc\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-cvc').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"vault\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').attr(\"disabled\", true);\n this.renderer.disableCreditCardFields();\n }\n\n enableCreditCardFields() {\n jQuery('label[for=\"ppcp-credit-card-gateway-card-number\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-number').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-expiry\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-expiry').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-cvc\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-cvc').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"vault\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').attr(\"disabled\", false);\n this.renderer.enableCreditCardFields();\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_CheckoutBootstap = (CheckoutBootstap);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/Subscriptions.js\nconst isChangePaymentPage = () => {\n const urlParams = new URLSearchParams(window.location.search);\n return urlParams.has('change_payment_method');\n};\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/PayNowBootstrap.js\n\n\n\nclass PayNowBootstrap extends ContextBootstrap_CheckoutBootstap {\n constructor(gateway, renderer, messages, spinner) {\n super(gateway, renderer, messages, spinner);\n }\n\n updateUi() {\n if (isChangePaymentPage()) {\n return;\n }\n\n super.updateUi();\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_PayNowBootstrap = (PayNowBootstrap);\n;// CONCATENATED MODULE: ./resources/js/modules/Renderer/Renderer.js\nclass Renderer {\n constructor(creditCardRenderer, defaultConfig, onSmartButtonClick, onSmartButtonsInit) {\n this.defaultConfig = defaultConfig;\n this.creditCardRenderer = creditCardRenderer;\n this.onSmartButtonClick = onSmartButtonClick;\n this.onSmartButtonsInit = onSmartButtonsInit;\n }\n\n render(wrapper, hostedFieldsWrapper, contextConfig) {\n this.renderButtons(wrapper, contextConfig);\n this.creditCardRenderer.render(hostedFieldsWrapper, contextConfig);\n }\n\n renderButtons(wrapper, contextConfig) {\n if (!document.querySelector(wrapper) || this.isAlreadyRendered(wrapper) || 'undefined' === typeof paypal.Buttons) {\n return;\n }\n\n const style = wrapper === this.defaultConfig.button.wrapper ? this.defaultConfig.button.style : this.defaultConfig.button.mini_cart_style;\n paypal.Buttons({\n style,\n ...contextConfig,\n onClick: this.onSmartButtonClick,\n onInit: this.onSmartButtonsInit\n }).render(wrapper);\n }\n\n isAlreadyRendered(wrapper) {\n return document.querySelector(wrapper).hasChildNodes();\n }\n\n hideButtons(element) {\n const domElement = document.querySelector(element);\n\n if (!domElement) {\n return false;\n }\n\n domElement.style.display = 'none';\n return true;\n }\n\n showButtons(element) {\n const domElement = document.querySelector(element);\n\n if (!domElement) {\n return false;\n }\n\n domElement.style.display = 'block';\n return true;\n }\n\n disableCreditCardFields() {\n this.creditCardRenderer.disableFields();\n }\n\n enableCreditCardFields() {\n this.creditCardRenderer.enableFields();\n }\n\n}\n\n/* harmony default export */ const Renderer_Renderer = (Renderer);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/DccInputFactory.js\nconst dccInputFactory = original => {\n const styles = window.getComputedStyle(original);\n const newElement = document.createElement('span');\n newElement.setAttribute('id', original.id);\n newElement.setAttribute('class', original.className);\n Object.values(styles).forEach(prop => {\n if (!styles[prop] || !isNaN(prop) || prop === 'background-image') {\n return;\n }\n\n newElement.style.setProperty(prop, '' + styles[prop]);\n });\n return newElement;\n};\n\n/* harmony default export */ const DccInputFactory = (dccInputFactory);\n;// CONCATENATED MODULE: ./resources/js/modules/Renderer/CreditCardRenderer.js\n\n\n\n\nclass CreditCardRenderer {\n constructor(defaultConfig, errorHandler, spinner) {\n this.defaultConfig = defaultConfig;\n this.errorHandler = errorHandler;\n this.spinner = spinner;\n this.cardValid = false;\n this.formValid = false;\n this.currentHostedFieldsInstance = null;\n }\n\n render(wrapper, contextConfig) {\n if (this.defaultConfig.context !== 'checkout' && this.defaultConfig.context !== 'pay-now' || wrapper === null || document.querySelector(wrapper) === null) {\n return;\n }\n\n if (typeof paypal.HostedFields === 'undefined' || !paypal.HostedFields.isEligible()) {\n const wrapperElement = document.querySelector(wrapper);\n wrapperElement.parentNode.removeChild(wrapperElement);\n return;\n }\n\n const buttonSelector = wrapper + ' button';\n\n if (this.currentHostedFieldsInstance) {\n this.currentHostedFieldsInstance.teardown().catch(err => console.error(`Hosted fields teardown error: ${err}`));\n this.currentHostedFieldsInstance = null;\n }\n\n const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway');\n\n if (!gateWayBox) {\n return;\n }\n\n const oldDisplayStyle = gateWayBox.style.display;\n gateWayBox.style.display = 'block';\n const hideDccGateway = document.querySelector('#ppcp-hide-dcc');\n\n if (hideDccGateway) {\n hideDccGateway.parentNode.removeChild(hideDccGateway);\n }\n\n const cardNumberField = document.querySelector('#ppcp-credit-card-gateway-card-number');\n const stylesRaw = window.getComputedStyle(cardNumberField);\n let styles = {};\n Object.values(stylesRaw).forEach(prop => {\n if (!stylesRaw[prop]) {\n return;\n }\n\n styles[prop] = '' + stylesRaw[prop];\n });\n const cardNumber = DccInputFactory(cardNumberField);\n cardNumberField.parentNode.replaceChild(cardNumber, cardNumberField);\n const cardExpiryField = document.querySelector('#ppcp-credit-card-gateway-card-expiry');\n const cardExpiry = DccInputFactory(cardExpiryField);\n cardExpiryField.parentNode.replaceChild(cardExpiry, cardExpiryField);\n const cardCodeField = document.querySelector('#ppcp-credit-card-gateway-card-cvc');\n const cardCode = DccInputFactory(cardCodeField);\n cardCodeField.parentNode.replaceChild(cardCode, cardCodeField);\n gateWayBox.style.display = oldDisplayStyle;\n const formWrapper = '.payment_box payment_method_ppcp-credit-card-gateway';\n\n if (this.defaultConfig.enforce_vault && document.querySelector(formWrapper + ' .ppcp-credit-card-vault')) {\n document.querySelector(formWrapper + ' .ppcp-credit-card-vault').checked = true;\n document.querySelector(formWrapper + ' .ppcp-credit-card-vault').setAttribute('disabled', true);\n }\n\n paypal.HostedFields.render({\n createOrder: contextConfig.createOrder,\n styles: {\n 'input': styles\n },\n fields: {\n number: {\n selector: '#ppcp-credit-card-gateway-card-number',\n placeholder: this.defaultConfig.hosted_fields.labels.credit_card_number\n },\n cvv: {\n selector: '#ppcp-credit-card-gateway-card-cvc',\n placeholder: this.defaultConfig.hosted_fields.labels.cvv\n },\n expirationDate: {\n selector: '#ppcp-credit-card-gateway-card-expiry',\n placeholder: this.defaultConfig.hosted_fields.labels.mm_yy\n }\n }\n }).then(hostedFields => {\n document.dispatchEvent(new CustomEvent(\"hosted_fields_loaded\"));\n this.currentHostedFieldsInstance = hostedFields;\n hostedFields.on('inputSubmitRequest', () => {\n this._submit(contextConfig);\n });\n hostedFields.on('cardTypeChange', event => {\n if (!event.cards.length) {\n this.cardValid = false;\n return;\n }\n\n const validCards = this.defaultConfig.hosted_fields.valid_cards;\n this.cardValid = validCards.indexOf(event.cards[0].type) !== -1;\n\n const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);\n\n this._recreateElementClassAttribute(cardNumber, cardNumberField.className);\n\n if (event.fields.number.isValid) {\n cardNumber.classList.add(className);\n }\n });\n hostedFields.on('validityChange', event => {\n const formValid = Object.keys(event.fields).every(function (key) {\n return event.fields[key].isValid;\n });\n\n const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);\n\n event.fields.number.isValid ? cardNumber.classList.add(className) : this._recreateElementClassAttribute(cardNumber, cardNumberField.className);\n this.formValid = formValid;\n });\n show(buttonSelector);\n\n if (document.querySelector(wrapper).getAttribute('data-ppcp-subscribed') !== true) {\n document.querySelector(buttonSelector).addEventListener('click', event => {\n event.preventDefault();\n\n this._submit(contextConfig);\n });\n document.querySelector(wrapper).setAttribute('data-ppcp-subscribed', true);\n }\n });\n document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener('click', () => {\n document.querySelector('label[for=ppcp-credit-card-gateway-card-number]').click();\n });\n }\n\n disableFields() {\n if (this.currentHostedFieldsInstance) {\n this.currentHostedFieldsInstance.setAttribute({\n field: 'number',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.setAttribute({\n field: 'cvv',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.setAttribute({\n field: 'expirationDate',\n attribute: 'disabled'\n });\n }\n }\n\n enableFields() {\n if (this.currentHostedFieldsInstance) {\n this.currentHostedFieldsInstance.removeAttribute({\n field: 'number',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.removeAttribute({\n field: 'cvv',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.removeAttribute({\n field: 'expirationDate',\n attribute: 'disabled'\n });\n }\n }\n\n _submit(contextConfig) {\n this.spinner.block();\n this.errorHandler.clear();\n\n if (this.formValid && this.cardValid) {\n const save_card = this.defaultConfig.can_save_vault_token ? true : false;\n let vault = document.getElementById('ppcp-credit-card-vault') ? document.getElementById('ppcp-credit-card-vault').checked : save_card;\n\n if (this.defaultConfig.enforce_vault) {\n vault = true;\n }\n\n const contingency = this.defaultConfig.hosted_fields.contingency;\n const hostedFieldsData = {\n vault: vault\n };\n\n if (contingency !== 'NO_3D_SECURE') {\n hostedFieldsData.contingencies = [contingency];\n }\n\n if (this.defaultConfig.payer) {\n hostedFieldsData.cardholderName = this.defaultConfig.payer.name.given_name + ' ' + this.defaultConfig.payer.name.surname;\n }\n\n if (!hostedFieldsData.cardholderName) {\n const firstName = document.getElementById('billing_first_name') ? document.getElementById('billing_first_name').value : '';\n const lastName = document.getElementById('billing_last_name') ? document.getElementById('billing_last_name').value : '';\n hostedFieldsData.cardholderName = firstName + ' ' + lastName;\n }\n\n this.currentHostedFieldsInstance.submit(hostedFieldsData).then(payload => {\n payload.orderID = payload.orderId;\n this.spinner.unblock();\n return contextConfig.onApprove(payload);\n }).catch(err => {\n this.spinner.unblock();\n this.errorHandler.clear();\n\n if (err.details) {\n this.errorHandler.message(err.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);\n }\n });\n } else {\n this.spinner.unblock();\n const message = !this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid;\n this.errorHandler.message(message);\n }\n }\n\n _cardNumberFiledCLassNameByCardType(cardType) {\n return cardType === 'american-express' ? 'amex' : cardType.replace('-', '');\n }\n\n _recreateElementClassAttribute(element, newClassName) {\n element.removeAttribute('class');\n element.setAttribute('class', newClassName);\n }\n\n}\n\n/* harmony default export */ const Renderer_CreditCardRenderer = (CreditCardRenderer);\n;// CONCATENATED MODULE: ./resources/js/modules/DataClientIdAttributeHandler.js\nconst storageKey = 'ppcp-data-client-id';\n\nconst validateToken = (token, user) => {\n if (!token) {\n return false;\n }\n\n if (token.user !== user) {\n return false;\n }\n\n const currentTime = new Date().getTime();\n const isExpired = currentTime >= token.expiration * 1000;\n return !isExpired;\n};\n\nconst storedTokenForUser = user => {\n const token = JSON.parse(sessionStorage.getItem(storageKey));\n\n if (validateToken(token, user)) {\n return token.token;\n }\n\n return null;\n};\n\nconst storeToken = token => {\n sessionStorage.setItem(storageKey, JSON.stringify(token));\n};\n\nconst dataClientIdAttributeHandler = (script, config) => {\n fetch(config.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: config.nonce\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n const isValid = validateToken(data, config.user);\n\n if (!isValid) {\n return;\n }\n\n storeToken(data);\n script.setAttribute('data-client-token', data.token);\n document.body.append(script);\n });\n};\n\n/* harmony default export */ const DataClientIdAttributeHandler = (dataClientIdAttributeHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/Renderer/MessageRenderer.js\nclass MessageRenderer {\n constructor(config) {\n this.config = config;\n }\n\n render() {\n if (!this.shouldRender()) {\n return;\n }\n\n paypal.Messages({\n amount: this.config.amount,\n placement: this.config.placement,\n style: this.config.style\n }).render(this.config.wrapper);\n jQuery(document.body).on('updated_cart_totals', () => {\n paypal.Messages({\n amount: this.config.amount,\n placement: this.config.placement,\n style: this.config.style\n }).render(this.config.wrapper);\n });\n }\n\n renderWithAmount(amount) {\n if (!this.shouldRender()) {\n return;\n }\n\n const newWrapper = document.createElement('div');\n newWrapper.setAttribute('id', this.config.wrapper.replace('#', ''));\n const sibling = document.querySelector(this.config.wrapper).nextSibling;\n document.querySelector(this.config.wrapper).parentElement.removeChild(document.querySelector(this.config.wrapper));\n sibling.parentElement.insertBefore(newWrapper, sibling);\n paypal.Messages({\n amount,\n placement: this.config.placement,\n style: this.config.style\n }).render(this.config.wrapper);\n }\n\n shouldRender() {\n if (typeof paypal.Messages === 'undefined' || typeof this.config.wrapper === 'undefined') {\n return false;\n }\n\n if (!document.querySelector(this.config.wrapper)) {\n return false;\n }\n\n return true;\n }\n\n hideMessages() {\n const domElement = document.querySelector(this.config.wrapper);\n\n if (!domElement) {\n return false;\n }\n\n domElement.style.display = 'none';\n return true;\n }\n\n}\n\n/* harmony default export */ const Renderer_MessageRenderer = (MessageRenderer);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/Spinner.js\nclass Spinner {\n constructor(target = 'form.woocommerce-checkout') {\n this.target = target;\n }\n\n setTarget(target) {\n this.target = target;\n }\n\n block() {\n jQuery(this.target).block({\n message: null,\n overlayCSS: {\n background: '#fff',\n opacity: 0.6\n }\n });\n }\n\n unblock() {\n jQuery(this.target).unblock();\n }\n\n}\n\n/* harmony default export */ const Helper_Spinner = (Spinner);\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/FreeTrialHandler.js\n\n\n\nclass FreeTrialHandler {\n constructor(config, spinner, errorHandler) {\n this.config = config;\n this.spinner = spinner;\n this.errorHandler = errorHandler;\n }\n\n handle() {\n this.spinner.block();\n fetch(this.config.ajax.vault_paypal.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.vault_paypal.nonce,\n return_url: location.href\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n if (!data.success) {\n this.spinner.unblock();\n console.error(data);\n this.errorHandler.message(data.data.message);\n throw Error(data.data.message);\n }\n\n location.href = data.data.approve_link;\n }).catch(error => {\n this.spinner.unblock();\n console.error(error);\n this.errorHandler.genericError();\n });\n }\n\n}\n\n/* harmony default export */ const ActionHandler_FreeTrialHandler = (FreeTrialHandler);\n;// CONCATENATED MODULE: ./resources/js/button.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst buttonsSpinner = new Helper_Spinner('.ppc-button-wrapper');\nconst cardsSpinner = new Helper_Spinner('#ppcp-hosted-fields');\n\nconst bootstrap = () => {\n const errorHandler = new modules_ErrorHandler(PayPalCommerceGateway.labels.error.generic);\n const spinner = new Helper_Spinner();\n const creditCardRenderer = new Renderer_CreditCardRenderer(PayPalCommerceGateway, errorHandler, spinner);\n const freeTrialHandler = new ActionHandler_FreeTrialHandler(PayPalCommerceGateway, spinner, errorHandler);\n\n const onSmartButtonClick = (data, actions) => {\n window.ppcpFundingSource = data.fundingSource;\n\n if (PayPalCommerceGateway.basic_checkout_validation_enabled) {\n // TODO: quick fix to get the error about empty form before attempting PayPal order\n // it should solve #513 for most of the users, but proper solution should be implemented later.\n const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');\n requiredFields.each((i, input) => {\n jQuery(input).trigger('validate');\n });\n\n if (jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible').length) {\n errorHandler.clear();\n errorHandler.message(PayPalCommerceGateway.labels.error.js_validation);\n return actions.reject();\n }\n }\n\n const form = document.querySelector('form.woocommerce-checkout');\n\n if (form) {\n jQuery('#ppcp-funding-source-form-input').remove();\n form.insertAdjacentHTML('beforeend', `<input type=\"hidden\" name=\"ppcp-funding-source\" value=\"${data.fundingSource}\" id=\"ppcp-funding-source-form-input\">`);\n }\n\n const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;\n\n if (isFreeTrial && data.fundingSource !== 'card') {\n freeTrialHandler.handle();\n return actions.reject();\n }\n };\n\n const onSmartButtonsInit = () => {\n buttonsSpinner.unblock();\n };\n\n const renderer = new Renderer_Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit);\n const messageRenderer = new Renderer_MessageRenderer(PayPalCommerceGateway.messages);\n const context = PayPalCommerceGateway.context;\n\n if (context === 'mini-cart' || context === 'product') {\n if (PayPalCommerceGateway.mini_cart_buttons_enabled === '1') {\n const miniCartBootstrap = new ContextBootstrap_MiniCartBootstap(PayPalCommerceGateway, renderer);\n miniCartBootstrap.init();\n }\n }\n\n if (context === 'product' && PayPalCommerceGateway.single_product_buttons_enabled === '1') {\n const singleProductBootstrap = new ContextBootstrap_SingleProductBootstap(PayPalCommerceGateway, renderer, messageRenderer);\n singleProductBootstrap.init();\n }\n\n if (context === 'cart') {\n const cartBootstrap = new CartBootstap(PayPalCommerceGateway, renderer);\n cartBootstrap.init();\n }\n\n if (context === 'checkout') {\n const checkoutBootstap = new ContextBootstrap_CheckoutBootstap(PayPalCommerceGateway, renderer, messageRenderer, spinner);\n checkoutBootstap.init();\n }\n\n if (context === 'pay-now') {\n const payNowBootstrap = new ContextBootstrap_PayNowBootstrap(PayPalCommerceGateway, renderer, messageRenderer, spinner);\n payNowBootstrap.init();\n }\n\n if (context !== 'checkout') {\n messageRenderer.render();\n }\n};\n\ndocument.addEventListener('DOMContentLoaded', () => {\n if (!typeof PayPalCommerceGateway) {\n console.error('PayPal button could not be configured.');\n return;\n }\n\n if (PayPalCommerceGateway.context !== 'checkout' && PayPalCommerceGateway.data_client_id.user === 0 && PayPalCommerceGateway.data_client_id.has_subscriptions) {\n return;\n } // Sometimes PayPal script takes long time to load,\n // so we additionally hide the standard order button here to avoid failed orders.\n // Normally it is hidden later after the script load.\n\n\n const hideOrderButtonIfPpcpGateway = () => {\n // only in checkout and pay now page, otherwise it may break things (e.g. payment via product page),\n // and also the loading spinner may look weird on other pages\n if (!['checkout', 'pay-now'].includes(PayPalCommerceGateway.context) || isChangePaymentPage() || PayPalCommerceGateway.is_free_trial_cart && PayPalCommerceGateway.vaulted_paypal_email !== '') {\n return;\n }\n\n const currentPaymentMethod = getCurrentPaymentMethod();\n const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;\n const isCards = currentPaymentMethod === PaymentMethods.CARDS;\n setVisible(ORDER_BUTTON_SELECTOR, !isPaypal && !isCards, true);\n\n if (isPaypal) {\n // stopped after the first rendering of the buttons, in onInit\n buttonsSpinner.block();\n } else {\n buttonsSpinner.unblock();\n }\n\n if (isCards) {\n cardsSpinner.block();\n } else {\n cardsSpinner.unblock();\n }\n };\n\n jQuery(document).on('hosted_fields_loaded', () => {\n cardsSpinner.unblock();\n });\n let bootstrapped = false;\n hideOrderButtonIfPpcpGateway();\n jQuery(document.body).on('updated_checkout payment_method_selected', () => {\n if (bootstrapped) {\n return;\n }\n\n hideOrderButtonIfPpcpGateway();\n });\n const script = document.createElement('script');\n script.addEventListener('load', event => {\n bootstrapped = true;\n bootstrap();\n });\n script.setAttribute('src', PayPalCommerceGateway.button.url);\n Object.entries(PayPalCommerceGateway.script_attributes).forEach(keyValue => {\n script.setAttribute(keyValue[0], keyValue[1]);\n });\n\n if (PayPalCommerceGateway.data_client_id.set_attribute) {\n DataClientIdAttributeHandler(script, PayPalCommerceGateway.data_client_id);\n return;\n }\n\n document.body.append(script);\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFDSCxDQXJGTCIsInNvdXJjZXMiOlsid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9FcnJvckhhbmRsZXIuanM/ZTY1YSIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvT25BcHByb3ZlSGFuZGxlci9vbkFwcHJvdmVGb3JDb250aW51ZS5qcz9jNDU0Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvUGF5ZXJEYXRhLmpzPzJhZjEiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlLmpzPzgwYTMiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvQ2FydEFjdGlvbkhhbmRsZXIuanM/ODJjZiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9NaW5pQ2FydEJvb3RzdGFwLmpzP2Q1NTIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9VcGRhdGVDYXJ0LmpzP2U0MjIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9CdXR0b25zVG9nZ2xlTGlzdGVuZXIuanM/ZTE5MyIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvRW50aXR5L1Byb2R1Y3QuanM/OWZmZiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQWN0aW9uSGFuZGxlci9TaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlci5qcz9kOWI3Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL1NpbmdsZVByb2R1Y3RCb290c3RhcC5qcz83YzE5Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL0NhcnRCb290c3RhcC5qcz81ZTk0Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvclBheU5vdy5qcz85MzA1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9BY3Rpb25IYW5kbGVyL0NoZWNrb3V0QWN0aW9uSGFuZGxlci5qcz84NTE1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvSGlkaW5nLmpzPzFkMzYiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2hlY2tvdXRCb290c3RhcC5qcz9jODU1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvU3Vic2NyaXB0aW9ucy5qcz9iODcwIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL1BheU5vd0Jvb3RzdHJhcC5qcz9kOWY1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9SZW5kZXJlci9SZW5kZXJlci5qcz9mYTkzIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvRGNjSW5wdXRGYWN0b3J5LmpzPzJhMmYiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL1JlbmRlcmVyL0NyZWRpdENhcmRSZW5kZXJlci5qcz8zODdhIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9EYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyLmpzP2VlMGIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL1JlbmRlcmVyL01lc3NhZ2VSZW5kZXJlci5qcz9jZDAyIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvU3Bpbm5lci5qcz8xNzA4Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9BY3Rpb25IYW5kbGVyL0ZyZWVUcmlhbEhhbmRsZXIuanM/YWI3NyIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL2J1dHRvbi5qcz8wNjBmIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEVycm9ySGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3RvcihnZW5lcmljRXJyb3JUZXh0KVxuICAgIHtcbiAgICAgICAgdGhpcy5nZW5lcmljRXJyb3JUZXh0ID0gZ2VuZXJpY0Vycm9yVGV4dDtcbiAgICAgICAgdGhpcy53cmFwcGVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndvb2NvbW1lcmNlLW5vdGljZXMtd3JhcHBlcicpO1xuICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ3VsLndvb2NvbW1lcmNlLWVycm9yJyk7XG4gICAgfVxuXG4gICAgZ2VuZXJpY0Vycm9yKCkge1xuICAgICAgICBpZiAodGhpcy53cmFwcGVyLmNsYXNzTGlzdC5jb250YWlucygncHBjcC1wZXJzaXN0JykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNsZWFyKCk7XG4gICAgICAgIHRoaXMubWVzc2FnZSh0aGlzLmdlbmVyaWNFcnJvclRleHQpXG4gICAgfVxuXG4gICAgYXBwZW5kUHJlcGFyZWRFcnJvck1lc3NhZ2VFbGVtZW50KGVycm9yTWVzc2FnZUVsZW1lbnQpXG4gICAge1xuICAgICAgICBpZih0aGlzLm1lc3NhZ2VzTGlzdCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5wcmVwYXJlTWVzc2FnZXNMaXN0KCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdC5yZXBsYWNlV2l0aChlcnJvck1lc3NhZ2VFbGVtZW50KTtcbiAgICB9XG5cbiAgICBtZXNzYWdlKHRleHQsIHBlcnNpc3QgPSBmYWxzZSlcbiAgICB7XG4gICAgICAgIGlmKCEgdHlwZW9mIFN0cmluZyB8fCB0ZXh0Lmxlbmd0aCA9PT0gMCl7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0EgbmV3IG1lc3NhZ2UgdGV4dCBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZy4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKHRoaXMubWVzc2FnZXNMaXN0ID09PSBudWxsKXtcbiAgICAgICAgICAgIHRoaXMucHJlcGFyZU1lc3NhZ2VzTGlzdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBlcnNpc3QpIHtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlci5jbGFzc0xpc3QuYWRkKCdwcGNwLXBlcnNpc3QnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlci5jbGFzc0xpc3QucmVtb3ZlKCdwcGNwLXBlcnNpc3QnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBtZXNzYWdlTm9kZSA9IHRoaXMucHJlcGFyZU1lc3NhZ2VzTGlzdEl0ZW0odGV4dCk7XG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LmFwcGVuZENoaWxkKG1lc3NhZ2VOb2RlKTtcblxuICAgICAgICBqUXVlcnkuc2Nyb2xsX3RvX25vdGljZXMoalF1ZXJ5KCcud29vY29tbWVyY2Utbm90aWNlcy13cmFwcGVyJykpXG4gICAgfVxuXG4gICAgcHJlcGFyZU1lc3NhZ2VzTGlzdCgpXG4gICAge1xuICAgICAgICBpZih0aGlzLm1lc3NhZ2VzTGlzdCA9PT0gbnVsbCl7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3VsJyk7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdC5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgJ3dvb2NvbW1lcmNlLWVycm9yJyk7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdC5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYWxlcnQnKTtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlci5hcHBlbmRDaGlsZCh0aGlzLm1lc3NhZ2VzTGlzdCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcmVwYXJlTWVzc2FnZXNMaXN0SXRlbShtZXNzYWdlKVxuICAgIHtcbiAgICAgICAgY29uc3QgbGkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpO1xuICAgICAgICBsaS5pbm5lckhUTUwgPSBtZXNzYWdlO1xuXG4gICAgICAgIHJldHVybiBsaTtcbiAgICB9XG5cbiAgICBzYW5pdGl6ZSh0ZXh0KVxuICAgIHtcbiAgICAgICAgY29uc3QgdGV4dGFyZWEgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZXh0YXJlYScpO1xuICAgICAgICB0ZXh0YXJlYS5pbm5lckhUTUwgPSB0ZXh0O1xuICAgICAgICByZXR1cm4gdGV4dGFyZWEudmFsdWUucmVwbGFjZSgnRXJyb3I6ICcsICcnKTtcbiAgICB9XG5cbiAgICBjbGVhcigpXG4gICAge1xuICAgICAgICBpZiAodGhpcy5tZXNzYWdlc0xpc3QgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LmlubmVySFRNTCA9ICcnO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgRXJyb3JIYW5kbGVyO1xuIiwiY29uc3Qgb25BcHByb3ZlID0gKGNvbnRleHQsIGVycm9ySGFuZGxlcikgPT4ge1xuICAgIHJldHVybiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICByZXR1cm4gZmV0Y2goY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBub25jZTogY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgIG9yZGVyX2lkOmRhdGEub3JkZXJJRCxcbiAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oKGRhdGEpPT57XG4gICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZXN0YXJ0KCkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbG9jYXRpb24uaHJlZiA9IGNvbnRleHQuY29uZmlnLnJlZGlyZWN0O1xuICAgICAgICB9KTtcblxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgb25BcHByb3ZlO1xuIiwiZXhwb3J0IGNvbnN0IHBheWVyRGF0YSA9ICgpID0+IHtcbiAgICBjb25zdCBwYXllciA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5wYXllcjtcbiAgICBpZiAoISBwYXllcikge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBwaG9uZSA9IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19waG9uZScpIHx8IHR5cGVvZiBwYXllci5waG9uZSAhPT0gJ3VuZGVmaW5lZCcpID9cbiAgICB7XG4gICAgICAgIHBob25lX3R5cGU6XCJIT01FXCIsXG4gICAgICAgICAgICBwaG9uZV9udW1iZXI6e1xuICAgICAgICAgICAgbmF0aW9uYWxfbnVtYmVyIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3Bob25lJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcGhvbmUnKS52YWx1ZSA6IHBheWVyLnBob25lLnBob25lX251bWJlci5uYXRpb25hbF9udW1iZXJcbiAgICAgICAgfVxuICAgIH0gOiBudWxsO1xuICAgIGNvbnN0IHBheWVyRGF0YSA9IHtcbiAgICAgICAgZW1haWxfYWRkcmVzczooZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfZW1haWwnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19lbWFpbCcpLnZhbHVlIDogcGF5ZXIuZW1haWxfYWRkcmVzcyxcbiAgICAgICAgbmFtZSA6IHtcbiAgICAgICAgICAgIHN1cm5hbWU6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19sYXN0X25hbWUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19sYXN0X25hbWUnKS52YWx1ZSA6IHBheWVyLm5hbWUuc3VybmFtZSxcbiAgICAgICAgICAgIGdpdmVuX25hbWU6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19maXJzdF9uYW1lJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfZmlyc3RfbmFtZScpLnZhbHVlIDogcGF5ZXIubmFtZS5naXZlbl9uYW1lXG4gICAgICAgIH0sXG4gICAgICAgIGFkZHJlc3MgOiB7XG4gICAgICAgICAgICBjb3VudHJ5X2NvZGUgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfY291bnRyeScpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2NvdW50cnknKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuY291bnRyeV9jb2RlLFxuICAgICAgICAgICAgYWRkcmVzc19saW5lXzEgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18xJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18xJykudmFsdWUgOiBwYXllci5hZGRyZXNzLmFkZHJlc3NfbGluZV8xLFxuICAgICAgICAgICAgYWRkcmVzc19saW5lXzIgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18yJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18yJykudmFsdWUgOiBwYXllci5hZGRyZXNzLmFkZHJlc3NfbGluZV8yLFxuICAgICAgICAgICAgYWRtaW5fYXJlYV8xIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3N0YXRlJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfc3RhdGUnKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRtaW5fYXJlYV8xLFxuICAgICAgICAgICAgYWRtaW5fYXJlYV8yIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2NpdHknKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19jaXR5JykudmFsdWUgOiBwYXllci5hZGRyZXNzLmFkbWluX2FyZWFfMixcbiAgICAgICAgICAgIHBvc3RhbF9jb2RlIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3Bvc3Rjb2RlJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcG9zdGNvZGUnKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MucG9zdGFsX2NvZGVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAocGhvbmUpIHtcbiAgICAgICAgcGF5ZXJEYXRhLnBob25lID0gcGhvbmU7XG4gICAgfVxuICAgIHJldHVybiBwYXllckRhdGE7XG59XG4iLCJleHBvcnQgY29uc3QgUGF5bWVudE1ldGhvZHMgPSB7XG4gICAgUEFZUEFMOiAncHBjcC1nYXRld2F5JyxcbiAgICBDQVJEUzogJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheScsXG59O1xuXG5leHBvcnQgY29uc3QgT1JERVJfQlVUVE9OX1NFTEVDVE9SID0gJyNwbGFjZV9vcmRlcic7XG5cbmV4cG9ydCBjb25zdCBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCA9ICgpID0+IHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2lucHV0W25hbWU9XCJwYXltZW50X21ldGhvZFwiXTpjaGVja2VkJyk7XG4gICAgaWYgKCFlbCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gZWwudmFsdWU7XG59O1xuXG5leHBvcnQgY29uc3QgaXNTYXZlZENhcmRTZWxlY3RlZCA9ICgpID0+IHtcbiAgICBjb25zdCBzYXZlZENhcmRMaXN0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3NhdmVkLWNyZWRpdC1jYXJkJyk7XG4gICAgcmV0dXJuIHNhdmVkQ2FyZExpc3QgJiYgc2F2ZWRDYXJkTGlzdC52YWx1ZSAhPT0gJyc7XG59O1xuIiwiaW1wb3J0IG9uQXBwcm92ZSBmcm9tICcuLi9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvckNvbnRpbnVlLmpzJztcbmltcG9ydCB7cGF5ZXJEYXRhfSBmcm9tIFwiLi4vSGVscGVyL1BheWVyRGF0YVwiO1xuaW1wb3J0IHtQYXltZW50TWV0aG9kc30gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENhcnRBY3Rpb25IYW5kbGVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGNvbmZpZywgZXJyb3JIYW5kbGVyKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICB9XG5cbiAgICBjb25maWd1cmF0aW9uKCkge1xuICAgICAgICBjb25zdCBjcmVhdGVPcmRlciA9IChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwYXllciA9IHBheWVyRGF0YSgpO1xuICAgICAgICAgICAgY29uc3QgYm5Db2RlID0gdHlwZW9mIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdICE9PSAndW5kZWZpbmVkJyA/XG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gOiAnJztcbiAgICAgICAgICAgIHJldHVybiBmZXRjaCh0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5lbmRwb2ludCwge1xuICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICBwdXJjaGFzZV91bml0czogW10sXG4gICAgICAgICAgICAgICAgICAgIHBheW1lbnRfbWV0aG9kOiBQYXltZW50TWV0aG9kcy5QQVlQQUwsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmRpbmdfc291cmNlOiB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgIGJuX2NvZGU6Ym5Db2RlLFxuICAgICAgICAgICAgICAgICAgICBwYXllcixcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dDp0aGlzLmNvbmZpZy5jb250ZXh0XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uKHJlcykge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5kYXRhLmlkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyLFxuICAgICAgICAgICAgb25BcHByb3ZlOiBvbkFwcHJvdmUodGhpcywgdGhpcy5lcnJvckhhbmRsZXIpLFxuICAgICAgICAgICAgb25FcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDYXJ0QWN0aW9uSGFuZGxlcjtcbiIsImltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcbmltcG9ydCBDYXJ0QWN0aW9uSGFuZGxlciBmcm9tICcuLi9BY3Rpb25IYW5kbGVyL0NhcnRBY3Rpb25IYW5kbGVyJztcblxuY2xhc3MgTWluaUNhcnRCb290c3RhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIpIHtcbiAgICAgICAgdGhpcy5nYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgICAgICB0aGlzLmFjdGlvbkhhbmRsZXIgPSBudWxsO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG5cbiAgICAgICAgdGhpcy5hY3Rpb25IYW5kbGVyID0gbmV3IENhcnRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbignd2NfZnJhZ21lbnRzX2xvYWRlZCB3Y19mcmFnbWVudHNfcmVmcmVzaGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc2hvdWxkUmVuZGVyKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLm1pbmlfY2FydF93cmFwcGVyKSAhPT0gbnVsbFxuICAgICAgICAgICAgfHwgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy5taW5pX2NhcnRfd3JhcHBlcikgIT09IG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LmJ1dHRvbi5taW5pX2NhcnRfd3JhcHBlcixcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLm1pbmlfY2FydF93cmFwcGVyLFxuICAgICAgICAgICAgdGhpcy5hY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKVxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgTWluaUNhcnRCb290c3RhcDtcbiIsImltcG9ydCBQcm9kdWN0IGZyb20gXCIuLi9FbnRpdHkvUHJvZHVjdFwiO1xuY2xhc3MgVXBkYXRlQ2FydCB7XG5cbiAgICBjb25zdHJ1Y3RvcihlbmRwb2ludCwgbm9uY2UpXG4gICAge1xuICAgICAgICB0aGlzLmVuZHBvaW50ID0gZW5kcG9pbnQ7XG4gICAgICAgIHRoaXMubm9uY2UgPSBub25jZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSBvblJlc29sdmVcbiAgICAgKiBAcGFyYW0ge1Byb2R1Y3RbXX0gcHJvZHVjdHNcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn1cbiAgICAgKi9cbiAgICB1cGRhdGUob25SZXNvbHZlLCBwcm9kdWN0cylcbiAgICB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBmZXRjaChcbiAgICAgICAgICAgICAgICB0aGlzLmVuZHBvaW50LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdHMsXG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKS50aGVuKFxuICAgICAgICAgICAgICAgIChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0Lmpzb24oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApLnRoZW4oKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghIHJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChyZXN1bHQuZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVzb2x2ZWQgPSBvblJlc29sdmUocmVzdWx0LmRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHJlc29sdmVkKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFVwZGF0ZUNhcnQ7IiwiLyoqXG4gKiBXaGVuIHlvdSBjYW4ndCBhZGQgc29tZXRoaW5nIHRvIHRoZSBjYXJ0LCB0aGUgUGF5UGFsIGJ1dHRvbnMgc2hvdWxkIG5vdCBzaG93LlxuICogVGhlcmVmb3JlIHdlIGxpc3RlbiBmb3IgY2hhbmdlcyBvbiB0aGUgYWRkIHRvIGNhcnQgYnV0dG9uIGFuZCBzaG93L2hpZGUgdGhlIGJ1dHRvbnMgYWNjb3JkaW5nbHkuXG4gKi9cblxuY2xhc3MgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyIHtcbiAgICBjb25zdHJ1Y3RvcihlbGVtZW50LCBzaG93Q2FsbGJhY2ssIGhpZGVDYWxsYmFjaylcbiAgICB7XG4gICAgICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgIHRoaXMuc2hvd0NhbGxiYWNrID0gc2hvd0NhbGxiYWNrO1xuICAgICAgICB0aGlzLmhpZGVDYWxsYmFjayA9IGhpZGVDYWxsYmFjaztcbiAgICAgICAgdGhpcy5vYnNlcnZlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaW5pdCgpXG4gICAge1xuICAgICAgICBjb25zdCBjb25maWcgPSB7IGF0dHJpYnV0ZXMgOiB0cnVlIH07XG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuZWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2Rpc2FibGVkJykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhpZGVDYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuc2hvd0NhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGNhbGxiYWNrKTtcbiAgICAgICAgdGhpcy5vYnNlcnZlci5vYnNlcnZlKHRoaXMuZWxlbWVudCwgY29uZmlnKTtcbiAgICAgICAgY2FsbGJhY2soKTtcbiAgICB9XG5cbiAgICBkaXNjb25uZWN0KClcbiAgICB7XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyOyIsImNsYXNzIFByb2R1Y3Qge1xuXG4gICAgY29uc3RydWN0b3IoaWQsIHF1YW50aXR5LCB2YXJpYXRpb25zKSB7XG4gICAgICAgIHRoaXMuaWQgPSBpZDtcbiAgICAgICAgdGhpcy5xdWFudGl0eSA9IHF1YW50aXR5O1xuICAgICAgICB0aGlzLnZhcmlhdGlvbnMgPSB2YXJpYXRpb25zO1xuICAgIH1cblxuICAgIGRhdGEoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBpZDp0aGlzLmlkLFxuICAgICAgICAgICAgcXVhbnRpdHk6dGhpcy5xdWFudGl0eSxcbiAgICAgICAgICAgIHZhcmlhdGlvbnM6dGhpcy52YXJpYXRpb25zXG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFByb2R1Y3Q7IiwiaW1wb3J0IEJ1dHRvbnNUb2dnbGVMaXN0ZW5lciBmcm9tICcuLi9IZWxwZXIvQnV0dG9uc1RvZ2dsZUxpc3RlbmVyJztcbmltcG9ydCBQcm9kdWN0IGZyb20gJy4uL0VudGl0eS9Qcm9kdWN0JztcbmltcG9ydCBvbkFwcHJvdmUgZnJvbSAnLi4vT25BcHByb3ZlSGFuZGxlci9vbkFwcHJvdmVGb3JDb250aW51ZSc7XG5pbXBvcnQge3BheWVyRGF0YX0gZnJvbSBcIi4uL0hlbHBlci9QYXllckRhdGFcIjtcbmltcG9ydCB7UGF5bWVudE1ldGhvZHN9IGZyb20gXCIuLi9IZWxwZXIvQ2hlY2tvdXRNZXRob2RTdGF0ZVwiO1xuXG5jbGFzcyBTaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgY29uZmlnLFxuICAgICAgICB1cGRhdGVDYXJ0LFxuICAgICAgICBzaG93QnV0dG9uQ2FsbGJhY2ssXG4gICAgICAgIGhpZGVCdXR0b25DYWxsYmFjayxcbiAgICAgICAgZm9ybUVsZW1lbnQsXG4gICAgICAgIGVycm9ySGFuZGxlclxuICAgICkge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy51cGRhdGVDYXJ0ID0gdXBkYXRlQ2FydDtcbiAgICAgICAgdGhpcy5zaG93QnV0dG9uQ2FsbGJhY2sgPSBzaG93QnV0dG9uQ2FsbGJhY2s7XG4gICAgICAgIHRoaXMuaGlkZUJ1dHRvbkNhbGxiYWNrID0gaGlkZUJ1dHRvbkNhbGxiYWNrO1xuICAgICAgICB0aGlzLmZvcm1FbGVtZW50ID0gZm9ybUVsZW1lbnQ7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyID0gZXJyb3JIYW5kbGVyO1xuICAgIH1cblxuICAgIGNvbmZpZ3VyYXRpb24oKVxuICAgIHtcblxuICAgICAgICBpZiAoIHRoaXMuaGFzVmFyaWF0aW9ucygpICkge1xuICAgICAgICAgICAgY29uc3Qgb2JzZXJ2ZXIgPSBuZXcgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyKFxuICAgICAgICAgICAgICAgIHRoaXMuZm9ybUVsZW1lbnQucXVlcnlTZWxlY3RvcignLnNpbmdsZV9hZGRfdG9fY2FydF9idXR0b24nKSxcbiAgICAgICAgICAgICAgICB0aGlzLnNob3dCdXR0b25DYWxsYmFjayxcbiAgICAgICAgICAgICAgICB0aGlzLmhpZGVCdXR0b25DYWxsYmFja1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIG9ic2VydmVyLmluaXQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjcmVhdGVPcmRlcjogdGhpcy5jcmVhdGVPcmRlcigpLFxuICAgICAgICAgICAgb25BcHByb3ZlOiBvbkFwcHJvdmUodGhpcywgdGhpcy5lcnJvckhhbmRsZXIpLFxuICAgICAgICAgICAgb25FcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjcmVhdGVPcmRlcigpXG4gICAge1xuICAgICAgICB2YXIgZ2V0UHJvZHVjdHMgPSBudWxsO1xuICAgICAgICBpZiAoISB0aGlzLmlzR3JvdXBlZFByb2R1Y3QoKSApIHtcbiAgICAgICAgICAgIGdldFByb2R1Y3RzID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlkID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW25hbWU9XCJhZGQtdG8tY2FydFwiXScpLnZhbHVlO1xuICAgICAgICAgICAgICAgIGNvbnN0IHF0eSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ1tuYW1lPVwicXVhbnRpdHlcIl0nKS52YWx1ZTtcbiAgICAgICAgICAgICAgICBjb25zdCB2YXJpYXRpb25zID0gdGhpcy52YXJpYXRpb25zKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtuZXcgUHJvZHVjdChpZCwgcXR5LCB2YXJpYXRpb25zKV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBnZXRQcm9kdWN0cyA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcm9kdWN0cyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMuZm9ybUVsZW1lbnQucXVlcnlTZWxlY3RvckFsbCgnaW5wdXRbdHlwZT1cIm51bWJlclwiXScpLmZvckVhY2goKGVsZW1lbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEgZWxlbWVudC52YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnROYW1lID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ25hbWUnKS5tYXRjaCgvcXVhbnRpdHlcXFsoW1xcZF0qKVxcXS8pO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudE5hbWUubGVuZ3RoICE9PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaWQgPSBwYXJzZUludChlbGVtZW50TmFtZVsxXSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHF1YW50aXR5ID0gcGFyc2VJbnQoZWxlbWVudC52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIHByb2R1Y3RzLnB1c2gobmV3IFByb2R1Y3QoaWQsIHF1YW50aXR5LCBudWxsKSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICByZXR1cm4gcHJvZHVjdHM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY3JlYXRlT3JkZXIgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICAgICAgY29uc3Qgb25SZXNvbHZlID0gKHB1cmNoYXNlX3VuaXRzKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGF5ZXIgPSBwYXllckRhdGEoKTtcbiAgICAgICAgICAgICAgICBjb25zdCBibkNvZGUgPSB0eXBlb2YgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gIT09ICd1bmRlZmluZWQnID9cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gOiAnJztcbiAgICAgICAgICAgICAgICByZXR1cm4gZmV0Y2godGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5ub25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHB1cmNoYXNlX3VuaXRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcGF5ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBibl9jb2RlOmJuQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBheW1lbnRfbWV0aG9kOiBQYXltZW50TWV0aG9kcy5QQVlQQUwsXG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dDp0aGlzLmNvbmZpZy5jb250ZXh0XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgICAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRhdGEuZGF0YS5pZDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGNvbnN0IHByb21pc2UgPSB0aGlzLnVwZGF0ZUNhcnQudXBkYXRlKG9uUmVzb2x2ZSwgZ2V0UHJvZHVjdHMoKSk7XG4gICAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZU9yZGVyO1xuICAgIH1cblxuICAgIHZhcmlhdGlvbnMoKVxuICAgIHtcblxuICAgICAgICBpZiAoISB0aGlzLmhhc1ZhcmlhdGlvbnMoKSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IFsuLi50aGlzLmZvcm1FbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXCJbbmFtZV49J2F0dHJpYnV0ZV8nXVwiKV0ubWFwKFxuICAgICAgICAgICAgKGVsZW1lbnQpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOmVsZW1lbnQudmFsdWUsXG4gICAgICAgICAgICAgICAgICAgIG5hbWU6ZWxlbWVudC5uYW1lXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gYXR0cmlidXRlcztcbiAgICB9XG5cbiAgICBoYXNWYXJpYXRpb25zKClcbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1FbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygndmFyaWF0aW9uc19mb3JtJyk7XG4gICAgfVxuXG4gICAgaXNHcm91cGVkUHJvZHVjdCgpXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtRWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2dyb3VwZWRfZm9ybScpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IFNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyO1xuIiwiaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuaW1wb3J0IFVwZGF0ZUNhcnQgZnJvbSBcIi4uL0hlbHBlci9VcGRhdGVDYXJ0XCI7XG5pbXBvcnQgU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXIgZnJvbSBcIi4uL0FjdGlvbkhhbmRsZXIvU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXJcIjtcblxuY2xhc3MgU2luZ2xlUHJvZHVjdEJvb3RzdGFwIHtcbiAgICBjb25zdHJ1Y3RvcihnYXRld2F5LCByZW5kZXJlciwgbWVzc2FnZXMpIHtcbiAgICAgICAgdGhpcy5nYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgICAgICB0aGlzLm1lc3NhZ2VzID0gbWVzc2FnZXM7XG4gICAgfVxuXG5cbiAgICBoYW5kbGVDaGFuZ2UoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5oaWRlQnV0dG9ucyh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKTtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKTtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXMuaGlkZU1lc3NhZ2VzKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG5cbiAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0JykuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5oYW5kbGVDaGFuZ2UuYmluZCh0aGlzKSlcblxuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcik7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLmhpZGVNZXNzYWdlcygpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcblxuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcblxuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0JykgIT09IG51bGwgJiYgIXRoaXMucHJpY2VBbW91bnRJc1plcm8oKTtcblxuICAgIH1cblxuICAgIHByaWNlQW1vdW50KCkge1xuXG4gICAgICAgIGxldCBwcmljZVRleHQgPSBcIjBcIjtcbiAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCBpbnMgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQgaW5zIC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKS5pbm5lclRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKSkge1xuICAgICAgICAgICAgcHJpY2VUZXh0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKS5pbm5lclRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnByb2R1Y3QgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcucHJvZHVjdCAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgcHJpY2VUZXh0ID0gcHJpY2VUZXh0LnJlcGxhY2UoLywvZywgJy4nKTtcblxuICAgICAgICByZXR1cm4gIHBhcnNlRmxvYXQocHJpY2VUZXh0LnJlcGxhY2UoLyhbXlxcZCxcXC5cXHNdKikvZywgJycpKTtcbiAgICB9XG5cbiAgICBwcmljZUFtb3VudElzWmVybygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJpY2VBbW91bnQoKSA9PT0gMDtcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGNvbnN0IGFjdGlvbkhhbmRsZXIgPSBuZXcgU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXksXG4gICAgICAgICAgICBuZXcgVXBkYXRlQ2FydChcbiAgICAgICAgICAgICAgICB0aGlzLmdhdGV3YXkuYWpheC5jaGFuZ2VfY2FydC5lbmRwb2ludCxcbiAgICAgICAgICAgICAgICB0aGlzLmdhdGV3YXkuYWpheC5jaGFuZ2VfY2FydC5ub25jZSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zaG93QnV0dG9ucyh0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpO1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2hvd0J1dHRvbnModGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcik7XG4gICAgICAgICAgICAgICAgdGhpcy5tZXNzYWdlcy5yZW5kZXJXaXRoQW1vdW50KHRoaXMucHJpY2VBbW91bnQoKSlcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5oaWRlQnV0dG9ucyh0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpO1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcik7XG4gICAgICAgICAgICAgICAgdGhpcy5tZXNzYWdlcy5oaWRlTWVzc2FnZXMoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQnKSxcbiAgICAgICAgICAgIG5ldyBFcnJvckhhbmRsZXIodGhpcy5nYXRld2F5LmxhYmVscy5lcnJvci5nZW5lcmljKSxcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnJlbmRlcmVyLnJlbmRlcihcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcixcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIsXG4gICAgICAgICAgICBhY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKSxcbiAgICAgICAgKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFNpbmdsZVByb2R1Y3RCb290c3RhcDtcbiIsImltcG9ydCBDYXJ0QWN0aW9uSGFuZGxlciBmcm9tICcuLi9BY3Rpb25IYW5kbGVyL0NhcnRBY3Rpb25IYW5kbGVyJztcbmltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcblxuY2xhc3MgQ2FydEJvb3RzdHJhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIpIHtcbiAgICAgICAgdGhpcy5nYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2FydF90b3RhbHMgdXBkYXRlZF9jaGVja291dCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKSAhPT1cbiAgICAgICAgICAgIG51bGwgfHwgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKSAhPT1cbiAgICAgICAgICAgIG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBjb25zdCBhY3Rpb25IYW5kbGVyID0gbmV3IENhcnRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyLFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcixcbiAgICAgICAgICAgIGFjdGlvbkhhbmRsZXIuY29uZmlndXJhdGlvbigpLFxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ2FydEJvb3RzdHJhcDtcbiIsImNvbnN0IG9uQXBwcm92ZSA9IChjb250ZXh0LCBlcnJvckhhbmRsZXIsIHNwaW5uZXIpID0+IHtcbiAgICByZXR1cm4gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgc3Bpbm5lci5ibG9jaygpO1xuICAgICAgICBlcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICByZXR1cm4gZmV0Y2goY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBub25jZTogY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgIG9yZGVyX2lkOmRhdGEub3JkZXJJRCxcbiAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oKGRhdGEpPT57XG4gICAgICAgICAgICBzcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuZGF0YS5jb2RlID09PSAxMDApIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBhY3Rpb25zICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgYWN0aW9ucy5yZXN0YXJ0ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZXN0YXJ0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcGxhY2Vfb3JkZXInKS5jbGljaygpXG4gICAgICAgIH0pO1xuXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBvbkFwcHJvdmU7XG4iLCJpbXBvcnQgb25BcHByb3ZlIGZyb20gJy4uL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yUGF5Tm93LmpzJztcbmltcG9ydCB7cGF5ZXJEYXRhfSBmcm9tIFwiLi4vSGVscGVyL1BheWVyRGF0YVwiO1xuaW1wb3J0IHtnZXRDdXJyZW50UGF5bWVudE1ldGhvZH0gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENoZWNrb3V0QWN0aW9uSGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3Rvcihjb25maWcsIGVycm9ySGFuZGxlciwgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgICAgIHRoaXMuc3Bpbm5lciA9IHNwaW5uZXI7XG4gICAgfVxuXG4gICAgY29uZmlndXJhdGlvbigpIHtcbiAgICAgICAgY29uc3Qgc3Bpbm5lciA9IHRoaXMuc3Bpbm5lcjtcbiAgICAgICAgY29uc3QgY3JlYXRlT3JkZXIgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGF5ZXIgPSBwYXllckRhdGEoKTtcbiAgICAgICAgICAgIGNvbnN0IGJuQ29kZSA9IHR5cGVvZiB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSAhPT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdIDogJyc7XG5cbiAgICAgICAgICAgIGNvbnN0IGVycm9ySGFuZGxlciA9IHRoaXMuZXJyb3JIYW5kbGVyO1xuXG4gICAgICAgICAgICBjb25zdCBmb3JtU2VsZWN0b3IgPSB0aGlzLmNvbmZpZy5jb250ZXh0ID09PSAnY2hlY2tvdXQnID8gJ2Zvcm0uY2hlY2tvdXQnIDogJ2Zvcm0jb3JkZXJfcmV2aWV3JztcbiAgICAgICAgICAgIGNvbnN0IGZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVNlbGVjdG9yKSk7XG4gICAgICAgICAgICAvLyB3aWxsIG5vdCBoYW5kbGUgZmllbGRzIHdpdGggbXVsdGlwbGUgdmFsdWVzIChjaGVja2JveGVzLCA8c2VsZWN0IG11bHRpcGxlPiksIGJ1dCB3ZSBkbyBub3QgY2FyZSBhYm91dCB0aGlzIGhlcmVcbiAgICAgICAgICAgIGNvbnN0IGZvcm1Kc29uT2JqID0gT2JqZWN0LmZyb21FbnRyaWVzKGZvcm1EYXRhKTtcblxuICAgICAgICAgICAgY29uc3QgY3JlYXRlYWNjb3VudCA9IGpRdWVyeSgnI2NyZWF0ZWFjY291bnQnKS5pcyhcIjpjaGVja2VkXCIpID8gdHJ1ZSA6IGZhbHNlO1xuXG4gICAgICAgICAgICByZXR1cm4gZmV0Y2godGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5ub25jZSxcbiAgICAgICAgICAgICAgICAgICAgcGF5ZXIsXG4gICAgICAgICAgICAgICAgICAgIGJuX2NvZGU6Ym5Db2RlLFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0OnRoaXMuY29uZmlnLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgIG9yZGVyX2lkOnRoaXMuY29uZmlnLm9yZGVyX2lkLFxuICAgICAgICAgICAgICAgICAgICBwYXltZW50X21ldGhvZDogZ2V0Q3VycmVudFBheW1lbnRNZXRob2QoKSxcbiAgICAgICAgICAgICAgICAgICAgZnVuZGluZ19zb3VyY2U6IHdpbmRvdy5wcGNwRnVuZGluZ1NvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgZm9ybTogZm9ybUpzb25PYmosXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZWFjY291bnQ6IGNyZWF0ZWFjY291bnRcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgICAgIC8vaGFuZGxlIGJvdGggbWVzc2FnZXMgc2VudCBmcm9tIFdvb2NvbW1lcmNlIChkYXRhLm1lc3NhZ2VzKSBhbmQgdGhpcyBwbHVnaW4gKGRhdGEuZGF0YS5tZXNzYWdlKVxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mKGRhdGEubWVzc2FnZXMpICE9PSAndW5kZWZpbmVkJyApXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGRvbVBhcnNlciA9IG5ldyBET01QYXJzZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5hcHBlbmRQcmVwYXJlZEVycm9yTWVzc2FnZUVsZW1lbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9tUGFyc2VyLnBhcnNlRnJvbVN0cmluZyhkYXRhLm1lc3NhZ2VzLCAndGV4dC9odG1sJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnF1ZXJ5U2VsZWN0b3IoJ3VsJylcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIuY2xlYXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkYXRhLmRhdGEuZGV0YWlscy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLmRldGFpbHMubWFwKGQgPT4gYCR7ZC5pc3N1ZX0gJHtkLmRlc2NyaXB0aW9ufWApLmpvaW4oJzxici8+JyksIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIubWVzc2FnZShkYXRhLmRhdGEubWVzc2FnZSwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XG4gICAgICAgICAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKCd0eXBlJywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZSgnbmFtZScsICdwcGNwLXJlc3VtZS1vcmRlcicpO1xuICAgICAgICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZSgndmFsdWUnLCBkYXRhLmRhdGEucHVyY2hhc2VfdW5pdHNbMF0uY3VzdG9tX2lkKTtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1TZWxlY3RvcikuYXBwZW5kKGlucHV0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5kYXRhLmlkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyLFxuICAgICAgICAgICAgb25BcHByb3ZlOm9uQXBwcm92ZSh0aGlzLCB0aGlzLmVycm9ySGFuZGxlciwgdGhpcy5zcGlubmVyKSxcbiAgICAgICAgICAgIG9uQ2FuY2VsOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25FcnJvcjogKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIHNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDaGVja291dEFjdGlvbkhhbmRsZXI7XG4iLCJjb25zdCBnZXRFbGVtZW50ID0gKHNlbGVjdG9yT3JFbGVtZW50KSA9PiB7XG4gICAgaWYgKHR5cGVvZiBzZWxlY3Rvck9yRWxlbWVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3JPckVsZW1lbnQpO1xuICAgIH1cbiAgICByZXR1cm4gc2VsZWN0b3JPckVsZW1lbnQ7XG59XG5cbmV4cG9ydCBjb25zdCBpc1Zpc2libGUgPSAoZWxlbWVudCkgPT4ge1xuICAgIHJldHVybiAhIShlbGVtZW50Lm9mZnNldFdpZHRoIHx8IGVsZW1lbnQub2Zmc2V0SGVpZ2h0IHx8IGVsZW1lbnQuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGgpO1xufVxuXG5leHBvcnQgY29uc3Qgc2V0VmlzaWJsZSA9IChzZWxlY3Rvck9yRWxlbWVudCwgc2hvdywgaW1wb3J0YW50ID0gZmFsc2UpID0+IHtcbiAgICBjb25zdCBlbGVtZW50ID0gZ2V0RWxlbWVudChzZWxlY3Rvck9yRWxlbWVudCk7XG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50VmFsdWUgPSBlbGVtZW50LnN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ2Rpc3BsYXknKTtcblxuICAgIGlmICghc2hvdykge1xuICAgICAgICBpZiAoY3VycmVudFZhbHVlID09PSAnbm9uZScpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGVsZW1lbnQuc3R5bGUuc2V0UHJvcGVydHkoJ2Rpc3BsYXknLCAnbm9uZScsIGltcG9ydGFudCA/ICdpbXBvcnRhbnQnIDogJycpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChjdXJyZW50VmFsdWUgPT09ICdub25lJykge1xuICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgnZGlzcGxheScpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3RpbGwgbm90IHZpc2libGUgKGlmIHNvbWV0aGluZyBlbHNlIGFkZGVkIGRpc3BsYXk6IG5vbmUgaW4gQ1NTKVxuICAgICAgICBpZiAoIWlzVmlzaWJsZShlbGVtZW50KSkge1xuICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eSgnZGlzcGxheScsICdibG9jaycpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGhpZGUgPSAoc2VsZWN0b3JPckVsZW1lbnQsIGltcG9ydGFudCA9IGZhbHNlKSA9PiB7XG4gICAgc2V0VmlzaWJsZShzZWxlY3Rvck9yRWxlbWVudCwgZmFsc2UsIGltcG9ydGFudCk7XG59O1xuXG5leHBvcnQgY29uc3Qgc2hvdyA9IChzZWxlY3Rvck9yRWxlbWVudCkgPT4ge1xuICAgIHNldFZpc2libGUoc2VsZWN0b3JPckVsZW1lbnQsIHRydWUpO1xufTtcbiIsImltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcbmltcG9ydCBDaGVja291dEFjdGlvbkhhbmRsZXIgZnJvbSAnLi4vQWN0aW9uSGFuZGxlci9DaGVja291dEFjdGlvbkhhbmRsZXInO1xuaW1wb3J0IHsgc2V0VmlzaWJsZSB9IGZyb20gJy4uL0hlbHBlci9IaWRpbmcnO1xuaW1wb3J0IHtcbiAgICBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCxcbiAgICBpc1NhdmVkQ2FyZFNlbGVjdGVkLCBPUkRFUl9CVVRUT05fU0VMRUNUT1IsXG4gICAgUGF5bWVudE1ldGhvZHNcbn0gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENoZWNrb3V0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgICAgIHRoaXMubWVzc2FnZXMgPSBtZXNzYWdlcztcbiAgICAgICAgdGhpcy5zcGlubmVyID0gc3Bpbm5lcjtcblxuICAgICAgICB0aGlzLnN0YW5kYXJkT3JkZXJCdXR0b25TZWxlY3RvciA9IE9SREVSX0JVVFRPTl9TRUxFQ1RPUjtcblxuICAgICAgICB0aGlzLmJ1dHRvbkNoYW5nZU9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKGVsKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVVpKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG4gICAgICAgIHRoaXMucmVuZGVyKCk7XG5cbiAgICAgICAgLy8gVW5zZWxlY3Qgc2F2ZWQgY2FyZC5cbiAgICAgICAgLy8gV0Mgc2F2ZXMgZm9ybSB2YWx1ZXMsIHNvIHdpdGggb3VyIGN1cnJlbnQgVUkgaXQgd291bGQgYmUgYSBiaXQgd2VpcmRcbiAgICAgICAgLy8gaWYgdGhlIHVzZXIgcGFpZCB3aXRoIHNhdmVkLCB0aGVuIGFmdGVyIHNvbWUgdGltZSB0cmllcyB0byBwYXkgYWdhaW4sXG4gICAgICAgIC8vIGJ1dCB3YW50cyB0byBlbnRlciBhIG5ldyBjYXJkLCBhbmQgdG8gZG8gdGhhdCB0aGV5IGhhdmUgdG8gY2hvb3NlIOKAnFNlbGVjdCBwYXltZW504oCdIGluIHRoZSBsaXN0LlxuICAgICAgICBqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCcpLnZhbChqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCBvcHRpb246Zmlyc3QnKS52YWwoKSk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NoZWNrb3V0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKVxuICAgICAgICB9KTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2hlY2tvdXQgcGF5bWVudF9tZXRob2Rfc2VsZWN0ZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVVpKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudCkub24oJ2hvc3RlZF9maWVsZHNfbG9hZGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgalF1ZXJ5KCcjc2F2ZWQtY3JlZGl0LWNhcmQnKS5vbignY2hhbmdlJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG4gICAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5idXR0b24uY2FuY2VsX3dyYXBwZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpICE9PSBudWxsIHx8IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcikgIT09IG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyICsgJz5kaXYnKSkge1xuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyICsgJz5kaXYnKS5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJycpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFjdGlvbkhhbmRsZXIgPSBuZXcgQ2hlY2tvdXRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICAgICAgdGhpcy5zcGlubmVyXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIsXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyLFxuICAgICAgICAgICAgYWN0aW9uSGFuZGxlci5jb25maWd1cmF0aW9uKCksXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5idXR0b25DaGFuZ2VPYnNlcnZlci5vYnNlcnZlKFxuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLnN0YW5kYXJkT3JkZXJCdXR0b25TZWxlY3RvciksXG4gICAgICAgICAgICB7YXR0cmlidXRlczogdHJ1ZX1cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICB1cGRhdGVVaSgpIHtcbiAgICAgICAgY29uc3QgY3VycmVudFBheW1lbnRNZXRob2QgPSBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCgpO1xuICAgICAgICBjb25zdCBpc1BheXBhbCA9IGN1cnJlbnRQYXltZW50TWV0aG9kID09PSBQYXltZW50TWV0aG9kcy5QQVlQQUw7XG4gICAgICAgIGNvbnN0IGlzQ2FyZCA9IGN1cnJlbnRQYXltZW50TWV0aG9kID09PSBQYXltZW50TWV0aG9kcy5DQVJEUztcbiAgICAgICAgY29uc3QgaXNTYXZlZENhcmQgPSBpc0NhcmQgJiYgaXNTYXZlZENhcmRTZWxlY3RlZCgpO1xuICAgICAgICBjb25zdCBpc05vdE91ckdhdGV3YXkgPSAhaXNQYXlwYWwgJiYgIWlzQ2FyZDtcbiAgICAgICAgY29uc3QgaXNGcmVlVHJpYWwgPSBQYXlQYWxDb21tZXJjZUdhdGV3YXkuaXNfZnJlZV90cmlhbF9jYXJ0O1xuICAgICAgICBjb25zdCBoYXNWYXVsdGVkUGF5cGFsID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LnZhdWx0ZWRfcGF5cGFsX2VtYWlsICE9PSAnJztcblxuICAgICAgICBzZXRWaXNpYmxlKHRoaXMuc3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yLCAgKGlzUGF5cGFsICYmIGlzRnJlZVRyaWFsICYmIGhhc1ZhdWx0ZWRQYXlwYWwpIHx8IGlzTm90T3VyR2F0ZXdheSB8fCBpc1NhdmVkQ2FyZCwgdHJ1ZSk7XG4gICAgICAgIHNldFZpc2libGUoJy5wcGNwLXZhdWx0ZWQtcGF5cGFsLWRldGFpbHMnLCBpc1BheXBhbCk7XG4gICAgICAgIHNldFZpc2libGUodGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyLCBpc1BheXBhbCAmJiAhKGlzRnJlZVRyaWFsICYmIGhhc1ZhdWx0ZWRQYXlwYWwpKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkubWVzc2FnZXMud3JhcHBlciwgaXNQYXlwYWwgJiYgIWlzRnJlZVRyaWFsKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyLCBpc0NhcmQgJiYgIWlzU2F2ZWRDYXJkKTtcblxuICAgICAgICBpZiAoaXNQYXlwYWwgJiYgIWlzRnJlZVRyaWFsKSB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnJlbmRlcigpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQ2FyZCkge1xuICAgICAgICAgICAgaWYgKGlzU2F2ZWRDYXJkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGRpc2FibGVDcmVkaXRDYXJkRmllbGRzKCkge1xuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlclwiXScpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5XCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5JykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmNcIl0nKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInZhdWx0XCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5hdHRyKFwiZGlzYWJsZWRcIiwgdHJ1ZSlcbiAgICAgICAgdGhpcy5yZW5kZXJlci5kaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpXG4gICAgfVxuXG4gICAgZW5hYmxlQ3JlZGl0Q2FyZEZpZWxkcygpIHtcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXJcIl0nKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXInKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeVwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjXCJdJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJ2YXVsdFwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuYXR0cihcImRpc2FibGVkXCIsIGZhbHNlKVxuICAgICAgICB0aGlzLnJlbmRlcmVyLmVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKVxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ2hlY2tvdXRCb290c3RhcFxuIiwiZXhwb3J0IGNvbnN0IGlzQ2hhbmdlUGF5bWVudFBhZ2UgPSAoKSA9PiB7XG4gICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKVxuICAgIHJldHVybiB1cmxQYXJhbXMuaGFzKCdjaGFuZ2VfcGF5bWVudF9tZXRob2QnKTtcbn1cbiIsImltcG9ydCBDaGVja291dEJvb3RzdGFwIGZyb20gJy4vQ2hlY2tvdXRCb290c3RhcCdcbmltcG9ydCB7aXNDaGFuZ2VQYXltZW50UGFnZX0gZnJvbSBcIi4uL0hlbHBlci9TdWJzY3JpcHRpb25zXCI7XG5cbmNsYXNzIFBheU5vd0Jvb3RzdHJhcCBleHRlbmRzIENoZWNrb3V0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcikge1xuICAgICAgICBzdXBlcihnYXRld2F5LCByZW5kZXJlciwgbWVzc2FnZXMsIHNwaW5uZXIpXG4gICAgfVxuXG4gICAgdXBkYXRlVWkoKSB7XG4gICAgICAgIGlmIChpc0NoYW5nZVBheW1lbnRQYWdlKCkpIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgc3VwZXIudXBkYXRlVWkoKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFBheU5vd0Jvb3RzdHJhcDtcbiIsImNsYXNzIFJlbmRlcmVyIHtcbiAgICBjb25zdHJ1Y3RvcihjcmVkaXRDYXJkUmVuZGVyZXIsIGRlZmF1bHRDb25maWcsIG9uU21hcnRCdXR0b25DbGljaywgb25TbWFydEJ1dHRvbnNJbml0KSB7XG4gICAgICAgIHRoaXMuZGVmYXVsdENvbmZpZyA9IGRlZmF1bHRDb25maWc7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyID0gY3JlZGl0Q2FyZFJlbmRlcmVyO1xuICAgICAgICB0aGlzLm9uU21hcnRCdXR0b25DbGljayA9IG9uU21hcnRCdXR0b25DbGljaztcbiAgICAgICAgdGhpcy5vblNtYXJ0QnV0dG9uc0luaXQgPSBvblNtYXJ0QnV0dG9uc0luaXQ7XG4gICAgfVxuXG4gICAgcmVuZGVyKHdyYXBwZXIsIGhvc3RlZEZpZWxkc1dyYXBwZXIsIGNvbnRleHRDb25maWcpIHtcblxuICAgICAgICB0aGlzLnJlbmRlckJ1dHRvbnMod3JhcHBlciwgY29udGV4dENvbmZpZyk7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyLnJlbmRlcihob3N0ZWRGaWVsZHNXcmFwcGVyLCBjb250ZXh0Q29uZmlnKTtcbiAgICB9XG5cbiAgICByZW5kZXJCdXR0b25zKHdyYXBwZXIsIGNvbnRleHRDb25maWcpIHtcbiAgICAgICAgaWYgKCEgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKSB8fCB0aGlzLmlzQWxyZWFkeVJlbmRlcmVkKHdyYXBwZXIpIHx8ICd1bmRlZmluZWQnID09PSB0eXBlb2YgcGF5cGFsLkJ1dHRvbnMgKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzdHlsZSA9IHdyYXBwZXIgPT09IHRoaXMuZGVmYXVsdENvbmZpZy5idXR0b24ud3JhcHBlciA/IHRoaXMuZGVmYXVsdENvbmZpZy5idXR0b24uc3R5bGUgOiB0aGlzLmRlZmF1bHRDb25maWcuYnV0dG9uLm1pbmlfY2FydF9zdHlsZTtcbiAgICAgICAgcGF5cGFsLkJ1dHRvbnMoe1xuICAgICAgICAgICAgc3R5bGUsXG4gICAgICAgICAgICAuLi5jb250ZXh0Q29uZmlnLFxuICAgICAgICAgICAgb25DbGljazogdGhpcy5vblNtYXJ0QnV0dG9uQ2xpY2ssXG4gICAgICAgICAgICBvbkluaXQ6IHRoaXMub25TbWFydEJ1dHRvbnNJbml0LFxuICAgICAgICB9KS5yZW5kZXIod3JhcHBlcik7XG4gICAgfVxuXG4gICAgaXNBbHJlYWR5UmVuZGVyZWQod3JhcHBlcikge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKS5oYXNDaGlsZE5vZGVzKCk7XG4gICAgfVxuXG4gICAgaGlkZUJ1dHRvbnMoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBkb21FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihlbGVtZW50KTtcbiAgICAgICAgaWYgKCEgZG9tRWxlbWVudCApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBkb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHNob3dCdXR0b25zKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZG9tRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZWxlbWVudCk7XG4gICAgICAgIGlmICghIGRvbUVsZW1lbnQgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZG9tRWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgZGlzYWJsZUNyZWRpdENhcmRGaWVsZHMoKSB7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyLmRpc2FibGVGaWVsZHMoKTtcbiAgICB9XG5cbiAgICBlbmFibGVDcmVkaXRDYXJkRmllbGRzKCkge1xuICAgICAgICB0aGlzLmNyZWRpdENhcmRSZW5kZXJlci5lbmFibGVGaWVsZHMoKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFJlbmRlcmVyO1xuIiwiY29uc3QgZGNjSW5wdXRGYWN0b3J5ID0gKG9yaWdpbmFsKSA9PiB7XG4gICAgY29uc3Qgc3R5bGVzID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUob3JpZ2luYWwpO1xuICAgIGNvbnN0IG5ld0VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG5cbiAgICBuZXdFbGVtZW50LnNldEF0dHJpYnV0ZSgnaWQnLCBvcmlnaW5hbC5pZCk7XG4gICAgbmV3RWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgb3JpZ2luYWwuY2xhc3NOYW1lKTtcblxuICAgIE9iamVjdC52YWx1ZXMoc3R5bGVzKS5mb3JFYWNoKCAocHJvcCkgPT4ge1xuICAgICAgICBpZiAoISBzdHlsZXNbcHJvcF0gfHwgISBpc05hTihwcm9wKSB8fCBwcm9wID09PSAnYmFja2dyb3VuZC1pbWFnZScgKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgbmV3RWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eShwcm9wLCcnICsgc3R5bGVzW3Byb3BdKTtcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3RWxlbWVudDtcbn1cblxuZXhwb3J0IGRlZmF1bHQgZGNjSW5wdXRGYWN0b3J5O1xuIiwiaW1wb3J0IGRjY0lucHV0RmFjdG9yeSBmcm9tIFwiLi4vSGVscGVyL0RjY0lucHV0RmFjdG9yeVwiO1xuaW1wb3J0IHtzaG93fSBmcm9tIFwiLi4vSGVscGVyL0hpZGluZ1wiO1xuaW1wb3J0IFByb2R1Y3QgZnJvbSBcIi4uL0VudGl0eS9Qcm9kdWN0XCI7XG5cbmNsYXNzIENyZWRpdENhcmRSZW5kZXJlciB7XG5cbiAgICBjb25zdHJ1Y3RvcihkZWZhdWx0Q29uZmlnLCBlcnJvckhhbmRsZXIsIHNwaW5uZXIpIHtcbiAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnID0gZGVmYXVsdENvbmZpZztcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgICAgIHRoaXMuc3Bpbm5lciA9IHNwaW5uZXI7XG4gICAgICAgIHRoaXMuY2FyZFZhbGlkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZm9ybVZhbGlkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlID0gbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIod3JhcHBlciwgY29udGV4dENvbmZpZykge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICAoXG4gICAgICAgICAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnLmNvbnRleHQgIT09ICdjaGVja291dCdcbiAgICAgICAgICAgICAgICAmJiB0aGlzLmRlZmF1bHRDb25maWcuY29udGV4dCAhPT0gJ3BheS1ub3cnXG4gICAgICAgICAgICApXG4gICAgICAgICAgICB8fCB3cmFwcGVyID09PSBudWxsXG4gICAgICAgICAgICB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpID09PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHR5cGVvZiBwYXlwYWwuSG9zdGVkRmllbGRzID09PSAndW5kZWZpbmVkJ1xuICAgICAgICAgICAgfHwgISBwYXlwYWwuSG9zdGVkRmllbGRzLmlzRWxpZ2libGUoKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIGNvbnN0IHdyYXBwZXJFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKTtcbiAgICAgICAgICAgIHdyYXBwZXJFbGVtZW50LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQod3JhcHBlckVsZW1lbnQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYnV0dG9uU2VsZWN0b3IgPSB3cmFwcGVyICsgJyBidXR0b24nO1xuXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UudGVhcmRvd24oKVxuICAgICAgICAgICAgICAgIC5jYXRjaChlcnIgPT4gY29uc29sZS5lcnJvcihgSG9zdGVkIGZpZWxkcyB0ZWFyZG93biBlcnJvcjogJHtlcnJ9YCkpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZ2F0ZVdheUJveCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5wYXltZW50X2JveC5wYXltZW50X21ldGhvZF9wcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXknKTtcbiAgICAgICAgaWYoISBnYXRlV2F5Qm94KSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBjb25zdCBvbGREaXNwbGF5U3R5bGUgPSBnYXRlV2F5Qm94LnN0eWxlLmRpc3BsYXk7XG4gICAgICAgIGdhdGVXYXlCb3guc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG5cbiAgICAgICAgY29uc3QgaGlkZURjY0dhdGV3YXkgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcHBjcC1oaWRlLWRjYycpO1xuICAgICAgICBpZiAoaGlkZURjY0dhdGV3YXkpIHtcbiAgICAgICAgICAgIGhpZGVEY2NHYXRld2F5LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoaGlkZURjY0dhdGV3YXkpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2FyZE51bWJlckZpZWxkID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicpO1xuXG4gICAgICAgIGNvbnN0IHN0eWxlc1JhdyA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGNhcmROdW1iZXJGaWVsZCk7XG4gICAgICAgIGxldCBzdHlsZXMgPSB7fTtcbiAgICAgICAgT2JqZWN0LnZhbHVlcyhzdHlsZXNSYXcpLmZvckVhY2goIChwcm9wKSA9PiB7XG4gICAgICAgICAgICBpZiAoISBzdHlsZXNSYXdbcHJvcF0pIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzdHlsZXNbcHJvcF0gPSAnJyArIHN0eWxlc1Jhd1twcm9wXTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY2FyZE51bWJlciA9IGRjY0lucHV0RmFjdG9yeShjYXJkTnVtYmVyRmllbGQpO1xuICAgICAgICBjYXJkTnVtYmVyRmllbGQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoY2FyZE51bWJlciwgY2FyZE51bWJlckZpZWxkKTtcblxuICAgICAgICBjb25zdCBjYXJkRXhwaXJ5RmllbGQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5Jyk7XG4gICAgICAgIGNvbnN0IGNhcmRFeHBpcnkgPSBkY2NJbnB1dEZhY3RvcnkoY2FyZEV4cGlyeUZpZWxkKTtcbiAgICAgICAgY2FyZEV4cGlyeUZpZWxkLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGNhcmRFeHBpcnksIGNhcmRFeHBpcnlGaWVsZCk7XG5cbiAgICAgICAgY29uc3QgY2FyZENvZGVGaWVsZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnKTtcbiAgICAgICAgY29uc3QgY2FyZENvZGUgPSBkY2NJbnB1dEZhY3RvcnkoY2FyZENvZGVGaWVsZCk7XG4gICAgICAgIGNhcmRDb2RlRmllbGQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoY2FyZENvZGUsIGNhcmRDb2RlRmllbGQpO1xuXG4gICAgICAgIGdhdGVXYXlCb3guc3R5bGUuZGlzcGxheSA9IG9sZERpc3BsYXlTdHlsZTtcblxuICAgICAgICBjb25zdCBmb3JtV3JhcHBlciA9ICcucGF5bWVudF9ib3ggcGF5bWVudF9tZXRob2RfcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5JztcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnLmVuZm9yY2VfdmF1bHRcbiAgICAgICAgICAgICYmIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVdyYXBwZXIgKyAnIC5wcGNwLWNyZWRpdC1jYXJkLXZhdWx0JylcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1XcmFwcGVyICsgJyAucHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmNoZWNrZWQgPSB0cnVlO1xuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihmb3JtV3JhcHBlciArICcgLnBwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5zZXRBdHRyaWJ1dGUoJ2Rpc2FibGVkJywgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcGF5cGFsLkhvc3RlZEZpZWxkcy5yZW5kZXIoe1xuICAgICAgICAgICAgY3JlYXRlT3JkZXI6IGNvbnRleHRDb25maWcuY3JlYXRlT3JkZXIsXG4gICAgICAgICAgICBzdHlsZXM6IHtcbiAgICAgICAgICAgICAgICAnaW5wdXQnOiBzdHlsZXNcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmaWVsZHM6IHtcbiAgICAgICAgICAgICAgICBudW1iZXI6IHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0b3I6ICcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtbnVtYmVyJyxcbiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI6IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5jcmVkaXRfY2FyZF9udW1iZXIsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBjdnY6IHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0b3I6ICcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjJyxcbiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI6IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5jdnYsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBleHBpcmF0aW9uRGF0ZToge1xuICAgICAgICAgICAgICAgICAgICBzZWxlY3RvcjogJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1leHBpcnknLFxuICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcjogdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLm1tX3l5LFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihob3N0ZWRGaWVsZHMgPT4ge1xuICAgICAgICAgICAgZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJob3N0ZWRfZmllbGRzX2xvYWRlZFwiKSk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSA9IGhvc3RlZEZpZWxkcztcblxuICAgICAgICAgICAgaG9zdGVkRmllbGRzLm9uKCdpbnB1dFN1Ym1pdFJlcXVlc3QnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fc3VibWl0KGNvbnRleHRDb25maWcpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBob3N0ZWRGaWVsZHMub24oJ2NhcmRUeXBlQ2hhbmdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCAhIGV2ZW50LmNhcmRzLmxlbmd0aCApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYXJkVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCB2YWxpZENhcmRzID0gdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMudmFsaWRfY2FyZHM7XG4gICAgICAgICAgICAgICAgdGhpcy5jYXJkVmFsaWQgPSB2YWxpZENhcmRzLmluZGV4T2YoZXZlbnQuY2FyZHNbMF0udHlwZSkgIT09IC0xO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgY2xhc3NOYW1lID0gdGhpcy5fY2FyZE51bWJlckZpbGVkQ0xhc3NOYW1lQnlDYXJkVHlwZShldmVudC5jYXJkc1swXS50eXBlKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9yZWNyZWF0ZUVsZW1lbnRDbGFzc0F0dHJpYnV0ZShjYXJkTnVtYmVyLCBjYXJkTnVtYmVyRmllbGQuY2xhc3NOYW1lKTtcbiAgICAgICAgICAgICAgICBpZiAoZXZlbnQuZmllbGRzLm51bWJlci5pc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhcmROdW1iZXIuY2xhc3NMaXN0LmFkZChjbGFzc05hbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICBob3N0ZWRGaWVsZHMub24oJ3ZhbGlkaXR5Q2hhbmdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZm9ybVZhbGlkID0gT2JqZWN0LmtleXMoZXZlbnQuZmllbGRzKS5ldmVyeShmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBldmVudC5maWVsZHNba2V5XS5pc1ZhbGlkO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgY2xhc3NOYW1lID0gdGhpcy5fY2FyZE51bWJlckZpbGVkQ0xhc3NOYW1lQnlDYXJkVHlwZShldmVudC5jYXJkc1swXS50eXBlKTtcbiAgICAgICAgICAgICAgICBldmVudC5maWVsZHMubnVtYmVyLmlzVmFsaWRcbiAgICAgICAgICAgICAgICAgICAgPyBjYXJkTnVtYmVyLmNsYXNzTGlzdC5hZGQoY2xhc3NOYW1lKVxuICAgICAgICAgICAgICAgICAgICA6IHRoaXMuX3JlY3JlYXRlRWxlbWVudENsYXNzQXR0cmlidXRlKGNhcmROdW1iZXIsIGNhcmROdW1iZXJGaWVsZC5jbGFzc05hbWUpO1xuXG4gICAgICAgICAgICAgICB0aGlzLmZvcm1WYWxpZCA9IGZvcm1WYWxpZDtcblxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHNob3coYnV0dG9uU2VsZWN0b3IpO1xuXG4gICAgICAgICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcHBjcC1zdWJzY3JpYmVkJykgIT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGJ1dHRvblNlbGVjdG9yKS5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICAgICAgICAnY2xpY2snLFxuICAgICAgICAgICAgICAgICAgICBldmVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fc3VibWl0KGNvbnRleHRDb25maWcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iod3JhcHBlcikuc2V0QXR0cmlidXRlKCdkYXRhLXBwY3Atc3Vic2NyaWJlZCcsIHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcGF5bWVudF9tZXRob2RfcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5JykuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgICAgICdjbGljaycsXG4gICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignbGFiZWxbZm9yPXBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcl0nKS5jbGljaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICApXG4gICAgfVxuXG4gICAgZGlzYWJsZUZpZWxkcygpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zZXRBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnbnVtYmVyJyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zZXRBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnY3Z2JyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zZXRBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnZXhwaXJhdGlvbkRhdGUnLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGVuYWJsZUZpZWxkcygpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5yZW1vdmVBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnbnVtYmVyJyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5yZW1vdmVBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnY3Z2JyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5yZW1vdmVBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnZXhwaXJhdGlvbkRhdGUnLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9zdWJtaXQoY29udGV4dENvbmZpZykge1xuICAgICAgICB0aGlzLnNwaW5uZXIuYmxvY2soKTtcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICBpZiAodGhpcy5mb3JtVmFsaWQgJiYgdGhpcy5jYXJkVmFsaWQpIHtcbiAgICAgICAgICAgIGNvbnN0IHNhdmVfY2FyZCA9IHRoaXMuZGVmYXVsdENvbmZpZy5jYW5fc2F2ZV92YXVsdF90b2tlbiA/IHRydWUgOiBmYWxzZTtcbiAgICAgICAgICAgIGxldCB2YXVsdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykgP1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuY2hlY2tlZCA6IHNhdmVfY2FyZDtcbiAgICAgICAgICAgIGlmICh0aGlzLmRlZmF1bHRDb25maWcuZW5mb3JjZV92YXVsdCkge1xuICAgICAgICAgICAgICAgIHZhdWx0ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGNvbnRpbmdlbmN5ID0gdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMuY29udGluZ2VuY3k7XG4gICAgICAgICAgICBjb25zdCBob3N0ZWRGaWVsZHNEYXRhID0ge1xuICAgICAgICAgICAgICAgIHZhdWx0OiB2YXVsdFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChjb250aW5nZW5jeSAhPT0gJ05PXzNEX1NFQ1VSRScpIHtcbiAgICAgICAgICAgICAgICBob3N0ZWRGaWVsZHNEYXRhLmNvbnRpbmdlbmNpZXMgPSBbY29udGluZ2VuY3ldO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5kZWZhdWx0Q29uZmlnLnBheWVyKSB7XG4gICAgICAgICAgICAgICAgaG9zdGVkRmllbGRzRGF0YS5jYXJkaG9sZGVyTmFtZSA9IHRoaXMuZGVmYXVsdENvbmZpZy5wYXllci5uYW1lLmdpdmVuX25hbWUgKyAnICcgKyB0aGlzLmRlZmF1bHRDb25maWcucGF5ZXIubmFtZS5zdXJuYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFob3N0ZWRGaWVsZHNEYXRhLmNhcmRob2xkZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlyc3ROYW1lID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JpbGxpbmdfZmlyc3RfbmFtZScpID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JpbGxpbmdfZmlyc3RfbmFtZScpLnZhbHVlIDogJyc7XG4gICAgICAgICAgICAgICAgY29uc3QgbGFzdE5hbWUgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYmlsbGluZ19sYXN0X25hbWUnKSA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdiaWxsaW5nX2xhc3RfbmFtZScpLnZhbHVlIDogJyc7XG5cbiAgICAgICAgICAgICAgICBob3N0ZWRGaWVsZHNEYXRhLmNhcmRob2xkZXJOYW1lID0gZmlyc3ROYW1lICsgJyAnICsgbGFzdE5hbWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnN1Ym1pdChob3N0ZWRGaWVsZHNEYXRhKS50aGVuKChwYXlsb2FkKSA9PiB7XG4gICAgICAgICAgICAgICAgcGF5bG9hZC5vcmRlcklEID0gcGF5bG9hZC5vcmRlcklkO1xuICAgICAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHRDb25maWcub25BcHByb3ZlKHBheWxvYWQpO1xuICAgICAgICAgICAgfSkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmNsZWFyKCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoZXJyLmRldGFpbHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIubWVzc2FnZShlcnIuZGV0YWlscy5tYXAoZCA9PiBgJHtkLmlzc3VlfSAke2QuZGVzY3JpcHRpb259YCkuam9pbignPGJyLz4nKSwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgY29uc3QgbWVzc2FnZSA9ICEgdGhpcy5jYXJkVmFsaWQgPyB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5sYWJlbHMuY2FyZF9ub3Rfc3VwcG9ydGVkIDogdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLmZpZWxkc19ub3RfdmFsaWQ7XG4gICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5tZXNzYWdlKG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX2NhcmROdW1iZXJGaWxlZENMYXNzTmFtZUJ5Q2FyZFR5cGUoY2FyZFR5cGUpIHtcbiAgICAgICAgcmV0dXJuIGNhcmRUeXBlID09PSAnYW1lcmljYW4tZXhwcmVzcycgPyAnYW1leCcgOiBjYXJkVHlwZS5yZXBsYWNlKCctJywgJycpO1xuICAgIH1cblxuICAgIF9yZWNyZWF0ZUVsZW1lbnRDbGFzc0F0dHJpYnV0ZShlbGVtZW50LCBuZXdDbGFzc05hbWUpIHtcbiAgICAgICAgZWxlbWVudC5yZW1vdmVBdHRyaWJ1dGUoJ2NsYXNzJylcbiAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgbmV3Q2xhc3NOYW1lKTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBDcmVkaXRDYXJkUmVuZGVyZXI7XG4iLCJjb25zdCBzdG9yYWdlS2V5ID0gJ3BwY3AtZGF0YS1jbGllbnQtaWQnO1xuXG5jb25zdCB2YWxpZGF0ZVRva2VuID0gKHRva2VuLCB1c2VyKSA9PiB7XG4gICAgaWYgKCEgdG9rZW4pIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAodG9rZW4udXNlciAhPT0gdXNlcikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGN1cnJlbnRUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgY29uc3QgaXNFeHBpcmVkID0gY3VycmVudFRpbWUgPj0gdG9rZW4uZXhwaXJhdGlvbiAqIDEwMDA7XG4gICAgcmV0dXJuICEgaXNFeHBpcmVkO1xufVxuXG5jb25zdCBzdG9yZWRUb2tlbkZvclVzZXIgPSAodXNlcikgPT4ge1xuICAgIGNvbnN0IHRva2VuID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmFnZS5nZXRJdGVtKHN0b3JhZ2VLZXkpKTtcbiAgICBpZiAodmFsaWRhdGVUb2tlbih0b2tlbiwgdXNlcikpIHtcbiAgICAgICAgcmV0dXJuIHRva2VuLnRva2VuO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuY29uc3Qgc3RvcmVUb2tlbiA9ICh0b2tlbikgPT4ge1xuICAgIHNlc3Npb25TdG9yYWdlLnNldEl0ZW0oc3RvcmFnZUtleSwgSlNPTi5zdHJpbmdpZnkodG9rZW4pKTtcbn1cblxuY29uc3QgZGF0YUNsaWVudElkQXR0cmlidXRlSGFuZGxlciA9IChzY3JpcHQsIGNvbmZpZykgPT4ge1xuICAgIGZldGNoKGNvbmZpZy5lbmRwb2ludCwge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgbm9uY2U6IGNvbmZpZy5ub25jZVxuICAgICAgICB9KVxuICAgIH0pLnRoZW4oKHJlcyk9PntcbiAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgfSkudGhlbigoZGF0YSk9PntcbiAgICAgICAgY29uc3QgaXNWYWxpZCA9IHZhbGlkYXRlVG9rZW4oZGF0YSwgY29uZmlnLnVzZXIpO1xuICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzdG9yZVRva2VuKGRhdGEpO1xuICAgICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKCdkYXRhLWNsaWVudC10b2tlbicsIGRhdGEudG9rZW4pO1xuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZChzY3JpcHQpO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyO1xuIiwiY2xhc3MgTWVzc2FnZVJlbmRlcmVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGNvbmZpZykge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGlmICghIHRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHBheXBhbC5NZXNzYWdlcyh7XG4gICAgICAgICAgICBhbW91bnQ6IHRoaXMuY29uZmlnLmFtb3VudCxcbiAgICAgICAgICAgIHBsYWNlbWVudDogdGhpcy5jb25maWcucGxhY2VtZW50LFxuICAgICAgICAgICAgc3R5bGU6IHRoaXMuY29uZmlnLnN0eWxlXG4gICAgICAgIH0pLnJlbmRlcih0aGlzLmNvbmZpZy53cmFwcGVyKTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2FydF90b3RhbHMnLCAoKSA9PiB7XG4gICAgICAgICAgICBwYXlwYWwuTWVzc2FnZXMoe1xuICAgICAgICAgICAgICAgIGFtb3VudDogdGhpcy5jb25maWcuYW1vdW50LFxuICAgICAgICAgICAgICAgIHBsYWNlbWVudDogdGhpcy5jb25maWcucGxhY2VtZW50LFxuICAgICAgICAgICAgICAgIHN0eWxlOiB0aGlzLmNvbmZpZy5zdHlsZVxuICAgICAgICAgICAgfSkucmVuZGVyKHRoaXMuY29uZmlnLndyYXBwZXIpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZW5kZXJXaXRoQW1vdW50KGFtb3VudCkge1xuXG4gICAgICAgIGlmICghIHRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5ld1dyYXBwZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgbmV3V3JhcHBlci5zZXRBdHRyaWJ1dGUoJ2lkJywgdGhpcy5jb25maWcud3JhcHBlci5yZXBsYWNlKCcjJywgJycpKTtcblxuICAgICAgICBjb25zdCBzaWJsaW5nID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKS5uZXh0U2libGluZztcbiAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKS5wYXJlbnRFbGVtZW50LnJlbW92ZUNoaWxkKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5jb25maWcud3JhcHBlcikpO1xuICAgICAgICBzaWJsaW5nLnBhcmVudEVsZW1lbnQuaW5zZXJ0QmVmb3JlKG5ld1dyYXBwZXIsIHNpYmxpbmcpO1xuICAgICAgICBwYXlwYWwuTWVzc2FnZXMoe1xuICAgICAgICAgICAgYW1vdW50LFxuICAgICAgICAgICAgcGxhY2VtZW50OiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQsXG4gICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuc3R5bGVcbiAgICAgICAgfSkucmVuZGVyKHRoaXMuY29uZmlnLndyYXBwZXIpO1xuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcblxuICAgICAgICBpZiAodHlwZW9mIHBheXBhbC5NZXNzYWdlcyA9PT0gJ3VuZGVmaW5lZCcgfHwgdHlwZW9mIHRoaXMuY29uZmlnLndyYXBwZXIgPT09ICd1bmRlZmluZWQnICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5jb25maWcud3JhcHBlcikpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBoaWRlTWVzc2FnZXMoKSB7XG4gICAgICAgIGNvbnN0IGRvbUVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpO1xuICAgICAgICBpZiAoISBkb21FbGVtZW50ICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGRvbUVsZW1lbnQuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgTWVzc2FnZVJlbmRlcmVyO1xuIiwiY2xhc3MgU3Bpbm5lciB7XG5cbiAgICBjb25zdHJ1Y3Rvcih0YXJnZXQgPSAnZm9ybS53b29jb21tZXJjZS1jaGVja291dCcpIHtcbiAgICAgICAgdGhpcy50YXJnZXQgPSB0YXJnZXQ7XG4gICAgfVxuXG4gICAgc2V0VGFyZ2V0KHRhcmdldCkge1xuICAgICAgICB0aGlzLnRhcmdldCA9IHRhcmdldDtcbiAgICB9XG5cbiAgICBibG9jaygpIHtcblxuICAgICAgICBqUXVlcnkoIHRoaXMudGFyZ2V0ICkuYmxvY2soe1xuICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgIG92ZXJsYXlDU1M6IHtcbiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiAnI2ZmZicsXG4gICAgICAgICAgICAgICAgb3BhY2l0eTogMC42XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHVuYmxvY2soKSB7XG5cbiAgICAgICAgalF1ZXJ5KCB0aGlzLnRhcmdldCApLnVuYmxvY2soKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFNwaW5uZXI7XG4iLCJpbXBvcnQge1BheW1lbnRNZXRob2RzfSBmcm9tIFwiLi4vSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSBcIi4uL0Vycm9ySGFuZGxlclwiO1xuXG5jbGFzcyBGcmVlVHJpYWxIYW5kbGVyIHtcbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgY29uZmlnLFxuICAgICAgICBzcGlubmVyLFxuICAgICAgICBlcnJvckhhbmRsZXJcbiAgICApIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgICAgIHRoaXMuc3Bpbm5lciA9IHNwaW5uZXI7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyID0gZXJyb3JIYW5kbGVyO1xuICAgIH1cblxuICAgIGhhbmRsZSgpXG4gICAge1xuICAgICAgICB0aGlzLnNwaW5uZXIuYmxvY2soKTtcblxuICAgICAgICBmZXRjaCh0aGlzLmNvbmZpZy5hamF4LnZhdWx0X3BheXBhbC5lbmRwb2ludCwge1xuICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMuY29uZmlnLmFqYXgudmF1bHRfcGF5cGFsLm5vbmNlLFxuICAgICAgICAgICAgICAgIHJldHVybl91cmw6IGxvY2F0aW9uLmhyZWZcbiAgICAgICAgICAgIH0pLFxuICAgICAgICB9KS50aGVuKHJlcyA9PiB7XG4gICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICAgICAgfSkudGhlbihkYXRhID0+IHtcbiAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGRhdGEpO1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGRhdGEuZGF0YS5tZXNzYWdlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbG9jYXRpb24uaHJlZiA9IGRhdGEuZGF0YS5hcHByb3ZlX2xpbms7XG4gICAgICAgIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICB9KTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBGcmVlVHJpYWxIYW5kbGVyO1xuIiwiaW1wb3J0IE1pbmlDYXJ0Qm9vdHN0YXAgZnJvbSAnLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvTWluaUNhcnRCb290c3RhcCc7XG5pbXBvcnQgU2luZ2xlUHJvZHVjdEJvb3RzdGFwIGZyb20gJy4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL1NpbmdsZVByb2R1Y3RCb290c3RhcCc7XG5pbXBvcnQgQ2FydEJvb3RzdHJhcCBmcm9tICcuL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9DYXJ0Qm9vdHN0YXAnO1xuaW1wb3J0IENoZWNrb3V0Qm9vdHN0YXAgZnJvbSAnLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2hlY2tvdXRCb290c3RhcCc7XG5pbXBvcnQgUGF5Tm93Qm9vdHN0cmFwIGZyb20gXCIuL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9QYXlOb3dCb290c3RyYXBcIjtcbmltcG9ydCBSZW5kZXJlciBmcm9tICcuL21vZHVsZXMvUmVuZGVyZXIvUmVuZGVyZXInO1xuaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuL21vZHVsZXMvRXJyb3JIYW5kbGVyJztcbmltcG9ydCBDcmVkaXRDYXJkUmVuZGVyZXIgZnJvbSBcIi4vbW9kdWxlcy9SZW5kZXJlci9DcmVkaXRDYXJkUmVuZGVyZXJcIjtcbmltcG9ydCBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyIGZyb20gXCIuL21vZHVsZXMvRGF0YUNsaWVudElkQXR0cmlidXRlSGFuZGxlclwiO1xuaW1wb3J0IE1lc3NhZ2VSZW5kZXJlciBmcm9tIFwiLi9tb2R1bGVzL1JlbmRlcmVyL01lc3NhZ2VSZW5kZXJlclwiO1xuaW1wb3J0IFNwaW5uZXIgZnJvbSBcIi4vbW9kdWxlcy9IZWxwZXIvU3Bpbm5lclwiO1xuaW1wb3J0IHtcbiAgICBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCxcbiAgICBPUkRFUl9CVVRUT05fU0VMRUNUT1IsXG4gICAgUGF5bWVudE1ldGhvZHNcbn0gZnJvbSBcIi4vbW9kdWxlcy9IZWxwZXIvQ2hlY2tvdXRNZXRob2RTdGF0ZVwiO1xuaW1wb3J0IHtoaWRlLCBzZXRWaXNpYmxlfSBmcm9tIFwiLi9tb2R1bGVzL0hlbHBlci9IaWRpbmdcIjtcbmltcG9ydCB7aXNDaGFuZ2VQYXltZW50UGFnZX0gZnJvbSBcIi4vbW9kdWxlcy9IZWxwZXIvU3Vic2NyaXB0aW9uc1wiO1xuaW1wb3J0IEZyZWVUcmlhbEhhbmRsZXIgZnJvbSBcIi4vbW9kdWxlcy9BY3Rpb25IYW5kbGVyL0ZyZWVUcmlhbEhhbmRsZXJcIjtcblxuY29uc3QgYnV0dG9uc1NwaW5uZXIgPSBuZXcgU3Bpbm5lcignLnBwYy1idXR0b24td3JhcHBlcicpO1xuY29uc3QgY2FyZHNTcGlubmVyID0gbmV3IFNwaW5uZXIoJyNwcGNwLWhvc3RlZC1maWVsZHMnKTtcblxuY29uc3QgYm9vdHN0cmFwID0gKCkgPT4ge1xuICAgIGNvbnN0IGVycm9ySGFuZGxlciA9IG5ldyBFcnJvckhhbmRsZXIoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmxhYmVscy5lcnJvci5nZW5lcmljKTtcbiAgICBjb25zdCBzcGlubmVyID0gbmV3IFNwaW5uZXIoKTtcbiAgICBjb25zdCBjcmVkaXRDYXJkUmVuZGVyZXIgPSBuZXcgQ3JlZGl0Q2FyZFJlbmRlcmVyKFBheVBhbENvbW1lcmNlR2F0ZXdheSwgZXJyb3JIYW5kbGVyLCBzcGlubmVyKTtcblxuICAgIGNvbnN0IGZyZWVUcmlhbEhhbmRsZXIgPSBuZXcgRnJlZVRyaWFsSGFuZGxlcihQYXlQYWxDb21tZXJjZUdhdGV3YXksIHNwaW5uZXIsIGVycm9ySGFuZGxlcik7XG5cbiAgICBjb25zdCBvblNtYXJ0QnV0dG9uQ2xpY2sgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UgPSBkYXRhLmZ1bmRpbmdTb3VyY2U7XG5cbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5iYXNpY19jaGVja291dF92YWxpZGF0aW9uX2VuYWJsZWQpIHtcbiAgICAgICAgICAgIC8vIFRPRE86IHF1aWNrIGZpeCB0byBnZXQgdGhlIGVycm9yIGFib3V0IGVtcHR5IGZvcm0gYmVmb3JlIGF0dGVtcHRpbmcgUGF5UGFsIG9yZGVyXG4gICAgICAgICAgICAvLyBpdCBzaG91bGQgc29sdmUgIzUxMyBmb3IgbW9zdCBvZiB0aGUgdXNlcnMsIGJ1dCBwcm9wZXIgc29sdXRpb24gc2hvdWxkIGJlIGltcGxlbWVudGVkIGxhdGVyLlxuICAgICAgICAgICAgY29uc3QgcmVxdWlyZWRGaWVsZHMgPSBqUXVlcnkoJ2Zvcm0ud29vY29tbWVyY2UtY2hlY2tvdXQgLnZhbGlkYXRlLXJlcXVpcmVkOnZpc2libGUgOmlucHV0Jyk7XG4gICAgICAgICAgICByZXF1aXJlZEZpZWxkcy5lYWNoKChpLCBpbnB1dCkgPT4ge1xuICAgICAgICAgICAgICAgIGpRdWVyeShpbnB1dCkudHJpZ2dlcigndmFsaWRhdGUnKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGpRdWVyeSgnZm9ybS53b29jb21tZXJjZS1jaGVja291dCAudmFsaWRhdGUtcmVxdWlyZWQud29vY29tbWVyY2UtaW52YWxpZDp2aXNpYmxlJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmNsZWFyKCk7XG4gICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmxhYmVscy5lcnJvci5qc192YWxpZGF0aW9uKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBhY3Rpb25zLnJlamVjdCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZm9ybSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0ud29vY29tbWVyY2UtY2hlY2tvdXQnKTtcbiAgICAgICAgaWYgKGZvcm0pIHtcbiAgICAgICAgICAgIGpRdWVyeSgnI3BwY3AtZnVuZGluZy1zb3VyY2UtZm9ybS1pbnB1dCcpLnJlbW92ZSgpO1xuICAgICAgICAgICAgZm9ybS5pbnNlcnRBZGphY2VudEhUTUwoXG4gICAgICAgICAgICAgICAgJ2JlZm9yZWVuZCcsXG4gICAgICAgICAgICAgICAgYDxpbnB1dCB0eXBlPVwiaGlkZGVuXCIgbmFtZT1cInBwY3AtZnVuZGluZy1zb3VyY2VcIiB2YWx1ZT1cIiR7ZGF0YS5mdW5kaW5nU291cmNlfVwiIGlkPVwicHBjcC1mdW5kaW5nLXNvdXJjZS1mb3JtLWlucHV0XCI+YFxuICAgICAgICAgICAgKVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaXNGcmVlVHJpYWwgPSBQYXlQYWxDb21tZXJjZUdhdGV3YXkuaXNfZnJlZV90cmlhbF9jYXJ0O1xuICAgICAgICBpZiAoaXNGcmVlVHJpYWwgJiYgZGF0YS5mdW5kaW5nU291cmNlICE9PSAnY2FyZCcpIHtcbiAgICAgICAgICAgIGZyZWVUcmlhbEhhbmRsZXIuaGFuZGxlKCk7XG4gICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZWplY3QoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgY29uc3Qgb25TbWFydEJ1dHRvbnNJbml0ID0gKCkgPT4ge1xuICAgICAgICBidXR0b25zU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgfTtcbiAgICBjb25zdCByZW5kZXJlciA9IG5ldyBSZW5kZXJlcihjcmVkaXRDYXJkUmVuZGVyZXIsIFBheVBhbENvbW1lcmNlR2F0ZXdheSwgb25TbWFydEJ1dHRvbkNsaWNrLCBvblNtYXJ0QnV0dG9uc0luaXQpO1xuICAgIGNvbnN0IG1lc3NhZ2VSZW5kZXJlciA9IG5ldyBNZXNzYWdlUmVuZGVyZXIoUGF5UGFsQ29tbWVyY2VHYXRld2F5Lm1lc3NhZ2VzKTtcbiAgICBjb25zdCBjb250ZXh0ID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LmNvbnRleHQ7XG4gICAgaWYgKGNvbnRleHQgPT09ICdtaW5pLWNhcnQnIHx8IGNvbnRleHQgPT09ICdwcm9kdWN0Jykge1xuICAgICAgICBpZiAoUGF5UGFsQ29tbWVyY2VHYXRld2F5Lm1pbmlfY2FydF9idXR0b25zX2VuYWJsZWQgPT09ICcxJykge1xuICAgICAgICAgICAgY29uc3QgbWluaUNhcnRCb290c3RyYXAgPSBuZXcgTWluaUNhcnRCb290c3RhcChcbiAgICAgICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICAgICAgcmVuZGVyZXJcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG1pbmlDYXJ0Qm9vdHN0cmFwLmluaXQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb250ZXh0ID09PSAncHJvZHVjdCcgJiYgUGF5UGFsQ29tbWVyY2VHYXRld2F5LnNpbmdsZV9wcm9kdWN0X2J1dHRvbnNfZW5hYmxlZCA9PT0gJzEnKSB7XG4gICAgICAgIGNvbnN0IHNpbmdsZVByb2R1Y3RCb290c3RyYXAgPSBuZXcgU2luZ2xlUHJvZHVjdEJvb3RzdGFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICAgICBtZXNzYWdlUmVuZGVyZXIsXG4gICAgICAgICk7XG5cbiAgICAgICAgc2luZ2xlUHJvZHVjdEJvb3RzdHJhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdjYXJ0Jykge1xuICAgICAgICBjb25zdCBjYXJ0Qm9vdHN0cmFwID0gbmV3IENhcnRCb290c3RyYXAoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICByZW5kZXJlcixcbiAgICAgICAgKTtcblxuICAgICAgICBjYXJ0Qm9vdHN0cmFwLmluaXQoKTtcbiAgICB9XG5cbiAgICBpZiAoY29udGV4dCA9PT0gJ2NoZWNrb3V0Jykge1xuICAgICAgICBjb25zdCBjaGVja291dEJvb3RzdGFwID0gbmV3IENoZWNrb3V0Qm9vdHN0YXAoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICByZW5kZXJlcixcbiAgICAgICAgICAgIG1lc3NhZ2VSZW5kZXJlcixcbiAgICAgICAgICAgIHNwaW5uZXJcbiAgICAgICAgKTtcblxuICAgICAgICBjaGVja291dEJvb3RzdGFwLmluaXQoKTtcbiAgICB9XG5cbiAgICBpZiAoY29udGV4dCA9PT0gJ3BheS1ub3cnICkge1xuICAgICAgICBjb25zdCBwYXlOb3dCb290c3RyYXAgPSBuZXcgUGF5Tm93Qm9vdHN0cmFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICAgICBtZXNzYWdlUmVuZGVyZXIsXG4gICAgICAgICAgICBzcGlubmVyXG4gICAgICAgICk7XG4gICAgICAgIHBheU5vd0Jvb3RzdHJhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgIT09ICdjaGVja291dCcpIHtcbiAgICAgICAgbWVzc2FnZVJlbmRlcmVyLnJlbmRlcigpO1xuICAgIH1cbn07XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKFxuICAgICdET01Db250ZW50TG9hZGVkJyxcbiAgICAoKSA9PiB7XG4gICAgICAgIGlmICghdHlwZW9mIChQYXlQYWxDb21tZXJjZUdhdGV3YXkpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdQYXlQYWwgYnV0dG9uIGNvdWxkIG5vdCBiZSBjb25maWd1cmVkLicpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmNvbnRleHQgIT09ICdjaGVja291dCdcbiAgICAgICAgICAgICYmIFBheVBhbENvbW1lcmNlR2F0ZXdheS5kYXRhX2NsaWVudF9pZC51c2VyID09PSAwXG4gICAgICAgICAgICAmJiBQYXlQYWxDb21tZXJjZUdhdGV3YXkuZGF0YV9jbGllbnRfaWQuaGFzX3N1YnNjcmlwdGlvbnNcbiAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTb21ldGltZXMgUGF5UGFsIHNjcmlwdCB0YWtlcyBsb25nIHRpbWUgdG8gbG9hZCxcbiAgICAgICAgLy8gc28gd2UgYWRkaXRpb25hbGx5IGhpZGUgdGhlIHN0YW5kYXJkIG9yZGVyIGJ1dHRvbiBoZXJlIHRvIGF2b2lkIGZhaWxlZCBvcmRlcnMuXG4gICAgICAgIC8vIE5vcm1hbGx5IGl0IGlzIGhpZGRlbiBsYXRlciBhZnRlciB0aGUgc2NyaXB0IGxvYWQuXG4gICAgICAgIGNvbnN0IGhpZGVPcmRlckJ1dHRvbklmUHBjcEdhdGV3YXkgPSAoKSA9PiB7XG4gICAgICAgICAgICAvLyBvbmx5IGluIGNoZWNrb3V0IGFuZCBwYXkgbm93IHBhZ2UsIG90aGVyd2lzZSBpdCBtYXkgYnJlYWsgdGhpbmdzIChlLmcuIHBheW1lbnQgdmlhIHByb2R1Y3QgcGFnZSksXG4gICAgICAgICAgICAvLyBhbmQgYWxzbyB0aGUgbG9hZGluZyBzcGlubmVyIG1heSBsb29rIHdlaXJkIG9uIG90aGVyIHBhZ2VzXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgIVsnY2hlY2tvdXQnLCAncGF5LW5vdyddLmluY2x1ZGVzKFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0KVxuICAgICAgICAgICAgICAgIHx8IGlzQ2hhbmdlUGF5bWVudFBhZ2UoKVxuICAgICAgICAgICAgICAgIHx8IChQYXlQYWxDb21tZXJjZUdhdGV3YXkuaXNfZnJlZV90cmlhbF9jYXJ0ICYmIFBheVBhbENvbW1lcmNlR2F0ZXdheS52YXVsdGVkX3BheXBhbF9lbWFpbCAhPT0gJycpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRQYXltZW50TWV0aG9kID0gZ2V0Q3VycmVudFBheW1lbnRNZXRob2QoKTtcbiAgICAgICAgICAgIGNvbnN0IGlzUGF5cGFsID0gY3VycmVudFBheW1lbnRNZXRob2QgPT09IFBheW1lbnRNZXRob2RzLlBBWVBBTDtcbiAgICAgICAgICAgIGNvbnN0IGlzQ2FyZHMgPSBjdXJyZW50UGF5bWVudE1ldGhvZCA9PT0gUGF5bWVudE1ldGhvZHMuQ0FSRFM7XG5cbiAgICAgICAgICAgIHNldFZpc2libGUoT1JERVJfQlVUVE9OX1NFTEVDVE9SLCAhaXNQYXlwYWwgJiYgIWlzQ2FyZHMsIHRydWUpO1xuXG4gICAgICAgICAgICBpZiAoaXNQYXlwYWwpIHtcbiAgICAgICAgICAgICAgICAvLyBzdG9wcGVkIGFmdGVyIHRoZSBmaXJzdCByZW5kZXJpbmcgb2YgdGhlIGJ1dHRvbnMsIGluIG9uSW5pdFxuICAgICAgICAgICAgICAgIGJ1dHRvbnNTcGlubmVyLmJsb2NrKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGJ1dHRvbnNTcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGlzQ2FyZHMpIHtcbiAgICAgICAgICAgICAgICBjYXJkc1NwaW5uZXIuYmxvY2soKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY2FyZHNTcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudCkub24oJ2hvc3RlZF9maWVsZHNfbG9hZGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgY2FyZHNTcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgbGV0IGJvb3RzdHJhcHBlZCA9IGZhbHNlO1xuXG4gICAgICAgIGhpZGVPcmRlckJ1dHRvbklmUHBjcEdhdGV3YXkoKTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2hlY2tvdXQgcGF5bWVudF9tZXRob2Rfc2VsZWN0ZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoYm9vdHN0cmFwcGVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5KCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpO1xuICAgICAgICBzY3JpcHQuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgYm9vdHN0cmFwcGVkID0gdHJ1ZTtcblxuICAgICAgICAgICAgYm9vdHN0cmFwKCk7XG4gICAgICAgIH0pO1xuICAgICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKCdzcmMnLCBQYXlQYWxDb21tZXJjZUdhdGV3YXkuYnV0dG9uLnVybCk7XG4gICAgICAgIE9iamVjdC5lbnRyaWVzKFBheVBhbENvbW1lcmNlR2F0ZXdheS5zY3JpcHRfYXR0cmlidXRlcykuZm9yRWFjaChcbiAgICAgICAgICAgIChrZXlWYWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHNjcmlwdC5zZXRBdHRyaWJ1dGUoa2V5VmFsdWVbMF0sIGtleVZhbHVlWzFdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkLnNldF9hdHRyaWJ1dGUpIHtcbiAgICAgICAgICAgIGRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIoc2NyaXB0LCBQYXlQYWxDb21tZXJjZUdhdGV3YXkuZGF0YV9jbGllbnRfaWQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmQoc2NyaXB0KTtcbiAgICB9LFxuKTtcbiJdLCJuYW1lcyI6WyJFcnJvckhhbmRsZXIiLCJjb25zdHJ1Y3RvciIsImdlbmVyaWNFcnJvclRleHQiLCJ3cmFwcGVyIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwibWVzc2FnZXNMaXN0IiwiZ2VuZXJpY0Vycm9yIiwiY2xhc3NMaXN0IiwiY29udGFpbnMiLCJjbGVhciIsIm1lc3NhZ2UiLCJhcHBlbmRQcmVwYXJlZEVycm9yTWVzc2FnZUVsZW1lbnQiLCJlcnJvck1lc3NhZ2VFbGVtZW50IiwicHJlcGFyZU1lc3NhZ2VzTGlzdCIsInJlcGxhY2VXaXRoIiwidGV4dCIsInBlcnNpc3QiLCJTdHJpbmciLCJsZW5ndGgiLCJFcnJvciIsImFkZCIsInJlbW92ZSIsIm1lc3NhZ2VOb2RlIiwicHJlcGFyZU1lc3NhZ2VzTGlzdEl0ZW0iLCJhcHBlbmRDaGlsZCIsImpRdWVyeSIsInNjcm9sbF90b19ub3RpY2VzIiwiY3JlYXRlRWxlbWVudCIsInNldEF0dHJpYnV0ZSIsImxpIiwiaW5uZXJIVE1MIiwic2FuaXRpemUiLCJ0ZXh0YXJlYSIsInZhbHVlIiwicmVwbGFjZSIsIm9uQXBwcm92ZSIsImNvbnRleHQiLCJlcnJvckhhbmRsZXIiLCJkYXRhIiwiYWN0aW9ucyIsImZldGNoIiwiY29uZmlnIiwiYWpheCIsImFwcHJvdmVfb3JkZXIiLCJlbmRwb2ludCIsIm1ldGhvZCIsImJvZHkiLCJKU09OIiwic3RyaW5naWZ5Iiwibm9uY2UiLCJvcmRlcl9pZCIsIm9yZGVySUQiLCJmdW5kaW5nX3NvdXJjZSIsIndpbmRvdyIsInBwY3BGdW5kaW5nU291cmNlIiwidGhlbiIsInJlcyIsImpzb24iLCJzdWNjZXNzIiwicmVzdGFydCIsImNhdGNoIiwiZXJyIiwibG9jYXRpb24iLCJocmVmIiwicmVkaXJlY3QiLCJwYXllckRhdGEiLCJwYXllciIsIlBheVBhbENvbW1lcmNlR2F0ZXdheSIsInBob25lIiwicGhvbmVfdHlwZSIsInBob25lX251bWJlciIsIm5hdGlvbmFsX251bWJlciIsImVtYWlsX2FkZHJlc3MiLCJuYW1lIiwic3VybmFtZSIsImdpdmVuX25hbWUiLCJhZGRyZXNzIiwiY291bnRyeV9jb2RlIiwiYWRkcmVzc19saW5lXzEiLCJhZGRyZXNzX2xpbmVfMiIsImFkbWluX2FyZWFfMSIsImFkbWluX2FyZWFfMiIsInBvc3RhbF9jb2RlIiwiUGF5bWVudE1ldGhvZHMiLCJQQVlQQUwiLCJDQVJEUyIsIk9SREVSX0JVVFRPTl9TRUxFQ1RPUiIsImdldEN1cnJlbnRQYXltZW50TWV0aG9kIiwiZWwiLCJpc1NhdmVkQ2FyZFNlbGVjdGVkIiwic2F2ZWRDYXJkTGlzdCIsIkNhcnRBY3Rpb25IYW5kbGVyIiwiY29uZmlndXJhdGlvbiIsImNyZWF0ZU9yZGVyIiwiYm5Db2RlIiwiYm5fY29kZXMiLCJjcmVhdGVfb3JkZXIiLCJwdXJjaGFzZV91bml0cyIsInBheW1lbnRfbWV0aG9kIiwiYm5fY29kZSIsImNvbnNvbGUiLCJlcnJvciIsImlkIiwib25FcnJvciIsIk1pbmlDYXJ0Qm9vdHN0YXAiLCJnYXRld2F5IiwicmVuZGVyZXIiLCJhY3Rpb25IYW5kbGVyIiwiaW5pdCIsImxhYmVscyIsImdlbmVyaWMiLCJyZW5kZXIiLCJvbiIsInNob3VsZFJlbmRlciIsImJ1dHRvbiIsIm1pbmlfY2FydF93cmFwcGVyIiwiaG9zdGVkX2ZpZWxkcyIsIlByb2R1Y3QiLCJVcGRhdGVDYXJ0IiwidXBkYXRlIiwib25SZXNvbHZlIiwicHJvZHVjdHMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInJlc3VsdCIsInJlc29sdmVkIiwiQnV0dG9uc1RvZ2dsZUxpc3RlbmVyIiwiZWxlbWVudCIsInNob3dDYWxsYmFjayIsImhpZGVDYWxsYmFjayIsIm9ic2VydmVyIiwiYXR0cmlidXRlcyIsImNhbGxiYWNrIiwiTXV0YXRpb25PYnNlcnZlciIsIm9ic2VydmUiLCJkaXNjb25uZWN0IiwicXVhbnRpdHkiLCJ2YXJpYXRpb25zIiwiU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXIiLCJ1cGRhdGVDYXJ0Iiwic2hvd0J1dHRvbkNhbGxiYWNrIiwiaGlkZUJ1dHRvbkNhbGxiYWNrIiwiZm9ybUVsZW1lbnQiLCJoYXNWYXJpYXRpb25zIiwiZ2V0UHJvZHVjdHMiLCJpc0dyb3VwZWRQcm9kdWN0IiwicXR5IiwicXVlcnlTZWxlY3RvckFsbCIsImZvckVhY2giLCJlbGVtZW50TmFtZSIsImdldEF0dHJpYnV0ZSIsIm1hdGNoIiwicGFyc2VJbnQiLCJwdXNoIiwicHJvbWlzZSIsIm1hcCIsIlNpbmdsZVByb2R1Y3RCb290c3RhcCIsIm1lc3NhZ2VzIiwiaGFuZGxlQ2hhbmdlIiwiaGlkZUJ1dHRvbnMiLCJoaWRlTWVzc2FnZXMiLCJhZGRFdmVudExpc3RlbmVyIiwiYmluZCIsInByaWNlQW1vdW50SXNaZXJvIiwicHJpY2VBbW91bnQiLCJwcmljZVRleHQiLCJpbm5lclRleHQiLCJwYXJzZUZsb2F0IiwiY2hhbmdlX2NhcnQiLCJzaG93QnV0dG9ucyIsInJlbmRlcldpdGhBbW91bnQiLCJDYXJ0Qm9vdHN0cmFwIiwic3Bpbm5lciIsImJsb2NrIiwidW5ibG9jayIsImNvZGUiLCJjbGljayIsIkNoZWNrb3V0QWN0aW9uSGFuZGxlciIsImZvcm1TZWxlY3RvciIsImZvcm1EYXRhIiwiRm9ybURhdGEiLCJmb3JtSnNvbk9iaiIsIk9iamVjdCIsImZyb21FbnRyaWVzIiwiY3JlYXRlYWNjb3VudCIsImlzIiwiZm9ybSIsImRvbVBhcnNlciIsIkRPTVBhcnNlciIsInBhcnNlRnJvbVN0cmluZyIsImRldGFpbHMiLCJkIiwiaXNzdWUiLCJkZXNjcmlwdGlvbiIsImpvaW4iLCJpbnB1dCIsImN1c3RvbV9pZCIsImFwcGVuZCIsIm9uQ2FuY2VsIiwiZ2V0RWxlbWVudCIsInNlbGVjdG9yT3JFbGVtZW50IiwiaXNWaXNpYmxlIiwib2Zmc2V0V2lkdGgiLCJvZmZzZXRIZWlnaHQiLCJnZXRDbGllbnRSZWN0cyIsInNldFZpc2libGUiLCJzaG93IiwiaW1wb3J0YW50IiwiY3VycmVudFZhbHVlIiwic3R5bGUiLCJnZXRQcm9wZXJ0eVZhbHVlIiwic2V0UHJvcGVydHkiLCJyZW1vdmVQcm9wZXJ0eSIsImhpZGUiLCJDaGVja291dEJvb3RzdGFwIiwic3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yIiwiYnV0dG9uQ2hhbmdlT2JzZXJ2ZXIiLCJ1cGRhdGVVaSIsInZhbCIsImNhbmNlbF93cmFwcGVyIiwiY3VycmVudFBheW1lbnRNZXRob2QiLCJpc1BheXBhbCIsImlzQ2FyZCIsImlzU2F2ZWRDYXJkIiwiaXNOb3RPdXJHYXRld2F5IiwiaXNGcmVlVHJpYWwiLCJpc19mcmVlX3RyaWFsX2NhcnQiLCJoYXNWYXVsdGVkUGF5cGFsIiwidmF1bHRlZF9wYXlwYWxfZW1haWwiLCJkaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcyIsImVuYWJsZUNyZWRpdENhcmRGaWVsZHMiLCJhZGRDbGFzcyIsImF0dHIiLCJyZW1vdmVDbGFzcyIsImlzQ2hhbmdlUGF5bWVudFBhZ2UiLCJ1cmxQYXJhbXMiLCJVUkxTZWFyY2hQYXJhbXMiLCJzZWFyY2giLCJoYXMiLCJQYXlOb3dCb290c3RyYXAiLCJSZW5kZXJlciIsImNyZWRpdENhcmRSZW5kZXJlciIsImRlZmF1bHRDb25maWciLCJvblNtYXJ0QnV0dG9uQ2xpY2siLCJvblNtYXJ0QnV0dG9uc0luaXQiLCJob3N0ZWRGaWVsZHNXcmFwcGVyIiwiY29udGV4dENvbmZpZyIsInJlbmRlckJ1dHRvbnMiLCJpc0FscmVhZHlSZW5kZXJlZCIsInBheXBhbCIsIkJ1dHRvbnMiLCJtaW5pX2NhcnRfc3R5bGUiLCJvbkNsaWNrIiwib25Jbml0IiwiaGFzQ2hpbGROb2RlcyIsImRvbUVsZW1lbnQiLCJkaXNwbGF5IiwiZGlzYWJsZUZpZWxkcyIsImVuYWJsZUZpZWxkcyIsImRjY0lucHV0RmFjdG9yeSIsIm9yaWdpbmFsIiwic3R5bGVzIiwiZ2V0Q29tcHV0ZWRTdHlsZSIsIm5ld0VsZW1lbnQiLCJjbGFzc05hbWUiLCJ2YWx1ZXMiLCJwcm9wIiwiaXNOYU4iLCJDcmVkaXRDYXJkUmVuZGVyZXIiLCJjYXJkVmFsaWQiLCJmb3JtVmFsaWQiLCJjdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UiLCJIb3N0ZWRGaWVsZHMiLCJpc0VsaWdpYmxlIiwid3JhcHBlckVsZW1lbnQiLCJwYXJlbnROb2RlIiwicmVtb3ZlQ2hpbGQiLCJidXR0b25TZWxlY3RvciIsInRlYXJkb3duIiwiZ2F0ZVdheUJveCIsIm9sZERpc3BsYXlTdHlsZSIsImhpZGVEY2NHYXRld2F5IiwiY2FyZE51bWJlckZpZWxkIiwic3R5bGVzUmF3IiwiY2FyZE51bWJlciIsInJlcGxhY2VDaGlsZCIsImNhcmRFeHBpcnlGaWVsZCIsImNhcmRFeHBpcnkiLCJjYXJkQ29kZUZpZWxkIiwiY2FyZENvZGUiLCJmb3JtV3JhcHBlciIsImVuZm9yY2VfdmF1bHQiLCJjaGVja2VkIiwiZmllbGRzIiwibnVtYmVyIiwic2VsZWN0b3IiLCJwbGFjZWhvbGRlciIsImNyZWRpdF9jYXJkX251bWJlciIsImN2diIsImV4cGlyYXRpb25EYXRlIiwibW1feXkiLCJob3N0ZWRGaWVsZHMiLCJkaXNwYXRjaEV2ZW50IiwiQ3VzdG9tRXZlbnQiLCJfc3VibWl0IiwiZXZlbnQiLCJjYXJkcyIsInZhbGlkQ2FyZHMiLCJ2YWxpZF9jYXJkcyIsImluZGV4T2YiLCJ0eXBlIiwiX2NhcmROdW1iZXJGaWxlZENMYXNzTmFtZUJ5Q2FyZFR5cGUiLCJfcmVjcmVhdGVFbGVtZW50Q2xhc3NBdHRyaWJ1dGUiLCJpc1ZhbGlkIiwia2V5cyIsImV2ZXJ5Iiwia2V5IiwicHJldmVudERlZmF1bHQiLCJmaWVsZCIsImF0dHJpYnV0ZSIsInJlbW92ZUF0dHJpYnV0ZSIsInNhdmVfY2FyZCIsImNhbl9zYXZlX3ZhdWx0X3Rva2VuIiwidmF1bHQiLCJnZXRFbGVtZW50QnlJZCIsImNvbnRpbmdlbmN5IiwiaG9zdGVkRmllbGRzRGF0YSIsImNvbnRpbmdlbmNpZXMiLCJjYXJkaG9sZGVyTmFtZSIsImZpcnN0TmFtZSIsImxhc3ROYW1lIiwic3VibWl0IiwicGF5bG9hZCIsIm9yZGVySWQiLCJjYXJkX25vdF9zdXBwb3J0ZWQiLCJmaWVsZHNfbm90X3ZhbGlkIiwiY2FyZFR5cGUiLCJuZXdDbGFzc05hbWUiLCJzdG9yYWdlS2V5IiwidmFsaWRhdGVUb2tlbiIsInRva2VuIiwidXNlciIsImN1cnJlbnRUaW1lIiwiRGF0ZSIsImdldFRpbWUiLCJpc0V4cGlyZWQiLCJleHBpcmF0aW9uIiwic3RvcmVkVG9rZW5Gb3JVc2VyIiwicGFyc2UiLCJzZXNzaW9uU3RvcmFnZSIsImdldEl0ZW0iLCJzdG9yZVRva2VuIiwic2V0SXRlbSIsImRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIiLCJzY3JpcHQiLCJNZXNzYWdlUmVuZGVyZXIiLCJNZXNzYWdlcyIsImFtb3VudCIsInBsYWNlbWVudCIsIm5ld1dyYXBwZXIiLCJzaWJsaW5nIiwibmV4dFNpYmxpbmciLCJwYXJlbnRFbGVtZW50IiwiaW5zZXJ0QmVmb3JlIiwiU3Bpbm5lciIsInRhcmdldCIsInNldFRhcmdldCIsIm92ZXJsYXlDU1MiLCJiYWNrZ3JvdW5kIiwib3BhY2l0eSIsIkZyZWVUcmlhbEhhbmRsZXIiLCJoYW5kbGUiLCJ2YXVsdF9wYXlwYWwiLCJyZXR1cm5fdXJsIiwiYXBwcm92ZV9saW5rIiwiYnV0dG9uc1NwaW5uZXIiLCJjYXJkc1NwaW5uZXIiLCJib290c3RyYXAiLCJmcmVlVHJpYWxIYW5kbGVyIiwiZnVuZGluZ1NvdXJjZSIsImJhc2ljX2NoZWNrb3V0X3ZhbGlkYXRpb25fZW5hYmxlZCIsInJlcXVpcmVkRmllbGRzIiwiZWFjaCIsImkiLCJ0cmlnZ2VyIiwianNfdmFsaWRhdGlvbiIsImluc2VydEFkamFjZW50SFRNTCIsIm1lc3NhZ2VSZW5kZXJlciIsIm1pbmlfY2FydF9idXR0b25zX2VuYWJsZWQiLCJtaW5pQ2FydEJvb3RzdHJhcCIsInNpbmdsZV9wcm9kdWN0X2J1dHRvbnNfZW5hYmxlZCIsInNpbmdsZVByb2R1Y3RCb290c3RyYXAiLCJjYXJ0Qm9vdHN0cmFwIiwiY2hlY2tvdXRCb290c3RhcCIsInBheU5vd0Jvb3RzdHJhcCIsImRhdGFfY2xpZW50X2lkIiwiaGFzX3N1YnNjcmlwdGlvbnMiLCJoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5IiwiaW5jbHVkZXMiLCJpc0NhcmRzIiwiYm9vdHN0cmFwcGVkIiwidXJsIiwiZW50cmllcyIsInNjcmlwdF9hdHRyaWJ1dGVzIiwia2V5VmFsdWUiLCJzZXRfYXR0cmlidXRlIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///536\n")}},__webpack_exports__={};__webpack_modules__[536]()})();
|
1 |
+
(()=>{"use strict";var __webpack_modules__={536:(__unused_webpack_module,__unused_webpack___webpack_exports__,__webpack_require__)=>{eval("\n;// CONCATENATED MODULE: ./resources/js/modules/ErrorHandler.js\nclass ErrorHandler {\n constructor(genericErrorText) {\n this.genericErrorText = genericErrorText;\n this.wrapper = document.querySelector('.woocommerce-notices-wrapper');\n this.messagesList = document.querySelector('ul.woocommerce-error');\n }\n\n genericError() {\n if (this.wrapper.classList.contains('ppcp-persist')) {\n return;\n }\n\n this.clear();\n this.message(this.genericErrorText);\n }\n\n appendPreparedErrorMessageElement(errorMessageElement) {\n if (this.messagesList === null) {\n this.prepareMessagesList();\n }\n\n this.messagesList.replaceWith(errorMessageElement);\n }\n\n message(text, persist = false) {\n if (!typeof String || text.length === 0) {\n throw new Error('A new message text must be a non-empty string.');\n }\n\n if (this.messagesList === null) {\n this.prepareMessagesList();\n }\n\n if (persist) {\n this.wrapper.classList.add('ppcp-persist');\n } else {\n this.wrapper.classList.remove('ppcp-persist');\n }\n\n let messageNode = this.prepareMessagesListItem(text);\n this.messagesList.appendChild(messageNode);\n jQuery.scroll_to_notices(jQuery('.woocommerce-notices-wrapper'));\n }\n\n prepareMessagesList() {\n if (this.messagesList === null) {\n this.messagesList = document.createElement('ul');\n this.messagesList.setAttribute('class', 'woocommerce-error');\n this.messagesList.setAttribute('role', 'alert');\n this.wrapper.appendChild(this.messagesList);\n }\n }\n\n prepareMessagesListItem(message) {\n const li = document.createElement('li');\n li.innerHTML = message;\n return li;\n }\n\n sanitize(text) {\n const textarea = document.createElement('textarea');\n textarea.innerHTML = text;\n return textarea.value.replace('Error: ', '');\n }\n\n clear() {\n if (this.messagesList === null) {\n return;\n }\n\n this.messagesList.innerHTML = '';\n }\n\n}\n\n/* harmony default export */ const modules_ErrorHandler = (ErrorHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/OnApproveHandler/onApproveForContinue.js\nconst onApprove = (context, errorHandler) => {\n return (data, actions) => {\n return fetch(context.config.ajax.approve_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: context.config.ajax.approve_order.nonce,\n order_id: data.orderID,\n funding_source: window.ppcpFundingSource\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n if (!data.success) {\n errorHandler.genericError();\n return actions.restart().catch(err => {\n errorHandler.genericError();\n });\n }\n\n location.href = context.config.redirect;\n });\n };\n};\n\n/* harmony default export */ const onApproveForContinue = (onApprove);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/PayerData.js\nconst payerData = () => {\n const payer = PayPalCommerceGateway.payer;\n\n if (!payer) {\n return null;\n }\n\n const phone = document.querySelector('#billing_phone') || typeof payer.phone !== 'undefined' ? {\n phone_type: \"HOME\",\n phone_number: {\n national_number: document.querySelector('#billing_phone') ? document.querySelector('#billing_phone').value : payer.phone.phone_number.national_number\n }\n } : null;\n const payerData = {\n email_address: document.querySelector('#billing_email') ? document.querySelector('#billing_email').value : payer.email_address,\n name: {\n surname: document.querySelector('#billing_last_name') ? document.querySelector('#billing_last_name').value : payer.name.surname,\n given_name: document.querySelector('#billing_first_name') ? document.querySelector('#billing_first_name').value : payer.name.given_name\n },\n address: {\n country_code: document.querySelector('#billing_country') ? document.querySelector('#billing_country').value : payer.address.country_code,\n address_line_1: document.querySelector('#billing_address_1') ? document.querySelector('#billing_address_1').value : payer.address.address_line_1,\n address_line_2: document.querySelector('#billing_address_2') ? document.querySelector('#billing_address_2').value : payer.address.address_line_2,\n admin_area_1: document.querySelector('#billing_state') ? document.querySelector('#billing_state').value : payer.address.admin_area_1,\n admin_area_2: document.querySelector('#billing_city') ? document.querySelector('#billing_city').value : payer.address.admin_area_2,\n postal_code: document.querySelector('#billing_postcode') ? document.querySelector('#billing_postcode').value : payer.address.postal_code\n }\n };\n\n if (phone) {\n payerData.phone = phone;\n }\n\n return payerData;\n};\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/CheckoutMethodState.js\nconst PaymentMethods = {\n PAYPAL: 'ppcp-gateway',\n CARDS: 'ppcp-credit-card-gateway',\n OXXO: 'ppcp-oxxo-gateway',\n CARD_BUTTON: 'ppcp-card-button-gateway'\n};\nconst ORDER_BUTTON_SELECTOR = '#place_order';\nconst getCurrentPaymentMethod = () => {\n const el = document.querySelector('input[name=\"payment_method\"]:checked');\n\n if (!el) {\n return null;\n }\n\n return el.value;\n};\nconst isSavedCardSelected = () => {\n const savedCardList = document.querySelector('#saved-credit-card');\n return savedCardList && savedCardList.value !== '';\n};\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/CartActionHandler.js\n\n\n\n\nclass CartActionHandler {\n constructor(config, errorHandler) {\n this.config = config;\n this.errorHandler = errorHandler;\n }\n\n configuration() {\n const createOrder = (data, actions) => {\n const payer = payerData();\n const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : '';\n return fetch(this.config.ajax.create_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.create_order.nonce,\n purchase_units: [],\n payment_method: PaymentMethods.PAYPAL,\n funding_source: window.ppcpFundingSource,\n bn_code: bnCode,\n payer,\n context: this.config.context\n })\n }).then(function (res) {\n return res.json();\n }).then(function (data) {\n if (!data.success) {\n console.error(data);\n throw Error(data.data.message);\n }\n\n return data.data.id;\n });\n };\n\n return {\n createOrder,\n onApprove: onApproveForContinue(this, this.errorHandler),\n onError: error => {\n this.errorHandler.genericError();\n }\n };\n }\n\n}\n\n/* harmony default export */ const ActionHandler_CartActionHandler = (CartActionHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/MiniCartBootstap.js\n\n\n\nclass MiniCartBootstap {\n constructor(gateway, renderer) {\n this.gateway = gateway;\n this.renderer = renderer;\n this.actionHandler = null;\n }\n\n init() {\n this.actionHandler = new ActionHandler_CartActionHandler(PayPalCommerceGateway, new modules_ErrorHandler(this.gateway.labels.error.generic));\n this.render();\n jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => {\n this.render();\n });\n }\n\n shouldRender() {\n return document.querySelector(this.gateway.button.mini_cart_wrapper) !== null || document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !== null;\n }\n\n render() {\n if (!this.shouldRender()) {\n return;\n }\n\n this.renderer.render(this.actionHandler.configuration(), {\n button: {\n wrapper: this.gateway.button.mini_cart_wrapper,\n style: this.gateway.button.mini_cart_style\n }\n });\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_MiniCartBootstap = (MiniCartBootstap);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/UpdateCart.js\n\n\nclass UpdateCart {\n constructor(endpoint, nonce) {\n this.endpoint = endpoint;\n this.nonce = nonce;\n }\n /**\n *\n * @param onResolve\n * @param {Product[]} products\n * @returns {Promise<unknown>}\n */\n\n\n update(onResolve, products) {\n return new Promise((resolve, reject) => {\n fetch(this.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.nonce,\n products\n })\n }).then(result => {\n return result.json();\n }).then(result => {\n if (!result.success) {\n reject(result.data);\n return;\n }\n\n const resolved = onResolve(result.data);\n resolve(resolved);\n });\n });\n }\n\n}\n\n/* harmony default export */ const Helper_UpdateCart = (UpdateCart);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/ButtonsToggleListener.js\n/**\n * When you can't add something to the cart, the PayPal buttons should not show.\n * Therefore we listen for changes on the add to cart button and show/hide the buttons accordingly.\n */\nclass ButtonsToggleListener {\n constructor(element, showCallback, hideCallback) {\n this.element = element;\n this.showCallback = showCallback;\n this.hideCallback = hideCallback;\n this.observer = null;\n }\n\n init() {\n const config = {\n attributes: true\n };\n\n const callback = () => {\n if (this.element.classList.contains('disabled')) {\n this.hideCallback();\n return;\n }\n\n this.showCallback();\n };\n\n this.observer = new MutationObserver(callback);\n this.observer.observe(this.element, config);\n callback();\n }\n\n disconnect() {\n this.observer.disconnect();\n }\n\n}\n\n/* harmony default export */ const Helper_ButtonsToggleListener = (ButtonsToggleListener);\n;// CONCATENATED MODULE: ./resources/js/modules/Entity/Product.js\nclass Product {\n constructor(id, quantity, variations) {\n this.id = id;\n this.quantity = quantity;\n this.variations = variations;\n }\n\n data() {\n return {\n id: this.id,\n quantity: this.quantity,\n variations: this.variations\n };\n }\n\n}\n\n/* harmony default export */ const Entity_Product = (Product);\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/SingleProductActionHandler.js\n\n\n\n\n\n\nclass SingleProductActionHandler {\n constructor(config, updateCart, showButtonCallback, hideButtonCallback, formElement, errorHandler) {\n this.config = config;\n this.updateCart = updateCart;\n this.showButtonCallback = showButtonCallback;\n this.hideButtonCallback = hideButtonCallback;\n this.formElement = formElement;\n this.errorHandler = errorHandler;\n }\n\n configuration() {\n if (this.hasVariations()) {\n const observer = new Helper_ButtonsToggleListener(this.formElement.querySelector('.single_add_to_cart_button'), this.showButtonCallback, this.hideButtonCallback);\n observer.init();\n }\n\n return {\n createOrder: this.createOrder(),\n onApprove: onApproveForContinue(this, this.errorHandler),\n onError: error => {\n this.errorHandler.genericError();\n }\n };\n }\n\n createOrder() {\n var getProducts = null;\n\n if (!this.isGroupedProduct()) {\n getProducts = () => {\n const id = document.querySelector('[name=\"add-to-cart\"]').value;\n const qty = document.querySelector('[name=\"quantity\"]').value;\n const variations = this.variations();\n return [new Entity_Product(id, qty, variations)];\n };\n } else {\n getProducts = () => {\n const products = [];\n this.formElement.querySelectorAll('input[type=\"number\"]').forEach(element => {\n if (!element.value) {\n return;\n }\n\n const elementName = element.getAttribute('name').match(/quantity\\[([\\d]*)\\]/);\n\n if (elementName.length !== 2) {\n return;\n }\n\n const id = parseInt(elementName[1]);\n const quantity = parseInt(element.value);\n products.push(new Entity_Product(id, quantity, null));\n });\n return products;\n };\n }\n\n const createOrder = (data, actions) => {\n this.errorHandler.clear();\n\n const onResolve = purchase_units => {\n const payer = payerData();\n const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : '';\n return fetch(this.config.ajax.create_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.create_order.nonce,\n purchase_units,\n payer,\n bn_code: bnCode,\n payment_method: PaymentMethods.PAYPAL,\n funding_source: window.ppcpFundingSource,\n context: this.config.context\n })\n }).then(function (res) {\n return res.json();\n }).then(function (data) {\n if (!data.success) {\n console.error(data);\n throw Error(data.data.message);\n }\n\n return data.data.id;\n });\n };\n\n const promise = this.updateCart.update(onResolve, getProducts());\n return promise;\n };\n\n return createOrder;\n }\n\n variations() {\n if (!this.hasVariations()) {\n return null;\n }\n\n const attributes = [...this.formElement.querySelectorAll(\"[name^='attribute_']\")].map(element => {\n return {\n value: element.value,\n name: element.name\n };\n });\n return attributes;\n }\n\n hasVariations() {\n return this.formElement.classList.contains('variations_form');\n }\n\n isGroupedProduct() {\n return this.formElement.classList.contains('grouped_form');\n }\n\n}\n\n/* harmony default export */ const ActionHandler_SingleProductActionHandler = (SingleProductActionHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/SingleProductBootstap.js\n\n\n\n\nclass SingleProductBootstap {\n constructor(gateway, renderer, messages) {\n this.gateway = gateway;\n this.renderer = renderer;\n this.messages = messages;\n }\n\n handleChange() {\n if (!this.shouldRender()) {\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\n this.renderer.hideButtons(this.gateway.button.wrapper);\n this.messages.hideMessages();\n return;\n }\n\n this.render();\n }\n\n init() {\n document.querySelector('form.cart').addEventListener('change', this.handleChange.bind(this));\n\n if (!this.shouldRender()) {\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\n this.messages.hideMessages();\n return;\n }\n\n this.render();\n }\n\n shouldRender() {\n return document.querySelector('form.cart') !== null && !this.priceAmountIsZero();\n }\n\n priceAmount() {\n let priceText = \"0\";\n\n if (document.querySelector('form.cart ins .woocommerce-Price-amount')) {\n priceText = document.querySelector('form.cart ins .woocommerce-Price-amount').innerText;\n } else if (document.querySelector('form.cart .woocommerce-Price-amount')) {\n priceText = document.querySelector('form.cart .woocommerce-Price-amount').innerText;\n } else if (document.querySelector('.product .woocommerce-Price-amount')) {\n priceText = document.querySelector('.product .woocommerce-Price-amount').innerText;\n }\n\n priceText = priceText.replace(/,/g, '.');\n return parseFloat(priceText.replace(/([^\\d,\\.\\s]*)/g, ''));\n }\n\n priceAmountIsZero() {\n return this.priceAmount() === 0;\n }\n\n render() {\n const actionHandler = new ActionHandler_SingleProductActionHandler(this.gateway, new Helper_UpdateCart(this.gateway.ajax.change_cart.endpoint, this.gateway.ajax.change_cart.nonce), () => {\n this.renderer.showButtons(this.gateway.button.wrapper);\n this.renderer.showButtons(this.gateway.hosted_fields.wrapper);\n this.messages.renderWithAmount(this.priceAmount());\n }, () => {\n this.renderer.hideButtons(this.gateway.button.wrapper);\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\n this.messages.hideMessages();\n }, document.querySelector('form.cart'), new modules_ErrorHandler(this.gateway.labels.error.generic));\n this.renderer.render(actionHandler.configuration());\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_SingleProductBootstap = (SingleProductBootstap);\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/CartBootstap.js\n\n\n\nclass CartBootstrap {\n constructor(gateway, renderer) {\n this.gateway = gateway;\n this.renderer = renderer;\n }\n\n init() {\n if (!this.shouldRender()) {\n return;\n }\n\n this.render();\n jQuery(document.body).on('updated_cart_totals updated_checkout', () => {\n this.render();\n });\n }\n\n shouldRender() {\n return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;\n }\n\n render() {\n const actionHandler = new ActionHandler_CartActionHandler(PayPalCommerceGateway, new modules_ErrorHandler(this.gateway.labels.error.generic));\n this.renderer.render(actionHandler.configuration());\n }\n\n}\n\n/* harmony default export */ const CartBootstap = (CartBootstrap);\n;// CONCATENATED MODULE: ./resources/js/modules/OnApproveHandler/onApproveForPayNow.js\nconst onApproveForPayNow_onApprove = (context, errorHandler, spinner) => {\n return (data, actions) => {\n spinner.block();\n errorHandler.clear();\n return fetch(context.config.ajax.approve_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: context.config.ajax.approve_order.nonce,\n order_id: data.orderID,\n funding_source: window.ppcpFundingSource\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n spinner.unblock();\n\n if (!data.success) {\n if (data.data.code === 100) {\n errorHandler.message(data.data.message);\n } else {\n errorHandler.genericError();\n }\n\n if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {\n return actions.restart();\n }\n\n throw new Error(data.data.message);\n }\n\n document.querySelector('#place_order').click();\n });\n };\n};\n\n/* harmony default export */ const onApproveForPayNow = (onApproveForPayNow_onApprove);\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/CheckoutActionHandler.js\n\n\n\n\nclass CheckoutActionHandler {\n constructor(config, errorHandler, spinner) {\n this.config = config;\n this.errorHandler = errorHandler;\n this.spinner = spinner;\n }\n\n configuration() {\n const spinner = this.spinner;\n\n const createOrder = (data, actions) => {\n const payer = payerData();\n const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : '';\n const errorHandler = this.errorHandler;\n const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';\n const formData = new FormData(document.querySelector(formSelector)); // will not handle fields with multiple values (checkboxes, <select multiple>), but we do not care about this here\n\n const formJsonObj = Object.fromEntries(formData);\n const createaccount = jQuery('#createaccount').is(\":checked\") ? true : false;\n const paymentMethod = getCurrentPaymentMethod();\n const fundingSource = window.ppcpFundingSource;\n return fetch(this.config.ajax.create_order.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.create_order.nonce,\n payer,\n bn_code: bnCode,\n context: this.config.context,\n order_id: this.config.order_id,\n payment_method: paymentMethod,\n funding_source: fundingSource,\n form: formJsonObj,\n createaccount: createaccount\n })\n }).then(function (res) {\n return res.json();\n }).then(function (data) {\n if (!data.success) {\n spinner.unblock(); //handle both messages sent from Woocommerce (data.messages) and this plugin (data.data.message)\n\n if (typeof data.messages !== 'undefined') {\n const domParser = new DOMParser();\n errorHandler.appendPreparedErrorMessageElement(domParser.parseFromString(data.messages, 'text/html').querySelector('ul'));\n } else {\n errorHandler.clear();\n\n if (data.data.details.length > 0) {\n errorHandler.message(data.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);\n } else {\n errorHandler.message(data.data.message, true);\n }\n }\n\n throw new Error(data.data.message);\n }\n\n const input = document.createElement('input');\n input.setAttribute('type', 'hidden');\n input.setAttribute('name', 'ppcp-resume-order');\n input.setAttribute('value', data.data.purchase_units[0].custom_id);\n document.querySelector(formSelector).append(input);\n return data.data.id;\n });\n };\n\n return {\n createOrder,\n onApprove: onApproveForPayNow(this, this.errorHandler, this.spinner),\n onCancel: () => {\n spinner.unblock();\n },\n onError: () => {\n this.errorHandler.genericError();\n spinner.unblock();\n }\n };\n }\n\n}\n\n/* harmony default export */ const ActionHandler_CheckoutActionHandler = (CheckoutActionHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/Hiding.js\nconst getElement = selectorOrElement => {\n if (typeof selectorOrElement === 'string') {\n return document.querySelector(selectorOrElement);\n }\n\n return selectorOrElement;\n};\n\nconst isVisible = element => {\n return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);\n};\nconst setVisible = (selectorOrElement, show, important = false) => {\n const element = getElement(selectorOrElement);\n\n if (!element) {\n return;\n }\n\n const currentValue = element.style.getPropertyValue('display');\n\n if (!show) {\n if (currentValue === 'none') {\n return;\n }\n\n element.style.setProperty('display', 'none', important ? 'important' : '');\n } else {\n if (currentValue === 'none') {\n element.style.removeProperty('display');\n } // still not visible (if something else added display: none in CSS)\n\n\n if (!isVisible(element)) {\n element.style.setProperty('display', 'block');\n }\n }\n};\nconst hide = (selectorOrElement, important = false) => {\n setVisible(selectorOrElement, false, important);\n};\nconst show = selectorOrElement => {\n setVisible(selectorOrElement, true);\n};\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/CheckoutBootstap.js\n\n\n\n\n\nclass CheckoutBootstap {\n constructor(gateway, renderer, messages, spinner) {\n this.gateway = gateway;\n this.renderer = renderer;\n this.messages = messages;\n this.spinner = spinner;\n this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;\n this.buttonChangeObserver = new MutationObserver(el => {\n this.updateUi();\n });\n }\n\n init() {\n this.render(); // Unselect saved card.\n // WC saves form values, so with our current UI it would be a bit weird\n // if the user paid with saved, then after some time tries to pay again,\n // but wants to enter a new card, and to do that they have to choose “Select payment” in the list.\n\n jQuery('#saved-credit-card').val(jQuery('#saved-credit-card option:first').val());\n jQuery(document.body).on('updated_checkout', () => {\n this.render();\n });\n jQuery(document.body).on('updated_checkout payment_method_selected', () => {\n this.updateUi();\n });\n jQuery(document).on('hosted_fields_loaded', () => {\n jQuery('#saved-credit-card').on('change', () => {\n this.updateUi();\n });\n });\n this.updateUi();\n }\n\n shouldRender() {\n if (document.querySelector(this.gateway.button.cancel_wrapper)) {\n return false;\n }\n\n return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;\n }\n\n render() {\n if (!this.shouldRender()) {\n return;\n }\n\n if (document.querySelector(this.gateway.hosted_fields.wrapper + '>div')) {\n document.querySelector(this.gateway.hosted_fields.wrapper + '>div').setAttribute('style', '');\n }\n\n const actionHandler = new ActionHandler_CheckoutActionHandler(PayPalCommerceGateway, new modules_ErrorHandler(this.gateway.labels.error.generic), this.spinner);\n this.renderer.render(actionHandler.configuration());\n this.buttonChangeObserver.observe(document.querySelector(this.standardOrderButtonSelector), {\n attributes: true\n });\n }\n\n updateUi() {\n const currentPaymentMethod = getCurrentPaymentMethod();\n const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;\n const isCard = currentPaymentMethod === PaymentMethods.CARDS;\n const isSeparateButtonGateway = [PaymentMethods.CARD_BUTTON].includes(currentPaymentMethod);\n const isSavedCard = isCard && isSavedCardSelected();\n const isNotOurGateway = !isPaypal && !isCard && !isSeparateButtonGateway;\n const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;\n const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';\n const paypalButtonWrappers = { ...Object.entries(PayPalCommerceGateway.separate_buttons).reduce((result, [k, data]) => {\n return { ...result,\n [data.id]: data.wrapper\n };\n }, {})\n };\n setVisible(this.standardOrderButtonSelector, isPaypal && isFreeTrial && hasVaultedPaypal || isNotOurGateway || isSavedCard, true);\n setVisible('.ppcp-vaulted-paypal-details', isPaypal);\n setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));\n setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial);\n setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);\n\n for (const [gatewayId, wrapper] of Object.entries(paypalButtonWrappers)) {\n setVisible(wrapper, gatewayId === currentPaymentMethod);\n }\n\n if (isPaypal && !isFreeTrial) {\n this.messages.render();\n }\n\n if (isCard) {\n if (isSavedCard) {\n this.disableCreditCardFields();\n } else {\n this.enableCreditCardFields();\n }\n }\n }\n\n disableCreditCardFields() {\n jQuery('label[for=\"ppcp-credit-card-gateway-card-number\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-number').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-expiry\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-expiry').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-cvc\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-cvc').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"vault\"]').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').addClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').attr(\"disabled\", true);\n this.renderer.disableCreditCardFields();\n }\n\n enableCreditCardFields() {\n jQuery('label[for=\"ppcp-credit-card-gateway-card-number\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-number').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-expiry\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-expiry').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"ppcp-credit-card-gateway-card-cvc\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-gateway-card-cvc').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('label[for=\"vault\"]').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').removeClass('ppcp-credit-card-gateway-form-field-disabled');\n jQuery('#ppcp-credit-card-vault').attr(\"disabled\", false);\n this.renderer.enableCreditCardFields();\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_CheckoutBootstap = (CheckoutBootstap);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/Subscriptions.js\nconst isChangePaymentPage = () => {\n const urlParams = new URLSearchParams(window.location.search);\n return urlParams.has('change_payment_method');\n};\n;// CONCATENATED MODULE: ./resources/js/modules/ContextBootstrap/PayNowBootstrap.js\n\n\n\nclass PayNowBootstrap extends ContextBootstrap_CheckoutBootstap {\n constructor(gateway, renderer, messages, spinner) {\n super(gateway, renderer, messages, spinner);\n }\n\n updateUi() {\n if (isChangePaymentPage()) {\n return;\n }\n\n super.updateUi();\n }\n\n}\n\n/* harmony default export */ const ContextBootstrap_PayNowBootstrap = (PayNowBootstrap);\n// EXTERNAL MODULE: ./node_modules/deepmerge/dist/cjs.js\nvar cjs = __webpack_require__(996);\nvar cjs_default = /*#__PURE__*/__webpack_require__.n(cjs);\n;// CONCATENATED MODULE: ./resources/js/modules/Renderer/Renderer.js\n\n\nclass Renderer {\n constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {\n this.defaultSettings = defaultSettings;\n this.creditCardRenderer = creditCardRenderer;\n this.onSmartButtonClick = onSmartButtonClick;\n this.onSmartButtonsInit = onSmartButtonsInit;\n this.renderedSources = new Set();\n }\n\n render(contextConfig, settingsOverride = {}) {\n const settings = cjs_default()(this.defaultSettings, settingsOverride);\n const enabledSeparateGateways = Object.fromEntries(Object.entries(settings.separate_buttons).filter(([s, data]) => document.querySelector(data.wrapper)));\n const hasEnabledSeparateGateways = Object.keys(enabledSeparateGateways).length !== 0;\n\n if (!hasEnabledSeparateGateways) {\n this.renderButtons(settings.button.wrapper, settings.button.style, contextConfig, hasEnabledSeparateGateways);\n } else {\n // render each button separately\n for (const fundingSource of paypal.getFundingSources().filter(s => !(s in enabledSeparateGateways))) {\n let style = settings.button.style;\n\n if (fundingSource !== 'paypal') {\n style = {\n shape: style.shape\n };\n }\n\n this.renderButtons(settings.button.wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource);\n }\n }\n\n this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfig);\n\n for (const [fundingSource, data] of Object.entries(enabledSeparateGateways)) {\n this.renderButtons(data.wrapper, data.style, contextConfig, hasEnabledSeparateGateways, fundingSource);\n }\n }\n\n renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {\n if (!document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) || 'undefined' === typeof paypal.Buttons) {\n return;\n }\n\n if (fundingSource) {\n contextConfig.fundingSource = fundingSource;\n }\n\n const btn = paypal.Buttons({\n style,\n ...contextConfig,\n onClick: this.onSmartButtonClick,\n onInit: this.onSmartButtonsInit\n });\n\n if (!btn.isEligible()) {\n return;\n }\n\n btn.render(wrapper);\n this.renderedSources.add(wrapper + fundingSource ?? '');\n }\n\n isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) {\n // Simply check that has child nodes when we do not need to render buttons separately,\n // this will reduce the risk of breaking with different themes/plugins\n // and on the cart page (where we also do not need to render separately), which may fully reload this part of the page.\n // Ideally we should also find a way to detect such full reloads and remove the corresponding keys from the set.\n if (!hasEnabledSeparateGateways) {\n return document.querySelector(wrapper).hasChildNodes();\n }\n\n return this.renderedSources.has(wrapper + fundingSource ?? '');\n }\n\n hideButtons(element) {\n const domElement = document.querySelector(element);\n\n if (!domElement) {\n return false;\n }\n\n domElement.style.display = 'none';\n return true;\n }\n\n showButtons(element) {\n const domElement = document.querySelector(element);\n\n if (!domElement) {\n return false;\n }\n\n domElement.style.display = 'block';\n return true;\n }\n\n disableCreditCardFields() {\n this.creditCardRenderer.disableFields();\n }\n\n enableCreditCardFields() {\n this.creditCardRenderer.enableFields();\n }\n\n}\n\n/* harmony default export */ const Renderer_Renderer = (Renderer);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/DccInputFactory.js\nconst dccInputFactory = original => {\n const styles = window.getComputedStyle(original);\n const newElement = document.createElement('span');\n newElement.setAttribute('id', original.id);\n newElement.setAttribute('class', original.className);\n Object.values(styles).forEach(prop => {\n if (!styles[prop] || !isNaN(prop) || prop === 'background-image') {\n return;\n }\n\n newElement.style.setProperty(prop, '' + styles[prop]);\n });\n return newElement;\n};\n\n/* harmony default export */ const DccInputFactory = (dccInputFactory);\n;// CONCATENATED MODULE: ./resources/js/modules/Renderer/CreditCardRenderer.js\n\n\n\n\nclass CreditCardRenderer {\n constructor(defaultConfig, errorHandler, spinner) {\n this.defaultConfig = defaultConfig;\n this.errorHandler = errorHandler;\n this.spinner = spinner;\n this.cardValid = false;\n this.formValid = false;\n this.currentHostedFieldsInstance = null;\n }\n\n render(wrapper, contextConfig) {\n if (this.defaultConfig.context !== 'checkout' && this.defaultConfig.context !== 'pay-now' || wrapper === null || document.querySelector(wrapper) === null) {\n return;\n }\n\n if (typeof paypal.HostedFields === 'undefined' || !paypal.HostedFields.isEligible()) {\n const wrapperElement = document.querySelector(wrapper);\n wrapperElement.parentNode.removeChild(wrapperElement);\n return;\n }\n\n const buttonSelector = wrapper + ' button';\n\n if (this.currentHostedFieldsInstance) {\n this.currentHostedFieldsInstance.teardown().catch(err => console.error(`Hosted fields teardown error: ${err}`));\n this.currentHostedFieldsInstance = null;\n }\n\n const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway');\n\n if (!gateWayBox) {\n return;\n }\n\n const oldDisplayStyle = gateWayBox.style.display;\n gateWayBox.style.display = 'block';\n const hideDccGateway = document.querySelector('#ppcp-hide-dcc');\n\n if (hideDccGateway) {\n hideDccGateway.parentNode.removeChild(hideDccGateway);\n }\n\n const cardNumberField = document.querySelector('#ppcp-credit-card-gateway-card-number');\n const stylesRaw = window.getComputedStyle(cardNumberField);\n let styles = {};\n Object.values(stylesRaw).forEach(prop => {\n if (!stylesRaw[prop]) {\n return;\n }\n\n styles[prop] = '' + stylesRaw[prop];\n });\n const cardNumber = DccInputFactory(cardNumberField);\n cardNumberField.parentNode.replaceChild(cardNumber, cardNumberField);\n const cardExpiryField = document.querySelector('#ppcp-credit-card-gateway-card-expiry');\n const cardExpiry = DccInputFactory(cardExpiryField);\n cardExpiryField.parentNode.replaceChild(cardExpiry, cardExpiryField);\n const cardCodeField = document.querySelector('#ppcp-credit-card-gateway-card-cvc');\n const cardCode = DccInputFactory(cardCodeField);\n cardCodeField.parentNode.replaceChild(cardCode, cardCodeField);\n gateWayBox.style.display = oldDisplayStyle;\n const formWrapper = '.payment_box payment_method_ppcp-credit-card-gateway';\n\n if (this.defaultConfig.enforce_vault && document.querySelector(formWrapper + ' .ppcp-credit-card-vault')) {\n document.querySelector(formWrapper + ' .ppcp-credit-card-vault').checked = true;\n document.querySelector(formWrapper + ' .ppcp-credit-card-vault').setAttribute('disabled', true);\n }\n\n paypal.HostedFields.render({\n createOrder: contextConfig.createOrder,\n styles: {\n 'input': styles\n },\n fields: {\n number: {\n selector: '#ppcp-credit-card-gateway-card-number',\n placeholder: this.defaultConfig.hosted_fields.labels.credit_card_number\n },\n cvv: {\n selector: '#ppcp-credit-card-gateway-card-cvc',\n placeholder: this.defaultConfig.hosted_fields.labels.cvv\n },\n expirationDate: {\n selector: '#ppcp-credit-card-gateway-card-expiry',\n placeholder: this.defaultConfig.hosted_fields.labels.mm_yy\n }\n }\n }).then(hostedFields => {\n document.dispatchEvent(new CustomEvent(\"hosted_fields_loaded\"));\n this.currentHostedFieldsInstance = hostedFields;\n hostedFields.on('inputSubmitRequest', () => {\n this._submit(contextConfig);\n });\n hostedFields.on('cardTypeChange', event => {\n if (!event.cards.length) {\n this.cardValid = false;\n return;\n }\n\n const validCards = this.defaultConfig.hosted_fields.valid_cards;\n this.cardValid = validCards.indexOf(event.cards[0].type) !== -1;\n\n const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);\n\n this._recreateElementClassAttribute(cardNumber, cardNumberField.className);\n\n if (event.fields.number.isValid) {\n cardNumber.classList.add(className);\n }\n });\n hostedFields.on('validityChange', event => {\n const formValid = Object.keys(event.fields).every(function (key) {\n return event.fields[key].isValid;\n });\n\n const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);\n\n event.fields.number.isValid ? cardNumber.classList.add(className) : this._recreateElementClassAttribute(cardNumber, cardNumberField.className);\n this.formValid = formValid;\n });\n show(buttonSelector);\n\n if (document.querySelector(wrapper).getAttribute('data-ppcp-subscribed') !== true) {\n document.querySelector(buttonSelector).addEventListener('click', event => {\n event.preventDefault();\n\n this._submit(contextConfig);\n });\n document.querySelector(wrapper).setAttribute('data-ppcp-subscribed', true);\n }\n });\n document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener('click', () => {\n document.querySelector('label[for=ppcp-credit-card-gateway-card-number]').click();\n });\n }\n\n disableFields() {\n if (this.currentHostedFieldsInstance) {\n this.currentHostedFieldsInstance.setAttribute({\n field: 'number',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.setAttribute({\n field: 'cvv',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.setAttribute({\n field: 'expirationDate',\n attribute: 'disabled'\n });\n }\n }\n\n enableFields() {\n if (this.currentHostedFieldsInstance) {\n this.currentHostedFieldsInstance.removeAttribute({\n field: 'number',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.removeAttribute({\n field: 'cvv',\n attribute: 'disabled'\n });\n this.currentHostedFieldsInstance.removeAttribute({\n field: 'expirationDate',\n attribute: 'disabled'\n });\n }\n }\n\n _submit(contextConfig) {\n this.spinner.block();\n this.errorHandler.clear();\n\n if (this.formValid && this.cardValid) {\n const save_card = this.defaultConfig.can_save_vault_token ? true : false;\n let vault = document.getElementById('ppcp-credit-card-vault') ? document.getElementById('ppcp-credit-card-vault').checked : save_card;\n\n if (this.defaultConfig.enforce_vault) {\n vault = true;\n }\n\n const contingency = this.defaultConfig.hosted_fields.contingency;\n const hostedFieldsData = {\n vault: vault\n };\n\n if (contingency !== 'NO_3D_SECURE') {\n hostedFieldsData.contingencies = [contingency];\n }\n\n if (this.defaultConfig.payer) {\n hostedFieldsData.cardholderName = this.defaultConfig.payer.name.given_name + ' ' + this.defaultConfig.payer.name.surname;\n }\n\n if (!hostedFieldsData.cardholderName) {\n const firstName = document.getElementById('billing_first_name') ? document.getElementById('billing_first_name').value : '';\n const lastName = document.getElementById('billing_last_name') ? document.getElementById('billing_last_name').value : '';\n hostedFieldsData.cardholderName = firstName + ' ' + lastName;\n }\n\n this.currentHostedFieldsInstance.submit(hostedFieldsData).then(payload => {\n payload.orderID = payload.orderId;\n this.spinner.unblock();\n return contextConfig.onApprove(payload);\n }).catch(err => {\n this.spinner.unblock();\n this.errorHandler.clear();\n\n if (err.details) {\n this.errorHandler.message(err.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);\n }\n });\n } else {\n this.spinner.unblock();\n const message = !this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid;\n this.errorHandler.message(message);\n }\n }\n\n _cardNumberFiledCLassNameByCardType(cardType) {\n return cardType === 'american-express' ? 'amex' : cardType.replace('-', '');\n }\n\n _recreateElementClassAttribute(element, newClassName) {\n element.removeAttribute('class');\n element.setAttribute('class', newClassName);\n }\n\n}\n\n/* harmony default export */ const Renderer_CreditCardRenderer = (CreditCardRenderer);\n;// CONCATENATED MODULE: ./resources/js/modules/DataClientIdAttributeHandler.js\nconst storageKey = 'ppcp-data-client-id';\n\nconst validateToken = (token, user) => {\n if (!token) {\n return false;\n }\n\n if (token.user !== user) {\n return false;\n }\n\n const currentTime = new Date().getTime();\n const isExpired = currentTime >= token.expiration * 1000;\n return !isExpired;\n};\n\nconst storedTokenForUser = user => {\n const token = JSON.parse(sessionStorage.getItem(storageKey));\n\n if (validateToken(token, user)) {\n return token.token;\n }\n\n return null;\n};\n\nconst storeToken = token => {\n sessionStorage.setItem(storageKey, JSON.stringify(token));\n};\n\nconst dataClientIdAttributeHandler = (script, config) => {\n fetch(config.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: config.nonce\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n const isValid = validateToken(data, config.user);\n\n if (!isValid) {\n return;\n }\n\n storeToken(data);\n script.setAttribute('data-client-token', data.token);\n document.body.append(script);\n });\n};\n\n/* harmony default export */ const DataClientIdAttributeHandler = (dataClientIdAttributeHandler);\n;// CONCATENATED MODULE: ./resources/js/modules/Renderer/MessageRenderer.js\nclass MessageRenderer {\n constructor(config) {\n this.config = config;\n }\n\n render() {\n if (!this.shouldRender()) {\n return;\n }\n\n paypal.Messages({\n amount: this.config.amount,\n placement: this.config.placement,\n style: this.config.style\n }).render(this.config.wrapper);\n jQuery(document.body).on('updated_cart_totals', () => {\n paypal.Messages({\n amount: this.config.amount,\n placement: this.config.placement,\n style: this.config.style\n }).render(this.config.wrapper);\n });\n }\n\n renderWithAmount(amount) {\n if (!this.shouldRender()) {\n return;\n }\n\n const newWrapper = document.createElement('div');\n newWrapper.setAttribute('id', this.config.wrapper.replace('#', ''));\n const sibling = document.querySelector(this.config.wrapper).nextSibling;\n document.querySelector(this.config.wrapper).parentElement.removeChild(document.querySelector(this.config.wrapper));\n sibling.parentElement.insertBefore(newWrapper, sibling);\n paypal.Messages({\n amount,\n placement: this.config.placement,\n style: this.config.style\n }).render(this.config.wrapper);\n }\n\n shouldRender() {\n if (typeof paypal.Messages === 'undefined' || typeof this.config.wrapper === 'undefined') {\n return false;\n }\n\n if (!document.querySelector(this.config.wrapper)) {\n return false;\n }\n\n return true;\n }\n\n hideMessages() {\n const domElement = document.querySelector(this.config.wrapper);\n\n if (!domElement) {\n return false;\n }\n\n domElement.style.display = 'none';\n return true;\n }\n\n}\n\n/* harmony default export */ const Renderer_MessageRenderer = (MessageRenderer);\n;// CONCATENATED MODULE: ./resources/js/modules/Helper/Spinner.js\nclass Spinner {\n constructor(target = 'form.woocommerce-checkout') {\n this.target = target;\n }\n\n setTarget(target) {\n this.target = target;\n }\n\n block() {\n jQuery(this.target).block({\n message: null,\n overlayCSS: {\n background: '#fff',\n opacity: 0.6\n }\n });\n }\n\n unblock() {\n jQuery(this.target).unblock();\n }\n\n}\n\n/* harmony default export */ const Helper_Spinner = (Spinner);\n;// CONCATENATED MODULE: ./resources/js/modules/ActionHandler/FreeTrialHandler.js\n\n\n\nclass FreeTrialHandler {\n constructor(config, spinner, errorHandler) {\n this.config = config;\n this.spinner = spinner;\n this.errorHandler = errorHandler;\n }\n\n handle() {\n this.spinner.block();\n fetch(this.config.ajax.vault_paypal.endpoint, {\n method: 'POST',\n body: JSON.stringify({\n nonce: this.config.ajax.vault_paypal.nonce,\n return_url: location.href\n })\n }).then(res => {\n return res.json();\n }).then(data => {\n if (!data.success) {\n this.spinner.unblock();\n console.error(data);\n this.errorHandler.message(data.data.message);\n throw Error(data.data.message);\n }\n\n location.href = data.data.approve_link;\n }).catch(error => {\n this.spinner.unblock();\n console.error(error);\n this.errorHandler.genericError();\n });\n }\n\n}\n\n/* harmony default export */ const ActionHandler_FreeTrialHandler = (FreeTrialHandler);\n;// CONCATENATED MODULE: ./resources/js/button.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n // TODO: could be a good idea to have a separate spinner for each gateway,\n// but I think we care mainly about the script loading, so one spinner should be enough.\n\nconst buttonsSpinner = new Helper_Spinner(document.querySelector('.ppc-button-wrapper'));\nconst cardsSpinner = new Helper_Spinner('#ppcp-hosted-fields');\n\nconst bootstrap = () => {\n const errorHandler = new modules_ErrorHandler(PayPalCommerceGateway.labels.error.generic);\n const spinner = new Helper_Spinner();\n const creditCardRenderer = new Renderer_CreditCardRenderer(PayPalCommerceGateway, errorHandler, spinner);\n const freeTrialHandler = new ActionHandler_FreeTrialHandler(PayPalCommerceGateway, spinner, errorHandler);\n\n const onSmartButtonClick = (data, actions) => {\n window.ppcpFundingSource = data.fundingSource;\n\n if (PayPalCommerceGateway.basic_checkout_validation_enabled) {\n // TODO: quick fix to get the error about empty form before attempting PayPal order\n // it should solve #513 for most of the users, but proper solution should be implemented later.\n const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');\n requiredFields.each((i, input) => {\n jQuery(input).trigger('validate');\n });\n const invalidFields = Array.from(jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible'));\n\n if (invalidFields.length) {\n const billingFieldsContainer = document.querySelector('.woocommerce-billing-fields');\n const shippingFieldsContainer = document.querySelector('.woocommerce-shipping-fields');\n const nameMessageMap = PayPalCommerceGateway.labels.error.required.elements;\n const messages = invalidFields.map(el => {\n const name = el.querySelector('[name]')?.getAttribute('name');\n\n if (name && name in nameMessageMap) {\n return nameMessageMap[name];\n }\n\n let label = el.querySelector('label').textContent.replaceAll('*', '').trim();\n\n if (billingFieldsContainer?.contains(el)) {\n label = PayPalCommerceGateway.labels.billing_field.replace('%s', label);\n }\n\n if (shippingFieldsContainer?.contains(el)) {\n label = PayPalCommerceGateway.labels.shipping_field.replace('%s', label);\n }\n\n return PayPalCommerceGateway.labels.error.required.field.replace('%s', `<strong>${label}</strong>`);\n }).filter(s => s.length > 2);\n errorHandler.clear();\n\n if (messages.length) {\n messages.forEach(s => errorHandler.message(s));\n } else {\n errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);\n }\n\n return actions.reject();\n }\n }\n\n const form = document.querySelector('form.woocommerce-checkout');\n\n if (form) {\n jQuery('#ppcp-funding-source-form-input').remove();\n form.insertAdjacentHTML('beforeend', `<input type=\"hidden\" name=\"ppcp-funding-source\" value=\"${data.fundingSource}\" id=\"ppcp-funding-source-form-input\">`);\n }\n\n const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;\n\n if (isFreeTrial && data.fundingSource !== 'card') {\n freeTrialHandler.handle();\n return actions.reject();\n }\n };\n\n const onSmartButtonsInit = () => {\n buttonsSpinner.unblock();\n };\n\n const renderer = new Renderer_Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit);\n const messageRenderer = new Renderer_MessageRenderer(PayPalCommerceGateway.messages);\n const context = PayPalCommerceGateway.context;\n\n if (context === 'mini-cart' || context === 'product') {\n if (PayPalCommerceGateway.mini_cart_buttons_enabled === '1') {\n const miniCartBootstrap = new ContextBootstrap_MiniCartBootstap(PayPalCommerceGateway, renderer);\n miniCartBootstrap.init();\n }\n }\n\n if (context === 'product' && PayPalCommerceGateway.single_product_buttons_enabled === '1') {\n const singleProductBootstrap = new ContextBootstrap_SingleProductBootstap(PayPalCommerceGateway, renderer, messageRenderer);\n singleProductBootstrap.init();\n }\n\n if (context === 'cart') {\n const cartBootstrap = new CartBootstap(PayPalCommerceGateway, renderer);\n cartBootstrap.init();\n }\n\n if (context === 'checkout') {\n const checkoutBootstap = new ContextBootstrap_CheckoutBootstap(PayPalCommerceGateway, renderer, messageRenderer, spinner);\n checkoutBootstap.init();\n }\n\n if (context === 'pay-now') {\n const payNowBootstrap = new ContextBootstrap_PayNowBootstrap(PayPalCommerceGateway, renderer, messageRenderer, spinner);\n payNowBootstrap.init();\n }\n\n if (context !== 'checkout') {\n messageRenderer.render();\n }\n};\n\ndocument.addEventListener('DOMContentLoaded', () => {\n if (!typeof PayPalCommerceGateway) {\n console.error('PayPal button could not be configured.');\n return;\n }\n\n if (PayPalCommerceGateway.context !== 'checkout' && PayPalCommerceGateway.data_client_id.user === 0 && PayPalCommerceGateway.data_client_id.has_subscriptions) {\n return;\n }\n\n const paypalButtonGatewayIds = [PaymentMethods.PAYPAL, ...Object.entries(PayPalCommerceGateway.separate_buttons).map(([k, data]) => data.id)]; // Sometimes PayPal script takes long time to load,\n // so we additionally hide the standard order button here to avoid failed orders.\n // Normally it is hidden later after the script load.\n\n const hideOrderButtonIfPpcpGateway = () => {\n // only in checkout and pay now page, otherwise it may break things (e.g. payment via product page),\n // and also the loading spinner may look weird on other pages\n if (!['checkout', 'pay-now'].includes(PayPalCommerceGateway.context) || isChangePaymentPage() || PayPalCommerceGateway.is_free_trial_cart && PayPalCommerceGateway.vaulted_paypal_email !== '') {\n return;\n }\n\n const currentPaymentMethod = getCurrentPaymentMethod();\n const isPaypalButton = paypalButtonGatewayIds.includes(currentPaymentMethod);\n const isCards = currentPaymentMethod === PaymentMethods.CARDS;\n setVisible(ORDER_BUTTON_SELECTOR, !isPaypalButton && !isCards, true);\n\n if (isPaypalButton) {\n // stopped after the first rendering of the buttons, in onInit\n buttonsSpinner.block();\n } else {\n buttonsSpinner.unblock();\n }\n\n if (isCards) {\n cardsSpinner.block();\n } else {\n cardsSpinner.unblock();\n }\n };\n\n jQuery(document).on('hosted_fields_loaded', () => {\n cardsSpinner.unblock();\n });\n let bootstrapped = false;\n hideOrderButtonIfPpcpGateway();\n jQuery(document.body).on('updated_checkout payment_method_selected', () => {\n if (bootstrapped) {\n return;\n }\n\n hideOrderButtonIfPpcpGateway();\n });\n const script = document.createElement('script');\n script.addEventListener('load', event => {\n bootstrapped = true;\n bootstrap();\n });\n script.setAttribute('src', PayPalCommerceGateway.button.url);\n Object.entries(PayPalCommerceGateway.script_attributes).forEach(keyValue => {\n script.setAttribute(keyValue[0], keyValue[1]);\n });\n\n if (PayPalCommerceGateway.data_client_id.set_attribute) {\n DataClientIdAttributeHandler(script, PayPalCommerceGateway.data_client_id);\n return;\n }\n\n document.body.append(script);\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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MVosRUFBQUEsTUFBTSxDQUFDdEIsUUFBUSxDQUFDMkMsSUFBVixDQUFOLENBQXNCb0UsRUFBdEIsQ0FBeUIsMENBQXpCLEVBQXFFLE1BQU07QUFDdkUsUUFBSW9VLFlBQUosRUFBa0I7QUFDZDtBQUNIOztBQUVESCxJQUFBQSw0QkFBNEI7QUFDL0IsR0FORDtBQVFBLFFBQU14RCxNQUFNLEdBQUd4WCxRQUFRLENBQUN3QixhQUFULENBQXVCLFFBQXZCLENBQWY7QUFDQWdXLEVBQUFBLE1BQU0sQ0FBQ3JOLGdCQUFQLENBQXdCLE1BQXhCLEVBQWlDcUssS0FBRCxJQUFXO0FBQ3ZDMkcsSUFBQUEsWUFBWSxHQUFHLElBQWY7QUFFQXBDLElBQUFBLFNBQVM7QUFDWixHQUpEO0FBS0F2QixFQUFBQSxNQUFNLENBQUMvVixZQUFQLENBQW9CLEtBQXBCLEVBQTJCdUMscUJBQXFCLENBQUNpRCxNQUF0QixDQUE2Qm1VLEdBQXhEO0FBQ0E1UCxFQUFBQSxNQUFNLENBQUNtRCxPQUFQLENBQWUzSyxxQkFBcUIsQ0FBQ3FYLGlCQUFyQyxFQUF3RC9SLE9BQXhELENBQ0tnUyxRQUFELElBQWM7QUFDVjlELElBQUFBLE1BQU0sQ0FBQy9WLFlBQVAsQ0FBb0I2WixRQUFRLENBQUMsQ0FBRCxDQUE1QixFQUFpQ0EsUUFBUSxDQUFDLENBQUQsQ0FBekM7QUFDSCxHQUhMOztBQU1BLE1BQUl0WCxxQkFBcUIsQ0FBQzZXLGNBQXRCLENBQXFDVSxhQUF6QyxFQUF3RDtBQUNwRGhFLElBQUFBLDRCQUE0QixDQUFDQyxNQUFELEVBQVN4VCxxQkFBcUIsQ0FBQzZXLGNBQS9CLENBQTVCO0FBQ0E7QUFDSDs7QUFFRDdhLEVBQUFBLFFBQVEsQ0FBQzJDLElBQVQsQ0FBYzhKLE1BQWQsQ0FBcUIrSyxNQUFyQjtBQUNILENBMUZMIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0Vycm9ySGFuZGxlci5qcz9lNjVhIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvckNvbnRpbnVlLmpzP2M0NTQiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9QYXllckRhdGEuanM/MmFmMSIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGUuanM/ODBhMyIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQWN0aW9uSGFuZGxlci9DYXJ0QWN0aW9uSGFuZGxlci5qcz84MmNmIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL01pbmlDYXJ0Qm9vdHN0YXAuanM/ZDU1MiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvSGVscGVyL1VwZGF0ZUNhcnQuanM/ZTQyMiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvSGVscGVyL0J1dHRvbnNUb2dnbGVMaXN0ZW5lci5qcz9lMTkzIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9FbnRpdHkvUHJvZHVjdC5qcz85ZmZmIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9BY3Rpb25IYW5kbGVyL1NpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyLmpzP2Q5YjciLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvU2luZ2xlUHJvZHVjdEJvb3RzdGFwLmpzPzdjMTkiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2FydEJvb3RzdGFwLmpzPzVlOTQiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yUGF5Tm93LmpzPzkzMDUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvQ2hlY2tvdXRBY3Rpb25IYW5kbGVyLmpzPzg1MTUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9IaWRpbmcuanM/MWQzNiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9DaGVja291dEJvb3RzdGFwLmpzP2M4NTUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9TdWJzY3JpcHRpb25zLmpzP2I4NzAiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvUGF5Tm93Qm9vdHN0cmFwLmpzP2Q5ZjUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL1JlbmRlcmVyL1JlbmRlcmVyLmpzP2ZhOTMiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9EY2NJbnB1dEZhY3RvcnkuanM/MmEyZiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvUmVuZGVyZXIvQ3JlZGl0Q2FyZFJlbmRlcmVyLmpzPzM4N2EiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0RhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIuanM/ZWUwYiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvUmVuZGVyZXIvTWVzc2FnZVJlbmRlcmVyLmpzP2NkMDIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9TcGlubmVyLmpzPzE3MDgiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvRnJlZVRyaWFsSGFuZGxlci5qcz9hYjc3Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvYnV0dG9uLmpzPzA2MGYiXSwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRXJyb3JIYW5kbGVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGdlbmVyaWNFcnJvclRleHQpXG4gICAge1xuICAgICAgICB0aGlzLmdlbmVyaWNFcnJvclRleHQgPSBnZW5lcmljRXJyb3JUZXh0O1xuICAgICAgICB0aGlzLndyYXBwZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcud29vY29tbWVyY2Utbm90aWNlcy13cmFwcGVyJyk7XG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigndWwud29vY29tbWVyY2UtZXJyb3InKTtcbiAgICB9XG5cbiAgICBnZW5lcmljRXJyb3IoKSB7XG4gICAgICAgIGlmICh0aGlzLndyYXBwZXIuY2xhc3NMaXN0LmNvbnRhaW5zKCdwcGNwLXBlcnNpc3QnKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5tZXNzYWdlKHRoaXMuZ2VuZXJpY0Vycm9yVGV4dClcbiAgICB9XG5cbiAgICBhcHBlbmRQcmVwYXJlZEVycm9yTWVzc2FnZUVsZW1lbnQoZXJyb3JNZXNzYWdlRWxlbWVudClcbiAgICB7XG4gICAgICAgIGlmKHRoaXMubWVzc2FnZXNMaXN0ID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnByZXBhcmVNZXNzYWdlc0xpc3QoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LnJlcGxhY2VXaXRoKGVycm9yTWVzc2FnZUVsZW1lbnQpO1xuICAgIH1cblxuICAgIG1lc3NhZ2UodGV4dCwgcGVyc2lzdCA9IGZhbHNlKVxuICAgIHtcbiAgICAgICAgaWYoISB0eXBlb2YgU3RyaW5nIHx8IHRleHQubGVuZ3RoID09PSAwKXtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQSBuZXcgbWVzc2FnZSB0ZXh0IG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYodGhpcy5tZXNzYWdlc0xpc3QgPT09IG51bGwpe1xuICAgICAgICAgICAgdGhpcy5wcmVwYXJlTWVzc2FnZXNMaXN0KCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGVyc2lzdCkge1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyLmNsYXNzTGlzdC5hZGQoJ3BwY3AtcGVyc2lzdCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyLmNsYXNzTGlzdC5yZW1vdmUoJ3BwY3AtcGVyc2lzdCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG1lc3NhZ2VOb2RlID0gdGhpcy5wcmVwYXJlTWVzc2FnZXNMaXN0SXRlbSh0ZXh0KTtcbiAgICAgICAgdGhpcy5tZXNzYWdlc0xpc3QuYXBwZW5kQ2hpbGQobWVzc2FnZU5vZGUpO1xuXG4gICAgICAgIGpRdWVyeS5zY3JvbGxfdG9fbm90aWNlcyhqUXVlcnkoJy53b29jb21tZXJjZS1ub3RpY2VzLXdyYXBwZXInKSlcbiAgICB9XG5cbiAgICBwcmVwYXJlTWVzc2FnZXNMaXN0KClcbiAgICB7XG4gICAgICAgIGlmKHRoaXMubWVzc2FnZXNMaXN0ID09PSBudWxsKXtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXNMaXN0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKTtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LnNldEF0dHJpYnV0ZSgnY2xhc3MnLCAnd29vY29tbWVyY2UtZXJyb3InKTtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LnNldEF0dHJpYnV0ZSgncm9sZScsICdhbGVydCcpO1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyLmFwcGVuZENoaWxkKHRoaXMubWVzc2FnZXNMaXN0KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByZXBhcmVNZXNzYWdlc0xpc3RJdGVtKG1lc3NhZ2UpXG4gICAge1xuICAgICAgICBjb25zdCBsaSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7XG4gICAgICAgIGxpLmlubmVySFRNTCA9IG1lc3NhZ2U7XG5cbiAgICAgICAgcmV0dXJuIGxpO1xuICAgIH1cblxuICAgIHNhbml0aXplKHRleHQpXG4gICAge1xuICAgICAgICBjb25zdCB0ZXh0YXJlYSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RleHRhcmVhJyk7XG4gICAgICAgIHRleHRhcmVhLmlubmVySFRNTCA9IHRleHQ7XG4gICAgICAgIHJldHVybiB0ZXh0YXJlYS52YWx1ZS5yZXBsYWNlKCdFcnJvcjogJywgJycpO1xuICAgIH1cblxuICAgIGNsZWFyKClcbiAgICB7XG4gICAgICAgIGlmICh0aGlzLm1lc3NhZ2VzTGlzdCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tZXNzYWdlc0xpc3QuaW5uZXJIVE1MID0gJyc7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBFcnJvckhhbmRsZXI7XG4iLCJjb25zdCBvbkFwcHJvdmUgPSAoY29udGV4dCwgZXJyb3JIYW5kbGVyKSA9PiB7XG4gICAgcmV0dXJuIChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgIHJldHVybiBmZXRjaChjb250ZXh0LmNvbmZpZy5hamF4LmFwcHJvdmVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIG5vbmNlOiBjb250ZXh0LmNvbmZpZy5hamF4LmFwcHJvdmVfb3JkZXIubm9uY2UsXG4gICAgICAgICAgICAgICAgb3JkZXJfaWQ6ZGF0YS5vcmRlcklELFxuICAgICAgICAgICAgICAgIGZ1bmRpbmdfc291cmNlOiB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UsXG4gICAgICAgICAgICB9KVxuICAgICAgICB9KS50aGVuKChyZXMpPT57XG4gICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICAgICAgfSkudGhlbigoZGF0YSk9PntcbiAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIHJldHVybiBhY3Rpb25zLnJlc3RhcnQoKS5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsb2NhdGlvbi5ocmVmID0gY29udGV4dC5jb25maWcucmVkaXJlY3Q7XG4gICAgICAgIH0pO1xuXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBvbkFwcHJvdmU7XG4iLCJleHBvcnQgY29uc3QgcGF5ZXJEYXRhID0gKCkgPT4ge1xuICAgIGNvbnN0IHBheWVyID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LnBheWVyO1xuICAgIGlmICghIHBheWVyKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHBob25lID0gKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3Bob25lJykgfHwgdHlwZW9mIHBheWVyLnBob25lICE9PSAndW5kZWZpbmVkJykgP1xuICAgIHtcbiAgICAgICAgcGhvbmVfdHlwZTpcIkhPTUVcIixcbiAgICAgICAgICAgIHBob25lX251bWJlcjp7XG4gICAgICAgICAgICBuYXRpb25hbF9udW1iZXIgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcGhvbmUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19waG9uZScpLnZhbHVlIDogcGF5ZXIucGhvbmUucGhvbmVfbnVtYmVyLm5hdGlvbmFsX251bWJlclxuICAgICAgICB9XG4gICAgfSA6IG51bGw7XG4gICAgY29uc3QgcGF5ZXJEYXRhID0ge1xuICAgICAgICBlbWFpbF9hZGRyZXNzOihkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19lbWFpbCcpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2VtYWlsJykudmFsdWUgOiBwYXllci5lbWFpbF9hZGRyZXNzLFxuICAgICAgICBuYW1lIDoge1xuICAgICAgICAgICAgc3VybmFtZTogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2xhc3RfbmFtZScpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2xhc3RfbmFtZScpLnZhbHVlIDogcGF5ZXIubmFtZS5zdXJuYW1lLFxuICAgICAgICAgICAgZ2l2ZW5fbmFtZTogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2ZpcnN0X25hbWUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19maXJzdF9uYW1lJykudmFsdWUgOiBwYXllci5uYW1lLmdpdmVuX25hbWVcbiAgICAgICAgfSxcbiAgICAgICAgYWRkcmVzcyA6IHtcbiAgICAgICAgICAgIGNvdW50cnlfY29kZSA6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19jb3VudHJ5JykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfY291bnRyeScpLnZhbHVlIDogcGF5ZXIuYWRkcmVzcy5jb3VudHJ5X2NvZGUsXG4gICAgICAgICAgICBhZGRyZXNzX2xpbmVfMSA6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzEnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzEnKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRkcmVzc19saW5lXzEsXG4gICAgICAgICAgICBhZGRyZXNzX2xpbmVfMiA6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzInKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzInKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRkcmVzc19saW5lXzIsXG4gICAgICAgICAgICBhZG1pbl9hcmVhXzEgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfc3RhdGUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19zdGF0ZScpLnZhbHVlIDogcGF5ZXIuYWRkcmVzcy5hZG1pbl9hcmVhXzEsXG4gICAgICAgICAgICBhZG1pbl9hcmVhXzIgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfY2l0eScpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2NpdHknKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRtaW5fYXJlYV8yLFxuICAgICAgICAgICAgcG9zdGFsX2NvZGUgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcG9zdGNvZGUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19wb3N0Y29kZScpLnZhbHVlIDogcGF5ZXIuYWRkcmVzcy5wb3N0YWxfY29kZVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIGlmIChwaG9uZSkge1xuICAgICAgICBwYXllckRhdGEucGhvbmUgPSBwaG9uZTtcbiAgICB9XG4gICAgcmV0dXJuIHBheWVyRGF0YTtcbn1cbiIsImV4cG9ydCBjb25zdCBQYXltZW50TWV0aG9kcyA9IHtcbiAgICBQQVlQQUw6ICdwcGNwLWdhdGV3YXknLFxuICAgIENBUkRTOiAncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5JyxcbiAgICBPWFhPOiAncHBjcC1veHhvLWdhdGV3YXknLFxuICAgIENBUkRfQlVUVE9OOiAncHBjcC1jYXJkLWJ1dHRvbi1nYXRld2F5Jyxcbn07XG5cbmV4cG9ydCBjb25zdCBPUkRFUl9CVVRUT05fU0VMRUNUT1IgPSAnI3BsYWNlX29yZGVyJztcblxuZXhwb3J0IGNvbnN0IGdldEN1cnJlbnRQYXltZW50TWV0aG9kID0gKCkgPT4ge1xuICAgIGNvbnN0IGVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignaW5wdXRbbmFtZT1cInBheW1lbnRfbWV0aG9kXCJdOmNoZWNrZWQnKTtcbiAgICBpZiAoIWVsKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBlbC52YWx1ZTtcbn07XG5cbmV4cG9ydCBjb25zdCBpc1NhdmVkQ2FyZFNlbGVjdGVkID0gKCkgPT4ge1xuICAgIGNvbnN0IHNhdmVkQ2FyZExpc3QgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjc2F2ZWQtY3JlZGl0LWNhcmQnKTtcbiAgICByZXR1cm4gc2F2ZWRDYXJkTGlzdCAmJiBzYXZlZENhcmRMaXN0LnZhbHVlICE9PSAnJztcbn07XG4iLCJpbXBvcnQgb25BcHByb3ZlIGZyb20gJy4uL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yQ29udGludWUuanMnO1xuaW1wb3J0IHtwYXllckRhdGF9IGZyb20gXCIuLi9IZWxwZXIvUGF5ZXJEYXRhXCI7XG5pbXBvcnQge1BheW1lbnRNZXRob2RzfSBmcm9tIFwiLi4vSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcblxuY2xhc3MgQ2FydEFjdGlvbkhhbmRsZXIge1xuXG4gICAgY29uc3RydWN0b3IoY29uZmlnLCBlcnJvckhhbmRsZXIpIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyID0gZXJyb3JIYW5kbGVyO1xuICAgIH1cblxuICAgIGNvbmZpZ3VyYXRpb24oKSB7XG4gICAgICAgIGNvbnN0IGNyZWF0ZU9yZGVyID0gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBheWVyID0gcGF5ZXJEYXRhKCk7XG4gICAgICAgICAgICBjb25zdCBibkNvZGUgPSB0eXBlb2YgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gIT09ICd1bmRlZmluZWQnID9cbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIGZldGNoKHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICBub25jZTogdGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIubm9uY2UsXG4gICAgICAgICAgICAgICAgICAgIHB1cmNoYXNlX3VuaXRzOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgcGF5bWVudF9tZXRob2Q6IFBheW1lbnRNZXRob2RzLlBBWVBBTCxcbiAgICAgICAgICAgICAgICAgICAgZnVuZGluZ19zb3VyY2U6IHdpbmRvdy5wcGNwRnVuZGluZ1NvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgYm5fY29kZTpibkNvZGUsXG4gICAgICAgICAgICAgICAgICAgIHBheWVyLFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0OnRoaXMuY29uZmlnLmNvbnRleHRcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24ocmVzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBkYXRhLmRhdGEuaWQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY3JlYXRlT3JkZXIsXG4gICAgICAgICAgICBvbkFwcHJvdmU6IG9uQXBwcm92ZSh0aGlzLCB0aGlzLmVycm9ySGFuZGxlciksXG4gICAgICAgICAgICBvbkVycm9yOiAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IENhcnRBY3Rpb25IYW5kbGVyO1xuIiwiaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuaW1wb3J0IENhcnRBY3Rpb25IYW5kbGVyIGZyb20gJy4uL0FjdGlvbkhhbmRsZXIvQ2FydEFjdGlvbkhhbmRsZXInO1xuXG5jbGFzcyBNaW5pQ2FydEJvb3RzdGFwIHtcbiAgICBjb25zdHJ1Y3RvcihnYXRld2F5LCByZW5kZXJlcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgICAgIHRoaXMuYWN0aW9uSGFuZGxlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaW5pdCgpIHtcblxuICAgICAgICB0aGlzLmFjdGlvbkhhbmRsZXIgPSBuZXcgQ2FydEFjdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICBuZXcgRXJyb3JIYW5kbGVyKHRoaXMuZ2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyksXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMucmVuZGVyKCk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd3Y19mcmFnbWVudHNfbG9hZGVkIHdjX2ZyYWdtZW50c19yZWZyZXNoZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5idXR0b24ubWluaV9jYXJ0X3dyYXBwZXIpICE9PSBudWxsXG4gICAgICAgICAgICB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLm1pbmlfY2FydF93cmFwcGVyKSAhPT0gbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICB0aGlzLmFjdGlvbkhhbmRsZXIuY29uZmlndXJhdGlvbigpLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGJ1dHRvbjoge1xuICAgICAgICAgICAgICAgICAgICB3cmFwcGVyOiB0aGlzLmdhdGV3YXkuYnV0dG9uLm1pbmlfY2FydF93cmFwcGVyLFxuICAgICAgICAgICAgICAgICAgICBzdHlsZTogdGhpcy5nYXRld2F5LmJ1dHRvbi5taW5pX2NhcnRfc3R5bGUsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IE1pbmlDYXJ0Qm9vdHN0YXA7XG4iLCJpbXBvcnQgUHJvZHVjdCBmcm9tIFwiLi4vRW50aXR5L1Byb2R1Y3RcIjtcbmNsYXNzIFVwZGF0ZUNhcnQge1xuXG4gICAgY29uc3RydWN0b3IoZW5kcG9pbnQsIG5vbmNlKVxuICAgIHtcbiAgICAgICAgdGhpcy5lbmRwb2ludCA9IGVuZHBvaW50O1xuICAgICAgICB0aGlzLm5vbmNlID0gbm9uY2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gb25SZXNvbHZlXG4gICAgICogQHBhcmFtIHtQcm9kdWN0W119IHByb2R1Y3RzXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59XG4gICAgICovXG4gICAgdXBkYXRlKG9uUmVzb2x2ZSwgcHJvZHVjdHMpXG4gICAge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgZmV0Y2goXG4gICAgICAgICAgICAgICAgdGhpcy5lbmRwb2ludCxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgICAgICAgICBub25jZTogdGhpcy5ub25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RzLFxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICkudGhlbihcbiAgICAgICAgICAgICAgICAocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdC5qc29uKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKS50aGVuKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoISByZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgICAgICByZWplY3QocmVzdWx0LmRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc29sdmVkID0gb25SZXNvbHZlKHJlc3VsdC5kYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShyZXNvbHZlZCk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBVcGRhdGVDYXJ0OyIsIi8qKlxuICogV2hlbiB5b3UgY2FuJ3QgYWRkIHNvbWV0aGluZyB0byB0aGUgY2FydCwgdGhlIFBheVBhbCBidXR0b25zIHNob3VsZCBub3Qgc2hvdy5cbiAqIFRoZXJlZm9yZSB3ZSBsaXN0ZW4gZm9yIGNoYW5nZXMgb24gdGhlIGFkZCB0byBjYXJ0IGJ1dHRvbiBhbmQgc2hvdy9oaWRlIHRoZSBidXR0b25zIGFjY29yZGluZ2x5LlxuICovXG5cbmNsYXNzIEJ1dHRvbnNUb2dnbGVMaXN0ZW5lciB7XG4gICAgY29uc3RydWN0b3IoZWxlbWVudCwgc2hvd0NhbGxiYWNrLCBoaWRlQ2FsbGJhY2spXG4gICAge1xuICAgICAgICB0aGlzLmVsZW1lbnQgPSBlbGVtZW50O1xuICAgICAgICB0aGlzLnNob3dDYWxsYmFjayA9IHNob3dDYWxsYmFjaztcbiAgICAgICAgdGhpcy5oaWRlQ2FsbGJhY2sgPSBoaWRlQ2FsbGJhY2s7XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIgPSBudWxsO1xuICAgIH1cblxuICAgIGluaXQoKVxuICAgIHtcbiAgICAgICAgY29uc3QgY29uZmlnID0geyBhdHRyaWJ1dGVzIDogdHJ1ZSB9O1xuICAgICAgICBjb25zdCBjYWxsYmFjayA9ICgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdkaXNhYmxlZCcpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5oaWRlQ2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNob3dDYWxsYmFjaygpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcihjYWxsYmFjayk7XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLmVsZW1lbnQsIGNvbmZpZyk7XG4gICAgICAgIGNhbGxiYWNrKCk7XG4gICAgfVxuXG4gICAgZGlzY29ubmVjdCgpXG4gICAge1xuICAgICAgICB0aGlzLm9ic2VydmVyLmRpc2Nvbm5lY3QoKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEJ1dHRvbnNUb2dnbGVMaXN0ZW5lcjsiLCJjbGFzcyBQcm9kdWN0IHtcblxuICAgIGNvbnN0cnVjdG9yKGlkLCBxdWFudGl0eSwgdmFyaWF0aW9ucykge1xuICAgICAgICB0aGlzLmlkID0gaWQ7XG4gICAgICAgIHRoaXMucXVhbnRpdHkgPSBxdWFudGl0eTtcbiAgICAgICAgdGhpcy52YXJpYXRpb25zID0gdmFyaWF0aW9ucztcbiAgICB9XG5cbiAgICBkYXRhKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgaWQ6dGhpcy5pZCxcbiAgICAgICAgICAgIHF1YW50aXR5OnRoaXMucXVhbnRpdHksXG4gICAgICAgICAgICB2YXJpYXRpb25zOnRoaXMudmFyaWF0aW9uc1xuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBQcm9kdWN0OyIsImltcG9ydCBCdXR0b25zVG9nZ2xlTGlzdGVuZXIgZnJvbSAnLi4vSGVscGVyL0J1dHRvbnNUb2dnbGVMaXN0ZW5lcic7XG5pbXBvcnQgUHJvZHVjdCBmcm9tICcuLi9FbnRpdHkvUHJvZHVjdCc7XG5pbXBvcnQgb25BcHByb3ZlIGZyb20gJy4uL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yQ29udGludWUnO1xuaW1wb3J0IHtwYXllckRhdGF9IGZyb20gXCIuLi9IZWxwZXIvUGF5ZXJEYXRhXCI7XG5pbXBvcnQge1BheW1lbnRNZXRob2RzfSBmcm9tIFwiLi4vSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcblxuY2xhc3MgU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXIge1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgdXBkYXRlQ2FydCxcbiAgICAgICAgc2hvd0J1dHRvbkNhbGxiYWNrLFxuICAgICAgICBoaWRlQnV0dG9uQ2FsbGJhY2ssXG4gICAgICAgIGZvcm1FbGVtZW50LFxuICAgICAgICBlcnJvckhhbmRsZXJcbiAgICApIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgICAgIHRoaXMudXBkYXRlQ2FydCA9IHVwZGF0ZUNhcnQ7XG4gICAgICAgIHRoaXMuc2hvd0J1dHRvbkNhbGxiYWNrID0gc2hvd0J1dHRvbkNhbGxiYWNrO1xuICAgICAgICB0aGlzLmhpZGVCdXR0b25DYWxsYmFjayA9IGhpZGVCdXR0b25DYWxsYmFjaztcbiAgICAgICAgdGhpcy5mb3JtRWxlbWVudCA9IGZvcm1FbGVtZW50O1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICB9XG5cbiAgICBjb25maWd1cmF0aW9uKClcbiAgICB7XG5cbiAgICAgICAgaWYgKCB0aGlzLmhhc1ZhcmlhdGlvbnMoKSApIHtcbiAgICAgICAgICAgIGNvbnN0IG9ic2VydmVyID0gbmV3IEJ1dHRvbnNUb2dnbGVMaXN0ZW5lcihcbiAgICAgICAgICAgICAgICB0aGlzLmZvcm1FbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zaW5nbGVfYWRkX3RvX2NhcnRfYnV0dG9uJyksXG4gICAgICAgICAgICAgICAgdGhpcy5zaG93QnV0dG9uQ2FsbGJhY2ssXG4gICAgICAgICAgICAgICAgdGhpcy5oaWRlQnV0dG9uQ2FsbGJhY2tcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBvYnNlcnZlci5pbml0KCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY3JlYXRlT3JkZXI6IHRoaXMuY3JlYXRlT3JkZXIoKSxcbiAgICAgICAgICAgIG9uQXBwcm92ZTogb25BcHByb3ZlKHRoaXMsIHRoaXMuZXJyb3JIYW5kbGVyKSxcbiAgICAgICAgICAgIG9uRXJyb3I6IChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgY3JlYXRlT3JkZXIoKVxuICAgIHtcbiAgICAgICAgdmFyIGdldFByb2R1Y3RzID0gbnVsbDtcbiAgICAgICAgaWYgKCEgdGhpcy5pc0dyb3VwZWRQcm9kdWN0KCkgKSB7XG4gICAgICAgICAgICBnZXRQcm9kdWN0cyA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBpZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ1tuYW1lPVwiYWRkLXRvLWNhcnRcIl0nKS52YWx1ZTtcbiAgICAgICAgICAgICAgICBjb25zdCBxdHkgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdbbmFtZT1cInF1YW50aXR5XCJdJykudmFsdWU7XG4gICAgICAgICAgICAgICAgY29uc3QgdmFyaWF0aW9ucyA9IHRoaXMudmFyaWF0aW9ucygpO1xuICAgICAgICAgICAgICAgIHJldHVybiBbbmV3IFByb2R1Y3QoaWQsIHF0eSwgdmFyaWF0aW9ucyldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZ2V0UHJvZHVjdHMgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgcHJvZHVjdHMgPSBbXTtcbiAgICAgICAgICAgICAgICB0aGlzLmZvcm1FbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ2lucHV0W3R5cGU9XCJudW1iZXJcIl0nKS5mb3JFYWNoKChlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghIGVsZW1lbnQudmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50TmFtZSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCduYW1lJykubWF0Y2goL3F1YW50aXR5XFxbKFtcXGRdKilcXF0vKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnROYW1lLmxlbmd0aCAhPT0gMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlkID0gcGFyc2VJbnQoZWxlbWVudE5hbWVbMV0pO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBxdWFudGl0eSA9IHBhcnNlSW50KGVsZW1lbnQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICBwcm9kdWN0cy5wdXNoKG5ldyBQcm9kdWN0KGlkLCBxdWFudGl0eSwgbnVsbCkpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgcmV0dXJuIHByb2R1Y3RzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNyZWF0ZU9yZGVyID0gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmNsZWFyKCk7XG5cbiAgICAgICAgICAgIGNvbnN0IG9uUmVzb2x2ZSA9IChwdXJjaGFzZV91bml0cykgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHBheWVyID0gcGF5ZXJEYXRhKCk7XG4gICAgICAgICAgICAgICAgY29uc3QgYm5Db2RlID0gdHlwZW9mIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdICE9PSAndW5kZWZpbmVkJyA/XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdIDogJyc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZldGNoKHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgICAgICAgICBub25jZTogdGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIubm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBwdXJjaGFzZV91bml0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBheWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgYm5fY29kZTpibkNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXltZW50X21ldGhvZDogUGF5bWVudE1ldGhvZHMuUEFZUEFMLFxuICAgICAgICAgICAgICAgICAgICAgICAgZnVuZGluZ19zb3VyY2U6IHdpbmRvdy5wcGNwRnVuZGluZ1NvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6dGhpcy5jb25maWcuY29udGV4dFxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICAgICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkYXRhLmRhdGEuaWQ7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBjb25zdCBwcm9taXNlID0gdGhpcy51cGRhdGVDYXJ0LnVwZGF0ZShvblJlc29sdmUsIGdldFByb2R1Y3RzKCkpO1xuICAgICAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBjcmVhdGVPcmRlcjtcbiAgICB9XG5cbiAgICB2YXJpYXRpb25zKClcbiAgICB7XG5cbiAgICAgICAgaWYgKCEgdGhpcy5oYXNWYXJpYXRpb25zKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBbLi4udGhpcy5mb3JtRWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKFwiW25hbWVePSdhdHRyaWJ1dGVfJ11cIildLm1hcChcbiAgICAgICAgICAgIChlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZTplbGVtZW50LnZhbHVlLFxuICAgICAgICAgICAgICAgICAgICBuYW1lOmVsZW1lbnQubmFtZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIGF0dHJpYnV0ZXM7XG4gICAgfVxuXG4gICAgaGFzVmFyaWF0aW9ucygpXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtRWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ3ZhcmlhdGlvbnNfZm9ybScpO1xuICAgIH1cblxuICAgIGlzR3JvdXBlZFByb2R1Y3QoKVxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZm9ybUVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdncm91cGVkX2Zvcm0nKTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBTaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlcjtcbiIsImltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcbmltcG9ydCBVcGRhdGVDYXJ0IGZyb20gXCIuLi9IZWxwZXIvVXBkYXRlQ2FydFwiO1xuaW1wb3J0IFNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyIGZyb20gXCIuLi9BY3Rpb25IYW5kbGVyL1NpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyXCI7XG5cbmNsYXNzIFNpbmdsZVByb2R1Y3RCb290c3RhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIsIG1lc3NhZ2VzKSB7XG4gICAgICAgIHRoaXMuZ2F0ZXdheSA9IGdhdGV3YXk7XG4gICAgICAgIHRoaXMucmVuZGVyZXIgPSByZW5kZXJlcjtcbiAgICAgICAgdGhpcy5tZXNzYWdlcyA9IG1lc3NhZ2VzO1xuICAgIH1cblxuXG4gICAgaGFuZGxlQ2hhbmdlKCkge1xuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcik7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcik7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLmhpZGVNZXNzYWdlcygpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICB9XG5cbiAgICBpbml0KCkge1xuXG4gICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHRoaXMuaGFuZGxlQ2hhbmdlLmJpbmQodGhpcykpXG5cbiAgICAgICAgaWYgKCF0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgdGhpcy5tZXNzYWdlcy5oaWRlTWVzc2FnZXMoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVuZGVyKCk7XG5cbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG5cbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCcpICE9PSBudWxsICYmICF0aGlzLnByaWNlQW1vdW50SXNaZXJvKCk7XG5cbiAgICB9XG5cbiAgICBwcmljZUFtb3VudCgpIHtcblxuICAgICAgICBsZXQgcHJpY2VUZXh0ID0gXCIwXCI7XG4gICAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQgaW5zIC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKSkge1xuICAgICAgICAgICAgcHJpY2VUZXh0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IGlucyAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykpIHtcbiAgICAgICAgICAgIHByaWNlVGV4dCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5wcm9kdWN0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKSkge1xuICAgICAgICAgICAgcHJpY2VUZXh0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnByb2R1Y3QgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpLmlubmVyVGV4dDtcbiAgICAgICAgfVxuXG4gICAgICAgIHByaWNlVGV4dCA9IHByaWNlVGV4dC5yZXBsYWNlKC8sL2csICcuJyk7XG5cbiAgICAgICAgcmV0dXJuICBwYXJzZUZsb2F0KHByaWNlVGV4dC5yZXBsYWNlKC8oW15cXGQsXFwuXFxzXSopL2csICcnKSk7XG4gICAgfVxuXG4gICAgcHJpY2VBbW91bnRJc1plcm8oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnByaWNlQW1vdW50KCkgPT09IDA7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBjb25zdCBhY3Rpb25IYW5kbGVyID0gbmV3IFNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LFxuICAgICAgICAgICAgbmV3IFVwZGF0ZUNhcnQoXG4gICAgICAgICAgICAgICAgdGhpcy5nYXRld2F5LmFqYXguY2hhbmdlX2NhcnQuZW5kcG9pbnQsXG4gICAgICAgICAgICAgICAgdGhpcy5nYXRld2F5LmFqYXguY2hhbmdlX2NhcnQubm9uY2UsXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2hvd0J1dHRvbnModGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNob3dCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgICAgIHRoaXMubWVzc2FnZXMucmVuZGVyV2l0aEFtb3VudCh0aGlzLnByaWNlQW1vdW50KCkpXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgICAgIHRoaXMubWVzc2FnZXMuaGlkZU1lc3NhZ2VzKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0JyksXG4gICAgICAgICAgICBuZXcgRXJyb3JIYW5kbGVyKHRoaXMuZ2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyksXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICBhY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKVxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgU2luZ2xlUHJvZHVjdEJvb3RzdGFwO1xuIiwiaW1wb3J0IENhcnRBY3Rpb25IYW5kbGVyIGZyb20gJy4uL0FjdGlvbkhhbmRsZXIvQ2FydEFjdGlvbkhhbmRsZXInO1xuaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuXG5jbGFzcyBDYXJ0Qm9vdHN0cmFwIHtcbiAgICBjb25zdHJ1Y3RvcihnYXRld2F5LCByZW5kZXJlcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgfVxuXG4gICAgaW5pdCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbigndXBkYXRlZF9jYXJ0X3RvdGFscyB1cGRhdGVkX2NoZWNrb3V0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc2hvdWxkUmVuZGVyKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpICE9PVxuICAgICAgICAgICAgbnVsbCB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpICE9PVxuICAgICAgICAgICAgbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGNvbnN0IGFjdGlvbkhhbmRsZXIgPSBuZXcgQ2FydEFjdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICBuZXcgRXJyb3JIYW5kbGVyKHRoaXMuZ2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyksXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICBhY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKVxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ2FydEJvb3RzdHJhcDtcbiIsImNvbnN0IG9uQXBwcm92ZSA9IChjb250ZXh0LCBlcnJvckhhbmRsZXIsIHNwaW5uZXIpID0+IHtcbiAgICByZXR1cm4gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgc3Bpbm5lci5ibG9jaygpO1xuICAgICAgICBlcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICByZXR1cm4gZmV0Y2goY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBub25jZTogY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgIG9yZGVyX2lkOmRhdGEub3JkZXJJRCxcbiAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oKGRhdGEpPT57XG4gICAgICAgICAgICBzcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuZGF0YS5jb2RlID09PSAxMDApIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBhY3Rpb25zICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgYWN0aW9ucy5yZXN0YXJ0ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZXN0YXJ0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcGxhY2Vfb3JkZXInKS5jbGljaygpXG4gICAgICAgIH0pO1xuXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBvbkFwcHJvdmU7XG4iLCJpbXBvcnQgb25BcHByb3ZlIGZyb20gJy4uL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yUGF5Tm93LmpzJztcbmltcG9ydCB7cGF5ZXJEYXRhfSBmcm9tIFwiLi4vSGVscGVyL1BheWVyRGF0YVwiO1xuaW1wb3J0IHtnZXRDdXJyZW50UGF5bWVudE1ldGhvZH0gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENoZWNrb3V0QWN0aW9uSGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3Rvcihjb25maWcsIGVycm9ySGFuZGxlciwgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgICAgIHRoaXMuc3Bpbm5lciA9IHNwaW5uZXI7XG4gICAgfVxuXG4gICAgY29uZmlndXJhdGlvbigpIHtcbiAgICAgICAgY29uc3Qgc3Bpbm5lciA9IHRoaXMuc3Bpbm5lcjtcbiAgICAgICAgY29uc3QgY3JlYXRlT3JkZXIgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGF5ZXIgPSBwYXllckRhdGEoKTtcbiAgICAgICAgICAgIGNvbnN0IGJuQ29kZSA9IHR5cGVvZiB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSAhPT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdIDogJyc7XG5cbiAgICAgICAgICAgIGNvbnN0IGVycm9ySGFuZGxlciA9IHRoaXMuZXJyb3JIYW5kbGVyO1xuXG4gICAgICAgICAgICBjb25zdCBmb3JtU2VsZWN0b3IgPSB0aGlzLmNvbmZpZy5jb250ZXh0ID09PSAnY2hlY2tvdXQnID8gJ2Zvcm0uY2hlY2tvdXQnIDogJ2Zvcm0jb3JkZXJfcmV2aWV3JztcbiAgICAgICAgICAgIGNvbnN0IGZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVNlbGVjdG9yKSk7XG4gICAgICAgICAgICAvLyB3aWxsIG5vdCBoYW5kbGUgZmllbGRzIHdpdGggbXVsdGlwbGUgdmFsdWVzIChjaGVja2JveGVzLCA8c2VsZWN0IG11bHRpcGxlPiksIGJ1dCB3ZSBkbyBub3QgY2FyZSBhYm91dCB0aGlzIGhlcmVcbiAgICAgICAgICAgIGNvbnN0IGZvcm1Kc29uT2JqID0gT2JqZWN0LmZyb21FbnRyaWVzKGZvcm1EYXRhKTtcblxuICAgICAgICAgICAgY29uc3QgY3JlYXRlYWNjb3VudCA9IGpRdWVyeSgnI2NyZWF0ZWFjY291bnQnKS5pcyhcIjpjaGVja2VkXCIpID8gdHJ1ZSA6IGZhbHNlO1xuXG4gICAgICAgICAgICBjb25zdCBwYXltZW50TWV0aG9kID0gZ2V0Q3VycmVudFBheW1lbnRNZXRob2QoKTtcbiAgICAgICAgICAgIGNvbnN0IGZ1bmRpbmdTb3VyY2UgPSB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2U7XG5cbiAgICAgICAgICAgIHJldHVybiBmZXRjaCh0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5lbmRwb2ludCwge1xuICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICBwYXllcixcbiAgICAgICAgICAgICAgICAgICAgYm5fY29kZTpibkNvZGUsXG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6dGhpcy5jb25maWcuY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgb3JkZXJfaWQ6dGhpcy5jb25maWcub3JkZXJfaWQsXG4gICAgICAgICAgICAgICAgICAgIHBheW1lbnRfbWV0aG9kOiBwYXltZW50TWV0aG9kLFxuICAgICAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogZnVuZGluZ1NvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgZm9ybTogZm9ybUpzb25PYmosXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZWFjY291bnQ6IGNyZWF0ZWFjY291bnRcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgICAgIC8vaGFuZGxlIGJvdGggbWVzc2FnZXMgc2VudCBmcm9tIFdvb2NvbW1lcmNlIChkYXRhLm1lc3NhZ2VzKSBhbmQgdGhpcyBwbHVnaW4gKGRhdGEuZGF0YS5tZXNzYWdlKVxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mKGRhdGEubWVzc2FnZXMpICE9PSAndW5kZWZpbmVkJyApXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGRvbVBhcnNlciA9IG5ldyBET01QYXJzZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5hcHBlbmRQcmVwYXJlZEVycm9yTWVzc2FnZUVsZW1lbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9tUGFyc2VyLnBhcnNlRnJvbVN0cmluZyhkYXRhLm1lc3NhZ2VzLCAndGV4dC9odG1sJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnF1ZXJ5U2VsZWN0b3IoJ3VsJylcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIuY2xlYXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkYXRhLmRhdGEuZGV0YWlscy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLmRldGFpbHMubWFwKGQgPT4gYCR7ZC5pc3N1ZX0gJHtkLmRlc2NyaXB0aW9ufWApLmpvaW4oJzxici8+JyksIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIubWVzc2FnZShkYXRhLmRhdGEubWVzc2FnZSwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XG4gICAgICAgICAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKCd0eXBlJywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZSgnbmFtZScsICdwcGNwLXJlc3VtZS1vcmRlcicpO1xuICAgICAgICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZSgndmFsdWUnLCBkYXRhLmRhdGEucHVyY2hhc2VfdW5pdHNbMF0uY3VzdG9tX2lkKTtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1TZWxlY3RvcikuYXBwZW5kKGlucHV0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5kYXRhLmlkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyLFxuICAgICAgICAgICAgb25BcHByb3ZlOm9uQXBwcm92ZSh0aGlzLCB0aGlzLmVycm9ySGFuZGxlciwgdGhpcy5zcGlubmVyKSxcbiAgICAgICAgICAgIG9uQ2FuY2VsOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25FcnJvcjogKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIHNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDaGVja291dEFjdGlvbkhhbmRsZXI7XG4iLCJjb25zdCBnZXRFbGVtZW50ID0gKHNlbGVjdG9yT3JFbGVtZW50KSA9PiB7XG4gICAgaWYgKHR5cGVvZiBzZWxlY3Rvck9yRWxlbWVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3JPckVsZW1lbnQpO1xuICAgIH1cbiAgICByZXR1cm4gc2VsZWN0b3JPckVsZW1lbnQ7XG59XG5cbmV4cG9ydCBjb25zdCBpc1Zpc2libGUgPSAoZWxlbWVudCkgPT4ge1xuICAgIHJldHVybiAhIShlbGVtZW50Lm9mZnNldFdpZHRoIHx8IGVsZW1lbnQub2Zmc2V0SGVpZ2h0IHx8IGVsZW1lbnQuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGgpO1xufVxuXG5leHBvcnQgY29uc3Qgc2V0VmlzaWJsZSA9IChzZWxlY3Rvck9yRWxlbWVudCwgc2hvdywgaW1wb3J0YW50ID0gZmFsc2UpID0+IHtcbiAgICBjb25zdCBlbGVtZW50ID0gZ2V0RWxlbWVudChzZWxlY3Rvck9yRWxlbWVudCk7XG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50VmFsdWUgPSBlbGVtZW50LnN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ2Rpc3BsYXknKTtcblxuICAgIGlmICghc2hvdykge1xuICAgICAgICBpZiAoY3VycmVudFZhbHVlID09PSAnbm9uZScpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGVsZW1lbnQuc3R5bGUuc2V0UHJvcGVydHkoJ2Rpc3BsYXknLCAnbm9uZScsIGltcG9ydGFudCA/ICdpbXBvcnRhbnQnIDogJycpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChjdXJyZW50VmFsdWUgPT09ICdub25lJykge1xuICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgnZGlzcGxheScpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3RpbGwgbm90IHZpc2libGUgKGlmIHNvbWV0aGluZyBlbHNlIGFkZGVkIGRpc3BsYXk6IG5vbmUgaW4gQ1NTKVxuICAgICAgICBpZiAoIWlzVmlzaWJsZShlbGVtZW50KSkge1xuICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eSgnZGlzcGxheScsICdibG9jaycpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGhpZGUgPSAoc2VsZWN0b3JPckVsZW1lbnQsIGltcG9ydGFudCA9IGZhbHNlKSA9PiB7XG4gICAgc2V0VmlzaWJsZShzZWxlY3Rvck9yRWxlbWVudCwgZmFsc2UsIGltcG9ydGFudCk7XG59O1xuXG5leHBvcnQgY29uc3Qgc2hvdyA9IChzZWxlY3Rvck9yRWxlbWVudCkgPT4ge1xuICAgIHNldFZpc2libGUoc2VsZWN0b3JPckVsZW1lbnQsIHRydWUpO1xufTtcbiIsImltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcbmltcG9ydCBDaGVja291dEFjdGlvbkhhbmRsZXIgZnJvbSAnLi4vQWN0aW9uSGFuZGxlci9DaGVja291dEFjdGlvbkhhbmRsZXInO1xuaW1wb3J0IHsgc2V0VmlzaWJsZSB9IGZyb20gJy4uL0hlbHBlci9IaWRpbmcnO1xuaW1wb3J0IHtcbiAgICBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCxcbiAgICBpc1NhdmVkQ2FyZFNlbGVjdGVkLCBPUkRFUl9CVVRUT05fU0VMRUNUT1IsXG4gICAgUGF5bWVudE1ldGhvZHNcbn0gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENoZWNrb3V0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgICAgIHRoaXMubWVzc2FnZXMgPSBtZXNzYWdlcztcbiAgICAgICAgdGhpcy5zcGlubmVyID0gc3Bpbm5lcjtcblxuICAgICAgICB0aGlzLnN0YW5kYXJkT3JkZXJCdXR0b25TZWxlY3RvciA9IE9SREVSX0JVVFRPTl9TRUxFQ1RPUjtcblxuICAgICAgICB0aGlzLmJ1dHRvbkNoYW5nZU9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKGVsKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVVpKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG4gICAgICAgIHRoaXMucmVuZGVyKCk7XG5cbiAgICAgICAgLy8gVW5zZWxlY3Qgc2F2ZWQgY2FyZC5cbiAgICAgICAgLy8gV0Mgc2F2ZXMgZm9ybSB2YWx1ZXMsIHNvIHdpdGggb3VyIGN1cnJlbnQgVUkgaXQgd291bGQgYmUgYSBiaXQgd2VpcmRcbiAgICAgICAgLy8gaWYgdGhlIHVzZXIgcGFpZCB3aXRoIHNhdmVkLCB0aGVuIGFmdGVyIHNvbWUgdGltZSB0cmllcyB0byBwYXkgYWdhaW4sXG4gICAgICAgIC8vIGJ1dCB3YW50cyB0byBlbnRlciBhIG5ldyBjYXJkLCBhbmQgdG8gZG8gdGhhdCB0aGV5IGhhdmUgdG8gY2hvb3NlIOKAnFNlbGVjdCBwYXltZW504oCdIGluIHRoZSBsaXN0LlxuICAgICAgICBqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCcpLnZhbChqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCBvcHRpb246Zmlyc3QnKS52YWwoKSk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NoZWNrb3V0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKVxuICAgICAgICB9KTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2hlY2tvdXQgcGF5bWVudF9tZXRob2Rfc2VsZWN0ZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVVpKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudCkub24oJ2hvc3RlZF9maWVsZHNfbG9hZGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgalF1ZXJ5KCcjc2F2ZWQtY3JlZGl0LWNhcmQnKS5vbignY2hhbmdlJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG4gICAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5idXR0b24uY2FuY2VsX3dyYXBwZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpICE9PSBudWxsIHx8IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcikgIT09IG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyICsgJz5kaXYnKSkge1xuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyICsgJz5kaXYnKS5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJycpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFjdGlvbkhhbmRsZXIgPSBuZXcgQ2hlY2tvdXRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICAgICAgdGhpcy5zcGlubmVyXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICBhY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuYnV0dG9uQ2hhbmdlT2JzZXJ2ZXIub2JzZXJ2ZShcbiAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5zdGFuZGFyZE9yZGVyQnV0dG9uU2VsZWN0b3IpLFxuICAgICAgICAgICAge2F0dHJpYnV0ZXM6IHRydWV9XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgdXBkYXRlVWkoKSB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRQYXltZW50TWV0aG9kID0gZ2V0Q3VycmVudFBheW1lbnRNZXRob2QoKTtcbiAgICAgICAgY29uc3QgaXNQYXlwYWwgPSBjdXJyZW50UGF5bWVudE1ldGhvZCA9PT0gUGF5bWVudE1ldGhvZHMuUEFZUEFMO1xuICAgICAgICBjb25zdCBpc0NhcmQgPSBjdXJyZW50UGF5bWVudE1ldGhvZCA9PT0gUGF5bWVudE1ldGhvZHMuQ0FSRFM7XG4gICAgICAgIGNvbnN0IGlzU2VwYXJhdGVCdXR0b25HYXRld2F5ID0gW1BheW1lbnRNZXRob2RzLkNBUkRfQlVUVE9OXS5pbmNsdWRlcyhjdXJyZW50UGF5bWVudE1ldGhvZCk7XG4gICAgICAgIGNvbnN0IGlzU2F2ZWRDYXJkID0gaXNDYXJkICYmIGlzU2F2ZWRDYXJkU2VsZWN0ZWQoKTtcbiAgICAgICAgY29uc3QgaXNOb3RPdXJHYXRld2F5ID0gIWlzUGF5cGFsICYmICFpc0NhcmQgJiYgIWlzU2VwYXJhdGVCdXR0b25HYXRld2F5O1xuICAgICAgICBjb25zdCBpc0ZyZWVUcmlhbCA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5pc19mcmVlX3RyaWFsX2NhcnQ7XG4gICAgICAgIGNvbnN0IGhhc1ZhdWx0ZWRQYXlwYWwgPSBQYXlQYWxDb21tZXJjZUdhdGV3YXkudmF1bHRlZF9wYXlwYWxfZW1haWwgIT09ICcnO1xuXG4gICAgICAgIGNvbnN0IHBheXBhbEJ1dHRvbldyYXBwZXJzID0ge1xuICAgICAgICAgICAgLi4uT2JqZWN0LmVudHJpZXMoUGF5UGFsQ29tbWVyY2VHYXRld2F5LnNlcGFyYXRlX2J1dHRvbnMpXG4gICAgICAgICAgICAgICAgLnJlZHVjZSgocmVzdWx0LCBbaywgZGF0YV0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsuLi5yZXN1bHQsIFtkYXRhLmlkXTogZGF0YS53cmFwcGVyfVxuICAgICAgICAgICAgICAgIH0sIHt9KSxcbiAgICAgICAgfTtcblxuICAgICAgICBzZXRWaXNpYmxlKHRoaXMuc3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yLCAgKGlzUGF5cGFsICYmIGlzRnJlZVRyaWFsICYmIGhhc1ZhdWx0ZWRQYXlwYWwpIHx8IGlzTm90T3VyR2F0ZXdheSB8fCBpc1NhdmVkQ2FyZCwgdHJ1ZSk7XG4gICAgICAgIHNldFZpc2libGUoJy5wcGNwLXZhdWx0ZWQtcGF5cGFsLWRldGFpbHMnLCBpc1BheXBhbCk7XG4gICAgICAgIHNldFZpc2libGUodGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyLCBpc1BheXBhbCAmJiAhKGlzRnJlZVRyaWFsICYmIGhhc1ZhdWx0ZWRQYXlwYWwpKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkubWVzc2FnZXMud3JhcHBlciwgaXNQYXlwYWwgJiYgIWlzRnJlZVRyaWFsKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyLCBpc0NhcmQgJiYgIWlzU2F2ZWRDYXJkKTtcbiAgICAgICAgZm9yIChjb25zdCBbZ2F0ZXdheUlkLCB3cmFwcGVyXSBvZiBPYmplY3QuZW50cmllcyhwYXlwYWxCdXR0b25XcmFwcGVycykpIHtcbiAgICAgICAgICAgIHNldFZpc2libGUod3JhcHBlciwgZ2F0ZXdheUlkID09PSBjdXJyZW50UGF5bWVudE1ldGhvZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNQYXlwYWwgJiYgIWlzRnJlZVRyaWFsKSB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnJlbmRlcigpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQ2FyZCkge1xuICAgICAgICAgICAgaWYgKGlzU2F2ZWRDYXJkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGRpc2FibGVDcmVkaXRDYXJkRmllbGRzKCkge1xuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlclwiXScpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5XCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5JykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmNcIl0nKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInZhdWx0XCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5hdHRyKFwiZGlzYWJsZWRcIiwgdHJ1ZSlcbiAgICAgICAgdGhpcy5yZW5kZXJlci5kaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpXG4gICAgfVxuXG4gICAgZW5hYmxlQ3JlZGl0Q2FyZEZpZWxkcygpIHtcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXJcIl0nKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXInKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeVwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjXCJdJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJ2YXVsdFwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuYXR0cihcImRpc2FibGVkXCIsIGZhbHNlKVxuICAgICAgICB0aGlzLnJlbmRlcmVyLmVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKVxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ2hlY2tvdXRCb290c3RhcFxuIiwiZXhwb3J0IGNvbnN0IGlzQ2hhbmdlUGF5bWVudFBhZ2UgPSAoKSA9PiB7XG4gICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKVxuICAgIHJldHVybiB1cmxQYXJhbXMuaGFzKCdjaGFuZ2VfcGF5bWVudF9tZXRob2QnKTtcbn1cbiIsImltcG9ydCBDaGVja291dEJvb3RzdGFwIGZyb20gJy4vQ2hlY2tvdXRCb290c3RhcCdcbmltcG9ydCB7aXNDaGFuZ2VQYXltZW50UGFnZX0gZnJvbSBcIi4uL0hlbHBlci9TdWJzY3JpcHRpb25zXCI7XG5cbmNsYXNzIFBheU5vd0Jvb3RzdHJhcCBleHRlbmRzIENoZWNrb3V0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcikge1xuICAgICAgICBzdXBlcihnYXRld2F5LCByZW5kZXJlciwgbWVzc2FnZXMsIHNwaW5uZXIpXG4gICAgfVxuXG4gICAgdXBkYXRlVWkoKSB7XG4gICAgICAgIGlmIChpc0NoYW5nZVBheW1lbnRQYWdlKCkpIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgc3VwZXIudXBkYXRlVWkoKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFBheU5vd0Jvb3RzdHJhcDtcbiIsImltcG9ydCBtZXJnZSBmcm9tIFwiZGVlcG1lcmdlXCI7XG5cbmNsYXNzIFJlbmRlcmVyIHtcbiAgICBjb25zdHJ1Y3RvcihjcmVkaXRDYXJkUmVuZGVyZXIsIGRlZmF1bHRTZXR0aW5ncywgb25TbWFydEJ1dHRvbkNsaWNrLCBvblNtYXJ0QnV0dG9uc0luaXQpIHtcbiAgICAgICAgdGhpcy5kZWZhdWx0U2V0dGluZ3MgPSBkZWZhdWx0U2V0dGluZ3M7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyID0gY3JlZGl0Q2FyZFJlbmRlcmVyO1xuICAgICAgICB0aGlzLm9uU21hcnRCdXR0b25DbGljayA9IG9uU21hcnRCdXR0b25DbGljaztcbiAgICAgICAgdGhpcy5vblNtYXJ0QnV0dG9uc0luaXQgPSBvblNtYXJ0QnV0dG9uc0luaXQ7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlZFNvdXJjZXMgPSBuZXcgU2V0KCk7XG4gICAgfVxuXG4gICAgcmVuZGVyKGNvbnRleHRDb25maWcsIHNldHRpbmdzT3ZlcnJpZGUgPSB7fSkge1xuICAgICAgICBjb25zdCBzZXR0aW5ncyA9IG1lcmdlKHRoaXMuZGVmYXVsdFNldHRpbmdzLCBzZXR0aW5nc092ZXJyaWRlKTtcblxuICAgICAgICBjb25zdCBlbmFibGVkU2VwYXJhdGVHYXRld2F5cyA9IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhcbiAgICAgICAgICAgIHNldHRpbmdzLnNlcGFyYXRlX2J1dHRvbnMpLmZpbHRlcigoW3MsIGRhdGFdKSA9PiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGRhdGEud3JhcHBlcilcbiAgICAgICAgKSk7XG4gICAgICAgIGNvbnN0IGhhc0VuYWJsZWRTZXBhcmF0ZUdhdGV3YXlzID0gT2JqZWN0LmtleXMoZW5hYmxlZFNlcGFyYXRlR2F0ZXdheXMpLmxlbmd0aCAhPT0gMDtcblxuICAgICAgICBpZiAoIWhhc0VuYWJsZWRTZXBhcmF0ZUdhdGV3YXlzKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlckJ1dHRvbnMoXG4gICAgICAgICAgICAgICAgc2V0dGluZ3MuYnV0dG9uLndyYXBwZXIsXG4gICAgICAgICAgICAgICAgc2V0dGluZ3MuYnV0dG9uLnN0eWxlLFxuICAgICAgICAgICAgICAgIGNvbnRleHRDb25maWcsXG4gICAgICAgICAgICAgICAgaGFzRW5hYmxlZFNlcGFyYXRlR2F0ZXdheXNcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyByZW5kZXIgZWFjaCBidXR0b24gc2VwYXJhdGVseVxuICAgICAgICAgICAgZm9yIChjb25zdCBmdW5kaW5nU291cmNlIG9mIHBheXBhbC5nZXRGdW5kaW5nU291cmNlcygpLmZpbHRlcihzID0+ICEocyBpbiBlbmFibGVkU2VwYXJhdGVHYXRld2F5cykpKSB7XG4gICAgICAgICAgICAgICAgbGV0IHN0eWxlID0gc2V0dGluZ3MuYnV0dG9uLnN0eWxlO1xuICAgICAgICAgICAgICAgIGlmIChmdW5kaW5nU291cmNlICE9PSAncGF5cGFsJykge1xuICAgICAgICAgICAgICAgICAgICBzdHlsZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlOiBzdHlsZS5zaGFwZSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlckJ1dHRvbnMoXG4gICAgICAgICAgICAgICAgICAgIHNldHRpbmdzLmJ1dHRvbi53cmFwcGVyLFxuICAgICAgICAgICAgICAgICAgICBzdHlsZSxcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dENvbmZpZyxcbiAgICAgICAgICAgICAgICAgICAgaGFzRW5hYmxlZFNlcGFyYXRlR2F0ZXdheXMsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmRpbmdTb3VyY2VcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jcmVkaXRDYXJkUmVuZGVyZXIucmVuZGVyKHNldHRpbmdzLmhvc3RlZF9maWVsZHMud3JhcHBlciwgY29udGV4dENvbmZpZyk7XG5cbiAgICAgICAgZm9yIChjb25zdCBbZnVuZGluZ1NvdXJjZSwgZGF0YV0gb2YgT2JqZWN0LmVudHJpZXMoZW5hYmxlZFNlcGFyYXRlR2F0ZXdheXMpKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlckJ1dHRvbnMoXG4gICAgICAgICAgICAgICAgZGF0YS53cmFwcGVyLFxuICAgICAgICAgICAgICAgIGRhdGEuc3R5bGUsXG4gICAgICAgICAgICAgICAgY29udGV4dENvbmZpZyxcbiAgICAgICAgICAgICAgICBoYXNFbmFibGVkU2VwYXJhdGVHYXRld2F5cyxcbiAgICAgICAgICAgICAgICBmdW5kaW5nU291cmNlXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmVuZGVyQnV0dG9ucyh3cmFwcGVyLCBzdHlsZSwgY29udGV4dENvbmZpZywgaGFzRW5hYmxlZFNlcGFyYXRlR2F0ZXdheXMsIGZ1bmRpbmdTb3VyY2UgPSBudWxsKSB7XG4gICAgICAgIGlmICghIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iod3JhcHBlcikgfHwgdGhpcy5pc0FscmVhZHlSZW5kZXJlZCh3cmFwcGVyLCBmdW5kaW5nU291cmNlLCBoYXNFbmFibGVkU2VwYXJhdGVHYXRld2F5cykgfHwgJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiBwYXlwYWwuQnV0dG9ucyApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChmdW5kaW5nU291cmNlKSB7XG4gICAgICAgICAgICBjb250ZXh0Q29uZmlnLmZ1bmRpbmdTb3VyY2UgPSBmdW5kaW5nU291cmNlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYnRuID0gcGF5cGFsLkJ1dHRvbnMoe1xuICAgICAgICAgICAgc3R5bGUsXG4gICAgICAgICAgICAuLi5jb250ZXh0Q29uZmlnLFxuICAgICAgICAgICAgb25DbGljazogdGhpcy5vblNtYXJ0QnV0dG9uQ2xpY2ssXG4gICAgICAgICAgICBvbkluaXQ6IHRoaXMub25TbWFydEJ1dHRvbnNJbml0LFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKCFidG4uaXNFbGlnaWJsZSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBidG4ucmVuZGVyKHdyYXBwZXIpO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZWRTb3VyY2VzLmFkZCh3cmFwcGVyICsgZnVuZGluZ1NvdXJjZSA/PyAnJyk7XG4gICAgfVxuXG4gICAgaXNBbHJlYWR5UmVuZGVyZWQod3JhcHBlciwgZnVuZGluZ1NvdXJjZSwgaGFzRW5hYmxlZFNlcGFyYXRlR2F0ZXdheXMpIHtcbiAgICAgICAgLy8gU2ltcGx5IGNoZWNrIHRoYXQgaGFzIGNoaWxkIG5vZGVzIHdoZW4gd2UgZG8gbm90IG5lZWQgdG8gcmVuZGVyIGJ1dHRvbnMgc2VwYXJhdGVseSxcbiAgICAgICAgLy8gdGhpcyB3aWxsIHJlZHVjZSB0aGUgcmlzayBvZiBicmVha2luZyB3aXRoIGRpZmZlcmVudCB0aGVtZXMvcGx1Z2luc1xuICAgICAgICAvLyBhbmQgb24gdGhlIGNhcnQgcGFnZSAod2hlcmUgd2UgYWxzbyBkbyBub3QgbmVlZCB0byByZW5kZXIgc2VwYXJhdGVseSksIHdoaWNoIG1heSBmdWxseSByZWxvYWQgdGhpcyBwYXJ0IG9mIHRoZSBwYWdlLlxuICAgICAgICAvLyBJZGVhbGx5IHdlIHNob3VsZCBhbHNvIGZpbmQgYSB3YXkgdG8gZGV0ZWN0IHN1Y2ggZnVsbCByZWxvYWRzIGFuZCByZW1vdmUgdGhlIGNvcnJlc3BvbmRpbmcga2V5cyBmcm9tIHRoZSBzZXQuXG4gICAgICAgIGlmICghaGFzRW5hYmxlZFNlcGFyYXRlR2F0ZXdheXMpIHtcbiAgICAgICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpLmhhc0NoaWxkTm9kZXMoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJlZFNvdXJjZXMuaGFzKHdyYXBwZXIgKyBmdW5kaW5nU291cmNlID8/ICcnKTtcbiAgICB9XG5cbiAgICBoaWRlQnV0dG9ucyhlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGRvbUVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGVsZW1lbnQpO1xuICAgICAgICBpZiAoISBkb21FbGVtZW50ICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGRvbUVsZW1lbnQuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgc2hvd0J1dHRvbnMoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBkb21FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihlbGVtZW50KTtcbiAgICAgICAgaWYgKCEgZG9tRWxlbWVudCApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBkb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBkaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpIHtcbiAgICAgICAgdGhpcy5jcmVkaXRDYXJkUmVuZGVyZXIuZGlzYWJsZUZpZWxkcygpO1xuICAgIH1cblxuICAgIGVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKSB7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyLmVuYWJsZUZpZWxkcygpO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUmVuZGVyZXI7XG4iLCJjb25zdCBkY2NJbnB1dEZhY3RvcnkgPSAob3JpZ2luYWwpID0+IHtcbiAgICBjb25zdCBzdHlsZXMgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShvcmlnaW5hbCk7XG4gICAgY29uc3QgbmV3RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcblxuICAgIG5ld0VsZW1lbnQuc2V0QXR0cmlidXRlKCdpZCcsIG9yaWdpbmFsLmlkKTtcbiAgICBuZXdFbGVtZW50LnNldEF0dHJpYnV0ZSgnY2xhc3MnLCBvcmlnaW5hbC5jbGFzc05hbWUpO1xuXG4gICAgT2JqZWN0LnZhbHVlcyhzdHlsZXMpLmZvckVhY2goIChwcm9wKSA9PiB7XG4gICAgICAgIGlmICghIHN0eWxlc1twcm9wXSB8fCAhIGlzTmFOKHByb3ApIHx8IHByb3AgPT09ICdiYWNrZ3JvdW5kLWltYWdlJyApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBuZXdFbGVtZW50LnN0eWxlLnNldFByb3BlcnR5KHByb3AsJycgKyBzdHlsZXNbcHJvcF0pO1xuICAgIH0pO1xuICAgIHJldHVybiBuZXdFbGVtZW50O1xufVxuXG5leHBvcnQgZGVmYXVsdCBkY2NJbnB1dEZhY3Rvcnk7XG4iLCJpbXBvcnQgZGNjSW5wdXRGYWN0b3J5IGZyb20gXCIuLi9IZWxwZXIvRGNjSW5wdXRGYWN0b3J5XCI7XG5pbXBvcnQge3Nob3d9IGZyb20gXCIuLi9IZWxwZXIvSGlkaW5nXCI7XG5pbXBvcnQgUHJvZHVjdCBmcm9tIFwiLi4vRW50aXR5L1Byb2R1Y3RcIjtcblxuY2xhc3MgQ3JlZGl0Q2FyZFJlbmRlcmVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGRlZmF1bHRDb25maWcsIGVycm9ySGFuZGxlciwgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmRlZmF1bHRDb25maWcgPSBkZWZhdWx0Q29uZmlnO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICAgICAgdGhpcy5zcGlubmVyID0gc3Bpbm5lcjtcbiAgICAgICAgdGhpcy5jYXJkVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5mb3JtVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UgPSBudWxsO1xuICAgIH1cblxuICAgIHJlbmRlcih3cmFwcGVyLCBjb250ZXh0Q29uZmlnKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIChcbiAgICAgICAgICAgICAgICB0aGlzLmRlZmF1bHRDb25maWcuY29udGV4dCAhPT0gJ2NoZWNrb3V0J1xuICAgICAgICAgICAgICAgICYmIHRoaXMuZGVmYXVsdENvbmZpZy5jb250ZXh0ICE9PSAncGF5LW5vdydcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIHx8IHdyYXBwZXIgPT09IG51bGxcbiAgICAgICAgICAgIHx8IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iod3JhcHBlcikgPT09IG51bGxcbiAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdHlwZW9mIHBheXBhbC5Ib3N0ZWRGaWVsZHMgPT09ICd1bmRlZmluZWQnXG4gICAgICAgICAgICB8fCAhIHBheXBhbC5Ib3N0ZWRGaWVsZHMuaXNFbGlnaWJsZSgpXG4gICAgICAgICkge1xuICAgICAgICAgICAgY29uc3Qgd3JhcHBlckVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpO1xuICAgICAgICAgICAgd3JhcHBlckVsZW1lbnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh3cmFwcGVyRWxlbWVudCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBidXR0b25TZWxlY3RvciA9IHdyYXBwZXIgKyAnIGJ1dHRvbic7XG5cbiAgICAgICAgaWYgKHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS50ZWFyZG93bigpXG4gICAgICAgICAgICAgICAgLmNhdGNoKGVyciA9PiBjb25zb2xlLmVycm9yKGBIb3N0ZWQgZmllbGRzIHRlYXJkb3duIGVycm9yOiAke2Vycn1gKSk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBnYXRlV2F5Qm94ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnBheW1lbnRfYm94LnBheW1lbnRfbWV0aG9kX3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheScpO1xuICAgICAgICBpZighIGdhdGVXYXlCb3gpIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG9sZERpc3BsYXlTdHlsZSA9IGdhdGVXYXlCb3guc3R5bGUuZGlzcGxheTtcbiAgICAgICAgZ2F0ZVdheUJveC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblxuICAgICAgICBjb25zdCBoaWRlRGNjR2F0ZXdheSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwcGNwLWhpZGUtZGNjJyk7XG4gICAgICAgIGlmIChoaWRlRGNjR2F0ZXdheSkge1xuICAgICAgICAgICAgaGlkZURjY0dhdGV3YXkucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChoaWRlRGNjR2F0ZXdheSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjYXJkTnVtYmVyRmllbGQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtbnVtYmVyJyk7XG5cbiAgICAgICAgY29uc3Qgc3R5bGVzUmF3ID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoY2FyZE51bWJlckZpZWxkKTtcbiAgICAgICAgbGV0IHN0eWxlcyA9IHt9O1xuICAgICAgICBPYmplY3QudmFsdWVzKHN0eWxlc1JhdykuZm9yRWFjaCggKHByb3ApID0+IHtcbiAgICAgICAgICAgIGlmICghIHN0eWxlc1Jhd1twcm9wXSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHN0eWxlc1twcm9wXSA9ICcnICsgc3R5bGVzUmF3W3Byb3BdO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBjYXJkTnVtYmVyID0gZGNjSW5wdXRGYWN0b3J5KGNhcmROdW1iZXJGaWVsZCk7XG4gICAgICAgIGNhcmROdW1iZXJGaWVsZC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChjYXJkTnVtYmVyLCBjYXJkTnVtYmVyRmllbGQpO1xuXG4gICAgICAgIGNvbnN0IGNhcmRFeHBpcnlGaWVsZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1leHBpcnknKTtcbiAgICAgICAgY29uc3QgY2FyZEV4cGlyeSA9IGRjY0lucHV0RmFjdG9yeShjYXJkRXhwaXJ5RmllbGQpO1xuICAgICAgICBjYXJkRXhwaXJ5RmllbGQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoY2FyZEV4cGlyeSwgY2FyZEV4cGlyeUZpZWxkKTtcblxuICAgICAgICBjb25zdCBjYXJkQ29kZUZpZWxkID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWN2YycpO1xuICAgICAgICBjb25zdCBjYXJkQ29kZSA9IGRjY0lucHV0RmFjdG9yeShjYXJkQ29kZUZpZWxkKTtcbiAgICAgICAgY2FyZENvZGVGaWVsZC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChjYXJkQ29kZSwgY2FyZENvZGVGaWVsZCk7XG5cbiAgICAgICAgZ2F0ZVdheUJveC5zdHlsZS5kaXNwbGF5ID0gb2xkRGlzcGxheVN0eWxlO1xuXG4gICAgICAgIGNvbnN0IGZvcm1XcmFwcGVyID0gJy5wYXltZW50X2JveCBwYXltZW50X21ldGhvZF9wcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXknO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLmRlZmF1bHRDb25maWcuZW5mb3JjZV92YXVsdFxuICAgICAgICAgICAgJiYgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihmb3JtV3JhcHBlciArICcgLnBwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVdyYXBwZXIgKyAnIC5wcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuY2hlY2tlZCA9IHRydWU7XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1XcmFwcGVyICsgJyAucHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLnNldEF0dHJpYnV0ZSgnZGlzYWJsZWQnLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICBwYXlwYWwuSG9zdGVkRmllbGRzLnJlbmRlcih7XG4gICAgICAgICAgICBjcmVhdGVPcmRlcjogY29udGV4dENvbmZpZy5jcmVhdGVPcmRlcixcbiAgICAgICAgICAgIHN0eWxlczoge1xuICAgICAgICAgICAgICAgICdpbnB1dCc6IHN0eWxlc1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZpZWxkczoge1xuICAgICAgICAgICAgICAgIG51bWJlcjoge1xuICAgICAgICAgICAgICAgICAgICBzZWxlY3RvcjogJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXInLFxuICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcjogdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLmNyZWRpdF9jYXJkX251bWJlcixcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGN2djoge1xuICAgICAgICAgICAgICAgICAgICBzZWxlY3RvcjogJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnLFxuICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcjogdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLmN2dixcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGV4cGlyYXRpb25EYXRlOiB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGVjdG9yOiAnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeScsXG4gICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyOiB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5sYWJlbHMubW1feXksXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KS50aGVuKGhvc3RlZEZpZWxkcyA9PiB7XG4gICAgICAgICAgICBkb2N1bWVudC5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcImhvc3RlZF9maWVsZHNfbG9hZGVkXCIpKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlID0gaG9zdGVkRmllbGRzO1xuXG4gICAgICAgICAgICBob3N0ZWRGaWVsZHMub24oJ2lucHV0U3VibWl0UmVxdWVzdCcsICgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLl9zdWJtaXQoY29udGV4dENvbmZpZyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGhvc3RlZEZpZWxkcy5vbignY2FyZFR5cGVDaGFuZ2UnLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoICEgZXZlbnQuY2FyZHMubGVuZ3RoICkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNhcmRWYWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbGlkQ2FyZHMgPSB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy52YWxpZF9jYXJkcztcbiAgICAgICAgICAgICAgICB0aGlzLmNhcmRWYWxpZCA9IHZhbGlkQ2FyZHMuaW5kZXhPZihldmVudC5jYXJkc1swXS50eXBlKSAhPT0gLTE7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBjbGFzc05hbWUgPSB0aGlzLl9jYXJkTnVtYmVyRmlsZWRDTGFzc05hbWVCeUNhcmRUeXBlKGV2ZW50LmNhcmRzWzBdLnR5cGUpO1xuICAgICAgICAgICAgICAgIHRoaXMuX3JlY3JlYXRlRWxlbWVudENsYXNzQXR0cmlidXRlKGNhcmROdW1iZXIsIGNhcmROdW1iZXJGaWVsZC5jbGFzc05hbWUpO1xuICAgICAgICAgICAgICAgIGlmIChldmVudC5maWVsZHMubnVtYmVyLmlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FyZE51bWJlci5jbGFzc0xpc3QuYWRkKGNsYXNzTmFtZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIGhvc3RlZEZpZWxkcy5vbigndmFsaWRpdHlDaGFuZ2UnLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBmb3JtVmFsaWQgPSBPYmplY3Qua2V5cyhldmVudC5maWVsZHMpLmV2ZXJ5KGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGV2ZW50LmZpZWxkc1trZXldLmlzVmFsaWQ7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBjbGFzc05hbWUgPSB0aGlzLl9jYXJkTnVtYmVyRmlsZWRDTGFzc05hbWVCeUNhcmRUeXBlKGV2ZW50LmNhcmRzWzBdLnR5cGUpO1xuICAgICAgICAgICAgICAgIGV2ZW50LmZpZWxkcy5udW1iZXIuaXNWYWxpZFxuICAgICAgICAgICAgICAgICAgICA/IGNhcmROdW1iZXIuY2xhc3NMaXN0LmFkZChjbGFzc05hbWUpXG4gICAgICAgICAgICAgICAgICAgIDogdGhpcy5fcmVjcmVhdGVFbGVtZW50Q2xhc3NBdHRyaWJ1dGUoY2FyZE51bWJlciwgY2FyZE51bWJlckZpZWxkLmNsYXNzTmFtZSk7XG5cbiAgICAgICAgICAgICAgIHRoaXMuZm9ybVZhbGlkID0gZm9ybVZhbGlkO1xuXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgc2hvdyhidXR0b25TZWxlY3Rvcik7XG5cbiAgICAgICAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpLmdldEF0dHJpYnV0ZSgnZGF0YS1wcGNwLXN1YnNjcmliZWQnKSAhPT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYnV0dG9uU2VsZWN0b3IpLmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAgICAgICAgICAgICAgICdjbGljaycsXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9zdWJtaXQoY29udGV4dENvbmZpZyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKS5zZXRBdHRyaWJ1dGUoJ2RhdGEtcHBjcC1zdWJzY3JpYmVkJywgdHJ1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwYXltZW50X21ldGhvZF9wcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXknKS5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgJ2NsaWNrJyxcbiAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdsYWJlbFtmb3I9cHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtbnVtYmVyXScpLmNsaWNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIClcbiAgICB9XG5cbiAgICBkaXNhYmxlRmllbGRzKCkge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnNldEF0dHJpYnV0ZSh7XG4gICAgICAgICAgICAgICAgZmllbGQ6ICdudW1iZXInLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnNldEF0dHJpYnV0ZSh7XG4gICAgICAgICAgICAgICAgZmllbGQ6ICdjdnYnLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnNldEF0dHJpYnV0ZSh7XG4gICAgICAgICAgICAgICAgZmllbGQ6ICdleHBpcmF0aW9uRGF0ZScsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiAnZGlzYWJsZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZW5hYmxlRmllbGRzKCkge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnJlbW92ZUF0dHJpYnV0ZSh7XG4gICAgICAgICAgICAgICAgZmllbGQ6ICdudW1iZXInLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnJlbW92ZUF0dHJpYnV0ZSh7XG4gICAgICAgICAgICAgICAgZmllbGQ6ICdjdnYnLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnJlbW92ZUF0dHJpYnV0ZSh7XG4gICAgICAgICAgICAgICAgZmllbGQ6ICdleHBpcmF0aW9uRGF0ZScsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiAnZGlzYWJsZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgX3N1Ym1pdChjb250ZXh0Q29uZmlnKSB7XG4gICAgICAgIHRoaXMuc3Bpbm5lci5ibG9jaygpO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5jbGVhcigpO1xuXG4gICAgICAgIGlmICh0aGlzLmZvcm1WYWxpZCAmJiB0aGlzLmNhcmRWYWxpZCkge1xuICAgICAgICAgICAgY29uc3Qgc2F2ZV9jYXJkID0gdGhpcy5kZWZhdWx0Q29uZmlnLmNhbl9zYXZlX3ZhdWx0X3Rva2VuID8gdHJ1ZSA6IGZhbHNlO1xuICAgICAgICAgICAgbGV0IHZhdWx0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKSA/XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5jaGVja2VkIDogc2F2ZV9jYXJkO1xuICAgICAgICAgICAgaWYgKHRoaXMuZGVmYXVsdENvbmZpZy5lbmZvcmNlX3ZhdWx0KSB7XG4gICAgICAgICAgICAgICAgdmF1bHQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgY29udGluZ2VuY3kgPSB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5jb250aW5nZW5jeTtcbiAgICAgICAgICAgIGNvbnN0IGhvc3RlZEZpZWxkc0RhdGEgPSB7XG4gICAgICAgICAgICAgICAgdmF1bHQ6IHZhdWx0XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGNvbnRpbmdlbmN5ICE9PSAnTk9fM0RfU0VDVVJFJykge1xuICAgICAgICAgICAgICAgIGhvc3RlZEZpZWxkc0RhdGEuY29udGluZ2VuY2llcyA9IFtjb250aW5nZW5jeV07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmRlZmF1bHRDb25maWcucGF5ZXIpIHtcbiAgICAgICAgICAgICAgICBob3N0ZWRGaWVsZHNEYXRhLmNhcmRob2xkZXJOYW1lID0gdGhpcy5kZWZhdWx0Q29uZmlnLnBheWVyLm5hbWUuZ2l2ZW5fbmFtZSArICcgJyArIHRoaXMuZGVmYXVsdENvbmZpZy5wYXllci5uYW1lLnN1cm5hbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWhvc3RlZEZpZWxkc0RhdGEuY2FyZGhvbGRlck5hbWUpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBmaXJzdE5hbWUgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYmlsbGluZ19maXJzdF9uYW1lJykgPyBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYmlsbGluZ19maXJzdF9uYW1lJykudmFsdWUgOiAnJztcbiAgICAgICAgICAgICAgICBjb25zdCBsYXN0TmFtZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdiaWxsaW5nX2xhc3RfbmFtZScpID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JpbGxpbmdfbGFzdF9uYW1lJykudmFsdWUgOiAnJztcblxuICAgICAgICAgICAgICAgIGhvc3RlZEZpZWxkc0RhdGEuY2FyZGhvbGRlck5hbWUgPSBmaXJzdE5hbWUgKyAnICcgKyBsYXN0TmFtZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2Uuc3VibWl0KGhvc3RlZEZpZWxkc0RhdGEpLnRoZW4oKHBheWxvYWQpID0+IHtcbiAgICAgICAgICAgICAgICBwYXlsb2FkLm9yZGVySUQgPSBwYXlsb2FkLm9yZGVySWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5zcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29udGV4dENvbmZpZy5vbkFwcHJvdmUocGF5bG9hZCk7XG4gICAgICAgICAgICB9KS5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICAgICAgICAgIGlmIChlcnIuZGV0YWlscykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5tZXNzYWdlKGVyci5kZXRhaWxzLm1hcChkID0+IGAke2QuaXNzdWV9ICR7ZC5kZXNjcmlwdGlvbn1gKS5qb2luKCc8YnIvPicpLCB0cnVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gISB0aGlzLmNhcmRWYWxpZCA/IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5jYXJkX25vdF9zdXBwb3J0ZWQgOiB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5sYWJlbHMuZmllbGRzX25vdF92YWxpZDtcbiAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLm1lc3NhZ2UobWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBfY2FyZE51bWJlckZpbGVkQ0xhc3NOYW1lQnlDYXJkVHlwZShjYXJkVHlwZSkge1xuICAgICAgICByZXR1cm4gY2FyZFR5cGUgPT09ICdhbWVyaWNhbi1leHByZXNzJyA/ICdhbWV4JyA6IGNhcmRUeXBlLnJlcGxhY2UoJy0nLCAnJyk7XG4gICAgfVxuXG4gICAgX3JlY3JlYXRlRWxlbWVudENsYXNzQXR0cmlidXRlKGVsZW1lbnQsIG5ld0NsYXNzTmFtZSkge1xuICAgICAgICBlbGVtZW50LnJlbW92ZUF0dHJpYnV0ZSgnY2xhc3MnKVxuICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZSgnY2xhc3MnLCBuZXdDbGFzc05hbWUpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IENyZWRpdENhcmRSZW5kZXJlcjtcbiIsImNvbnN0IHN0b3JhZ2VLZXkgPSAncHBjcC1kYXRhLWNsaWVudC1pZCc7XG5cbmNvbnN0IHZhbGlkYXRlVG9rZW4gPSAodG9rZW4sIHVzZXIpID0+IHtcbiAgICBpZiAoISB0b2tlbikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICh0b2tlbi51c2VyICE9PSB1c2VyKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgY3VycmVudFRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICBjb25zdCBpc0V4cGlyZWQgPSBjdXJyZW50VGltZSA+PSB0b2tlbi5leHBpcmF0aW9uICogMTAwMDtcbiAgICByZXR1cm4gISBpc0V4cGlyZWQ7XG59XG5cbmNvbnN0IHN0b3JlZFRva2VuRm9yVXNlciA9ICh1c2VyKSA9PiB7XG4gICAgY29uc3QgdG9rZW4gPSBKU09OLnBhcnNlKHNlc3Npb25TdG9yYWdlLmdldEl0ZW0oc3RvcmFnZUtleSkpO1xuICAgIGlmICh2YWxpZGF0ZVRva2VuKHRva2VuLCB1c2VyKSkge1xuICAgICAgICByZXR1cm4gdG9rZW4udG9rZW47XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuXG5jb25zdCBzdG9yZVRva2VuID0gKHRva2VuKSA9PiB7XG4gICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShzdG9yYWdlS2V5LCBKU09OLnN0cmluZ2lmeSh0b2tlbikpO1xufVxuXG5jb25zdCBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyID0gKHNjcmlwdCwgY29uZmlnKSA9PiB7XG4gICAgZmV0Y2goY29uZmlnLmVuZHBvaW50LCB7XG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBub25jZTogY29uZmlnLm5vbmNlXG4gICAgICAgIH0pXG4gICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICB9KS50aGVuKChkYXRhKT0+e1xuICAgICAgICBjb25zdCBpc1ZhbGlkID0gdmFsaWRhdGVUb2tlbihkYXRhLCBjb25maWcudXNlcik7XG4gICAgICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHN0b3JlVG9rZW4oZGF0YSk7XG4gICAgICAgIHNjcmlwdC5zZXRBdHRyaWJ1dGUoJ2RhdGEtY2xpZW50LXRva2VuJywgZGF0YS50b2tlbik7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKHNjcmlwdCk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXI7XG4iLCJjbGFzcyBNZXNzYWdlUmVuZGVyZXIge1xuXG4gICAgY29uc3RydWN0b3IoY29uZmlnKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIH1cblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgaWYgKCEgdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgcGF5cGFsLk1lc3NhZ2VzKHtcbiAgICAgICAgICAgIGFtb3VudDogdGhpcy5jb25maWcuYW1vdW50LFxuICAgICAgICAgICAgcGxhY2VtZW50OiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQsXG4gICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuc3R5bGVcbiAgICAgICAgfSkucmVuZGVyKHRoaXMuY29uZmlnLndyYXBwZXIpO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbigndXBkYXRlZF9jYXJ0X3RvdGFscycsICgpID0+IHtcbiAgICAgICAgICAgIHBheXBhbC5NZXNzYWdlcyh7XG4gICAgICAgICAgICAgICAgYW1vdW50OiB0aGlzLmNvbmZpZy5hbW91bnQsXG4gICAgICAgICAgICAgICAgcGxhY2VtZW50OiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQsXG4gICAgICAgICAgICAgICAgc3R5bGU6IHRoaXMuY29uZmlnLnN0eWxlXG4gICAgICAgICAgICB9KS5yZW5kZXIodGhpcy5jb25maWcud3JhcHBlcik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHJlbmRlcldpdGhBbW91bnQoYW1vdW50KSB7XG5cbiAgICAgICAgaWYgKCEgdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbmV3V3JhcHBlciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBuZXdXcmFwcGVyLnNldEF0dHJpYnV0ZSgnaWQnLCB0aGlzLmNvbmZpZy53cmFwcGVyLnJlcGxhY2UoJyMnLCAnJykpO1xuXG4gICAgICAgIGNvbnN0IHNpYmxpbmcgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpLm5leHRTaWJsaW5nO1xuICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpLnBhcmVudEVsZW1lbnQucmVtb3ZlQ2hpbGQoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKSk7XG4gICAgICAgIHNpYmxpbmcucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUobmV3V3JhcHBlciwgc2libGluZyk7XG4gICAgICAgIHBheXBhbC5NZXNzYWdlcyh7XG4gICAgICAgICAgICBhbW91bnQsXG4gICAgICAgICAgICBwbGFjZW1lbnQ6IHRoaXMuY29uZmlnLnBsYWNlbWVudCxcbiAgICAgICAgICAgIHN0eWxlOiB0aGlzLmNvbmZpZy5zdHlsZVxuICAgICAgICB9KS5yZW5kZXIodGhpcy5jb25maWcud3JhcHBlcik7XG4gICAgfVxuXG4gICAgc2hvdWxkUmVuZGVyKCkge1xuXG4gICAgICAgIGlmICh0eXBlb2YgcGF5cGFsLk1lc3NhZ2VzID09PSAndW5kZWZpbmVkJyB8fCB0eXBlb2YgdGhpcy5jb25maWcud3JhcHBlciA9PT0gJ3VuZGVmaW5lZCcgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCEgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGhpZGVNZXNzYWdlcygpIHtcbiAgICAgICAgY29uc3QgZG9tRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5jb25maWcud3JhcHBlcik7XG4gICAgICAgIGlmICghIGRvbUVsZW1lbnQgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZG9tRWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBNZXNzYWdlUmVuZGVyZXI7XG4iLCJjbGFzcyBTcGlubmVyIHtcblxuICAgIGNvbnN0cnVjdG9yKHRhcmdldCA9ICdmb3JtLndvb2NvbW1lcmNlLWNoZWNrb3V0Jykge1xuICAgICAgICB0aGlzLnRhcmdldCA9IHRhcmdldDtcbiAgICB9XG5cbiAgICBzZXRUYXJnZXQodGFyZ2V0KSB7XG4gICAgICAgIHRoaXMudGFyZ2V0ID0gdGFyZ2V0O1xuICAgIH1cblxuICAgIGJsb2NrKCkge1xuXG4gICAgICAgIGpRdWVyeSggdGhpcy50YXJnZXQgKS5ibG9jayh7XG4gICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgb3ZlcmxheUNTUzoge1xuICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICcjZmZmJyxcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiAwLjZcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgdW5ibG9jaygpIHtcblxuICAgICAgICBqUXVlcnkoIHRoaXMudGFyZ2V0ICkudW5ibG9jaygpO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgU3Bpbm5lcjtcbiIsImltcG9ydCB7UGF5bWVudE1ldGhvZHN9IGZyb20gXCIuLi9IZWxwZXIvQ2hlY2tvdXRNZXRob2RTdGF0ZVwiO1xuaW1wb3J0IGVycm9ySGFuZGxlciBmcm9tIFwiLi4vRXJyb3JIYW5kbGVyXCI7XG5cbmNsYXNzIEZyZWVUcmlhbEhhbmRsZXIge1xuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBjb25maWcsXG4gICAgICAgIHNwaW5uZXIsXG4gICAgICAgIGVycm9ySGFuZGxlclxuICAgICkge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy5zcGlubmVyID0gc3Bpbm5lcjtcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgfVxuXG4gICAgaGFuZGxlKClcbiAgICB7XG4gICAgICAgIHRoaXMuc3Bpbm5lci5ibG9jaygpO1xuXG4gICAgICAgIGZldGNoKHRoaXMuY29uZmlnLmFqYXgudmF1bHRfcGF5cGFsLmVuZHBvaW50LCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBub25jZTogdGhpcy5jb25maWcuYWpheC52YXVsdF9wYXlwYWwubm9uY2UsXG4gICAgICAgICAgICAgICAgcmV0dXJuX3VybDogbG9jYXRpb24uaHJlZlxuICAgICAgICAgICAgfSksXG4gICAgICAgIH0pLnRoZW4ocmVzID0+IHtcbiAgICAgICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgICAgICB9KS50aGVuKGRhdGEgPT4ge1xuICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZGF0YSk7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIubWVzc2FnZShkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsb2NhdGlvbi5ocmVmID0gZGF0YS5kYXRhLmFwcHJvdmVfbGluaztcbiAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgdGhpcy5zcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEZyZWVUcmlhbEhhbmRsZXI7XG4iLCJpbXBvcnQgTWluaUNhcnRCb290c3RhcCBmcm9tICcuL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9NaW5pQ2FydEJvb3RzdGFwJztcbmltcG9ydCBTaW5nbGVQcm9kdWN0Qm9vdHN0YXAgZnJvbSAnLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvU2luZ2xlUHJvZHVjdEJvb3RzdGFwJztcbmltcG9ydCBDYXJ0Qm9vdHN0cmFwIGZyb20gJy4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL0NhcnRCb290c3RhcCc7XG5pbXBvcnQgQ2hlY2tvdXRCb290c3RhcCBmcm9tICcuL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9DaGVja291dEJvb3RzdGFwJztcbmltcG9ydCBQYXlOb3dCb290c3RyYXAgZnJvbSBcIi4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL1BheU5vd0Jvb3RzdHJhcFwiO1xuaW1wb3J0IFJlbmRlcmVyIGZyb20gJy4vbW9kdWxlcy9SZW5kZXJlci9SZW5kZXJlcic7XG5pbXBvcnQgRXJyb3JIYW5kbGVyIGZyb20gJy4vbW9kdWxlcy9FcnJvckhhbmRsZXInO1xuaW1wb3J0IENyZWRpdENhcmRSZW5kZXJlciBmcm9tIFwiLi9tb2R1bGVzL1JlbmRlcmVyL0NyZWRpdENhcmRSZW5kZXJlclwiO1xuaW1wb3J0IGRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIgZnJvbSBcIi4vbW9kdWxlcy9EYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyXCI7XG5pbXBvcnQgTWVzc2FnZVJlbmRlcmVyIGZyb20gXCIuL21vZHVsZXMvUmVuZGVyZXIvTWVzc2FnZVJlbmRlcmVyXCI7XG5pbXBvcnQgU3Bpbm5lciBmcm9tIFwiLi9tb2R1bGVzL0hlbHBlci9TcGlubmVyXCI7XG5pbXBvcnQge1xuICAgIGdldEN1cnJlbnRQYXltZW50TWV0aG9kLFxuICAgIE9SREVSX0JVVFRPTl9TRUxFQ1RPUixcbiAgICBQYXltZW50TWV0aG9kc1xufSBmcm9tIFwiLi9tb2R1bGVzL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5pbXBvcnQge2hpZGUsIHNldFZpc2libGV9IGZyb20gXCIuL21vZHVsZXMvSGVscGVyL0hpZGluZ1wiO1xuaW1wb3J0IHtpc0NoYW5nZVBheW1lbnRQYWdlfSBmcm9tIFwiLi9tb2R1bGVzL0hlbHBlci9TdWJzY3JpcHRpb25zXCI7XG5pbXBvcnQgRnJlZVRyaWFsSGFuZGxlciBmcm9tIFwiLi9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvRnJlZVRyaWFsSGFuZGxlclwiO1xuXG4vLyBUT0RPOiBjb3VsZCBiZSBhIGdvb2QgaWRlYSB0byBoYXZlIGEgc2VwYXJhdGUgc3Bpbm5lciBmb3IgZWFjaCBnYXRld2F5LFxuLy8gYnV0IEkgdGhpbmsgd2UgY2FyZSBtYWlubHkgYWJvdXQgdGhlIHNjcmlwdCBsb2FkaW5nLCBzbyBvbmUgc3Bpbm5lciBzaG91bGQgYmUgZW5vdWdoLlxuY29uc3QgYnV0dG9uc1NwaW5uZXIgPSBuZXcgU3Bpbm5lcihkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcucHBjLWJ1dHRvbi13cmFwcGVyJykpO1xuY29uc3QgY2FyZHNTcGlubmVyID0gbmV3IFNwaW5uZXIoJyNwcGNwLWhvc3RlZC1maWVsZHMnKTtcblxuY29uc3QgYm9vdHN0cmFwID0gKCkgPT4ge1xuICAgIGNvbnN0IGVycm9ySGFuZGxlciA9IG5ldyBFcnJvckhhbmRsZXIoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmxhYmVscy5lcnJvci5nZW5lcmljKTtcbiAgICBjb25zdCBzcGlubmVyID0gbmV3IFNwaW5uZXIoKTtcbiAgICBjb25zdCBjcmVkaXRDYXJkUmVuZGVyZXIgPSBuZXcgQ3JlZGl0Q2FyZFJlbmRlcmVyKFBheVBhbENvbW1lcmNlR2F0ZXdheSwgZXJyb3JIYW5kbGVyLCBzcGlubmVyKTtcblxuICAgIGNvbnN0IGZyZWVUcmlhbEhhbmRsZXIgPSBuZXcgRnJlZVRyaWFsSGFuZGxlcihQYXlQYWxDb21tZXJjZUdhdGV3YXksIHNwaW5uZXIsIGVycm9ySGFuZGxlcik7XG5cbiAgICBjb25zdCBvblNtYXJ0QnV0dG9uQ2xpY2sgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UgPSBkYXRhLmZ1bmRpbmdTb3VyY2U7XG5cbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5iYXNpY19jaGVja291dF92YWxpZGF0aW9uX2VuYWJsZWQpIHtcbiAgICAgICAgICAgIC8vIFRPRE86IHF1aWNrIGZpeCB0byBnZXQgdGhlIGVycm9yIGFib3V0IGVtcHR5IGZvcm0gYmVmb3JlIGF0dGVtcHRpbmcgUGF5UGFsIG9yZGVyXG4gICAgICAgICAgICAvLyBpdCBzaG91bGQgc29sdmUgIzUxMyBmb3IgbW9zdCBvZiB0aGUgdXNlcnMsIGJ1dCBwcm9wZXIgc29sdXRpb24gc2hvdWxkIGJlIGltcGxlbWVudGVkIGxhdGVyLlxuICAgICAgICAgICAgY29uc3QgcmVxdWlyZWRGaWVsZHMgPSBqUXVlcnkoJ2Zvcm0ud29vY29tbWVyY2UtY2hlY2tvdXQgLnZhbGlkYXRlLXJlcXVpcmVkOnZpc2libGUgOmlucHV0Jyk7XG4gICAgICAgICAgICByZXF1aXJlZEZpZWxkcy5lYWNoKChpLCBpbnB1dCkgPT4ge1xuICAgICAgICAgICAgICAgIGpRdWVyeShpbnB1dCkudHJpZ2dlcigndmFsaWRhdGUnKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgaW52YWxpZEZpZWxkcyA9IEFycmF5LmZyb20oalF1ZXJ5KCdmb3JtLndvb2NvbW1lcmNlLWNoZWNrb3V0IC52YWxpZGF0ZS1yZXF1aXJlZC53b29jb21tZXJjZS1pbnZhbGlkOnZpc2libGUnKSk7XG4gICAgICAgICAgICBpZiAoaW52YWxpZEZpZWxkcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBiaWxsaW5nRmllbGRzQ29udGFpbmVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndvb2NvbW1lcmNlLWJpbGxpbmctZmllbGRzJyk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2hpcHBpbmdGaWVsZHNDb250YWluZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcud29vY29tbWVyY2Utc2hpcHBpbmctZmllbGRzJyk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBuYW1lTWVzc2FnZU1hcCA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5sYWJlbHMuZXJyb3IucmVxdWlyZWQuZWxlbWVudHM7XG4gICAgICAgICAgICAgICAgY29uc3QgbWVzc2FnZXMgPSBpbnZhbGlkRmllbGRzLm1hcChlbCA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBlbC5xdWVyeVNlbGVjdG9yKCdbbmFtZV0nKT8uZ2V0QXR0cmlidXRlKCduYW1lJyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChuYW1lICYmIG5hbWUgaW4gbmFtZU1lc3NhZ2VNYXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBuYW1lTWVzc2FnZU1hcFtuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBsZXQgbGFiZWwgPSBlbC5xdWVyeVNlbGVjdG9yKCdsYWJlbCcpLnRleHRDb250ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZUFsbCgnKicsICcnKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRyaW0oKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGJpbGxpbmdGaWVsZHNDb250YWluZXI/LmNvbnRhaW5zKGVsKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBQYXlQYWxDb21tZXJjZUdhdGV3YXkubGFiZWxzLmJpbGxpbmdfZmllbGQucmVwbGFjZSgnJXMnLCBsYWJlbCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHNoaXBwaW5nRmllbGRzQ29udGFpbmVyPy5jb250YWlucyhlbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LmxhYmVscy5zaGlwcGluZ19maWVsZC5yZXBsYWNlKCclcycsIGxhYmVsKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gUGF5UGFsQ29tbWVyY2VHYXRld2F5LmxhYmVscy5lcnJvci5yZXF1aXJlZC5maWVsZFxuICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoJyVzJywgYDxzdHJvbmc+JHtsYWJlbH08L3N0cm9uZz5gKVxuICAgICAgICAgICAgICAgIH0pLmZpbHRlcihzID0+IHMubGVuZ3RoID4gMik7XG5cbiAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIuY2xlYXIoKTtcbiAgICAgICAgICAgICAgICBpZiAobWVzc2FnZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2VzLmZvckVhY2gocyA9PiBlcnJvckhhbmRsZXIubWVzc2FnZShzKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmxhYmVscy5lcnJvci5yZXF1aXJlZC5nZW5lcmljKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZWplY3QoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGZvcm0gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLndvb2NvbW1lcmNlLWNoZWNrb3V0Jyk7XG4gICAgICAgIGlmIChmb3JtKSB7XG4gICAgICAgICAgICBqUXVlcnkoJyNwcGNwLWZ1bmRpbmctc291cmNlLWZvcm0taW5wdXQnKS5yZW1vdmUoKTtcbiAgICAgICAgICAgIGZvcm0uaW5zZXJ0QWRqYWNlbnRIVE1MKFxuICAgICAgICAgICAgICAgICdiZWZvcmVlbmQnLFxuICAgICAgICAgICAgICAgIGA8aW5wdXQgdHlwZT1cImhpZGRlblwiIG5hbWU9XCJwcGNwLWZ1bmRpbmctc291cmNlXCIgdmFsdWU9XCIke2RhdGEuZnVuZGluZ1NvdXJjZX1cIiBpZD1cInBwY3AtZnVuZGluZy1zb3VyY2UtZm9ybS1pbnB1dFwiPmBcbiAgICAgICAgICAgIClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGlzRnJlZVRyaWFsID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LmlzX2ZyZWVfdHJpYWxfY2FydDtcbiAgICAgICAgaWYgKGlzRnJlZVRyaWFsICYmIGRhdGEuZnVuZGluZ1NvdXJjZSAhPT0gJ2NhcmQnKSB7XG4gICAgICAgICAgICBmcmVlVHJpYWxIYW5kbGVyLmhhbmRsZSgpO1xuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbnMucmVqZWN0KCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IG9uU21hcnRCdXR0b25zSW5pdCA9ICgpID0+IHtcbiAgICAgICAgYnV0dG9uc1NwaW5uZXIudW5ibG9jaygpO1xuICAgIH07XG4gICAgY29uc3QgcmVuZGVyZXIgPSBuZXcgUmVuZGVyZXIoY3JlZGl0Q2FyZFJlbmRlcmVyLCBQYXlQYWxDb21tZXJjZUdhdGV3YXksIG9uU21hcnRCdXR0b25DbGljaywgb25TbWFydEJ1dHRvbnNJbml0KTtcbiAgICBjb25zdCBtZXNzYWdlUmVuZGVyZXIgPSBuZXcgTWVzc2FnZVJlbmRlcmVyKFBheVBhbENvbW1lcmNlR2F0ZXdheS5tZXNzYWdlcyk7XG4gICAgY29uc3QgY29udGV4dCA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0O1xuICAgIGlmIChjb250ZXh0ID09PSAnbWluaS1jYXJ0JyB8fCBjb250ZXh0ID09PSAncHJvZHVjdCcpIHtcbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5taW5pX2NhcnRfYnV0dG9uc19lbmFibGVkID09PSAnMScpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pbmlDYXJ0Qm9vdHN0cmFwID0gbmV3IE1pbmlDYXJ0Qm9vdHN0YXAoXG4gICAgICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgICAgIHJlbmRlcmVyXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBtaW5pQ2FydEJvb3RzdHJhcC5pbml0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29udGV4dCA9PT0gJ3Byb2R1Y3QnICYmIFBheVBhbENvbW1lcmNlR2F0ZXdheS5zaW5nbGVfcHJvZHVjdF9idXR0b25zX2VuYWJsZWQgPT09ICcxJykge1xuICAgICAgICBjb25zdCBzaW5nbGVQcm9kdWN0Qm9vdHN0cmFwID0gbmV3IFNpbmdsZVByb2R1Y3RCb290c3RhcChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheSxcbiAgICAgICAgICAgIHJlbmRlcmVyLFxuICAgICAgICAgICAgbWVzc2FnZVJlbmRlcmVyLFxuICAgICAgICApO1xuXG4gICAgICAgIHNpbmdsZVByb2R1Y3RCb290c3RyYXAuaW5pdCgpO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0ID09PSAnY2FydCcpIHtcbiAgICAgICAgY29uc3QgY2FydEJvb3RzdHJhcCA9IG5ldyBDYXJ0Qm9vdHN0cmFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICk7XG5cbiAgICAgICAgY2FydEJvb3RzdHJhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdjaGVja291dCcpIHtcbiAgICAgICAgY29uc3QgY2hlY2tvdXRCb290c3RhcCA9IG5ldyBDaGVja291dEJvb3RzdGFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICAgICBtZXNzYWdlUmVuZGVyZXIsXG4gICAgICAgICAgICBzcGlubmVyXG4gICAgICAgICk7XG5cbiAgICAgICAgY2hlY2tvdXRCb290c3RhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdwYXktbm93JyApIHtcbiAgICAgICAgY29uc3QgcGF5Tm93Qm9vdHN0cmFwID0gbmV3IFBheU5vd0Jvb3RzdHJhcChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheSxcbiAgICAgICAgICAgIHJlbmRlcmVyLFxuICAgICAgICAgICAgbWVzc2FnZVJlbmRlcmVyLFxuICAgICAgICAgICAgc3Bpbm5lclxuICAgICAgICApO1xuICAgICAgICBwYXlOb3dCb290c3RyYXAuaW5pdCgpO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0ICE9PSAnY2hlY2tvdXQnKSB7XG4gICAgICAgIG1lc3NhZ2VSZW5kZXJlci5yZW5kZXIoKTtcbiAgICB9XG59O1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAnRE9NQ29udGVudExvYWRlZCcsXG4gICAgKCkgPT4ge1xuICAgICAgICBpZiAoIXR5cGVvZiAoUGF5UGFsQ29tbWVyY2VHYXRld2F5KSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignUGF5UGFsIGJ1dHRvbiBjb3VsZCBub3QgYmUgY29uZmlndXJlZC4nKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0ICE9PSAnY2hlY2tvdXQnXG4gICAgICAgICAgICAmJiBQYXlQYWxDb21tZXJjZUdhdGV3YXkuZGF0YV9jbGllbnRfaWQudXNlciA9PT0gMFxuICAgICAgICAgICAgJiYgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkLmhhc19zdWJzY3JpcHRpb25zXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcGF5cGFsQnV0dG9uR2F0ZXdheUlkcyA9IFtcbiAgICAgICAgICAgIFBheW1lbnRNZXRob2RzLlBBWVBBTCxcbiAgICAgICAgICAgIC4uLk9iamVjdC5lbnRyaWVzKFBheVBhbENvbW1lcmNlR2F0ZXdheS5zZXBhcmF0ZV9idXR0b25zKS5tYXAoKFtrLCBkYXRhXSkgPT4gZGF0YS5pZCksXG4gICAgICAgIF1cblxuICAgICAgICAvLyBTb21ldGltZXMgUGF5UGFsIHNjcmlwdCB0YWtlcyBsb25nIHRpbWUgdG8gbG9hZCxcbiAgICAgICAgLy8gc28gd2UgYWRkaXRpb25hbGx5IGhpZGUgdGhlIHN0YW5kYXJkIG9yZGVyIGJ1dHRvbiBoZXJlIHRvIGF2b2lkIGZhaWxlZCBvcmRlcnMuXG4gICAgICAgIC8vIE5vcm1hbGx5IGl0IGlzIGhpZGRlbiBsYXRlciBhZnRlciB0aGUgc2NyaXB0IGxvYWQuXG4gICAgICAgIGNvbnN0IGhpZGVPcmRlckJ1dHRvbklmUHBjcEdhdGV3YXkgPSAoKSA9PiB7XG4gICAgICAgICAgICAvLyBvbmx5IGluIGNoZWNrb3V0IGFuZCBwYXkgbm93IHBhZ2UsIG90aGVyd2lzZSBpdCBtYXkgYnJlYWsgdGhpbmdzIChlLmcuIHBheW1lbnQgdmlhIHByb2R1Y3QgcGFnZSksXG4gICAgICAgICAgICAvLyBhbmQgYWxzbyB0aGUgbG9hZGluZyBzcGlubmVyIG1heSBsb29rIHdlaXJkIG9uIG90aGVyIHBhZ2VzXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgIVsnY2hlY2tvdXQnLCAncGF5LW5vdyddLmluY2x1ZGVzKFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0KVxuICAgICAgICAgICAgICAgIHx8IGlzQ2hhbmdlUGF5bWVudFBhZ2UoKVxuICAgICAgICAgICAgICAgIHx8IChQYXlQYWxDb21tZXJjZUdhdGV3YXkuaXNfZnJlZV90cmlhbF9jYXJ0ICYmIFBheVBhbENvbW1lcmNlR2F0ZXdheS52YXVsdGVkX3BheXBhbF9lbWFpbCAhPT0gJycpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRQYXltZW50TWV0aG9kID0gZ2V0Q3VycmVudFBheW1lbnRNZXRob2QoKTtcbiAgICAgICAgICAgIGNvbnN0IGlzUGF5cGFsQnV0dG9uID0gcGF5cGFsQnV0dG9uR2F0ZXdheUlkcy5pbmNsdWRlcyhjdXJyZW50UGF5bWVudE1ldGhvZCk7XG4gICAgICAgICAgICBjb25zdCBpc0NhcmRzID0gY3VycmVudFBheW1lbnRNZXRob2QgPT09IFBheW1lbnRNZXRob2RzLkNBUkRTO1xuXG4gICAgICAgICAgICBzZXRWaXNpYmxlKE9SREVSX0JVVFRPTl9TRUxFQ1RPUiwgIWlzUGF5cGFsQnV0dG9uICYmICFpc0NhcmRzLCB0cnVlKTtcblxuICAgICAgICAgICAgaWYgKGlzUGF5cGFsQnV0dG9uKSB7XG4gICAgICAgICAgICAgICAgLy8gc3RvcHBlZCBhZnRlciB0aGUgZmlyc3QgcmVuZGVyaW5nIG9mIHRoZSBidXR0b25zLCBpbiBvbkluaXRcbiAgICAgICAgICAgICAgICBidXR0b25zU3Bpbm5lci5ibG9jaygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBidXR0b25zU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpc0NhcmRzKSB7XG4gICAgICAgICAgICAgICAgY2FyZHNTcGlubmVyLmJsb2NrKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhcmRzU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQpLm9uKCdob3N0ZWRfZmllbGRzX2xvYWRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIGNhcmRzU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGxldCBib290c3RyYXBwZWQgPSBmYWxzZTtcblxuICAgICAgICBoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5KCk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NoZWNrb3V0IHBheW1lbnRfbWV0aG9kX3NlbGVjdGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGJvb3RzdHJhcHBlZCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaGlkZU9yZGVyQnV0dG9uSWZQcGNwR2F0ZXdheSgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgICAgICAgc2NyaXB0LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGJvb3RzdHJhcHBlZCA9IHRydWU7XG5cbiAgICAgICAgICAgIGJvb3RzdHJhcCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgc2NyaXB0LnNldEF0dHJpYnV0ZSgnc3JjJywgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmJ1dHRvbi51cmwpO1xuICAgICAgICBPYmplY3QuZW50cmllcyhQYXlQYWxDb21tZXJjZUdhdGV3YXkuc2NyaXB0X2F0dHJpYnV0ZXMpLmZvckVhY2goXG4gICAgICAgICAgICAoa2V5VmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKGtleVZhbHVlWzBdLCBrZXlWYWx1ZVsxXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5kYXRhX2NsaWVudF9pZC5zZXRfYXR0cmlidXRlKSB7XG4gICAgICAgICAgICBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyKHNjcmlwdCwgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKHNjcmlwdCk7XG4gICAgfSxcbik7XG4iXSwibmFtZXMiOlsiRXJyb3JIYW5kbGVyIiwiY29uc3RydWN0b3IiLCJnZW5lcmljRXJyb3JUZXh0Iiwid3JhcHBlciIsImRvY3VtZW50IiwicXVlcnlTZWxlY3RvciIsIm1lc3NhZ2VzTGlzdCIsImdlbmVyaWNFcnJvciIsImNsYXNzTGlzdCIsImNvbnRhaW5zIiwiY2xlYXIiLCJtZXNzYWdlIiwiYXBwZW5kUHJlcGFyZWRFcnJvck1lc3NhZ2VFbGVtZW50IiwiZXJyb3JNZXNzYWdlRWxlbWVudCIsInByZXBhcmVNZXNzYWdlc0xpc3QiLCJyZXBsYWNlV2l0aCIsInRleHQiLCJwZXJzaXN0IiwiU3RyaW5nIiwibGVuZ3RoIiwiRXJyb3IiLCJhZGQiLCJyZW1vdmUiLCJtZXNzYWdlTm9kZSIsInByZXBhcmVNZXNzYWdlc0xpc3RJdGVtIiwiYXBwZW5kQ2hpbGQiLCJqUXVlcnkiLCJzY3JvbGxfdG9fbm90aWNlcyIsImNyZWF0ZUVsZW1lbnQiLCJzZXRBdHRyaWJ1dGUiLCJsaSIsImlubmVySFRNTCIsInNhbml0aXplIiwidGV4dGFyZWEiLCJ2YWx1ZSIsInJlcGxhY2UiLCJvbkFwcHJvdmUiLCJjb250ZXh0IiwiZXJyb3JIYW5kbGVyIiwiZGF0YSIsImFjdGlvbnMiLCJmZXRjaCIsImNvbmZpZyIsImFqYXgiLCJhcHByb3ZlX29yZGVyIiwiZW5kcG9pbnQiLCJtZXRob2QiLCJib2R5IiwiSlNPTiIsInN0cmluZ2lmeSIsIm5vbmNlIiwib3JkZXJfaWQiLCJvcmRlcklEIiwiZnVuZGluZ19zb3VyY2UiLCJ3aW5kb3ciLCJwcGNwRnVuZGluZ1NvdXJjZSIsInRoZW4iLCJyZXMiLCJqc29uIiwic3VjY2VzcyIsInJlc3RhcnQiLCJjYXRjaCIsImVyciIsImxvY2F0aW9uIiwiaHJlZiIsInJlZGlyZWN0IiwicGF5ZXJEYXRhIiwicGF5ZXIiLCJQYXlQYWxDb21tZXJjZUdhdGV3YXkiLCJwaG9uZSIsInBob25lX3R5cGUiLCJwaG9uZV9udW1iZXIiLCJuYXRpb25hbF9udW1iZXIiLCJlbWFpbF9hZGRyZXNzIiwibmFtZSIsInN1cm5hbWUiLCJnaXZlbl9uYW1lIiwiYWRkcmVzcyIsImNvdW50cnlfY29kZSIsImFkZHJlc3NfbGluZV8xIiwiYWRkcmVzc19saW5lXzIiLCJhZG1pbl9hcmVhXzEiLCJhZG1pbl9hcmVhXzIiLCJwb3N0YWxfY29kZSIsIlBheW1lbnRNZXRob2RzIiwiUEFZUEFMIiwiQ0FSRFMiLCJPWFhPIiwiQ0FSRF9CVVRUT04iLCJPUkRFUl9CVVRUT05fU0VMRUNUT1IiLCJnZXRDdXJyZW50UGF5bWVudE1ldGhvZCIsImVsIiwiaXNTYXZlZENhcmRTZWxlY3RlZCIsInNhdmVkQ2FyZExpc3QiLCJDYXJ0QWN0aW9uSGFuZGxlciIsImNvbmZpZ3VyYXRpb24iLCJjcmVhdGVPcmRlciIsImJuQ29kZSIsImJuX2NvZGVzIiwiY3JlYXRlX29yZGVyIiwicHVyY2hhc2VfdW5pdHMiLCJwYXltZW50X21ldGhvZCIsImJuX2NvZGUiLCJjb25zb2xlIiwiZXJyb3IiLCJpZCIsIm9uRXJyb3IiLCJNaW5pQ2FydEJvb3RzdGFwIiwiZ2F0ZXdheSIsInJlbmRlcmVyIiwiYWN0aW9uSGFuZGxlciIsImluaXQiLCJsYWJlbHMiLCJnZW5lcmljIiwicmVuZGVyIiwib24iLCJzaG91bGRSZW5kZXIiLCJidXR0b24iLCJtaW5pX2NhcnRfd3JhcHBlciIsImhvc3RlZF9maWVsZHMiLCJzdHlsZSIsIm1pbmlfY2FydF9zdHlsZSIsIlByb2R1Y3QiLCJVcGRhdGVDYXJ0IiwidXBkYXRlIiwib25SZXNvbHZlIiwicHJvZHVjdHMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInJlc3VsdCIsInJlc29sdmVkIiwiQnV0dG9uc1RvZ2dsZUxpc3RlbmVyIiwiZWxlbWVudCIsInNob3dDYWxsYmFjayIsImhpZGVDYWxsYmFjayIsIm9ic2VydmVyIiwiYXR0cmlidXRlcyIsImNhbGxiYWNrIiwiTXV0YXRpb25PYnNlcnZlciIsIm9ic2VydmUiLCJkaXNjb25uZWN0IiwicXVhbnRpdHkiLCJ2YXJpYXRpb25zIiwiU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXIiLCJ1cGRhdGVDYXJ0Iiwic2hvd0J1dHRvbkNhbGxiYWNrIiwiaGlkZUJ1dHRvbkNhbGxiYWNrIiwiZm9ybUVsZW1lbnQiLCJoYXNWYXJpYXRpb25zIiwiZ2V0UHJvZHVjdHMiLCJpc0dyb3VwZWRQcm9kdWN0IiwicXR5IiwicXVlcnlTZWxlY3RvckFsbCIsImZvckVhY2giLCJlbGVtZW50TmFtZSIsImdldEF0dHJpYnV0ZSIsIm1hdGNoIiwicGFyc2VJbnQiLCJwdXNoIiwicHJvbWlzZSIsIm1hcCIsIlNpbmdsZVByb2R1Y3RCb290c3RhcCIsIm1lc3NhZ2VzIiwiaGFuZGxlQ2hhbmdlIiwiaGlkZUJ1dHRvbnMiLCJoaWRlTWVzc2FnZXMiLCJhZGRFdmVudExpc3RlbmVyIiwiYmluZCIsInByaWNlQW1vdW50SXNaZXJvIiwicHJpY2VBbW91bnQiLCJwcmljZVRleHQiLCJpbm5lclRleHQiLCJwYXJzZUZsb2F0IiwiY2hhbmdlX2NhcnQiLCJzaG93QnV0dG9ucyIsInJlbmRlcldpdGhBbW91bnQiLCJDYXJ0Qm9vdHN0cmFwIiwic3Bpbm5lciIsImJsb2NrIiwidW5ibG9jayIsImNvZGUiLCJjbGljayIsIkNoZWNrb3V0QWN0aW9uSGFuZGxlciIsImZvcm1TZWxlY3RvciIsImZvcm1EYXRhIiwiRm9ybURhdGEiLCJmb3JtSnNvbk9iaiIsIk9iamVjdCIsImZyb21FbnRyaWVzIiwiY3JlYXRlYWNjb3VudCIsImlzIiwicGF5bWVudE1ldGhvZCIsImZ1bmRpbmdTb3VyY2UiLCJmb3JtIiwiZG9tUGFyc2VyIiwiRE9NUGFyc2VyIiwicGFyc2VGcm9tU3RyaW5nIiwiZGV0YWlscyIsImQiLCJpc3N1ZSIsImRlc2NyaXB0aW9uIiwiam9pbiIsImlucHV0IiwiY3VzdG9tX2lkIiwiYXBwZW5kIiwib25DYW5jZWwiLCJnZXRFbGVtZW50Iiwic2VsZWN0b3JPckVsZW1lbnQiLCJpc1Zpc2libGUiLCJvZmZzZXRXaWR0aCIsIm9mZnNldEhlaWdodCIsImdldENsaWVudFJlY3RzIiwic2V0VmlzaWJsZSIsInNob3ciLCJpbXBvcnRhbnQiLCJjdXJyZW50VmFsdWUiLCJnZXRQcm9wZXJ0eVZhbHVlIiwic2V0UHJvcGVydHkiLCJyZW1vdmVQcm9wZXJ0eSIsImhpZGUiLCJDaGVja291dEJvb3RzdGFwIiwic3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yIiwiYnV0dG9uQ2hhbmdlT2JzZXJ2ZXIiLCJ1cGRhdGVVaSIsInZhbCIsImNhbmNlbF93cmFwcGVyIiwiY3VycmVudFBheW1lbnRNZXRob2QiLCJpc1BheXBhbCIsImlzQ2FyZCIsImlzU2VwYXJhdGVCdXR0b25HYXRld2F5IiwiaW5jbHVkZXMiLCJpc1NhdmVkQ2FyZCIsImlzTm90T3VyR2F0ZXdheSIsImlzRnJlZVRyaWFsIiwiaXNfZnJlZV90cmlhbF9jYXJ0IiwiaGFzVmF1bHRlZFBheXBhbCIsInZhdWx0ZWRfcGF5cGFsX2VtYWlsIiwicGF5cGFsQnV0dG9uV3JhcHBlcnMiLCJlbnRyaWVzIiwic2VwYXJhdGVfYnV0dG9ucyIsInJlZHVjZSIsImsiLCJnYXRld2F5SWQiLCJkaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcyIsImVuYWJsZUNyZWRpdENhcmRGaWVsZHMiLCJhZGRDbGFzcyIsImF0dHIiLCJyZW1vdmVDbGFzcyIsImlzQ2hhbmdlUGF5bWVudFBhZ2UiLCJ1cmxQYXJhbXMiLCJVUkxTZWFyY2hQYXJhbXMiLCJzZWFyY2giLCJoYXMiLCJQYXlOb3dCb290c3RyYXAiLCJtZXJnZSIsIlJlbmRlcmVyIiwiY3JlZGl0Q2FyZFJlbmRlcmVyIiwiZGVmYXVsdFNldHRpbmdzIiwib25TbWFydEJ1dHRvbkNsaWNrIiwib25TbWFydEJ1dHRvbnNJbml0IiwicmVuZGVyZWRTb3VyY2VzIiwiU2V0IiwiY29udGV4dENvbmZpZyIsInNldHRpbmdzT3ZlcnJpZGUiLCJzZXR0aW5ncyIsImVuYWJsZWRTZXBhcmF0ZUdhdGV3YXlzIiwiZmlsdGVyIiwicyIsImhhc0VuYWJsZWRTZXBhcmF0ZUdhdGV3YXlzIiwia2V5cyIsInJlbmRlckJ1dHRvbnMiLCJwYXlwYWwiLCJnZXRGdW5kaW5nU291cmNlcyIsInNoYXBlIiwiaXNBbHJlYWR5UmVuZGVyZWQiLCJCdXR0b25zIiwiYnRuIiwib25DbGljayIsIm9uSW5pdCIsImlzRWxpZ2libGUiLCJoYXNDaGlsZE5vZGVzIiwiZG9tRWxlbWVudCIsImRpc3BsYXkiLCJkaXNhYmxlRmllbGRzIiwiZW5hYmxlRmllbGRzIiwiZGNjSW5wdXRGYWN0b3J5Iiwib3JpZ2luYWwiLCJzdHlsZXMiLCJnZXRDb21wdXRlZFN0eWxlIiwibmV3RWxlbWVudCIsImNsYXNzTmFtZSIsInZhbHVlcyIsInByb3AiLCJpc05hTiIsIkNyZWRpdENhcmRSZW5kZXJlciIsImRlZmF1bHRDb25maWciLCJjYXJkVmFsaWQiLCJmb3JtVmFsaWQiLCJjdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UiLCJIb3N0ZWRGaWVsZHMiLCJ3cmFwcGVyRWxlbWVudCIsInBhcmVudE5vZGUiLCJyZW1vdmVDaGlsZCIsImJ1dHRvblNlbGVjdG9yIiwidGVhcmRvd24iLCJnYXRlV2F5Qm94Iiwib2xkRGlzcGxheVN0eWxlIiwiaGlkZURjY0dhdGV3YXkiLCJjYXJkTnVtYmVyRmllbGQiLCJzdHlsZXNSYXciLCJjYXJkTnVtYmVyIiwicmVwbGFjZUNoaWxkIiwiY2FyZEV4cGlyeUZpZWxkIiwiY2FyZEV4cGlyeSIsImNhcmRDb2RlRmllbGQiLCJjYXJkQ29kZSIsImZvcm1XcmFwcGVyIiwiZW5mb3JjZV92YXVsdCIsImNoZWNrZWQiLCJmaWVsZHMiLCJudW1iZXIiLCJzZWxlY3RvciIsInBsYWNlaG9sZGVyIiwiY3JlZGl0X2NhcmRfbnVtYmVyIiwiY3Z2IiwiZXhwaXJhdGlvbkRhdGUiLCJtbV95eSIsImhvc3RlZEZpZWxkcyIsImRpc3BhdGNoRXZlbnQiLCJDdXN0b21FdmVudCIsIl9zdWJtaXQiLCJldmVudCIsImNhcmRzIiwidmFsaWRDYXJkcyIsInZhbGlkX2NhcmRzIiwiaW5kZXhPZiIsInR5cGUiLCJfY2FyZE51bWJlckZpbGVkQ0xhc3NOYW1lQnlDYXJkVHlwZSIsIl9yZWNyZWF0ZUVsZW1lbnRDbGFzc0F0dHJpYnV0ZSIsImlzVmFsaWQiLCJldmVyeSIsImtleSIsInByZXZlbnREZWZhdWx0IiwiZmllbGQiLCJhdHRyaWJ1dGUiLCJyZW1vdmVBdHRyaWJ1dGUiLCJzYXZlX2NhcmQiLCJjYW5fc2F2ZV92YXVsdF90b2tlbiIsInZhdWx0IiwiZ2V0RWxlbWVudEJ5SWQiLCJjb250aW5nZW5jeSIsImhvc3RlZEZpZWxkc0RhdGEiLCJjb250aW5nZW5jaWVzIiwiY2FyZGhvbGRlck5hbWUiLCJmaXJzdE5hbWUiLCJsYXN0TmFtZSIsInN1Ym1pdCIsInBheWxvYWQiLCJvcmRlcklkIiwiY2FyZF9ub3Rfc3VwcG9ydGVkIiwiZmllbGRzX25vdF92YWxpZCIsImNhcmRUeXBlIiwibmV3Q2xhc3NOYW1lIiwic3RvcmFnZUtleSIsInZhbGlkYXRlVG9rZW4iLCJ0b2tlbiIsInVzZXIiLCJjdXJyZW50VGltZSIsIkRhdGUiLCJnZXRUaW1lIiwiaXNFeHBpcmVkIiwiZXhwaXJhdGlvbiIsInN0b3JlZFRva2VuRm9yVXNlciIsInBhcnNlIiwic2Vzc2lvblN0b3JhZ2UiLCJnZXRJdGVtIiwic3RvcmVUb2tlbiIsInNldEl0ZW0iLCJkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyIiwic2NyaXB0IiwiTWVzc2FnZVJlbmRlcmVyIiwiTWVzc2FnZXMiLCJhbW91bnQiLCJwbGFjZW1lbnQiLCJuZXdXcmFwcGVyIiwic2libGluZyIsIm5leHRTaWJsaW5nIiwicGFyZW50RWxlbWVudCIsImluc2VydEJlZm9yZSIsIlNwaW5uZXIiLCJ0YXJnZXQiLCJzZXRUYXJnZXQiLCJvdmVybGF5Q1NTIiwiYmFja2dyb3VuZCIsIm9wYWNpdHkiLCJGcmVlVHJpYWxIYW5kbGVyIiwiaGFuZGxlIiwidmF1bHRfcGF5cGFsIiwicmV0dXJuX3VybCIsImFwcHJvdmVfbGluayIsImJ1dHRvbnNTcGlubmVyIiwiY2FyZHNTcGlubmVyIiwiYm9vdHN0cmFwIiwiZnJlZVRyaWFsSGFuZGxlciIsImJhc2ljX2NoZWNrb3V0X3ZhbGlkYXRpb25fZW5hYmxlZCIsInJlcXVpcmVkRmllbGRzIiwiZWFjaCIsImkiLCJ0cmlnZ2VyIiwiaW52YWxpZEZpZWxkcyIsIkFycmF5IiwiZnJvbSIsImJpbGxpbmdGaWVsZHNDb250YWluZXIiLCJzaGlwcGluZ0ZpZWxkc0NvbnRhaW5lciIsIm5hbWVNZXNzYWdlTWFwIiwicmVxdWlyZWQiLCJlbGVtZW50cyIsImxhYmVsIiwidGV4dENvbnRlbnQiLCJyZXBsYWNlQWxsIiwidHJpbSIsImJpbGxpbmdfZmllbGQiLCJzaGlwcGluZ19maWVsZCIsImluc2VydEFkamFjZW50SFRNTCIsIm1lc3NhZ2VSZW5kZXJlciIsIm1pbmlfY2FydF9idXR0b25zX2VuYWJsZWQiLCJtaW5pQ2FydEJvb3RzdHJhcCIsInNpbmdsZV9wcm9kdWN0X2J1dHRvbnNfZW5hYmxlZCIsInNpbmdsZVByb2R1Y3RCb290c3RyYXAiLCJjYXJ0Qm9vdHN0cmFwIiwiY2hlY2tvdXRCb290c3RhcCIsInBheU5vd0Jvb3RzdHJhcCIsImRhdGFfY2xpZW50X2lkIiwiaGFzX3N1YnNjcmlwdGlvbnMiLCJwYXlwYWxCdXR0b25HYXRld2F5SWRzIiwiaGlkZU9yZGVyQnV0dG9uSWZQcGNwR2F0ZXdheSIsImlzUGF5cGFsQnV0dG9uIiwiaXNDYXJkcyIsImJvb3RzdHJhcHBlZCIsInVybCIsInNjcmlwdF9hdHRyaWJ1dGVzIiwia2V5VmFsdWUiLCJzZXRfYXR0cmlidXRlIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///536\n")},996:module=>{eval("\n\nvar isMergeableObject = function isMergeableObject(value) {\n\treturn isNonNullObject(value)\n\t\t&& !isSpecial(value)\n};\n\nfunction isNonNullObject(value) {\n\treturn !!value && typeof value === 'object'\n}\n\nfunction isSpecial(value) {\n\tvar stringValue = Object.prototype.toString.call(value);\n\n\treturn stringValue === '[object RegExp]'\n\t\t|| stringValue === '[object Date]'\n\t\t|| isReactElement(value)\n}\n\n// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25\nvar canUseSymbol = typeof Symbol === 'function' && Symbol.for;\nvar REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;\n\nfunction isReactElement(value) {\n\treturn value.$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction emptyTarget(val) {\n\treturn Array.isArray(val) ? [] : {}\n}\n\nfunction cloneUnlessOtherwiseSpecified(value, options) {\n\treturn (options.clone !== false && options.isMergeableObject(value))\n\t\t? deepmerge(emptyTarget(value), value, options)\n\t\t: value\n}\n\nfunction defaultArrayMerge(target, source, options) {\n\treturn target.concat(source).map(function(element) {\n\t\treturn cloneUnlessOtherwiseSpecified(element, options)\n\t})\n}\n\nfunction getMergeFunction(key, options) {\n\tif (!options.customMerge) {\n\t\treturn deepmerge\n\t}\n\tvar customMerge = options.customMerge(key);\n\treturn typeof customMerge === 'function' ? customMerge : deepmerge\n}\n\nfunction getEnumerableOwnPropertySymbols(target) {\n\treturn Object.getOwnPropertySymbols\n\t\t? Object.getOwnPropertySymbols(target).filter(function(symbol) {\n\t\t\treturn target.propertyIsEnumerable(symbol)\n\t\t})\n\t\t: []\n}\n\nfunction getKeys(target) {\n\treturn Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))\n}\n\nfunction propertyIsOnObject(object, property) {\n\ttry {\n\t\treturn property in object\n\t} catch(_) {\n\t\treturn false\n\t}\n}\n\n// Protects from prototype poisoning and unexpected merging up the prototype chain.\nfunction propertyIsUnsafe(target, key) {\n\treturn propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,\n\t\t&& !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,\n\t\t\t&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.\n}\n\nfunction mergeObject(target, source, options) {\n\tvar destination = {};\n\tif (options.isMergeableObject(target)) {\n\t\tgetKeys(target).forEach(function(key) {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(target[key], options);\n\t\t});\n\t}\n\tgetKeys(source).forEach(function(key) {\n\t\tif (propertyIsUnsafe(target, key)) {\n\t\t\treturn\n\t\t}\n\n\t\tif (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {\n\t\t\tdestination[key] = getMergeFunction(key, options)(target[key], source[key], options);\n\t\t} else {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(source[key], options);\n\t\t}\n\t});\n\treturn destination\n}\n\nfunction deepmerge(target, source, options) {\n\toptions = options || {};\n\toptions.arrayMerge = options.arrayMerge || defaultArrayMerge;\n\toptions.isMergeableObject = options.isMergeableObject || isMergeableObject;\n\t// cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()\n\t// implementations can use it. The caller may not replace it.\n\toptions.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;\n\n\tvar sourceIsArray = Array.isArray(source);\n\tvar targetIsArray = Array.isArray(target);\n\tvar sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;\n\n\tif (!sourceAndTargetTypesMatch) {\n\t\treturn cloneUnlessOtherwiseSpecified(source, options)\n\t} else if (sourceIsArray) {\n\t\treturn options.arrayMerge(target, source, options)\n\t} else {\n\t\treturn mergeObject(target, source, options)\n\t}\n}\n\ndeepmerge.all = function deepmergeAll(array, options) {\n\tif (!Array.isArray(array)) {\n\t\tthrow new Error('first argument should be an array')\n\t}\n\n\treturn array.reduce(function(prev, next) {\n\t\treturn deepmerge(prev, next, options)\n\t}, {})\n};\n\nvar deepmerge_1 = deepmerge;\n\nmodule.exports = deepmerge_1;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiOTk2LmpzIiwibWFwcGluZ3MiOiJBQUFhOztBQUViO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUUsSUFBSTtBQUNOOztBQUVBOztBQUVBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL25vZGVfbW9kdWxlcy9kZWVwbWVyZ2UvZGlzdC9janMuanM/M2M0ZSJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbnZhciBpc01lcmdlYWJsZU9iamVjdCA9IGZ1bmN0aW9uIGlzTWVyZ2VhYmxlT2JqZWN0KHZhbHVlKSB7XG5cdHJldHVybiBpc05vbk51bGxPYmplY3QodmFsdWUpXG5cdFx0JiYgIWlzU3BlY2lhbCh2YWx1ZSlcbn07XG5cbmZ1bmN0aW9uIGlzTm9uTnVsbE9iamVjdCh2YWx1ZSkge1xuXHRyZXR1cm4gISF2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnXG59XG5cbmZ1bmN0aW9uIGlzU3BlY2lhbCh2YWx1ZSkge1xuXHR2YXIgc3RyaW5nVmFsdWUgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpO1xuXG5cdHJldHVybiBzdHJpbmdWYWx1ZSA9PT0gJ1tvYmplY3QgUmVnRXhwXSdcblx0XHR8fCBzdHJpbmdWYWx1ZSA9PT0gJ1tvYmplY3QgRGF0ZV0nXG5cdFx0fHwgaXNSZWFjdEVsZW1lbnQodmFsdWUpXG59XG5cbi8vIHNlZSBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2svcmVhY3QvYmxvYi9iNWFjOTYzZmI3OTFkMTI5OGU3ZjM5NjIzNjM4M2JjOTU1ZjkxNmMxL3NyYy9pc29tb3JwaGljL2NsYXNzaWMvZWxlbWVudC9SZWFjdEVsZW1lbnQuanMjTDIxLUwyNVxudmFyIGNhblVzZVN5bWJvbCA9IHR5cGVvZiBTeW1ib2wgPT09ICdmdW5jdGlvbicgJiYgU3ltYm9sLmZvcjtcbnZhciBSRUFDVF9FTEVNRU5UX1RZUEUgPSBjYW5Vc2VTeW1ib2wgPyBTeW1ib2wuZm9yKCdyZWFjdC5lbGVtZW50JykgOiAweGVhYzc7XG5cbmZ1bmN0aW9uIGlzUmVhY3RFbGVtZW50KHZhbHVlKSB7XG5cdHJldHVybiB2YWx1ZS4kJHR5cGVvZiA9PT0gUkVBQ1RfRUxFTUVOVF9UWVBFXG59XG5cbmZ1bmN0aW9uIGVtcHR5VGFyZ2V0KHZhbCkge1xuXHRyZXR1cm4gQXJyYXkuaXNBcnJheSh2YWwpID8gW10gOiB7fVxufVxuXG5mdW5jdGlvbiBjbG9uZVVubGVzc090aGVyd2lzZVNwZWNpZmllZCh2YWx1ZSwgb3B0aW9ucykge1xuXHRyZXR1cm4gKG9wdGlvbnMuY2xvbmUgIT09IGZhbHNlICYmIG9wdGlvbnMuaXNNZXJnZWFibGVPYmplY3QodmFsdWUpKVxuXHRcdD8gZGVlcG1lcmdlKGVtcHR5VGFyZ2V0KHZhbHVlKSwgdmFsdWUsIG9wdGlvbnMpXG5cdFx0OiB2YWx1ZVxufVxuXG5mdW5jdGlvbiBkZWZhdWx0QXJyYXlNZXJnZSh0YXJnZXQsIHNvdXJjZSwgb3B0aW9ucykge1xuXHRyZXR1cm4gdGFyZ2V0LmNvbmNhdChzb3VyY2UpLm1hcChmdW5jdGlvbihlbGVtZW50KSB7XG5cdFx0cmV0dXJuIGNsb25lVW5sZXNzT3RoZXJ3aXNlU3BlY2lmaWVkKGVsZW1lbnQsIG9wdGlvbnMpXG5cdH0pXG59XG5cbmZ1bmN0aW9uIGdldE1lcmdlRnVuY3Rpb24oa2V5LCBvcHRpb25zKSB7XG5cdGlmICghb3B0aW9ucy5jdXN0b21NZXJnZSkge1xuXHRcdHJldHVybiBkZWVwbWVyZ2Vcblx0fVxuXHR2YXIgY3VzdG9tTWVyZ2UgPSBvcHRpb25zLmN1c3RvbU1lcmdlKGtleSk7XG5cdHJldHVybiB0eXBlb2YgY3VzdG9tTWVyZ2UgPT09ICdmdW5jdGlvbicgPyBjdXN0b21NZXJnZSA6IGRlZXBtZXJnZVxufVxuXG5mdW5jdGlvbiBnZXRFbnVtZXJhYmxlT3duUHJvcGVydHlTeW1ib2xzKHRhcmdldCkge1xuXHRyZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9sc1xuXHRcdD8gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyh0YXJnZXQpLmZpbHRlcihmdW5jdGlvbihzeW1ib2wpIHtcblx0XHRcdHJldHVybiB0YXJnZXQucHJvcGVydHlJc0VudW1lcmFibGUoc3ltYm9sKVxuXHRcdH0pXG5cdFx0OiBbXVxufVxuXG5mdW5jdGlvbiBnZXRLZXlzKHRhcmdldCkge1xuXHRyZXR1cm4gT2JqZWN0LmtleXModGFyZ2V0KS5jb25jYXQoZ2V0RW51bWVyYWJsZU93blByb3BlcnR5U3ltYm9scyh0YXJnZXQpKVxufVxuXG5mdW5jdGlvbiBwcm9wZXJ0eUlzT25PYmplY3Qob2JqZWN0LCBwcm9wZXJ0eSkge1xuXHR0cnkge1xuXHRcdHJldHVybiBwcm9wZXJ0eSBpbiBvYmplY3Rcblx0fSBjYXRjaChfKSB7XG5cdFx0cmV0dXJuIGZhbHNlXG5cdH1cbn1cblxuLy8gUHJvdGVjdHMgZnJvbSBwcm90b3R5cGUgcG9pc29uaW5nIGFuZCB1bmV4cGVjdGVkIG1lcmdpbmcgdXAgdGhlIHByb3RvdHlwZSBjaGFpbi5cbmZ1bmN0aW9uIHByb3BlcnR5SXNVbnNhZmUodGFyZ2V0LCBrZXkpIHtcblx0cmV0dXJuIHByb3BlcnR5SXNPbk9iamVjdCh0YXJnZXQsIGtleSkgLy8gUHJvcGVydGllcyBhcmUgc2FmZSB0byBtZXJnZSBpZiB0aGV5IGRvbid0IGV4aXN0IGluIHRoZSB0YXJnZXQgeWV0LFxuXHRcdCYmICEoT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwodGFyZ2V0LCBrZXkpIC8vIHVuc2FmZSBpZiB0aGV5IGV4aXN0IHVwIHRoZSBwcm90b3R5cGUgY2hhaW4sXG5cdFx0XHQmJiBPYmplY3QucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbCh0YXJnZXQsIGtleSkpIC8vIGFuZCBhbHNvIHVuc2FmZSBpZiB0aGV5J3JlIG5vbmVudW1lcmFibGUuXG59XG5cbmZ1bmN0aW9uIG1lcmdlT2JqZWN0KHRhcmdldCwgc291cmNlLCBvcHRpb25zKSB7XG5cdHZhciBkZXN0aW5hdGlvbiA9IHt9O1xuXHRpZiAob3B0aW9ucy5pc01lcmdlYWJsZU9iamVjdCh0YXJnZXQpKSB7XG5cdFx0Z2V0S2V5cyh0YXJnZXQpLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG5cdFx0XHRkZXN0aW5hdGlvbltrZXldID0gY2xvbmVVbmxlc3NPdGhlcndpc2VTcGVjaWZpZWQodGFyZ2V0W2tleV0sIG9wdGlvbnMpO1xuXHRcdH0pO1xuXHR9XG5cdGdldEtleXMoc291cmNlKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuXHRcdGlmIChwcm9wZXJ0eUlzVW5zYWZlKHRhcmdldCwga2V5KSkge1xuXHRcdFx0cmV0dXJuXG5cdFx0fVxuXG5cdFx0aWYgKHByb3BlcnR5SXNPbk9iamVjdCh0YXJnZXQsIGtleSkgJiYgb3B0aW9ucy5pc01lcmdlYWJsZU9iamVjdChzb3VyY2Vba2V5XSkpIHtcblx0XHRcdGRlc3RpbmF0aW9uW2tleV0gPSBnZXRNZXJnZUZ1bmN0aW9uKGtleSwgb3B0aW9ucykodGFyZ2V0W2tleV0sIHNvdXJjZVtrZXldLCBvcHRpb25zKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZGVzdGluYXRpb25ba2V5XSA9IGNsb25lVW5sZXNzT3RoZXJ3aXNlU3BlY2lmaWVkKHNvdXJjZVtrZXldLCBvcHRpb25zKTtcblx0XHR9XG5cdH0pO1xuXHRyZXR1cm4gZGVzdGluYXRpb25cbn1cblxuZnVuY3Rpb24gZGVlcG1lcmdlKHRhcmdldCwgc291cmNlLCBvcHRpb25zKSB7XG5cdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXHRvcHRpb25zLmFycmF5TWVyZ2UgPSBvcHRpb25zLmFycmF5TWVyZ2UgfHwgZGVmYXVsdEFycmF5TWVyZ2U7XG5cdG9wdGlvbnMuaXNNZXJnZWFibGVPYmplY3QgPSBvcHRpb25zLmlzTWVyZ2VhYmxlT2JqZWN0IHx8IGlzTWVyZ2VhYmxlT2JqZWN0O1xuXHQvLyBjbG9uZVVubGVzc090aGVyd2lzZVNwZWNpZmllZCBpcyBhZGRlZCB0byBgb3B0aW9uc2Agc28gdGhhdCBjdXN0b20gYXJyYXlNZXJnZSgpXG5cdC8vIGltcGxlbWVudGF0aW9ucyBjYW4gdXNlIGl0LiBUaGUgY2FsbGVyIG1heSBub3QgcmVwbGFjZSBpdC5cblx0b3B0aW9ucy5jbG9uZVVubGVzc090aGVyd2lzZVNwZWNpZmllZCA9IGNsb25lVW5sZXNzT3RoZXJ3aXNlU3BlY2lmaWVkO1xuXG5cdHZhciBzb3VyY2VJc0FycmF5ID0gQXJyYXkuaXNBcnJheShzb3VyY2UpO1xuXHR2YXIgdGFyZ2V0SXNBcnJheSA9IEFycmF5LmlzQXJyYXkodGFyZ2V0KTtcblx0dmFyIHNvdXJjZUFuZFRhcmdldFR5cGVzTWF0Y2ggPSBzb3VyY2VJc0FycmF5ID09PSB0YXJnZXRJc0FycmF5O1xuXG5cdGlmICghc291cmNlQW5kVGFyZ2V0VHlwZXNNYXRjaCkge1xuXHRcdHJldHVybiBjbG9uZVVubGVzc090aGVyd2lzZVNwZWNpZmllZChzb3VyY2UsIG9wdGlvbnMpXG5cdH0gZWxzZSBpZiAoc291cmNlSXNBcnJheSkge1xuXHRcdHJldHVybiBvcHRpb25zLmFycmF5TWVyZ2UodGFyZ2V0LCBzb3VyY2UsIG9wdGlvbnMpXG5cdH0gZWxzZSB7XG5cdFx0cmV0dXJuIG1lcmdlT2JqZWN0KHRhcmdldCwgc291cmNlLCBvcHRpb25zKVxuXHR9XG59XG5cbmRlZXBtZXJnZS5hbGwgPSBmdW5jdGlvbiBkZWVwbWVyZ2VBbGwoYXJyYXksIG9wdGlvbnMpIHtcblx0aWYgKCFBcnJheS5pc0FycmF5KGFycmF5KSkge1xuXHRcdHRocm93IG5ldyBFcnJvcignZmlyc3QgYXJndW1lbnQgc2hvdWxkIGJlIGFuIGFycmF5Jylcblx0fVxuXG5cdHJldHVybiBhcnJheS5yZWR1Y2UoZnVuY3Rpb24ocHJldiwgbmV4dCkge1xuXHRcdHJldHVybiBkZWVwbWVyZ2UocHJldiwgbmV4dCwgb3B0aW9ucylcblx0fSwge30pXG59O1xuXG52YXIgZGVlcG1lcmdlXzEgPSBkZWVwbWVyZ2U7XG5cbm1vZHVsZS5leHBvcnRzID0gZGVlcG1lcmdlXzE7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///996\n")}},__webpack_module_cache__={};function __webpack_require__(Q){var F=__webpack_module_cache__[Q];if(void 0!==F)return F.exports;var B=__webpack_module_cache__[Q]={exports:{}};return __webpack_modules__[Q](B,B.exports,__webpack_require__),B.exports}__webpack_require__.n=Q=>{var F=Q&&Q.__esModule?()=>Q.default:()=>Q;return __webpack_require__.d(F,{a:F}),F},__webpack_require__.d=(Q,F)=>{for(var B in F)__webpack_require__.o(F,B)&&!__webpack_require__.o(Q,B)&&Object.defineProperty(Q,B,{enumerable:!0,get:F[B]})},__webpack_require__.o=(Q,F)=>Object.prototype.hasOwnProperty.call(Q,F);var __webpack_exports__=__webpack_require__(536)})();
|
modules/ppcp-button/resources/js/button.js
CHANGED
@@ -18,7 +18,9 @@ import {hide, setVisible} from "./modules/Helper/Hiding";
|
|
18 |
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
|
19 |
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
|
20 |
|
21 |
-
|
|
|
|
|
22 |
const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
23 |
|
24 |
const bootstrap = () => {
|
@@ -38,9 +40,36 @@ const bootstrap = () => {
|
|
38 |
requiredFields.each((i, input) => {
|
39 |
jQuery(input).trigger('validate');
|
40 |
});
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
errorHandler.clear();
|
43 |
-
|
|
|
|
|
|
|
|
|
44 |
|
45 |
return actions.reject();
|
46 |
}
|
@@ -138,6 +167,11 @@ document.addEventListener(
|
|
138 |
return;
|
139 |
}
|
140 |
|
|
|
|
|
|
|
|
|
|
|
141 |
// Sometimes PayPal script takes long time to load,
|
142 |
// so we additionally hide the standard order button here to avoid failed orders.
|
143 |
// Normally it is hidden later after the script load.
|
@@ -153,12 +187,12 @@ document.addEventListener(
|
|
153 |
}
|
154 |
|
155 |
const currentPaymentMethod = getCurrentPaymentMethod();
|
156 |
-
const
|
157 |
const isCards = currentPaymentMethod === PaymentMethods.CARDS;
|
158 |
|
159 |
-
setVisible(ORDER_BUTTON_SELECTOR, !
|
160 |
|
161 |
-
if (
|
162 |
// stopped after the first rendering of the buttons, in onInit
|
163 |
buttonsSpinner.block();
|
164 |
} else {
|
18 |
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
|
19 |
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
|
20 |
|
21 |
+
// TODO: could be a good idea to have a separate spinner for each gateway,
|
22 |
+
// but I think we care mainly about the script loading, so one spinner should be enough.
|
23 |
+
const buttonsSpinner = new Spinner(document.querySelector('.ppc-button-wrapper'));
|
24 |
const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
25 |
|
26 |
const bootstrap = () => {
|
40 |
requiredFields.each((i, input) => {
|
41 |
jQuery(input).trigger('validate');
|
42 |
});
|
43 |
+
const invalidFields = Array.from(jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible'));
|
44 |
+
if (invalidFields.length) {
|
45 |
+
const billingFieldsContainer = document.querySelector('.woocommerce-billing-fields');
|
46 |
+
const shippingFieldsContainer = document.querySelector('.woocommerce-shipping-fields');
|
47 |
+
|
48 |
+
const nameMessageMap = PayPalCommerceGateway.labels.error.required.elements;
|
49 |
+
const messages = invalidFields.map(el => {
|
50 |
+
const name = el.querySelector('[name]')?.getAttribute('name');
|
51 |
+
if (name && name in nameMessageMap) {
|
52 |
+
return nameMessageMap[name];
|
53 |
+
}
|
54 |
+
let label = el.querySelector('label').textContent
|
55 |
+
.replaceAll('*', '')
|
56 |
+
.trim();
|
57 |
+
if (billingFieldsContainer?.contains(el)) {
|
58 |
+
label = PayPalCommerceGateway.labels.billing_field.replace('%s', label);
|
59 |
+
}
|
60 |
+
if (shippingFieldsContainer?.contains(el)) {
|
61 |
+
label = PayPalCommerceGateway.labels.shipping_field.replace('%s', label);
|
62 |
+
}
|
63 |
+
return PayPalCommerceGateway.labels.error.required.field
|
64 |
+
.replace('%s', `<strong>${label}</strong>`)
|
65 |
+
}).filter(s => s.length > 2);
|
66 |
+
|
67 |
errorHandler.clear();
|
68 |
+
if (messages.length) {
|
69 |
+
messages.forEach(s => errorHandler.message(s));
|
70 |
+
} else {
|
71 |
+
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
|
72 |
+
}
|
73 |
|
74 |
return actions.reject();
|
75 |
}
|
167 |
return;
|
168 |
}
|
169 |
|
170 |
+
const paypalButtonGatewayIds = [
|
171 |
+
PaymentMethods.PAYPAL,
|
172 |
+
...Object.entries(PayPalCommerceGateway.separate_buttons).map(([k, data]) => data.id),
|
173 |
+
]
|
174 |
+
|
175 |
// Sometimes PayPal script takes long time to load,
|
176 |
// so we additionally hide the standard order button here to avoid failed orders.
|
177 |
// Normally it is hidden later after the script load.
|
187 |
}
|
188 |
|
189 |
const currentPaymentMethod = getCurrentPaymentMethod();
|
190 |
+
const isPaypalButton = paypalButtonGatewayIds.includes(currentPaymentMethod);
|
191 |
const isCards = currentPaymentMethod === PaymentMethods.CARDS;
|
192 |
|
193 |
+
setVisible(ORDER_BUTTON_SELECTOR, !isPaypalButton && !isCards, true);
|
194 |
|
195 |
+
if (isPaypalButton) {
|
196 |
// stopped after the first rendering of the buttons, in onInit
|
197 |
buttonsSpinner.block();
|
198 |
} else {
|
modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js
CHANGED
@@ -26,6 +26,9 @@ class CheckoutActionHandler {
|
|
26 |
|
27 |
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
28 |
|
|
|
|
|
|
|
29 |
return fetch(this.config.ajax.create_order.endpoint, {
|
30 |
method: 'POST',
|
31 |
body: JSON.stringify({
|
@@ -34,8 +37,8 @@ class CheckoutActionHandler {
|
|
34 |
bn_code:bnCode,
|
35 |
context:this.config.context,
|
36 |
order_id:this.config.order_id,
|
37 |
-
payment_method:
|
38 |
-
funding_source:
|
39 |
form: formJsonObj,
|
40 |
createaccount: createaccount
|
41 |
})
|
26 |
|
27 |
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
28 |
|
29 |
+
const paymentMethod = getCurrentPaymentMethod();
|
30 |
+
const fundingSource = window.ppcpFundingSource;
|
31 |
+
|
32 |
return fetch(this.config.ajax.create_order.endpoint, {
|
33 |
method: 'POST',
|
34 |
body: JSON.stringify({
|
37 |
bn_code:bnCode,
|
38 |
context:this.config.context,
|
39 |
order_id:this.config.order_id,
|
40 |
+
payment_method: paymentMethod,
|
41 |
+
funding_source: fundingSource,
|
42 |
form: formJsonObj,
|
43 |
createaccount: createaccount
|
44 |
})
|
modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js
CHANGED
@@ -32,9 +32,7 @@ class CartBootstrap {
|
|
32 |
);
|
33 |
|
34 |
this.renderer.render(
|
35 |
-
|
36 |
-
this.gateway.hosted_fields.wrapper,
|
37 |
-
actionHandler.configuration(),
|
38 |
);
|
39 |
}
|
40 |
}
|
32 |
);
|
33 |
|
34 |
this.renderer.render(
|
35 |
+
actionHandler.configuration()
|
|
|
|
|
36 |
);
|
37 |
}
|
38 |
}
|
modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js
CHANGED
@@ -69,9 +69,7 @@ class CheckoutBootstap {
|
|
69 |
);
|
70 |
|
71 |
this.renderer.render(
|
72 |
-
|
73 |
-
this.gateway.hosted_fields.wrapper,
|
74 |
-
actionHandler.configuration(),
|
75 |
);
|
76 |
|
77 |
this.buttonChangeObserver.observe(
|
@@ -84,16 +82,27 @@ class CheckoutBootstap {
|
|
84 |
const currentPaymentMethod = getCurrentPaymentMethod();
|
85 |
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
86 |
const isCard = currentPaymentMethod === PaymentMethods.CARDS;
|
|
|
87 |
const isSavedCard = isCard && isSavedCardSelected();
|
88 |
-
const isNotOurGateway = !isPaypal && !isCard;
|
89 |
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
90 |
const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';
|
91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
setVisible(this.standardOrderButtonSelector, (isPaypal && isFreeTrial && hasVaultedPaypal) || isNotOurGateway || isSavedCard, true);
|
93 |
setVisible('.ppcp-vaulted-paypal-details', isPaypal);
|
94 |
setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));
|
95 |
setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial);
|
96 |
setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);
|
|
|
|
|
|
|
97 |
|
98 |
if (isPaypal && !isFreeTrial) {
|
99 |
this.messages.render();
|
69 |
);
|
70 |
|
71 |
this.renderer.render(
|
72 |
+
actionHandler.configuration()
|
|
|
|
|
73 |
);
|
74 |
|
75 |
this.buttonChangeObserver.observe(
|
82 |
const currentPaymentMethod = getCurrentPaymentMethod();
|
83 |
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
84 |
const isCard = currentPaymentMethod === PaymentMethods.CARDS;
|
85 |
+
const isSeparateButtonGateway = [PaymentMethods.CARD_BUTTON].includes(currentPaymentMethod);
|
86 |
const isSavedCard = isCard && isSavedCardSelected();
|
87 |
+
const isNotOurGateway = !isPaypal && !isCard && !isSeparateButtonGateway;
|
88 |
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
89 |
const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';
|
90 |
|
91 |
+
const paypalButtonWrappers = {
|
92 |
+
...Object.entries(PayPalCommerceGateway.separate_buttons)
|
93 |
+
.reduce((result, [k, data]) => {
|
94 |
+
return {...result, [data.id]: data.wrapper}
|
95 |
+
}, {}),
|
96 |
+
};
|
97 |
+
|
98 |
setVisible(this.standardOrderButtonSelector, (isPaypal && isFreeTrial && hasVaultedPaypal) || isNotOurGateway || isSavedCard, true);
|
99 |
setVisible('.ppcp-vaulted-paypal-details', isPaypal);
|
100 |
setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));
|
101 |
setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial);
|
102 |
setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);
|
103 |
+
for (const [gatewayId, wrapper] of Object.entries(paypalButtonWrappers)) {
|
104 |
+
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
105 |
+
}
|
106 |
|
107 |
if (isPaypal && !isFreeTrial) {
|
108 |
this.messages.render();
|
modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js
CHANGED
@@ -32,9 +32,13 @@ class MiniCartBootstap {
|
|
32 |
}
|
33 |
|
34 |
this.renderer.render(
|
35 |
-
this.
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
38 |
);
|
39 |
}
|
40 |
}
|
32 |
}
|
33 |
|
34 |
this.renderer.render(
|
35 |
+
this.actionHandler.configuration(),
|
36 |
+
{
|
37 |
+
button: {
|
38 |
+
wrapper: this.gateway.button.mini_cart_wrapper,
|
39 |
+
style: this.gateway.button.mini_cart_style,
|
40 |
+
},
|
41 |
+
}
|
42 |
);
|
43 |
}
|
44 |
}
|
modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js
CHANGED
@@ -85,9 +85,7 @@ class SingleProductBootstap {
|
|
85 |
);
|
86 |
|
87 |
this.renderer.render(
|
88 |
-
|
89 |
-
this.gateway.hosted_fields.wrapper,
|
90 |
-
actionHandler.configuration(),
|
91 |
);
|
92 |
}
|
93 |
}
|
85 |
);
|
86 |
|
87 |
this.renderer.render(
|
88 |
+
actionHandler.configuration()
|
|
|
|
|
89 |
);
|
90 |
}
|
91 |
}
|
modules/ppcp-button/resources/js/modules/Helper/CheckoutMethodState.js
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
export const PaymentMethods = {
|
2 |
PAYPAL: 'ppcp-gateway',
|
3 |
CARDS: 'ppcp-credit-card-gateway',
|
|
|
|
|
4 |
};
|
5 |
|
6 |
export const ORDER_BUTTON_SELECTOR = '#place_order';
|
1 |
export const PaymentMethods = {
|
2 |
PAYPAL: 'ppcp-gateway',
|
3 |
CARDS: 'ppcp-credit-card-gateway',
|
4 |
+
OXXO: 'ppcp-oxxo-gateway',
|
5 |
+
CARD_BUTTON: 'ppcp-card-button-gateway',
|
6 |
};
|
7 |
|
8 |
export const ORDER_BUTTON_SELECTOR = '#place_order';
|
modules/ppcp-button/resources/js/modules/Renderer/Renderer.js
CHANGED
@@ -1,33 +1,96 @@
|
|
|
|
|
|
1 |
class Renderer {
|
2 |
-
constructor(creditCardRenderer,
|
3 |
-
this.
|
4 |
this.creditCardRenderer = creditCardRenderer;
|
5 |
this.onSmartButtonClick = onSmartButtonClick;
|
6 |
this.onSmartButtonsInit = onSmartButtonsInit;
|
|
|
|
|
7 |
}
|
8 |
|
9 |
-
render(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
}
|
14 |
|
15 |
-
renderButtons(wrapper, contextConfig) {
|
16 |
-
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper) || 'undefined' === typeof paypal.Buttons ) {
|
17 |
return;
|
18 |
}
|
19 |
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
22 |
style,
|
23 |
...contextConfig,
|
24 |
onClick: this.onSmartButtonClick,
|
25 |
onInit: this.onSmartButtonsInit,
|
26 |
-
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
-
isAlreadyRendered(wrapper) {
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
hideButtons(element) {
|
1 |
+
import merge from "deepmerge";
|
2 |
+
|
3 |
class Renderer {
|
4 |
+
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
|
5 |
+
this.defaultSettings = defaultSettings;
|
6 |
this.creditCardRenderer = creditCardRenderer;
|
7 |
this.onSmartButtonClick = onSmartButtonClick;
|
8 |
this.onSmartButtonsInit = onSmartButtonsInit;
|
9 |
+
|
10 |
+
this.renderedSources = new Set();
|
11 |
}
|
12 |
|
13 |
+
render(contextConfig, settingsOverride = {}) {
|
14 |
+
const settings = merge(this.defaultSettings, settingsOverride);
|
15 |
+
|
16 |
+
const enabledSeparateGateways = Object.fromEntries(Object.entries(
|
17 |
+
settings.separate_buttons).filter(([s, data]) => document.querySelector(data.wrapper)
|
18 |
+
));
|
19 |
+
const hasEnabledSeparateGateways = Object.keys(enabledSeparateGateways).length !== 0;
|
20 |
+
|
21 |
+
if (!hasEnabledSeparateGateways) {
|
22 |
+
this.renderButtons(
|
23 |
+
settings.button.wrapper,
|
24 |
+
settings.button.style,
|
25 |
+
contextConfig,
|
26 |
+
hasEnabledSeparateGateways
|
27 |
+
);
|
28 |
+
} else {
|
29 |
+
// render each button separately
|
30 |
+
for (const fundingSource of paypal.getFundingSources().filter(s => !(s in enabledSeparateGateways))) {
|
31 |
+
let style = settings.button.style;
|
32 |
+
if (fundingSource !== 'paypal') {
|
33 |
+
style = {
|
34 |
+
shape: style.shape,
|
35 |
+
};
|
36 |
+
}
|
37 |
|
38 |
+
this.renderButtons(
|
39 |
+
settings.button.wrapper,
|
40 |
+
style,
|
41 |
+
contextConfig,
|
42 |
+
hasEnabledSeparateGateways,
|
43 |
+
fundingSource
|
44 |
+
);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfig);
|
49 |
+
|
50 |
+
for (const [fundingSource, data] of Object.entries(enabledSeparateGateways)) {
|
51 |
+
this.renderButtons(
|
52 |
+
data.wrapper,
|
53 |
+
data.style,
|
54 |
+
contextConfig,
|
55 |
+
hasEnabledSeparateGateways,
|
56 |
+
fundingSource
|
57 |
+
);
|
58 |
+
}
|
59 |
}
|
60 |
|
61 |
+
renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {
|
62 |
+
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) || 'undefined' === typeof paypal.Buttons ) {
|
63 |
return;
|
64 |
}
|
65 |
|
66 |
+
if (fundingSource) {
|
67 |
+
contextConfig.fundingSource = fundingSource;
|
68 |
+
}
|
69 |
+
|
70 |
+
const btn = paypal.Buttons({
|
71 |
style,
|
72 |
...contextConfig,
|
73 |
onClick: this.onSmartButtonClick,
|
74 |
onInit: this.onSmartButtonsInit,
|
75 |
+
});
|
76 |
+
if (!btn.isEligible()) {
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
|
80 |
+
btn.render(wrapper);
|
81 |
+
|
82 |
+
this.renderedSources.add(wrapper + fundingSource ?? '');
|
83 |
}
|
84 |
|
85 |
+
isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) {
|
86 |
+
// Simply check that has child nodes when we do not need to render buttons separately,
|
87 |
+
// this will reduce the risk of breaking with different themes/plugins
|
88 |
+
// and on the cart page (where we also do not need to render separately), which may fully reload this part of the page.
|
89 |
+
// Ideally we should also find a way to detect such full reloads and remove the corresponding keys from the set.
|
90 |
+
if (!hasEnabledSeparateGateways) {
|
91 |
+
return document.querySelector(wrapper).hasChildNodes();
|
92 |
+
}
|
93 |
+
return this.renderedSources.has(wrapper + fundingSource ?? '');
|
94 |
}
|
95 |
|
96 |
hideButtons(element) {
|
modules/ppcp-button/services.php
CHANGED
@@ -133,6 +133,7 @@ return array(
|
|
133 |
$settings,
|
134 |
$early_order_handler,
|
135 |
$registration_needed,
|
|
|
136 |
$logger
|
137 |
);
|
138 |
},
|
133 |
$settings,
|
134 |
$early_order_handler,
|
135 |
$registration_needed,
|
136 |
+
$container->get( 'wcgateway.settings.card_billing_data_mode' ),
|
137 |
$logger
|
138 |
);
|
139 |
},
|
modules/ppcp-button/src/Assets/SmartButton.php
CHANGED
@@ -28,7 +28,9 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|
28 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
29 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
30 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
|
|
31 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
|
|
32 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
33 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
34 |
|
@@ -421,16 +423,23 @@ class SmartButton implements SmartButtonInterface {
|
|
421 |
) {
|
422 |
add_action(
|
423 |
$this->single_product_renderer_hook(),
|
424 |
-
|
425 |
-
$
|
426 |
-
|
427 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
31
|
429 |
);
|
430 |
}
|
431 |
|
432 |
-
add_action( $this->pay_order_renderer_hook(), array( $this, 'button_renderer' ), 10 );
|
433 |
-
|
434 |
$not_enabled_on_minicart = $this->settings->has( 'button_mini_cart_enabled' ) &&
|
435 |
! $this->settings->get( 'button_mini_cart_enabled' );
|
436 |
if (
|
@@ -457,21 +466,38 @@ class SmartButton implements SmartButtonInterface {
|
|
457 |
);
|
458 |
}
|
459 |
|
460 |
-
|
461 |
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
469 |
}
|
|
|
470 |
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
475 |
|
476 |
return true;
|
477 |
}
|
@@ -524,32 +550,24 @@ class SmartButton implements SmartButtonInterface {
|
|
524 |
|
525 |
/**
|
526 |
* Renders the HTML for the buttons.
|
|
|
|
|
527 |
*/
|
528 |
-
public function button_renderer() {
|
529 |
|
530 |
if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) {
|
531 |
return;
|
532 |
}
|
533 |
|
534 |
-
$product = wc_get_product();
|
535 |
-
|
536 |
-
if (
|
537 |
-
! is_checkout() && is_a( $product, WC_Product::class )
|
538 |
-
&& ! $this->product_supports_payment( $product )
|
539 |
-
) {
|
540 |
-
|
541 |
-
return;
|
542 |
-
}
|
543 |
-
|
544 |
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
545 |
|
546 |
-
if ( ! isset( $available_gateways[
|
547 |
return;
|
548 |
}
|
549 |
|
550 |
// The wrapper is needed for the loading spinner,
|
551 |
// otherwise jQuery block() prevents buttons rendering.
|
552 |
-
echo '<div class="ppc-button-wrapper"><div id="ppc-button"></div></div>';
|
553 |
}
|
554 |
|
555 |
/**
|
@@ -810,7 +828,7 @@ class SmartButton implements SmartButtonInterface {
|
|
810 |
'bn_codes' => $this->bn_codes(),
|
811 |
'payer' => $this->payerData(),
|
812 |
'button' => array(
|
813 |
-
'wrapper' => '#ppc-button',
|
814 |
'mini_cart_wrapper' => '#ppc-button-minicart',
|
815 |
'cancel_wrapper' => '#ppcp-cancel',
|
816 |
'url' => $this->url(),
|
@@ -830,10 +848,19 @@ class SmartButton implements SmartButtonInterface {
|
|
830 |
'tagline' => $this->style_for_context( 'tagline', $this->context() ),
|
831 |
),
|
832 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
833 |
'hosted_fields' => array(
|
834 |
-
'wrapper'
|
835 |
-
'
|
836 |
-
'labels' => array(
|
837 |
'credit_card_number' => '',
|
838 |
'cvv' => '',
|
839 |
'mm_yy' => __( 'MM/YY', 'woocommerce-paypal-payments' ),
|
@@ -847,21 +874,36 @@ class SmartButton implements SmartButtonInterface {
|
|
847 |
),
|
848 |
'cardholder_name_required' => __( 'Cardholder\'s first and last name are required, please fill the checkout form required fields.', 'woocommerce-paypal-payments' ),
|
849 |
),
|
850 |
-
'valid_cards'
|
851 |
-
'contingency'
|
852 |
),
|
853 |
'messages' => $this->message_values(),
|
854 |
'labels' => array(
|
855 |
-
'error'
|
856 |
-
'generic'
|
857 |
'Something went wrong. Please try again or choose another payment source.',
|
858 |
'woocommerce-paypal-payments'
|
859 |
),
|
860 |
-
'
|
861 |
-
'
|
862 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
863 |
),
|
864 |
),
|
|
|
|
|
|
|
|
|
865 |
),
|
866 |
'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
|
867 |
'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ),
|
@@ -870,10 +912,10 @@ class SmartButton implements SmartButtonInterface {
|
|
870 |
);
|
871 |
|
872 |
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
|
873 |
-
|
874 |
}
|
875 |
if ( $this->style_for_context( 'layout', $this->context() ) !== 'horizontal' ) {
|
876 |
-
|
877 |
}
|
878 |
|
879 |
$this->request_data->dequeue_nonce_fix();
|
@@ -901,7 +943,9 @@ class SmartButton implements SmartButtonInterface {
|
|
901 |
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting was not found.
|
902 |
*/
|
903 |
private function url(): string {
|
904 |
-
$intent
|
|
|
|
|
905 |
|
906 |
$params = array(
|
907 |
'client-id' => $this->client_id,
|
@@ -910,9 +954,7 @@ class SmartButton implements SmartButtonInterface {
|
|
910 |
'components' => implode( ',', $this->components() ),
|
911 |
'vault' => $this->can_save_vault_token() ? 'true' : 'false',
|
912 |
'commit' => is_checkout() ? 'true' : 'false',
|
913 |
-
'intent' =>
|
914 |
-
? 'authorize'
|
915 |
-
: $intent,
|
916 |
);
|
917 |
if (
|
918 |
$this->environment->current_environment_is( Environment::SANDBOX )
|
@@ -933,7 +975,10 @@ class SmartButton implements SmartButtonInterface {
|
|
933 |
|
934 |
$is_dcc_enabled = $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' );
|
935 |
|
936 |
-
|
|
|
|
|
|
|
937 |
$key = array_search( 'card', $disable_funding, true );
|
938 |
if ( false !== $key ) {
|
939 |
unset( $disable_funding[ $key ] );
|
@@ -942,7 +987,7 @@ class SmartButton implements SmartButtonInterface {
|
|
942 |
|
943 |
if ( $this->is_free_trial_cart() ) {
|
944 |
$all_sources = array_keys( $this->all_funding_sources );
|
945 |
-
if ( $is_dcc_enabled ) {
|
946 |
$all_sources = array_diff( $all_sources, array( 'card' ) );
|
947 |
}
|
948 |
$disable_funding = $all_sources;
|
@@ -1018,6 +1063,7 @@ class SmartButton implements SmartButtonInterface {
|
|
1018 |
|
1019 |
if ( $this->load_button_component() ) {
|
1020 |
$components[] = 'buttons';
|
|
|
1021 |
}
|
1022 |
if (
|
1023 |
$this->messages_apply->for_country()
|
@@ -1049,9 +1095,10 @@ class SmartButton implements SmartButtonInterface {
|
|
1049 |
}
|
1050 |
if (
|
1051 |
$this->context() === 'product'
|
1052 |
-
&&
|
1053 |
-
|
1054 |
-
|
|
|
1055 |
) {
|
1056 |
$load_buttons = true;
|
1057 |
}
|
@@ -1061,14 +1108,17 @@ class SmartButton implements SmartButtonInterface {
|
|
1061 |
) {
|
1062 |
$load_buttons = true;
|
1063 |
}
|
|
|
1064 |
if (
|
1065 |
$this->context() === 'cart'
|
1066 |
-
&&
|
1067 |
-
|
1068 |
-
|
|
|
1069 |
) {
|
1070 |
$load_buttons = true;
|
1071 |
}
|
|
|
1072 |
if ( $this->context() === 'pay-now' ) {
|
1073 |
$load_buttons = true;
|
1074 |
}
|
@@ -1112,6 +1162,9 @@ class SmartButton implements SmartButtonInterface {
|
|
1112 |
if ( $source && $source->card() ) {
|
1113 |
return false; // Ignore for DCC.
|
1114 |
}
|
|
|
|
|
|
|
1115 |
return true;
|
1116 |
}
|
1117 |
|
28 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
29 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
30 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
31 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
32 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
33 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
34 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
35 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
36 |
|
423 |
) {
|
424 |
add_action(
|
425 |
$this->single_product_renderer_hook(),
|
426 |
+
function () {
|
427 |
+
$product = wc_get_product();
|
428 |
+
|
429 |
+
if (
|
430 |
+
is_a( $product, WC_Product::class )
|
431 |
+
&& ! $this->product_supports_payment( $product )
|
432 |
+
) {
|
433 |
+
|
434 |
+
return;
|
435 |
+
}
|
436 |
+
|
437 |
+
$this->button_renderer( PayPalGateway::ID );
|
438 |
+
},
|
439 |
31
|
440 |
);
|
441 |
}
|
442 |
|
|
|
|
|
443 |
$not_enabled_on_minicart = $this->settings->has( 'button_mini_cart_enabled' ) &&
|
444 |
! $this->settings->get( 'button_mini_cart_enabled' );
|
445 |
if (
|
466 |
);
|
467 |
}
|
468 |
|
469 |
+
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
470 |
|
471 |
+
if ( isset( $available_gateways['ppcp-gateway'] ) ) {
|
472 |
+
add_action(
|
473 |
+
$this->pay_order_renderer_hook(),
|
474 |
+
function (): void {
|
475 |
+
$this->button_renderer( PayPalGateway::ID );
|
476 |
+
$this->button_renderer( CardButtonGateway::ID );
|
477 |
+
}
|
478 |
+
);
|
479 |
+
add_action(
|
480 |
+
$this->checkout_button_renderer_hook(),
|
481 |
+
function (): void {
|
482 |
+
$this->button_renderer( PayPalGateway::ID );
|
483 |
+
$this->button_renderer( CardButtonGateway::ID );
|
484 |
}
|
485 |
+
);
|
486 |
|
487 |
+
$not_enabled_on_cart = $this->settings->has( 'button_cart_enabled' ) &&
|
488 |
+
! $this->settings->get( 'button_cart_enabled' );
|
489 |
+
add_action(
|
490 |
+
$this->proceed_to_checkout_button_renderer_hook(),
|
491 |
+
function() use ( $not_enabled_on_cart ) {
|
492 |
+
if ( ! is_cart() || $not_enabled_on_cart || $this->is_free_trial_cart() || $this->is_cart_price_total_zero() ) {
|
493 |
+
return;
|
494 |
+
}
|
495 |
+
|
496 |
+
$this->button_renderer( PayPalGateway::ID );
|
497 |
+
},
|
498 |
+
20
|
499 |
+
);
|
500 |
+
}
|
501 |
|
502 |
return true;
|
503 |
}
|
550 |
|
551 |
/**
|
552 |
* Renders the HTML for the buttons.
|
553 |
+
*
|
554 |
+
* @param string $gateway_id The gateway ID, like 'ppcp-gateway'.
|
555 |
*/
|
556 |
+
public function button_renderer( string $gateway_id ) {
|
557 |
|
558 |
if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) {
|
559 |
return;
|
560 |
}
|
561 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
562 |
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
563 |
|
564 |
+
if ( ! isset( $available_gateways[ $gateway_id ] ) ) {
|
565 |
return;
|
566 |
}
|
567 |
|
568 |
// The wrapper is needed for the loading spinner,
|
569 |
// otherwise jQuery block() prevents buttons rendering.
|
570 |
+
echo '<div class="ppc-button-wrapper"><div id="ppc-button-' . esc_attr( $gateway_id ) . '"></div></div>';
|
571 |
}
|
572 |
|
573 |
/**
|
828 |
'bn_codes' => $this->bn_codes(),
|
829 |
'payer' => $this->payerData(),
|
830 |
'button' => array(
|
831 |
+
'wrapper' => '#ppc-button-' . PayPalGateway::ID,
|
832 |
'mini_cart_wrapper' => '#ppc-button-minicart',
|
833 |
'cancel_wrapper' => '#ppcp-cancel',
|
834 |
'url' => $this->url(),
|
848 |
'tagline' => $this->style_for_context( 'tagline', $this->context() ),
|
849 |
),
|
850 |
),
|
851 |
+
'separate_buttons' => array(
|
852 |
+
'card' => array(
|
853 |
+
'id' => CardButtonGateway::ID,
|
854 |
+
'wrapper' => '#ppc-button-' . CardButtonGateway::ID,
|
855 |
+
'style' => array(
|
856 |
+
'shape' => $this->style_for_context( 'shape', $this->context() ),
|
857 |
+
// TODO: color black, white from the gateway settings.
|
858 |
+
),
|
859 |
+
),
|
860 |
+
),
|
861 |
'hosted_fields' => array(
|
862 |
+
'wrapper' => '#ppcp-hosted-fields',
|
863 |
+
'labels' => array(
|
|
|
864 |
'credit_card_number' => '',
|
865 |
'cvv' => '',
|
866 |
'mm_yy' => __( 'MM/YY', 'woocommerce-paypal-payments' ),
|
874 |
),
|
875 |
'cardholder_name_required' => __( 'Cardholder\'s first and last name are required, please fill the checkout form required fields.', 'woocommerce-paypal-payments' ),
|
876 |
),
|
877 |
+
'valid_cards' => $this->dcc_applies->valid_cards(),
|
878 |
+
'contingency' => $this->get_3ds_contingency(),
|
879 |
),
|
880 |
'messages' => $this->message_values(),
|
881 |
'labels' => array(
|
882 |
+
'error' => array(
|
883 |
+
'generic' => __(
|
884 |
'Something went wrong. Please try again or choose another payment source.',
|
885 |
'woocommerce-paypal-payments'
|
886 |
),
|
887 |
+
'required' => array(
|
888 |
+
'generic' => __(
|
889 |
+
'Required form fields are not filled.',
|
890 |
+
'woocommerce-paypal-payments'
|
891 |
+
),
|
892 |
+
// phpcs:ignore WordPress.WP.I18n
|
893 |
+
'field' => __( '%s is a required field.', 'woocommerce' ),
|
894 |
+
'elements' => array( // Map <form element name> => text for error messages.
|
895 |
+
'terms' => __(
|
896 |
+
'Please read and accept the terms and conditions to proceed with your order.',
|
897 |
+
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
898 |
+
'woocommerce'
|
899 |
+
),
|
900 |
+
),
|
901 |
),
|
902 |
),
|
903 |
+
// phpcs:ignore WordPress.WP.I18n
|
904 |
+
'billing_field' => _x( 'Billing %s', 'checkout-validation', 'woocommerce' ),
|
905 |
+
// phpcs:ignore WordPress.WP.I18n
|
906 |
+
'shipping_field' => _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ),
|
907 |
),
|
908 |
'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
|
909 |
'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ),
|
912 |
);
|
913 |
|
914 |
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
|
915 |
+
$localize['button']['mini_cart_style']['tagline'] = false;
|
916 |
}
|
917 |
if ( $this->style_for_context( 'layout', $this->context() ) !== 'horizontal' ) {
|
918 |
+
$localize['button']['style']['tagline'] = false;
|
919 |
}
|
920 |
|
921 |
$this->request_data->dequeue_nonce_fix();
|
943 |
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting was not found.
|
944 |
*/
|
945 |
private function url(): string {
|
946 |
+
$intent = ( $this->settings->has( 'intent' ) ) ? $this->settings->get( 'intent' ) : 'capture';
|
947 |
+
$product_intent = $this->subscription_helper->current_product_is_subscription() ? 'authorize' : $intent;
|
948 |
+
$other_context_intent = $this->subscription_helper->cart_contains_subscription() ? 'authorize' : $intent;
|
949 |
|
950 |
$params = array(
|
951 |
'client-id' => $this->client_id,
|
954 |
'components' => implode( ',', $this->components() ),
|
955 |
'vault' => $this->can_save_vault_token() ? 'true' : 'false',
|
956 |
'commit' => is_checkout() ? 'true' : 'false',
|
957 |
+
'intent' => $this->context() === 'product' ? $product_intent : $other_context_intent,
|
|
|
|
|
958 |
);
|
959 |
if (
|
960 |
$this->environment->current_environment_is( Environment::SANDBOX )
|
975 |
|
976 |
$is_dcc_enabled = $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' );
|
977 |
|
978 |
+
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
979 |
+
$is_separate_card_enabled = isset( $available_gateways[ CardButtonGateway::ID ] );
|
980 |
+
|
981 |
+
if ( is_checkout() && ( $is_dcc_enabled || $is_separate_card_enabled ) ) {
|
982 |
$key = array_search( 'card', $disable_funding, true );
|
983 |
if ( false !== $key ) {
|
984 |
unset( $disable_funding[ $key ] );
|
987 |
|
988 |
if ( $this->is_free_trial_cart() ) {
|
989 |
$all_sources = array_keys( $this->all_funding_sources );
|
990 |
+
if ( $is_dcc_enabled || $is_separate_card_enabled ) {
|
991 |
$all_sources = array_diff( $all_sources, array( 'card' ) );
|
992 |
}
|
993 |
$disable_funding = $all_sources;
|
1063 |
|
1064 |
if ( $this->load_button_component() ) {
|
1065 |
$components[] = 'buttons';
|
1066 |
+
$components[] = 'funding-eligibility';
|
1067 |
}
|
1068 |
if (
|
1069 |
$this->messages_apply->for_country()
|
1095 |
}
|
1096 |
if (
|
1097 |
$this->context() === 'product'
|
1098 |
+
&& (
|
1099 |
+
( $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ) ) ||
|
1100 |
+
( $this->settings->has( 'message_product_enabled' ) && $this->settings->get( 'message_product_enabled' ) )
|
1101 |
+
)
|
1102 |
) {
|
1103 |
$load_buttons = true;
|
1104 |
}
|
1108 |
) {
|
1109 |
$load_buttons = true;
|
1110 |
}
|
1111 |
+
|
1112 |
if (
|
1113 |
$this->context() === 'cart'
|
1114 |
+
&& (
|
1115 |
+
( $this->settings->has( 'button_cart_enabled' ) && $this->settings->get( 'button_cart_enabled' ) ) ||
|
1116 |
+
( $this->settings->has( 'message_cart_enabled' ) && $this->settings->get( 'message_cart_enabled' ) )
|
1117 |
+
)
|
1118 |
) {
|
1119 |
$load_buttons = true;
|
1120 |
}
|
1121 |
+
|
1122 |
if ( $this->context() === 'pay-now' ) {
|
1123 |
$load_buttons = true;
|
1124 |
}
|
1162 |
if ( $source && $source->card() ) {
|
1163 |
return false; // Ignore for DCC.
|
1164 |
}
|
1165 |
+
if ( 'card' === $this->session_handler->funding_source() ) {
|
1166 |
+
return false; // Ignore for card buttons.
|
1167 |
+
}
|
1168 |
return true;
|
1169 |
}
|
1170 |
|
modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php
CHANGED
@@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
|
|
14 |
use stdClass;
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
|
|
|
17 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
18 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
19 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
@@ -27,7 +28,9 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
|
27 |
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
28 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
29 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
|
|
30 |
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
|
|
31 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
32 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
33 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
@@ -118,6 +121,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
118 |
*/
|
119 |
private $registration_needed;
|
120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
/**
|
122 |
* The logger.
|
123 |
*
|
@@ -137,6 +147,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
137 |
* @param Settings $settings The Settings object.
|
138 |
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
139 |
* @param bool $registration_needed Whether a new user must be registered during checkout.
|
|
|
140 |
* @param LoggerInterface $logger The logger.
|
141 |
*/
|
142 |
public function __construct(
|
@@ -149,6 +160,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
149 |
Settings $settings,
|
150 |
EarlyOrderHandler $early_order_handler,
|
151 |
bool $registration_needed,
|
|
|
152 |
LoggerInterface $logger
|
153 |
) {
|
154 |
|
@@ -161,6 +173,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
161 |
$this->settings = $settings;
|
162 |
$this->early_order_handler = $early_order_handler;
|
163 |
$this->registration_needed = $registration_needed;
|
|
|
164 |
$this->logger = $logger;
|
165 |
}
|
166 |
|
@@ -204,7 +217,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
204 |
|
205 |
// The cart does not have any info about payment method, so we must handle free trial here.
|
206 |
if ( (
|
207 |
-
CreditCardGateway::ID
|
208 |
|| ( PayPalGateway::ID === $payment_method && 'card' === $funding_source )
|
209 |
)
|
210 |
&& $this->is_free_trial_cart()
|
@@ -331,18 +344,40 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
331 |
private function create_paypal_order( \WC_Order $wc_order = null ): Order {
|
332 |
assert( $this->purchase_unit instanceof PurchaseUnit );
|
333 |
|
|
|
|
|
|
|
334 |
$shipping_preference = $this->shipping_preference_factory->from_state(
|
335 |
$this->purchase_unit,
|
336 |
$this->parsed_request_data['context'],
|
337 |
WC()->cart,
|
338 |
-
$
|
339 |
);
|
340 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
try {
|
342 |
return $this->api_endpoint->create(
|
343 |
array( $this->purchase_unit ),
|
344 |
$shipping_preference,
|
345 |
-
$
|
346 |
null,
|
347 |
$this->payment_method()
|
348 |
);
|
@@ -364,7 +399,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|
364 |
return $this->api_endpoint->create(
|
365 |
array( $this->purchase_unit ),
|
366 |
$shipping_preference,
|
367 |
-
$
|
368 |
null,
|
369 |
$this->payment_method()
|
370 |
);
|
14 |
use stdClass;
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
|
17 |
+
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
18 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
19 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
20 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
28 |
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
29 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
30 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
31 |
+
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
32 |
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
33 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
34 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
35 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
36 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
121 |
*/
|
122 |
private $registration_needed;
|
123 |
|
124 |
+
/**
|
125 |
+
* The value of card_billing_data_mode from the settings.
|
126 |
+
*
|
127 |
+
* @var string
|
128 |
+
*/
|
129 |
+
protected $card_billing_data_mode;
|
130 |
+
|
131 |
/**
|
132 |
* The logger.
|
133 |
*
|
147 |
* @param Settings $settings The Settings object.
|
148 |
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
149 |
* @param bool $registration_needed Whether a new user must be registered during checkout.
|
150 |
+
* @param string $card_billing_data_mode The value of card_billing_data_mode from the settings.
|
151 |
* @param LoggerInterface $logger The logger.
|
152 |
*/
|
153 |
public function __construct(
|
160 |
Settings $settings,
|
161 |
EarlyOrderHandler $early_order_handler,
|
162 |
bool $registration_needed,
|
163 |
+
string $card_billing_data_mode,
|
164 |
LoggerInterface $logger
|
165 |
) {
|
166 |
|
173 |
$this->settings = $settings;
|
174 |
$this->early_order_handler = $early_order_handler;
|
175 |
$this->registration_needed = $registration_needed;
|
176 |
+
$this->card_billing_data_mode = $card_billing_data_mode;
|
177 |
$this->logger = $logger;
|
178 |
}
|
179 |
|
217 |
|
218 |
// The cart does not have any info about payment method, so we must handle free trial here.
|
219 |
if ( (
|
220 |
+
in_array( $payment_method, array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
221 |
|| ( PayPalGateway::ID === $payment_method && 'card' === $funding_source )
|
222 |
)
|
223 |
&& $this->is_free_trial_cart()
|
344 |
private function create_paypal_order( \WC_Order $wc_order = null ): Order {
|
345 |
assert( $this->purchase_unit instanceof PurchaseUnit );
|
346 |
|
347 |
+
$funding_source = $this->parsed_request_data['funding_source'] ?? '';
|
348 |
+
$payer = $this->payer( $this->parsed_request_data, $wc_order );
|
349 |
+
|
350 |
$shipping_preference = $this->shipping_preference_factory->from_state(
|
351 |
$this->purchase_unit,
|
352 |
$this->parsed_request_data['context'],
|
353 |
WC()->cart,
|
354 |
+
$funding_source
|
355 |
);
|
356 |
|
357 |
+
if ( 'card' === $funding_source ) {
|
358 |
+
if ( CardBillingMode::MINIMAL_INPUT === $this->card_billing_data_mode ) {
|
359 |
+
if ( ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS === $shipping_preference ) {
|
360 |
+
if ( $payer ) {
|
361 |
+
$payer->set_address( null );
|
362 |
+
}
|
363 |
+
}
|
364 |
+
if ( ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING === $shipping_preference ) {
|
365 |
+
if ( $payer ) {
|
366 |
+
$payer->set_name( null );
|
367 |
+
}
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
+
if ( CardBillingMode::NO_WC === $this->card_billing_data_mode ) {
|
372 |
+
$payer = null;
|
373 |
+
}
|
374 |
+
}
|
375 |
+
|
376 |
try {
|
377 |
return $this->api_endpoint->create(
|
378 |
array( $this->purchase_unit ),
|
379 |
$shipping_preference,
|
380 |
+
$payer,
|
381 |
null,
|
382 |
$this->payment_method()
|
383 |
);
|
399 |
return $this->api_endpoint->create(
|
400 |
array( $this->purchase_unit ),
|
401 |
$shipping_preference,
|
402 |
+
$payer,
|
403 |
null,
|
404 |
$this->payment_method()
|
405 |
);
|
modules/ppcp-session/src/Cancellation/CancelController.php
CHANGED
@@ -70,6 +70,10 @@ class CancelController {
|
|
70 |
return; // Ignore for DCC.
|
71 |
}
|
72 |
|
|
|
|
|
|
|
|
|
73 |
$url = add_query_arg( array( $param_name => wp_create_nonce( $nonce ) ), wc_get_checkout_url() );
|
74 |
add_action(
|
75 |
'woocommerce_review_order_after_submit',
|
70 |
return; // Ignore for DCC.
|
71 |
}
|
72 |
|
73 |
+
if ( 'card' === $this->session_handler->funding_source() ) {
|
74 |
+
return; // Ignore for card buttons.
|
75 |
+
}
|
76 |
+
|
77 |
$url = add_query_arg( array( $param_name => wp_create_nonce( $nonce ) ), wc_get_checkout_url() );
|
78 |
add_action(
|
79 |
'woocommerce_review_order_after_submit',
|
modules/ppcp-subscription/services.php
CHANGED
@@ -24,6 +24,8 @@ return array(
|
|
24 |
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
25 |
$payer_factory = $container->get( 'api.factory.payer' );
|
26 |
$environment = $container->get( 'onboarding.environment' );
|
|
|
|
|
27 |
return new RenewalHandler(
|
28 |
$logger,
|
29 |
$repository,
|
@@ -31,7 +33,9 @@ return array(
|
|
31 |
$purchase_unit_factory,
|
32 |
$container->get( 'api.factory.shipping-preference' ),
|
33 |
$payer_factory,
|
34 |
-
$environment
|
|
|
|
|
35 |
);
|
36 |
},
|
37 |
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
|
24 |
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
25 |
$payer_factory = $container->get( 'api.factory.payer' );
|
26 |
$environment = $container->get( 'onboarding.environment' );
|
27 |
+
$settings = $container->get( 'wcgateway.settings' );
|
28 |
+
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
|
29 |
return new RenewalHandler(
|
30 |
$logger,
|
31 |
$repository,
|
33 |
$purchase_unit_factory,
|
34 |
$container->get( 'api.factory.shipping-preference' ),
|
35 |
$payer_factory,
|
36 |
+
$environment,
|
37 |
+
$settings,
|
38 |
+
$authorized_payments_processor
|
39 |
);
|
40 |
},
|
41 |
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
|
modules/ppcp-subscription/src/RenewalHandler.php
CHANGED
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
|
10 |
namespace WooCommerce\PayPalCommerce\Subscription;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
|
|
13 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
14 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
@@ -17,10 +18,12 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
|
17 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
18 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
19 |
use Psr\Log\LoggerInterface;
|
|
|
20 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
21 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
23 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
|
|
24 |
|
25 |
/**
|
26 |
* Class RenewalHandler
|
@@ -80,16 +83,32 @@ class RenewalHandler {
|
|
80 |
*/
|
81 |
protected $environment;
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
/**
|
84 |
* RenewalHandler constructor.
|
85 |
*
|
86 |
-
* @param LoggerInterface
|
87 |
-
* @param PaymentTokenRepository
|
88 |
-
* @param OrderEndpoint
|
89 |
-
* @param PurchaseUnitFactory
|
90 |
-
* @param ShippingPreferenceFactory
|
91 |
-
* @param PayerFactory
|
92 |
-
* @param Environment
|
|
|
|
|
93 |
*/
|
94 |
public function __construct(
|
95 |
LoggerInterface $logger,
|
@@ -98,16 +117,20 @@ class RenewalHandler {
|
|
98 |
PurchaseUnitFactory $purchase_unit_factory,
|
99 |
ShippingPreferenceFactory $shipping_preference_factory,
|
100 |
PayerFactory $payer_factory,
|
101 |
-
Environment $environment
|
|
|
|
|
102 |
) {
|
103 |
|
104 |
-
$this->logger
|
105 |
-
$this->repository
|
106 |
-
$this->order_endpoint
|
107 |
-
$this->purchase_unit_factory
|
108 |
-
$this->shipping_preference_factory
|
109 |
-
$this->payer_factory
|
110 |
-
$this->environment
|
|
|
|
|
111 |
}
|
112 |
|
113 |
/**
|
@@ -179,6 +202,14 @@ class RenewalHandler {
|
|
179 |
}
|
180 |
|
181 |
$this->handle_new_order_status( $order, $wc_order );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
}
|
183 |
|
184 |
/**
|
@@ -229,4 +260,39 @@ class RenewalHandler {
|
|
229 |
|
230 |
return current( $tokens );
|
231 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
}
|
10 |
namespace WooCommerce\PayPalCommerce\Subscription;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
13 |
+
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
14 |
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
18 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
19 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
20 |
use Psr\Log\LoggerInterface;
|
21 |
+
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
23 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
24 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
25 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
26 |
+
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
27 |
|
28 |
/**
|
29 |
* Class RenewalHandler
|
83 |
*/
|
84 |
protected $environment;
|
85 |
|
86 |
+
/**
|
87 |
+
* The settings
|
88 |
+
*
|
89 |
+
* @var Settings
|
90 |
+
*/
|
91 |
+
protected $settings;
|
92 |
+
|
93 |
+
/**
|
94 |
+
* The processor for authorized payments.
|
95 |
+
*
|
96 |
+
* @var AuthorizedPaymentsProcessor
|
97 |
+
*/
|
98 |
+
protected $authorized_payments_processor;
|
99 |
+
|
100 |
/**
|
101 |
* RenewalHandler constructor.
|
102 |
*
|
103 |
+
* @param LoggerInterface $logger The logger.
|
104 |
+
* @param PaymentTokenRepository $repository The payment token repository.
|
105 |
+
* @param OrderEndpoint $order_endpoint The order endpoint.
|
106 |
+
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
107 |
+
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
108 |
+
* @param PayerFactory $payer_factory The payer factory.
|
109 |
+
* @param Environment $environment The environment.
|
110 |
+
* @param Settings $settings The Settings.
|
111 |
+
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
|
112 |
*/
|
113 |
public function __construct(
|
114 |
LoggerInterface $logger,
|
117 |
PurchaseUnitFactory $purchase_unit_factory,
|
118 |
ShippingPreferenceFactory $shipping_preference_factory,
|
119 |
PayerFactory $payer_factory,
|
120 |
+
Environment $environment,
|
121 |
+
Settings $settings,
|
122 |
+
AuthorizedPaymentsProcessor $authorized_payments_processor
|
123 |
) {
|
124 |
|
125 |
+
$this->logger = $logger;
|
126 |
+
$this->repository = $repository;
|
127 |
+
$this->order_endpoint = $order_endpoint;
|
128 |
+
$this->purchase_unit_factory = $purchase_unit_factory;
|
129 |
+
$this->shipping_preference_factory = $shipping_preference_factory;
|
130 |
+
$this->payer_factory = $payer_factory;
|
131 |
+
$this->environment = $environment;
|
132 |
+
$this->settings = $settings;
|
133 |
+
$this->authorized_payments_processor = $authorized_payments_processor;
|
134 |
}
|
135 |
|
136 |
/**
|
202 |
}
|
203 |
|
204 |
$this->handle_new_order_status( $order, $wc_order );
|
205 |
+
|
206 |
+
if ( $this->capture_authorized_downloads( $order ) && AuthorizedPaymentsProcessor::SUCCESSFUL === $this->authorized_payments_processor->process( $wc_order ) ) {
|
207 |
+
$wc_order->add_order_note(
|
208 |
+
__( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
|
209 |
+
);
|
210 |
+
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
|
211 |
+
$wc_order->update_status( 'completed' );
|
212 |
+
}
|
213 |
}
|
214 |
|
215 |
/**
|
260 |
|
261 |
return current( $tokens );
|
262 |
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Returns if an order should be captured immediately.
|
266 |
+
*
|
267 |
+
* @param Order $order The PayPal order.
|
268 |
+
*
|
269 |
+
* @return bool
|
270 |
+
* @throws NotFoundException When a setting was not found.
|
271 |
+
*/
|
272 |
+
protected function capture_authorized_downloads( Order $order ): bool {
|
273 |
+
if (
|
274 |
+
! $this->settings->has( 'capture_for_virtual_only' )
|
275 |
+
|| ! $this->settings->get( 'capture_for_virtual_only' )
|
276 |
+
) {
|
277 |
+
return false;
|
278 |
+
}
|
279 |
+
|
280 |
+
if ( $order->intent() === 'CAPTURE' ) {
|
281 |
+
return false;
|
282 |
+
}
|
283 |
+
|
284 |
+
/**
|
285 |
+
* We fetch the order again as the authorize endpoint (from which the Order derives)
|
286 |
+
* drops the item's category, making it impossible to check, if purchase units contain
|
287 |
+
* physical goods.
|
288 |
+
*/
|
289 |
+
$order = $this->order_endpoint->order( $order->id() );
|
290 |
+
|
291 |
+
foreach ( $order->purchase_units() as $unit ) {
|
292 |
+
if ( $unit->contains_physical_goods() ) {
|
293 |
+
return false;
|
294 |
+
}
|
295 |
+
}
|
296 |
+
return true;
|
297 |
+
}
|
298 |
}
|
modules/ppcp-vaulting/src/PaymentTokenChecker.php
CHANGED
@@ -16,6 +16,7 @@ use WC_Order;
|
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
17 |
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
18 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
|
|
19 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
20 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
21 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
@@ -118,7 +119,7 @@ class PaymentTokenChecker {
|
|
118 |
if ( $tokens ) {
|
119 |
try {
|
120 |
if ( $this->is_free_trial_order( $wc_order ) ) {
|
121 |
-
if (
|
122 |
|| ( PayPalGateway::ID === $wc_order->get_payment_method() && 'card' === $wc_order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
123 |
) {
|
124 |
$order = $this->order_repository->for_wc_order( $wc_order );
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
17 |
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
18 |
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
19 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
20 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
21 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
119 |
if ( $tokens ) {
|
120 |
try {
|
121 |
if ( $this->is_free_trial_order( $wc_order ) ) {
|
122 |
+
if ( in_array( $wc_order->get_payment_method(), array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
123 |
|| ( PayPalGateway::ID === $wc_order->get_payment_method() && 'card' === $wc_order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
124 |
) {
|
125 |
$order = $this->order_repository->for_wc_order( $wc_order );
|
modules/ppcp-wc-gateway/assets/images/oxxo.svg
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<svg width="42px" height="20px" viewBox="0 0 42 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3 |
+
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
4 |
+
<title>logo OXXO</title>
|
5 |
+
<desc>Created with Sketch.</desc>
|
6 |
+
<defs/>
|
7 |
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
8 |
+
<g id="SPB_&_AltPay_NewAssets" transform="translate(-100.000000, -159.000000)">
|
9 |
+
<g id="logo-OXXO" transform="translate(100.000000, 159.000000)">
|
10 |
+
<path d="M0.142456528,1.48437917 C0.142456528,0.77043992 0.728159303,0.186243119 1.44446761,0.186243119 L40.6503931,0.186243119 C41.3667014,0.186243119 41.9524042,0.77043992 41.9524042,1.48437917 L41.9524042,18.1011373 C41.9524042,18.8150765 41.3667014,19.3990362 40.6503931,19.3990362 L1.44446761,19.3990362 C0.728159303,19.3990362 0.142456528,18.8150765 0.142456528,18.1011373 L0.142456528,1.48437917 Z" id="Fill-2" fill="#EDA42D"/>
|
11 |
+
<polygon id="Fill-4" fill="#FEFEFE" points="0.142480318 17.5124813 41.952428 17.5124813 41.952428 2.07265562 0.142480318 2.07265562"/>
|
12 |
+
<path d="M35.5752619,6.08262231 C33.662331,6.08262231 32.1029152,7.63763417 32.1029152,9.54463469 C32.1029152,11.4511608 33.662331,13.0064099 35.5752619,13.0064099 C37.4877171,13.0064099 39.0471329,11.4511608 39.0471329,9.54463469 C39.0471329,7.63763417 37.4877171,6.08262231 35.5752619,6.08262231" id="Fill-6" fill="#EC1D24"/>
|
13 |
+
<path d="M6.95585459,6.08262231 C5.04268574,6.08262231 3.48326994,7.63763417 3.48326994,9.54463469 C3.48326994,11.4511608 5.04268574,13.0064099 6.95585459,13.0064099 C8.86807185,13.0064099 10.4277255,11.4511608 10.4277255,9.54463469 C10.4277255,7.63763417 8.86807185,6.08262231 6.95585459,6.08262231" id="Fill-7" fill="#EC1D24"/>
|
14 |
+
<path d="M35.5752619,15.0141446 C32.5537303,15.0141446 30.0893537,12.5573397 30.0893537,9.54480072 C30.0893537,6.53155015 32.5537303,4.07521964 35.5752619,4.07521964 C38.5970315,4.07521964 41.0609322,6.53155015 41.0609322,9.54480072 C41.0609322,12.5573397 38.5970315,15.0141446 35.5752619,15.0141446 Z M12.4411918,9.54480072 C12.4411918,12.5573397 9.97729109,15.0141446 6.95575943,15.0141446 C3.93351408,15.0141446 1.46985124,12.5573397 1.46985124,9.54480072 C1.46985124,6.53155015 3.93351408,4.07521964 6.95575943,4.07521964 C9.97729109,4.07521964 12.4411918,6.53155015 12.4411918,9.54480072 Z M35.3028697,3.03585692 C32.0884035,2.9620911 30.5772808,5.01709763 28.384107,7.55170056 L26.3151155,9.94232969 L29.591435,13.8526295 C30.3719756,15.0542296 28.8822636,16.2465793 27.9580332,15.1472077 L24.9288888,11.5447794 L21.9772989,14.9562705 C21.0373673,16.0421223 19.5645461,14.8288999 20.3617394,13.6386849 L23.5659761,9.92382894 L21.4667717,7.42693908 L22.8173138,5.75949957 L24.9522028,8.31639828 L26.7923372,6.18217058 C27.6953948,5.13569219 28.6162946,3.74884741 29.8098246,3.03585692 L0.142385159,3.03585692 L0.142385159,16.549707 L7.07875226,16.549707 C10.2934564,16.549707 11.7529554,14.6332189 13.8866549,12.0492806 L15.8999784,9.61097649 L12.5334959,5.77752594 C11.726073,4.59418943 13.1874752,3.36815887 14.1371606,4.44594623 L17.2483795,7.9779294 L20.1209875,4.49931378 C21.0354641,3.39164059 22.5356435,4.57118208 21.7662842,5.77942346 L18.6486421,9.56757088 L20.8051797,12.0153626 L19.4463112,13.6197098 L17.2997653,11.2058361 L15.5095892,13.3813347 C14.6310351,14.4484486 13.7415376,15.8094397 12.5646605,16.549707 L41.9523328,16.549707 L41.9523328,3.03585692 L35.3028697,3.03585692 Z" id="Fill-8" fill="#EC1D24"/>
|
15 |
+
</g>
|
16 |
+
</g>
|
17 |
+
</g>
|
18 |
+
</svg>
|
modules/ppcp-wc-gateway/assets/js/oxxo.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(()=>{var __webpack_modules__={901:()=>{eval("document.addEventListener('DOMContentLoaded', function () {\n jQuery('form.checkout').on('checkout_place_order_success', function (type, data) {\n if (data.payer_action && data.payer_action !== '') {\n const width = screen.width / 2;\n const height = screen.height / 2;\n const left = width - width / 2;\n const top = height - height / 2;\n window.open(data.payer_action, '_blank', 'popup, width=' + width + ', height=' + height + ', top=' + top + ', left=' + left);\n }\n });\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9wcGNwLXdjLWdhdGV3YXkvLi9yZXNvdXJjZXMvanMvb3h4by5qcz81MDQ1Il0sIm5hbWVzIjpbImRvY3VtZW50IiwiYWRkRXZlbnRMaXN0ZW5lciIsImpRdWVyeSIsIm9uIiwidHlwZSIsImRhdGEiLCJwYXllcl9hY3Rpb24iLCJ3aWR0aCIsInNjcmVlbiIsImhlaWdodCIsImxlZnQiLCJ0b3AiLCJ3aW5kb3ciLCJvcGVuIl0sIm1hcHBpbmdzIjoiQUFBQUEsUUFBUSxDQUFDQyxnQkFBVCxDQUNJLGtCQURKLEVBRUksWUFBVztBQUNQQyxFQUFBQSxNQUFNLENBQUMsZUFBRCxDQUFOLENBQXdCQyxFQUF4QixDQUEyQiw4QkFBM0IsRUFBMkQsVUFBU0MsSUFBVCxFQUFlQyxJQUFmLEVBQXNCO0FBQzdFLFFBQUdBLElBQUksQ0FBQ0MsWUFBTCxJQUFxQkQsSUFBSSxDQUFDQyxZQUFMLEtBQXNCLEVBQTlDLEVBQWtEO0FBQzFDLFlBQU1DLEtBQUssR0FBR0MsTUFBTSxDQUFDRCxLQUFQLEdBQWUsQ0FBN0I7QUFDQSxZQUFNRSxNQUFNLEdBQUdELE1BQU0sQ0FBQ0MsTUFBUCxHQUFnQixDQUEvQjtBQUNBLFlBQU1DLElBQUksR0FBR0gsS0FBSyxHQUFJQSxLQUFLLEdBQUcsQ0FBOUI7QUFDQSxZQUFNSSxHQUFHLEdBQUdGLE1BQU0sR0FBSUEsTUFBTSxHQUFHLENBQS9CO0FBQ0FHLE1BQUFBLE1BQU0sQ0FBQ0MsSUFBUCxDQUNJUixJQUFJLENBQUNDLFlBRFQsRUFFSSxRQUZKLEVBR0ksa0JBQWtCQyxLQUFsQixHQUEwQixXQUExQixHQUF3Q0UsTUFBeEMsR0FBaUQsUUFBakQsR0FBNERFLEdBQTVELEdBQWtFLFNBQWxFLEdBQThFRCxJQUhsRjtBQUtQO0FBQ0osR0FaRDtBQWFILENBaEJMIiwic291cmNlc0NvbnRlbnQiOlsiZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAnRE9NQ29udGVudExvYWRlZCcsXG4gICAgZnVuY3Rpb24oKSB7XG4gICAgICAgIGpRdWVyeSgnZm9ybS5jaGVja291dCcpLm9uKCdjaGVja291dF9wbGFjZV9vcmRlcl9zdWNjZXNzJywgZnVuY3Rpb24odHlwZSwgZGF0YSkgIHtcbiAgICAgICAgICAgIGlmKGRhdGEucGF5ZXJfYWN0aW9uICYmIGRhdGEucGF5ZXJfYWN0aW9uICE9PSAnJykge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB3aWR0aCA9IHNjcmVlbi53aWR0aCAvIDI7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhlaWdodCA9IHNjcmVlbi5oZWlnaHQgLyAyO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBsZWZ0ID0gd2lkdGggLSAod2lkdGggLyAyKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdG9wID0gaGVpZ2h0IC0gKGhlaWdodCAvIDIpO1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cub3BlbihcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEucGF5ZXJfYWN0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ19ibGFuaycsXG4gICAgICAgICAgICAgICAgICAgICAgICAncG9wdXAsIHdpZHRoPScgKyB3aWR0aCArICcsIGhlaWdodD0nICsgaGVpZ2h0ICsgJywgdG9wPScgKyB0b3AgKyAnLCBsZWZ0PScgKyBsZWZ0XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbik7XG4iXSwiZmlsZSI6IjkwMS5qcyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///901\n")}},__webpack_exports__={};__webpack_modules__[901]()})();
|
modules/ppcp-wc-gateway/resources/js/oxxo.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
document.addEventListener(
|
2 |
+
'DOMContentLoaded',
|
3 |
+
function() {
|
4 |
+
jQuery('form.checkout').on('checkout_place_order_success', function(type, data) {
|
5 |
+
if(data.payer_action && data.payer_action !== '') {
|
6 |
+
const width = screen.width / 2;
|
7 |
+
const height = screen.height / 2;
|
8 |
+
const left = width - (width / 2);
|
9 |
+
const top = height - (height / 2);
|
10 |
+
window.open(
|
11 |
+
data.payer_action,
|
12 |
+
'_blank',
|
13 |
+
'popup, width=' + width + ', height=' + height + ', top=' + top + ', left=' + left
|
14 |
+
);
|
15 |
+
}
|
16 |
+
});
|
17 |
+
}
|
18 |
+
);
|
modules/ppcp-wc-gateway/services.php
CHANGED
@@ -29,7 +29,11 @@ use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
|
|
29 |
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
30 |
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
31 |
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
|
|
32 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
|
|
|
|
|
|
33 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
34 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
|
35 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId;
|
@@ -38,13 +42,14 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFac
|
|
38 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice;
|
39 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
40 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
|
|
41 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
42 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
43 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
44 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
45 |
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
46 |
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
47 |
-
use WooCommerce\PayPalCommerce\WcGateway\Notice\
|
48 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
49 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
50 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
@@ -55,11 +60,10 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
|
55 |
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
56 |
|
57 |
return array(
|
58 |
-
'wcgateway.paypal-gateway'
|
59 |
$order_processor = $container->get( 'wcgateway.order-processor' );
|
60 |
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
61 |
$funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
|
62 |
-
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
63 |
$settings = $container->get( 'wcgateway.settings' );
|
64 |
$session_handler = $container->get( 'session.handler' );
|
65 |
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
@@ -68,8 +72,6 @@ return array(
|
|
68 |
$subscription_helper = $container->get( 'subscription.helper' );
|
69 |
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
70 |
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
71 |
-
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
72 |
-
$order_endpoint = $container->get( 'api.endpoint.order' );
|
73 |
$environment = $container->get( 'onboarding.environment' );
|
74 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
75 |
$api_shop_country = $container->get( 'api.shop.country' );
|
@@ -77,7 +79,6 @@ return array(
|
|
77 |
$settings_renderer,
|
78 |
$funding_source_renderer,
|
79 |
$order_processor,
|
80 |
-
$authorized_payments,
|
81 |
$settings,
|
82 |
$session_handler,
|
83 |
$refund_processor,
|
@@ -87,14 +88,11 @@ return array(
|
|
87 |
$page_id,
|
88 |
$environment,
|
89 |
$payment_token_repository,
|
90 |
-
$container->get( 'api.factory.shipping-preference' ),
|
91 |
$logger,
|
92 |
-
$payments_endpoint,
|
93 |
-
$order_endpoint,
|
94 |
$api_shop_country
|
95 |
);
|
96 |
},
|
97 |
-
'wcgateway.credit-card-gateway'
|
98 |
$order_processor = $container->get( 'wcgateway.order-processor' );
|
99 |
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
100 |
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
@@ -133,27 +131,43 @@ return array(
|
|
133 |
$payments_endpoint
|
134 |
);
|
135 |
},
|
136 |
-
'wcgateway.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
$session_handler = $container->get( 'session.handler' );
|
138 |
$settings = $container->get( 'wcgateway.settings' );
|
139 |
return new DisableGateways( $session_handler, $settings );
|
140 |
},
|
141 |
-
'wcgateway.is-wc-payments-page'
|
142 |
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
|
143 |
$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
|
144 |
return 'wc-settings' === $page && 'checkout' === $tab;
|
145 |
},
|
146 |
|
147 |
-
'wcgateway.is-ppcp-settings-page'
|
148 |
if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
|
149 |
return false;
|
150 |
}
|
151 |
|
152 |
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
|
153 |
-
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID ), true );
|
154 |
},
|
155 |
|
156 |
-
'wcgateway.current-ppcp-settings-page-id'
|
157 |
if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
|
158 |
return '';
|
159 |
}
|
@@ -164,36 +178,70 @@ return array(
|
|
164 |
return $ppcp_tab ? $ppcp_tab : $section;
|
165 |
},
|
166 |
|
167 |
-
'wcgateway.settings'
|
168 |
return new Settings();
|
169 |
},
|
170 |
-
'wcgateway.notice.connect'
|
171 |
$state = $container->get( 'onboarding.state' );
|
172 |
$settings = $container->get( 'wcgateway.settings' );
|
173 |
return new ConnectAdminNotice( $state, $settings );
|
174 |
},
|
175 |
-
'wcgateway.notice.dcc-without-paypal'
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
},
|
182 |
-
'wcgateway.notice.authorize-order-action'
|
183 |
static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
|
184 |
return new AuthorizeOrderActionNotice();
|
185 |
},
|
186 |
-
'wcgateway.settings.sections-renderer'
|
187 |
return new SectionsRenderer(
|
188 |
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
189 |
-
$container->get( '
|
190 |
);
|
191 |
},
|
192 |
-
'wcgateway.settings.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
$settings = $container->get( 'wcgateway.settings' );
|
194 |
return new SettingsStatus( $settings );
|
195 |
},
|
196 |
-
'wcgateway.settings.render'
|
197 |
$settings = $container->get( 'wcgateway.settings' );
|
198 |
$state = $container->get( 'onboarding.state' );
|
199 |
$fields = $container->get( 'wcgateway.settings.fields' );
|
@@ -213,7 +261,7 @@ return array(
|
|
213 |
$page_id
|
214 |
);
|
215 |
},
|
216 |
-
'wcgateway.settings.listener'
|
217 |
$settings = $container->get( 'wcgateway.settings' );
|
218 |
$fields = $container->get( 'wcgateway.settings.fields' );
|
219 |
$webhook_registrar = $container->get( 'webhook.registrar' );
|
@@ -235,7 +283,7 @@ return array(
|
|
235 |
$signup_link_ids
|
236 |
);
|
237 |
},
|
238 |
-
'wcgateway.order-processor'
|
239 |
|
240 |
$session_handler = $container->get( 'session.handler' );
|
241 |
$order_endpoint = $container->get( 'api.endpoint.order' );
|
@@ -260,13 +308,13 @@ return array(
|
|
260 |
$order_helper
|
261 |
);
|
262 |
},
|
263 |
-
'wcgateway.processor.refunds'
|
264 |
$order_endpoint = $container->get( 'api.endpoint.order' );
|
265 |
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
266 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
267 |
return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger );
|
268 |
},
|
269 |
-
'wcgateway.processor.authorized-payments'
|
270 |
$order_endpoint = $container->get( 'api.endpoint.order' );
|
271 |
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
272 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
@@ -282,23 +330,23 @@ return array(
|
|
282 |
$subscription_helper
|
283 |
);
|
284 |
},
|
285 |
-
'wcgateway.admin.render-authorize-action'
|
286 |
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
287 |
return new RenderAuthorizeAction( $column );
|
288 |
},
|
289 |
-
'wcgateway.admin.order-payment-status'
|
290 |
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
291 |
return new PaymentStatusOrderDetail( $column );
|
292 |
},
|
293 |
-
'wcgateway.admin.orders-payment-status-column'
|
294 |
$settings = $container->get( 'wcgateway.settings' );
|
295 |
return new OrderTablePaymentStatusColumn( $settings );
|
296 |
},
|
297 |
-
'wcgateway.admin.fees-renderer'
|
298 |
return new FeesRenderer();
|
299 |
},
|
300 |
|
301 |
-
'wcgateway.settings.fields'
|
302 |
|
303 |
$state = $container->get( 'onboarding.state' );
|
304 |
assert( $state instanceof State );
|
@@ -861,6 +909,40 @@ return array(
|
|
861 |
'requirements' => array(),
|
862 |
'gateway' => 'paypal',
|
863 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
864 |
|
865 |
// General button styles.
|
866 |
'button_style_heading' => array(
|
@@ -2071,10 +2153,14 @@ return array(
|
|
2071 |
$fields['disable_cards']['options'] = $card_options;
|
2072 |
$fields['card_icons']['options'] = array_merge( $dark_versions, $card_options );
|
2073 |
|
|
|
|
|
|
|
|
|
2074 |
return $fields;
|
2075 |
},
|
2076 |
|
2077 |
-
'wcgateway.all-funding-sources'
|
2078 |
return array(
|
2079 |
'card' => _x( 'Credit or debit cards', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
2080 |
'credit' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
@@ -2092,28 +2178,28 @@ return array(
|
|
2092 |
);
|
2093 |
},
|
2094 |
|
2095 |
-
'wcgateway.checkout.address-preset'
|
2096 |
|
2097 |
return new CheckoutPayPalAddressPreset(
|
2098 |
$container->get( 'session.handler' )
|
2099 |
);
|
2100 |
},
|
2101 |
-
'wcgateway.url'
|
2102 |
return plugins_url(
|
2103 |
$container->get( 'wcgateway.relative-path' ),
|
2104 |
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
2105 |
);
|
2106 |
},
|
2107 |
-
'wcgateway.relative-path'
|
2108 |
return 'modules/ppcp-wc-gateway/';
|
2109 |
},
|
2110 |
-
'wcgateway.absolute-path'
|
2111 |
return plugin_dir_path(
|
2112 |
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
2113 |
) .
|
2114 |
$container->get( 'wcgateway.relative-path' );
|
2115 |
},
|
2116 |
-
'wcgateway.endpoint.return-url'
|
2117 |
$gateway = $container->get( 'wcgateway.paypal-gateway' );
|
2118 |
$endpoint = $container->get( 'api.endpoint.order' );
|
2119 |
$prefix = $container->get( 'api.prefix' );
|
@@ -2124,40 +2210,43 @@ return array(
|
|
2124 |
);
|
2125 |
},
|
2126 |
|
2127 |
-
'wcgateway.transaction-url-sandbox'
|
2128 |
return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
2129 |
},
|
2130 |
|
2131 |
-
'wcgateway.transaction-url-live'
|
2132 |
return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
2133 |
},
|
2134 |
|
2135 |
-
'wcgateway.transaction-url-provider'
|
2136 |
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
2137 |
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
2138 |
|
2139 |
return new TransactionUrlProvider( $sandbox_url_base, $live_url_base );
|
2140 |
},
|
2141 |
|
2142 |
-
'wcgateway.helper.dcc-product-status'
|
2143 |
|
2144 |
$settings = $container->get( 'wcgateway.settings' );
|
2145 |
$partner_endpoint = $container->get( 'api.endpoint.partners' );
|
2146 |
return new DCCProductStatus( $settings, $partner_endpoint );
|
2147 |
},
|
2148 |
|
2149 |
-
'button.helper.messages-disclaimers'
|
2150 |
return new MessagesDisclaimers(
|
2151 |
$container->get( 'api.shop.country' )
|
2152 |
);
|
2153 |
},
|
2154 |
|
2155 |
-
'wcgateway.funding-source.renderer'
|
2156 |
return new FundingSourceRenderer(
|
2157 |
$container->get( 'wcgateway.settings' )
|
2158 |
);
|
2159 |
},
|
2160 |
-
'wcgateway.
|
|
|
|
|
|
|
2161 |
return new PayUponInvoiceOrderEndpoint(
|
2162 |
$container->get( 'api.host' ),
|
2163 |
$container->get( 'api.bearer' ),
|
@@ -2166,10 +2255,10 @@ return array(
|
|
2166 |
$container->get( 'woocommerce.logger.woocommerce' )
|
2167 |
);
|
2168 |
},
|
2169 |
-
'wcgateway.pay-upon-invoice-payment-source-factory'
|
2170 |
return new PaymentSourceFactory();
|
2171 |
},
|
2172 |
-
'wcgateway.pay-upon-invoice-gateway'
|
2173 |
return new PayUponInvoiceGateway(
|
2174 |
$container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
|
2175 |
$container->get( 'api.factory.purchase-unit' ),
|
@@ -2177,16 +2266,17 @@ return array(
|
|
2177 |
$container->get( 'onboarding.environment' ),
|
2178 |
$container->get( 'wcgateway.transaction-url-provider' ),
|
2179 |
$container->get( 'woocommerce.logger.woocommerce' ),
|
2180 |
-
$container->get( 'wcgateway.pay-upon-invoice-helper' )
|
|
|
2181 |
);
|
2182 |
},
|
2183 |
-
'wcgateway.pay-upon-invoice-fraudnet-session-id'
|
2184 |
return new FraudNetSessionId();
|
2185 |
},
|
2186 |
'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
|
2187 |
return new FraudNetSourceWebsiteId( $container->get( 'api.merchant_id' ) );
|
2188 |
},
|
2189 |
-
'wcgateway.pay-upon-invoice-fraudnet'
|
2190 |
$session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' );
|
2191 |
$source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' );
|
2192 |
return new FraudNet(
|
@@ -2194,16 +2284,18 @@ return array(
|
|
2194 |
(string) $source_website_id()
|
2195 |
);
|
2196 |
},
|
2197 |
-
'wcgateway.pay-upon-invoice-helper'
|
2198 |
-
return new PayUponInvoiceHelper(
|
|
|
|
|
2199 |
},
|
2200 |
-
'wcgateway.pay-upon-invoice-product-status'
|
2201 |
return new PayUponInvoiceProductStatus(
|
2202 |
$container->get( 'wcgateway.settings' ),
|
2203 |
$container->get( 'api.endpoint.partners' )
|
2204 |
);
|
2205 |
},
|
2206 |
-
'wcgateway.pay-upon-invoice'
|
2207 |
return new PayUponInvoice(
|
2208 |
$container->get( 'wcgateway.url' ),
|
2209 |
$container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
|
@@ -2217,10 +2309,36 @@ return array(
|
|
2217 |
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
2218 |
$container->get( 'wcgateway.pay-upon-invoice-product-status' ),
|
2219 |
$container->get( 'wcgateway.pay-upon-invoice-helper' ),
|
|
|
2220 |
$container->get( 'api.factory.capture' )
|
2221 |
);
|
2222 |
},
|
2223 |
-
'wcgateway.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2224 |
$settings = $container->get( 'wcgateway.settings' );
|
2225 |
|
2226 |
/**
|
@@ -2232,7 +2350,7 @@ return array(
|
|
2232 |
);
|
2233 |
},
|
2234 |
|
2235 |
-
'wcgateway.helper.vaulting-scope'
|
2236 |
try {
|
2237 |
$token = $container->get( 'api.bearer' )->bearer();
|
2238 |
return $token->vaulting_available();
|
@@ -2241,7 +2359,7 @@ return array(
|
|
2241 |
}
|
2242 |
},
|
2243 |
|
2244 |
-
'button.helper.vaulting-label'
|
2245 |
$vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' );
|
2246 |
|
2247 |
if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) {
|
@@ -2263,7 +2381,7 @@ return array(
|
|
2263 |
return $vaulting_label;
|
2264 |
},
|
2265 |
|
2266 |
-
'wcgateway.settings.fields.pay-later-label'
|
2267 |
$pay_later_label = '<span class="ppcp-pay-later-enabled-label">%s</span>';
|
2268 |
$pay_later_label .= '<span class="ppcp-pay-later-disabled-label">';
|
2269 |
$pay_later_label .= __( "You have PayPal vaulting enabled, that's why Pay Later Messaging options are unavailable now. You cannot use both features at the same time.", 'woocommerce-paypal-payments' );
|
@@ -2271,4 +2389,32 @@ return array(
|
|
2271 |
|
2272 |
return $pay_later_label;
|
2273 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2274 |
);
|
29 |
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
30 |
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
31 |
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
32 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
33 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
34 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
|
35 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOEndpoint;
|
36 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
37 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
38 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
|
39 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId;
|
42 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice;
|
43 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
44 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
45 |
+
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
46 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
47 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
48 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
49 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
50 |
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
51 |
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
52 |
+
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
|
53 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
54 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
55 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
60 |
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
61 |
|
62 |
return array(
|
63 |
+
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
64 |
$order_processor = $container->get( 'wcgateway.order-processor' );
|
65 |
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
66 |
$funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
|
|
|
67 |
$settings = $container->get( 'wcgateway.settings' );
|
68 |
$session_handler = $container->get( 'session.handler' );
|
69 |
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
72 |
$subscription_helper = $container->get( 'subscription.helper' );
|
73 |
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
74 |
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
|
|
|
|
75 |
$environment = $container->get( 'onboarding.environment' );
|
76 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
77 |
$api_shop_country = $container->get( 'api.shop.country' );
|
79 |
$settings_renderer,
|
80 |
$funding_source_renderer,
|
81 |
$order_processor,
|
|
|
82 |
$settings,
|
83 |
$session_handler,
|
84 |
$refund_processor,
|
88 |
$page_id,
|
89 |
$environment,
|
90 |
$payment_token_repository,
|
|
|
91 |
$logger,
|
|
|
|
|
92 |
$api_shop_country
|
93 |
);
|
94 |
},
|
95 |
+
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
96 |
$order_processor = $container->get( 'wcgateway.order-processor' );
|
97 |
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
98 |
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
131 |
$payments_endpoint
|
132 |
);
|
133 |
},
|
134 |
+
'wcgateway.card-button-gateway' => static function ( ContainerInterface $container ): CardButtonGateway {
|
135 |
+
return new CardButtonGateway(
|
136 |
+
$container->get( 'wcgateway.settings.render' ),
|
137 |
+
$container->get( 'wcgateway.order-processor' ),
|
138 |
+
$container->get( 'wcgateway.settings' ),
|
139 |
+
$container->get( 'session.handler' ),
|
140 |
+
$container->get( 'wcgateway.processor.refunds' ),
|
141 |
+
$container->get( 'onboarding.state' ),
|
142 |
+
$container->get( 'wcgateway.transaction-url-provider' ),
|
143 |
+
$container->get( 'subscription.helper' ),
|
144 |
+
$container->get( 'wcgateway.settings.allow_card_button_gateway.default' ),
|
145 |
+
$container->get( 'onboarding.environment' ),
|
146 |
+
$container->get( 'vaulting.repository.payment-token' ),
|
147 |
+
$container->get( 'woocommerce.logger.woocommerce' )
|
148 |
+
);
|
149 |
+
},
|
150 |
+
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
151 |
$session_handler = $container->get( 'session.handler' );
|
152 |
$settings = $container->get( 'wcgateway.settings' );
|
153 |
return new DisableGateways( $session_handler, $settings );
|
154 |
},
|
155 |
+
'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
|
156 |
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
|
157 |
$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
|
158 |
return 'wc-settings' === $page && 'checkout' === $tab;
|
159 |
},
|
160 |
|
161 |
+
'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
|
162 |
if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
|
163 |
return false;
|
164 |
}
|
165 |
|
166 |
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
|
167 |
+
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID, CardButtonGateway::ID, OXXOGateway::ID ), true );
|
168 |
},
|
169 |
|
170 |
+
'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
|
171 |
if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
|
172 |
return '';
|
173 |
}
|
178 |
return $ppcp_tab ? $ppcp_tab : $section;
|
179 |
},
|
180 |
|
181 |
+
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
182 |
return new Settings();
|
183 |
},
|
184 |
+
'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
|
185 |
$state = $container->get( 'onboarding.state' );
|
186 |
$settings = $container->get( 'wcgateway.settings' );
|
187 |
return new ConnectAdminNotice( $state, $settings );
|
188 |
},
|
189 |
+
'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): GatewayWithoutPayPalAdminNotice {
|
190 |
+
return new GatewayWithoutPayPalAdminNotice(
|
191 |
+
CreditCardGateway::ID,
|
192 |
+
$container->get( 'onboarding.state' ),
|
193 |
+
$container->get( 'wcgateway.settings' ),
|
194 |
+
$container->get( 'wcgateway.is-wc-payments-page' ),
|
195 |
+
$container->get( 'wcgateway.is-ppcp-settings-page' )
|
196 |
+
);
|
197 |
+
},
|
198 |
+
'wcgateway.notice.card-button-without-paypal' => static function ( ContainerInterface $container ): GatewayWithoutPayPalAdminNotice {
|
199 |
+
return new GatewayWithoutPayPalAdminNotice(
|
200 |
+
CardButtonGateway::ID,
|
201 |
+
$container->get( 'onboarding.state' ),
|
202 |
+
$container->get( 'wcgateway.settings' ),
|
203 |
+
$container->get( 'wcgateway.is-wc-payments-page' ),
|
204 |
+
$container->get( 'wcgateway.is-ppcp-settings-page' )
|
205 |
+
);
|
206 |
},
|
207 |
+
'wcgateway.notice.authorize-order-action' =>
|
208 |
static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
|
209 |
return new AuthorizeOrderActionNotice();
|
210 |
},
|
211 |
+
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
212 |
return new SectionsRenderer(
|
213 |
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
214 |
+
$container->get( 'wcgateway.settings.sections' )
|
215 |
);
|
216 |
},
|
217 |
+
'wcgateway.settings.sections' => static function ( ContainerInterface $container ): array {
|
218 |
+
$sections = array(
|
219 |
+
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
220 |
+
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
221 |
+
CardButtonGateway::ID => __( 'PayPal Card Button', 'woocommerce-paypal-payments' ),
|
222 |
+
OXXOGateway::ID => __( 'OXXO', 'woocommerce-paypal-payments' ),
|
223 |
+
PayUponInvoiceGateway::ID => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
|
224 |
+
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
|
225 |
+
);
|
226 |
+
|
227 |
+
// Remove for all not registered in WC gateways that cannot render anything in this case.
|
228 |
+
$gateways = WC()->payment_gateways->payment_gateways();
|
229 |
+
foreach ( array_diff(
|
230 |
+
array_keys( $sections ),
|
231 |
+
array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID )
|
232 |
+
) as $id ) {
|
233 |
+
if ( ! isset( $gateways[ $id ] ) ) {
|
234 |
+
unset( $sections[ $id ] );
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
return $sections;
|
239 |
+
},
|
240 |
+
'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
|
241 |
$settings = $container->get( 'wcgateway.settings' );
|
242 |
return new SettingsStatus( $settings );
|
243 |
},
|
244 |
+
'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
|
245 |
$settings = $container->get( 'wcgateway.settings' );
|
246 |
$state = $container->get( 'onboarding.state' );
|
247 |
$fields = $container->get( 'wcgateway.settings.fields' );
|
261 |
$page_id
|
262 |
);
|
263 |
},
|
264 |
+
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
265 |
$settings = $container->get( 'wcgateway.settings' );
|
266 |
$fields = $container->get( 'wcgateway.settings.fields' );
|
267 |
$webhook_registrar = $container->get( 'webhook.registrar' );
|
283 |
$signup_link_ids
|
284 |
);
|
285 |
},
|
286 |
+
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
|
287 |
|
288 |
$session_handler = $container->get( 'session.handler' );
|
289 |
$order_endpoint = $container->get( 'api.endpoint.order' );
|
308 |
$order_helper
|
309 |
);
|
310 |
},
|
311 |
+
'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
|
312 |
$order_endpoint = $container->get( 'api.endpoint.order' );
|
313 |
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
314 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
315 |
return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger );
|
316 |
},
|
317 |
+
'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
|
318 |
$order_endpoint = $container->get( 'api.endpoint.order' );
|
319 |
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
320 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
330 |
$subscription_helper
|
331 |
);
|
332 |
},
|
333 |
+
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
334 |
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
335 |
return new RenderAuthorizeAction( $column );
|
336 |
},
|
337 |
+
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
338 |
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
339 |
return new PaymentStatusOrderDetail( $column );
|
340 |
},
|
341 |
+
'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
|
342 |
$settings = $container->get( 'wcgateway.settings' );
|
343 |
return new OrderTablePaymentStatusColumn( $settings );
|
344 |
},
|
345 |
+
'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
|
346 |
return new FeesRenderer();
|
347 |
},
|
348 |
|
349 |
+
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
350 |
|
351 |
$state = $container->get( 'onboarding.state' );
|
352 |
assert( $state instanceof State );
|
909 |
'requirements' => array(),
|
910 |
'gateway' => 'paypal',
|
911 |
),
|
912 |
+
'card_billing_data_mode' => array(
|
913 |
+
'title' => __( 'Card billing data handling', 'woocommerce-paypal-payments' ),
|
914 |
+
'type' => 'select',
|
915 |
+
'class' => array(),
|
916 |
+
'input_class' => array( 'wc-enhanced-select' ),
|
917 |
+
'desc_tip' => true,
|
918 |
+
'description' => __( 'Using the WC form data increases convenience for the customers, but can cause issues if card details do not match the billing data in the checkout form.', 'woocommerce-paypal-payments' ),
|
919 |
+
'default' => $container->get( 'wcgateway.settings.card_billing_data_mode.default' ),
|
920 |
+
'options' => array(
|
921 |
+
CardBillingMode::USE_WC => __( 'Use WC checkout form data (do not show any address fields)', 'woocommerce-paypal-payments' ),
|
922 |
+
CardBillingMode::MINIMAL_INPUT => __( 'Request only name and postal code', 'woocommerce-paypal-payments' ),
|
923 |
+
CardBillingMode::NO_WC => __( 'Do not use WC checkout form data (request all address fields)', 'woocommerce-paypal-payments' ),
|
924 |
+
),
|
925 |
+
'screens' => array(
|
926 |
+
State::STATE_START,
|
927 |
+
State::STATE_ONBOARDED,
|
928 |
+
),
|
929 |
+
'requirements' => array(),
|
930 |
+
'gateway' => array( 'paypal', CardButtonGateway::ID ),
|
931 |
+
),
|
932 |
+
'allow_card_button_gateway' => array(
|
933 |
+
'title' => __( 'Separate Card Button from PayPal gateway', 'woocommerce-paypal-payments' ),
|
934 |
+
'type' => 'checkbox',
|
935 |
+
'desc_tip' => true,
|
936 |
+
'label' => __( 'Enable a separate payment gateway for the branded PayPal Debit or Credit Card button.', 'woocommerce-paypal-payments' ),
|
937 |
+
'description' => __( 'By default, the Debit or Credit Card button is displayed in the PayPal Checkout payment gateway. This setting creates a second gateway for the Card button.', 'woocommerce-paypal-payments' ),
|
938 |
+
'default' => $container->get( 'wcgateway.settings.allow_card_button_gateway.default' ),
|
939 |
+
'screens' => array(
|
940 |
+
State::STATE_START,
|
941 |
+
State::STATE_ONBOARDED,
|
942 |
+
),
|
943 |
+
'requirements' => array(),
|
944 |
+
'gateway' => 'paypal',
|
945 |
+
),
|
946 |
|
947 |
// General button styles.
|
948 |
'button_style_heading' => array(
|
2153 |
$fields['disable_cards']['options'] = $card_options;
|
2154 |
$fields['card_icons']['options'] = array_merge( $dark_versions, $card_options );
|
2155 |
|
2156 |
+
if ( defined( 'PPCP_FLAG_SEPARATE_APM_BUTTONS' ) && PPCP_FLAG_SEPARATE_APM_BUTTONS === false ) {
|
2157 |
+
unset( $fields['allow_card_button_gateway'] );
|
2158 |
+
}
|
2159 |
+
|
2160 |
return $fields;
|
2161 |
},
|
2162 |
|
2163 |
+
'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
|
2164 |
return array(
|
2165 |
'card' => _x( 'Credit or debit cards', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
2166 |
'credit' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
2178 |
);
|
2179 |
},
|
2180 |
|
2181 |
+
'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
|
2182 |
|
2183 |
return new CheckoutPayPalAddressPreset(
|
2184 |
$container->get( 'session.handler' )
|
2185 |
);
|
2186 |
},
|
2187 |
+
'wcgateway.url' => static function ( ContainerInterface $container ): string {
|
2188 |
return plugins_url(
|
2189 |
$container->get( 'wcgateway.relative-path' ),
|
2190 |
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
2191 |
);
|
2192 |
},
|
2193 |
+
'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
|
2194 |
return 'modules/ppcp-wc-gateway/';
|
2195 |
},
|
2196 |
+
'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
|
2197 |
return plugin_dir_path(
|
2198 |
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
2199 |
) .
|
2200 |
$container->get( 'wcgateway.relative-path' );
|
2201 |
},
|
2202 |
+
'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
|
2203 |
$gateway = $container->get( 'wcgateway.paypal-gateway' );
|
2204 |
$endpoint = $container->get( 'api.endpoint.order' );
|
2205 |
$prefix = $container->get( 'api.prefix' );
|
2210 |
);
|
2211 |
},
|
2212 |
|
2213 |
+
'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
|
2214 |
return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
2215 |
},
|
2216 |
|
2217 |
+
'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
|
2218 |
return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
2219 |
},
|
2220 |
|
2221 |
+
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
2222 |
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
2223 |
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
2224 |
|
2225 |
return new TransactionUrlProvider( $sandbox_url_base, $live_url_base );
|
2226 |
},
|
2227 |
|
2228 |
+
'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
|
2229 |
|
2230 |
$settings = $container->get( 'wcgateway.settings' );
|
2231 |
$partner_endpoint = $container->get( 'api.endpoint.partners' );
|
2232 |
return new DCCProductStatus( $settings, $partner_endpoint );
|
2233 |
},
|
2234 |
|
2235 |
+
'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
|
2236 |
return new MessagesDisclaimers(
|
2237 |
$container->get( 'api.shop.country' )
|
2238 |
);
|
2239 |
},
|
2240 |
|
2241 |
+
'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
|
2242 |
return new FundingSourceRenderer(
|
2243 |
$container->get( 'wcgateway.settings' )
|
2244 |
);
|
2245 |
},
|
2246 |
+
'wcgateway.checkout-helper' => static function ( ContainerInterface $container ): CheckoutHelper {
|
2247 |
+
return new CheckoutHelper();
|
2248 |
+
},
|
2249 |
+
'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
|
2250 |
return new PayUponInvoiceOrderEndpoint(
|
2251 |
$container->get( 'api.host' ),
|
2252 |
$container->get( 'api.bearer' ),
|
2255 |
$container->get( 'woocommerce.logger.woocommerce' )
|
2256 |
);
|
2257 |
},
|
2258 |
+
'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory {
|
2259 |
return new PaymentSourceFactory();
|
2260 |
},
|
2261 |
+
'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
|
2262 |
return new PayUponInvoiceGateway(
|
2263 |
$container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
|
2264 |
$container->get( 'api.factory.purchase-unit' ),
|
2266 |
$container->get( 'onboarding.environment' ),
|
2267 |
$container->get( 'wcgateway.transaction-url-provider' ),
|
2268 |
$container->get( 'woocommerce.logger.woocommerce' ),
|
2269 |
+
$container->get( 'wcgateway.pay-upon-invoice-helper' ),
|
2270 |
+
$container->get( 'wcgateway.checkout-helper' )
|
2271 |
);
|
2272 |
},
|
2273 |
+
'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
|
2274 |
return new FraudNetSessionId();
|
2275 |
},
|
2276 |
'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
|
2277 |
return new FraudNetSourceWebsiteId( $container->get( 'api.merchant_id' ) );
|
2278 |
},
|
2279 |
+
'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
|
2280 |
$session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' );
|
2281 |
$source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' );
|
2282 |
return new FraudNet(
|
2284 |
(string) $source_website_id()
|
2285 |
);
|
2286 |
},
|
2287 |
+
'wcgateway.pay-upon-invoice-helper' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
|
2288 |
+
return new PayUponInvoiceHelper(
|
2289 |
+
$container->get( 'wcgateway.checkout-helper' )
|
2290 |
+
);
|
2291 |
},
|
2292 |
+
'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
|
2293 |
return new PayUponInvoiceProductStatus(
|
2294 |
$container->get( 'wcgateway.settings' ),
|
2295 |
$container->get( 'api.endpoint.partners' )
|
2296 |
);
|
2297 |
},
|
2298 |
+
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
|
2299 |
return new PayUponInvoice(
|
2300 |
$container->get( 'wcgateway.url' ),
|
2301 |
$container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
|
2309 |
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
2310 |
$container->get( 'wcgateway.pay-upon-invoice-product-status' ),
|
2311 |
$container->get( 'wcgateway.pay-upon-invoice-helper' ),
|
2312 |
+
$container->get( 'wcgateway.checkout-helper' ),
|
2313 |
$container->get( 'api.factory.capture' )
|
2314 |
);
|
2315 |
},
|
2316 |
+
'wcgateway.oxxo' => static function( ContainerInterface $container ): OXXO {
|
2317 |
+
return new OXXO(
|
2318 |
+
$container->get( 'wcgateway.checkout-helper' ),
|
2319 |
+
$container->get( 'wcgateway.url' ),
|
2320 |
+
$container->get( 'ppcp.asset-version' )
|
2321 |
+
);
|
2322 |
+
},
|
2323 |
+
'wcgateway.oxxo-gateway' => static function( ContainerInterface $container ): OXXOGateway {
|
2324 |
+
return new OXXOGateway(
|
2325 |
+
$container->get( 'api.endpoint.order' ),
|
2326 |
+
$container->get( 'api.factory.purchase-unit' ),
|
2327 |
+
$container->get( 'api.factory.shipping-preference' ),
|
2328 |
+
$container->get( 'wcgateway.url' ),
|
2329 |
+
$container->get( 'woocommerce.logger.woocommerce' )
|
2330 |
+
);
|
2331 |
+
},
|
2332 |
+
'wcgateway.endpoint.oxxo' => static function ( ContainerInterface $container ): OXXOEndpoint {
|
2333 |
+
return new OXXOEndpoint(
|
2334 |
+
$container->get( 'button.request-data' ),
|
2335 |
+
$container->get( 'api.endpoint.order' ),
|
2336 |
+
$container->get( 'api.factory.purchase-unit' ),
|
2337 |
+
$container->get( 'api.factory.shipping-preference' ),
|
2338 |
+
$container->get( 'woocommerce.logger.woocommerce' )
|
2339 |
+
);
|
2340 |
+
},
|
2341 |
+
'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
|
2342 |
$settings = $container->get( 'wcgateway.settings' );
|
2343 |
|
2344 |
/**
|
2350 |
);
|
2351 |
},
|
2352 |
|
2353 |
+
'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
|
2354 |
try {
|
2355 |
$token = $container->get( 'api.bearer' )->bearer();
|
2356 |
return $token->vaulting_available();
|
2359 |
}
|
2360 |
},
|
2361 |
|
2362 |
+
'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
|
2363 |
$vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' );
|
2364 |
|
2365 |
if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) {
|
2381 |
return $vaulting_label;
|
2382 |
},
|
2383 |
|
2384 |
+
'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
|
2385 |
$pay_later_label = '<span class="ppcp-pay-later-enabled-label">%s</span>';
|
2386 |
$pay_later_label .= '<span class="ppcp-pay-later-disabled-label">';
|
2387 |
$pay_later_label .= __( "You have PayPal vaulting enabled, that's why Pay Later Messaging options are unavailable now. You cannot use both features at the same time.", 'woocommerce-paypal-payments' );
|
2389 |
|
2390 |
return $pay_later_label;
|
2391 |
},
|
2392 |
+
|
2393 |
+
'wcgateway.settings.card_billing_data_mode.default' => static function ( ContainerInterface $container ): string {
|
2394 |
+
return $container->get( 'api.shop.is-latin-america' ) ? CardBillingMode::MINIMAL_INPUT : CardBillingMode::USE_WC;
|
2395 |
+
},
|
2396 |
+
'wcgateway.settings.card_billing_data_mode' => static function ( ContainerInterface $container ): string {
|
2397 |
+
$settings = $container->get( 'wcgateway.settings' );
|
2398 |
+
assert( $settings instanceof ContainerInterface );
|
2399 |
+
|
2400 |
+
return $settings->has( 'card_billing_data_mode' ) ?
|
2401 |
+
(string) $settings->get( 'card_billing_data_mode' ) :
|
2402 |
+
$container->get( 'wcgateway.settings.card_billing_data_mode.default' );
|
2403 |
+
},
|
2404 |
+
|
2405 |
+
'wcgateway.settings.allow_card_button_gateway.default' => static function ( ContainerInterface $container ): bool {
|
2406 |
+
return $container->get( 'api.shop.is-latin-america' );
|
2407 |
+
},
|
2408 |
+
'wcgateway.settings.allow_card_button_gateway' => static function ( ContainerInterface $container ): bool {
|
2409 |
+
if ( defined( 'PPCP_FLAG_SEPARATE_APM_BUTTONS' ) && PPCP_FLAG_SEPARATE_APM_BUTTONS === false ) {
|
2410 |
+
return false;
|
2411 |
+
}
|
2412 |
+
|
2413 |
+
$settings = $container->get( 'wcgateway.settings' );
|
2414 |
+
assert( $settings instanceof ContainerInterface );
|
2415 |
+
|
2416 |
+
return $settings->has( 'allow_card_button_gateway' ) ?
|
2417 |
+
(bool) $settings->get( 'allow_card_button_gateway' ) :
|
2418 |
+
$container->get( 'wcgateway.settings.allow_card_button_gateway.default' );
|
2419 |
+
},
|
2420 |
);
|
modules/ppcp-wc-gateway/src/CardBillingMode.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Possible values of card_billing_data_mode.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare( strict_types=1 );
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class CardBillingMode
|
14 |
+
*/
|
15 |
+
interface CardBillingMode {
|
16 |
+
public const USE_WC = 'use_wc';
|
17 |
+
public const MINIMAL_INPUT = 'minimal_input';
|
18 |
+
public const NO_WC = 'no_wc';
|
19 |
+
}
|
modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php
CHANGED
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Checkout;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|
|
13 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
14 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
15 |
use Psr\Container\ContainerInterface;
|
@@ -59,9 +60,10 @@ class DisableGateways {
|
|
59 |
if ( ! isset( $methods[ PayPalGateway::ID ] ) && ! isset( $methods[ CreditCardGateway::ID ] ) ) {
|
60 |
return $methods;
|
61 |
}
|
62 |
-
if ( $this->
|
63 |
unset( $methods[ PayPalGateway::ID ] );
|
64 |
unset( $methods[ CreditCardGateway::ID ] );
|
|
|
65 |
return $methods;
|
66 |
}
|
67 |
|
@@ -77,21 +79,15 @@ class DisableGateways {
|
|
77 |
return $methods;
|
78 |
}
|
79 |
|
80 |
-
if ( $this->is_credit_card() ) {
|
81 |
-
return array(
|
82 |
-
CreditCardGateway::ID => $methods[ CreditCardGateway::ID ],
|
83 |
-
PayPalGateway::ID => $methods[ PayPalGateway::ID ],
|
84 |
-
);
|
85 |
-
}
|
86 |
return array( PayPalGateway::ID => $methods[ PayPalGateway::ID ] );
|
87 |
}
|
88 |
|
89 |
/**
|
90 |
-
* Whether
|
91 |
*
|
92 |
* @return bool
|
93 |
*/
|
94 |
-
private function
|
95 |
if ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) ) {
|
96 |
return true;
|
97 |
}
|
@@ -110,22 +106,20 @@ class DisableGateways {
|
|
110 |
* @return bool
|
111 |
*/
|
112 |
private function needs_to_disable_gateways(): bool {
|
113 |
-
return $this->session_handler->order() !== null;
|
114 |
-
}
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Whether the current PayPal session is done via DCC payment.
|
118 |
-
*
|
119 |
-
* @return bool
|
120 |
-
*/
|
121 |
-
private function is_credit_card(): bool {
|
122 |
$order = $this->session_handler->order();
|
123 |
if ( ! $order ) {
|
124 |
return false;
|
125 |
}
|
126 |
-
|
127 |
-
|
|
|
|
|
128 |
}
|
|
|
|
|
|
|
|
|
|
|
129 |
return true;
|
130 |
}
|
131 |
}
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Checkout;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
13 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
14 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
15 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
16 |
use Psr\Container\ContainerInterface;
|
60 |
if ( ! isset( $methods[ PayPalGateway::ID ] ) && ! isset( $methods[ CreditCardGateway::ID ] ) ) {
|
61 |
return $methods;
|
62 |
}
|
63 |
+
if ( $this->disable_all_gateways() ) {
|
64 |
unset( $methods[ PayPalGateway::ID ] );
|
65 |
unset( $methods[ CreditCardGateway::ID ] );
|
66 |
+
unset( $methods[ CardButtonGateway::ID ] );
|
67 |
return $methods;
|
68 |
}
|
69 |
|
79 |
return $methods;
|
80 |
}
|
81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
return array( PayPalGateway::ID => $methods[ PayPalGateway::ID ] );
|
83 |
}
|
84 |
|
85 |
/**
|
86 |
+
* Whether all gateways should be disabled or not.
|
87 |
*
|
88 |
* @return bool
|
89 |
*/
|
90 |
+
private function disable_all_gateways() : bool {
|
91 |
if ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) ) {
|
92 |
return true;
|
93 |
}
|
106 |
* @return bool
|
107 |
*/
|
108 |
private function needs_to_disable_gateways(): bool {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
$order = $this->session_handler->order();
|
110 |
if ( ! $order ) {
|
111 |
return false;
|
112 |
}
|
113 |
+
|
114 |
+
$source = $order->payment_source();
|
115 |
+
if ( $source && $source->card() ) {
|
116 |
+
return false; // DCC.
|
117 |
}
|
118 |
+
|
119 |
+
if ( 'card' === $this->session_handler->funding_source() ) {
|
120 |
+
return false; // Card buttons.
|
121 |
+
}
|
122 |
+
|
123 |
return true;
|
124 |
}
|
125 |
}
|
modules/ppcp-wc-gateway/src/Endpoint/ReturnUrlEndpoint.php
CHANGED
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Endpoint;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
|
|
13 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
14 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PrefixTrait;
|
15 |
|
@@ -51,7 +52,7 @@ class ReturnUrlEndpoint {
|
|
51 |
/**
|
52 |
* Handles the incoming request.
|
53 |
*/
|
54 |
-
public function handle_request() {
|
55 |
|
56 |
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
57 |
if ( ! isset( $_GET['token'] ) ) {
|
@@ -68,7 +69,12 @@ class ReturnUrlEndpoint {
|
|
68 |
}
|
69 |
|
70 |
$wc_order = wc_get_order( $wc_order_id );
|
71 |
-
if ( ! $wc_order ) {
|
|
|
|
|
|
|
|
|
|
|
72 |
exit();
|
73 |
}
|
74 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Endpoint;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
13 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
14 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
15 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PrefixTrait;
|
16 |
|
52 |
/**
|
53 |
* Handles the incoming request.
|
54 |
*/
|
55 |
+
public function handle_request(): void {
|
56 |
|
57 |
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
58 |
if ( ! isset( $_GET['token'] ) ) {
|
69 |
}
|
70 |
|
71 |
$wc_order = wc_get_order( $wc_order_id );
|
72 |
+
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
73 |
+
exit();
|
74 |
+
}
|
75 |
+
|
76 |
+
if ( $wc_order->get_payment_method() === OXXOGateway::ID ) {
|
77 |
+
wp_safe_redirect( wc_get_checkout_url() );
|
78 |
exit();
|
79 |
}
|
80 |
|
modules/ppcp-wc-gateway/src/Exception/GatewayGenericException.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Wrapper for more detailed gateway error.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Exception
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Exception;
|
11 |
+
|
12 |
+
use Exception;
|
13 |
+
use Throwable;
|
14 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\Messages;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Class GatewayGenericException
|
18 |
+
*/
|
19 |
+
class GatewayGenericException extends Exception {
|
20 |
+
/**
|
21 |
+
* GatewayGenericException constructor.
|
22 |
+
*
|
23 |
+
* @param Throwable|null $inner The exception.
|
24 |
+
*/
|
25 |
+
public function __construct( ?Throwable $inner = null ) {
|
26 |
+
parent::__construct(
|
27 |
+
Messages::generic_payment_error_message(),
|
28 |
+
$inner ? (int) $inner->getCode() : 0,
|
29 |
+
$inner
|
30 |
+
);
|
31 |
+
}
|
32 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
ADDED
@@ -0,0 +1,364 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The PayPal Card Button Gateway
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
+
|
12 |
+
use Exception;
|
13 |
+
use Psr\Log\LoggerInterface;
|
14 |
+
use WC_Order;
|
15 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
16 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
17 |
+
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
18 |
+
use WooCommerce\PayPalCommerce\Onboarding\State;
|
19 |
+
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
20 |
+
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
21 |
+
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
22 |
+
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
23 |
+
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
24 |
+
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
25 |
+
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
26 |
+
use Psr\Container\ContainerInterface;
|
27 |
+
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Class CardButtonGateway
|
31 |
+
*/
|
32 |
+
class CardButtonGateway extends \WC_Payment_Gateway {
|
33 |
+
|
34 |
+
use ProcessPaymentTrait, FreeTrialHandlerTrait, GatewaySettingsRendererTrait;
|
35 |
+
|
36 |
+
const ID = 'ppcp-card-button-gateway';
|
37 |
+
|
38 |
+
/**
|
39 |
+
* The Settings Renderer.
|
40 |
+
*
|
41 |
+
* @var SettingsRenderer
|
42 |
+
*/
|
43 |
+
protected $settings_renderer;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* The processor for orders.
|
47 |
+
*
|
48 |
+
* @var OrderProcessor
|
49 |
+
*/
|
50 |
+
protected $order_processor;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* The settings.
|
54 |
+
*
|
55 |
+
* @var ContainerInterface
|
56 |
+
*/
|
57 |
+
protected $config;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* The Session Handler.
|
61 |
+
*
|
62 |
+
* @var SessionHandler
|
63 |
+
*/
|
64 |
+
protected $session_handler;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* The Refund Processor.
|
68 |
+
*
|
69 |
+
* @var RefundProcessor
|
70 |
+
*/
|
71 |
+
private $refund_processor;
|
72 |
+
|
73 |
+
/**
|
74 |
+
* The state.
|
75 |
+
*
|
76 |
+
* @var State
|
77 |
+
*/
|
78 |
+
protected $state;
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Service able to provide transaction url for an order.
|
82 |
+
*
|
83 |
+
* @var TransactionUrlProvider
|
84 |
+
*/
|
85 |
+
protected $transaction_url_provider;
|
86 |
+
|
87 |
+
/**
|
88 |
+
* The subscription helper.
|
89 |
+
*
|
90 |
+
* @var SubscriptionHelper
|
91 |
+
*/
|
92 |
+
protected $subscription_helper;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* The payment token repository.
|
96 |
+
*
|
97 |
+
* @var PaymentTokenRepository
|
98 |
+
*/
|
99 |
+
protected $payment_token_repository;
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Whether the plugin is in onboarded state.
|
103 |
+
*
|
104 |
+
* @var bool
|
105 |
+
*/
|
106 |
+
private $onboarded;
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Whether the gateway should be enabled by default.
|
110 |
+
*
|
111 |
+
* @var bool
|
112 |
+
*/
|
113 |
+
private $default_enabled;
|
114 |
+
|
115 |
+
/**
|
116 |
+
* The environment.
|
117 |
+
*
|
118 |
+
* @var Environment
|
119 |
+
*/
|
120 |
+
protected $environment;
|
121 |
+
|
122 |
+
/**
|
123 |
+
* The logger.
|
124 |
+
*
|
125 |
+
* @var LoggerInterface
|
126 |
+
*/
|
127 |
+
private $logger;
|
128 |
+
|
129 |
+
/**
|
130 |
+
* CardButtonGateway constructor.
|
131 |
+
*
|
132 |
+
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
133 |
+
* @param OrderProcessor $order_processor The Order Processor.
|
134 |
+
* @param ContainerInterface $config The settings.
|
135 |
+
* @param SessionHandler $session_handler The Session Handler.
|
136 |
+
* @param RefundProcessor $refund_processor The Refund Processor.
|
137 |
+
* @param State $state The state.
|
138 |
+
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
139 |
+
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
140 |
+
* @param bool $default_enabled Whether the gateway should be enabled by default.
|
141 |
+
* @param Environment $environment The environment.
|
142 |
+
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
143 |
+
* @param LoggerInterface $logger The logger.
|
144 |
+
*/
|
145 |
+
public function __construct(
|
146 |
+
SettingsRenderer $settings_renderer,
|
147 |
+
OrderProcessor $order_processor,
|
148 |
+
ContainerInterface $config,
|
149 |
+
SessionHandler $session_handler,
|
150 |
+
RefundProcessor $refund_processor,
|
151 |
+
State $state,
|
152 |
+
TransactionUrlProvider $transaction_url_provider,
|
153 |
+
SubscriptionHelper $subscription_helper,
|
154 |
+
bool $default_enabled,
|
155 |
+
Environment $environment,
|
156 |
+
PaymentTokenRepository $payment_token_repository,
|
157 |
+
LoggerInterface $logger
|
158 |
+
) {
|
159 |
+
$this->id = self::ID;
|
160 |
+
$this->settings_renderer = $settings_renderer;
|
161 |
+
$this->order_processor = $order_processor;
|
162 |
+
$this->config = $config;
|
163 |
+
$this->session_handler = $session_handler;
|
164 |
+
$this->refund_processor = $refund_processor;
|
165 |
+
$this->state = $state;
|
166 |
+
$this->transaction_url_provider = $transaction_url_provider;
|
167 |
+
$this->subscription_helper = $subscription_helper;
|
168 |
+
$this->default_enabled = $default_enabled;
|
169 |
+
$this->environment = $environment;
|
170 |
+
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
171 |
+
$this->payment_token_repository = $payment_token_repository;
|
172 |
+
$this->logger = $logger;
|
173 |
+
|
174 |
+
if ( $this->onboarded ) {
|
175 |
+
$this->supports = array( 'refunds' );
|
176 |
+
}
|
177 |
+
if (
|
178 |
+
defined( 'PPCP_FLAG_SUBSCRIPTION' )
|
179 |
+
&& PPCP_FLAG_SUBSCRIPTION
|
180 |
+
&& $this->gateways_enabled()
|
181 |
+
&& $this->vault_setting_enabled()
|
182 |
+
) {
|
183 |
+
$this->supports = array(
|
184 |
+
'refunds',
|
185 |
+
'products',
|
186 |
+
'subscriptions',
|
187 |
+
'subscription_cancellation',
|
188 |
+
'subscription_suspension',
|
189 |
+
'subscription_reactivation',
|
190 |
+
'subscription_amount_changes',
|
191 |
+
'subscription_date_changes',
|
192 |
+
'subscription_payment_method_change',
|
193 |
+
'subscription_payment_method_change_customer',
|
194 |
+
'subscription_payment_method_change_admin',
|
195 |
+
'multiple_subscriptions',
|
196 |
+
);
|
197 |
+
}
|
198 |
+
|
199 |
+
$this->method_title = __( 'PayPal Card Button', 'woocommerce-paypal-payments' );
|
200 |
+
$this->method_description = __( 'The separate payment gateway with the card button. If disabled, the button is included in the PayPal gateway.', 'woocommerce-paypal-payments' );
|
201 |
+
$this->title = $this->get_option( 'title', __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ) );
|
202 |
+
$this->description = $this->get_option( 'description', '' );
|
203 |
+
|
204 |
+
$this->init_form_fields();
|
205 |
+
$this->init_settings();
|
206 |
+
|
207 |
+
add_action(
|
208 |
+
'woocommerce_update_options_payment_gateways_' . $this->id,
|
209 |
+
array(
|
210 |
+
$this,
|
211 |
+
'process_admin_options',
|
212 |
+
)
|
213 |
+
);
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Whether the Gateway needs to be setup.
|
218 |
+
*
|
219 |
+
* @return bool
|
220 |
+
*/
|
221 |
+
public function needs_setup(): bool {
|
222 |
+
return ! $this->onboarded;
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Initializes the form fields.
|
227 |
+
*/
|
228 |
+
public function init_form_fields() {
|
229 |
+
$this->form_fields = array(
|
230 |
+
'enabled' => array(
|
231 |
+
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
232 |
+
'type' => 'checkbox',
|
233 |
+
'label' => __( 'Enable PayPal Card Button', 'woocommerce-paypal-payments' ),
|
234 |
+
'default' => $this->default_enabled ? 'yes' : 'no',
|
235 |
+
'desc_tip' => true,
|
236 |
+
'description' => __( 'Enable/Disable the separate payment gateway with the card button.', 'woocommerce-paypal-payments' ),
|
237 |
+
),
|
238 |
+
'title' => array(
|
239 |
+
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
240 |
+
'type' => 'text',
|
241 |
+
'default' => $this->title,
|
242 |
+
'desc_tip' => true,
|
243 |
+
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
244 |
+
),
|
245 |
+
'description' => array(
|
246 |
+
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
247 |
+
'type' => 'text',
|
248 |
+
'default' => $this->description,
|
249 |
+
'desc_tip' => true,
|
250 |
+
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
251 |
+
),
|
252 |
+
'ppcp' => array(
|
253 |
+
'type' => 'ppcp',
|
254 |
+
),
|
255 |
+
);
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Process payment for a WooCommerce order.
|
260 |
+
*
|
261 |
+
* @param int $order_id The WooCommerce order id.
|
262 |
+
*
|
263 |
+
* @return array
|
264 |
+
*/
|
265 |
+
public function process_payment( $order_id ) {
|
266 |
+
$wc_order = wc_get_order( $order_id );
|
267 |
+
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
268 |
+
return $this->handle_payment_failure(
|
269 |
+
null,
|
270 |
+
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
271 |
+
);
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* If customer has chosen change Subscription payment.
|
276 |
+
*/
|
277 |
+
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
278 |
+
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
279 |
+
if ( $saved_paypal_payment ) {
|
280 |
+
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
281 |
+
|
282 |
+
return $this->handle_payment_success( $wc_order );
|
283 |
+
}
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* If the WC_Order is paid through the approved webhook.
|
288 |
+
*/
|
289 |
+
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
290 |
+
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
291 |
+
return $this->handle_payment_success( $wc_order );
|
292 |
+
}
|
293 |
+
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
294 |
+
|
295 |
+
try {
|
296 |
+
if ( ! $this->order_processor->process( $wc_order ) ) {
|
297 |
+
return $this->handle_payment_failure(
|
298 |
+
$wc_order,
|
299 |
+
new Exception(
|
300 |
+
$this->order_processor->last_error()
|
301 |
+
)
|
302 |
+
);
|
303 |
+
}
|
304 |
+
|
305 |
+
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
306 |
+
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
307 |
+
}
|
308 |
+
|
309 |
+
return $this->handle_payment_success( $wc_order );
|
310 |
+
} catch ( PayPalApiException $error ) {
|
311 |
+
return $this->handle_payment_failure(
|
312 |
+
$wc_order,
|
313 |
+
new Exception(
|
314 |
+
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
315 |
+
$error->getCode(),
|
316 |
+
$error
|
317 |
+
)
|
318 |
+
);
|
319 |
+
} catch ( RuntimeException $error ) {
|
320 |
+
return $this->handle_payment_failure( $wc_order, $error );
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Process refund.
|
326 |
+
*
|
327 |
+
* If the gateway declares 'refunds' support, this will allow it to refund.
|
328 |
+
* a passed in amount.
|
329 |
+
*
|
330 |
+
* @param int $order_id Order ID.
|
331 |
+
* @param float $amount Refund amount.
|
332 |
+
* @param string $reason Refund reason.
|
333 |
+
* @return boolean True or false based on success, or a WP_Error object.
|
334 |
+
*/
|
335 |
+
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
336 |
+
$order = wc_get_order( $order_id );
|
337 |
+
if ( ! is_a( $order, \WC_Order::class ) ) {
|
338 |
+
return false;
|
339 |
+
}
|
340 |
+
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Return transaction url for this gateway and given order.
|
345 |
+
*
|
346 |
+
* @param \WC_Order $order WC order to get transaction url by.
|
347 |
+
*
|
348 |
+
* @return string
|
349 |
+
*/
|
350 |
+
public function get_transaction_url( $order ): string {
|
351 |
+
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
352 |
+
|
353 |
+
return parent::get_transaction_url( $order );
|
354 |
+
}
|
355 |
+
|
356 |
+
/**
|
357 |
+
* Returns the settings renderer.
|
358 |
+
*
|
359 |
+
* @return SettingsRenderer
|
360 |
+
*/
|
361 |
+
protected function settings_renderer(): SettingsRenderer {
|
362 |
+
return $this->settings_renderer;
|
363 |
+
}
|
364 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
CHANGED
@@ -9,20 +9,30 @@ declare(strict_types=1);
|
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
|
|
|
12 |
use Psr\Log\LoggerInterface;
|
|
|
13 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
14 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
|
|
|
|
|
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
17 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
18 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
19 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
20 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|
|
21 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
22 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
|
|
23 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
|
|
24 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
|
|
25 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
|
|
26 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
27 |
use Psr\Container\ContainerInterface;
|
28 |
|
@@ -31,7 +41,8 @@ use Psr\Container\ContainerInterface;
|
|
31 |
*/
|
32 |
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
33 |
|
34 |
-
use ProcessPaymentTrait
|
|
|
35 |
|
36 |
const ID = 'ppcp-credit-card-gateway';
|
37 |
|
@@ -203,15 +214,25 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|
203 |
Environment $environment,
|
204 |
PaymentsEndpoint $payments_endpoint
|
205 |
) {
|
206 |
-
|
207 |
$this->id = self::ID;
|
|
|
208 |
$this->order_processor = $order_processor;
|
209 |
$this->authorized_payments_processor = $authorized_payments_processor;
|
210 |
-
$this->settings_renderer = $settings_renderer;
|
211 |
$this->config = $config;
|
|
|
212 |
$this->session_handler = $session_handler;
|
213 |
$this->refund_processor = $refund_processor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
$this->environment = $environment;
|
|
|
215 |
|
216 |
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
217 |
$this->supports = array( 'refunds' );
|
@@ -261,18 +282,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|
261 |
'process_admin_options',
|
262 |
)
|
263 |
);
|
264 |
-
|
265 |
-
$this->module_url = $module_url;
|
266 |
-
$this->payment_token_repository = $payment_token_repository;
|
267 |
-
$this->purchase_unit_factory = $purchase_unit_factory;
|
268 |
-
$this->shipping_preference_factory = $shipping_preference_factory;
|
269 |
-
$this->payer_factory = $payer_factory;
|
270 |
-
$this->order_endpoint = $order_endpoint;
|
271 |
-
$this->transaction_url_provider = $transaction_url_provider;
|
272 |
-
$this->subscription_helper = $subscription_helper;
|
273 |
-
$this->logger = $logger;
|
274 |
-
$this->payments_endpoint = $payments_endpoint;
|
275 |
-
$this->state = $state;
|
276 |
}
|
277 |
|
278 |
/**
|
@@ -295,20 +304,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|
295 |
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
296 |
}
|
297 |
|
298 |
-
/**
|
299 |
-
* Renders the settings.
|
300 |
-
*
|
301 |
-
* @return string
|
302 |
-
*/
|
303 |
-
public function generate_ppcp_html(): string {
|
304 |
-
|
305 |
-
ob_start();
|
306 |
-
$this->settings_renderer->render();
|
307 |
-
$content = ob_get_contents();
|
308 |
-
ob_end_clean();
|
309 |
-
return $content;
|
310 |
-
}
|
311 |
-
|
312 |
/**
|
313 |
* Replace WooCommerce credit card field label.
|
314 |
*
|
@@ -409,6 +404,158 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|
409 |
return $this->is_enabled();
|
410 |
}
|
411 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
|
413 |
/**
|
414 |
* Process refund.
|
@@ -500,11 +647,11 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|
500 |
}
|
501 |
|
502 |
/**
|
503 |
-
* Returns the
|
504 |
*
|
505 |
-
* @return
|
506 |
*/
|
507 |
-
protected function
|
508 |
-
return $this->
|
509 |
}
|
510 |
}
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
|
12 |
+
use Exception;
|
13 |
use Psr\Log\LoggerInterface;
|
14 |
+
use WC_Order;
|
15 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
17 |
+
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
18 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
19 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
20 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
21 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
22 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
23 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
24 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
25 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
26 |
+
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
27 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
28 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
29 |
+
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
30 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
31 |
+
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
32 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
33 |
+
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
34 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
35 |
+
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
36 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
37 |
use Psr\Container\ContainerInterface;
|
38 |
|
41 |
*/
|
42 |
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
43 |
|
44 |
+
use ProcessPaymentTrait, OrderMetaTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait,
|
45 |
+
GatewaySettingsRendererTrait;
|
46 |
|
47 |
const ID = 'ppcp-credit-card-gateway';
|
48 |
|
214 |
Environment $environment,
|
215 |
PaymentsEndpoint $payments_endpoint
|
216 |
) {
|
|
|
217 |
$this->id = self::ID;
|
218 |
+
$this->settings_renderer = $settings_renderer;
|
219 |
$this->order_processor = $order_processor;
|
220 |
$this->authorized_payments_processor = $authorized_payments_processor;
|
|
|
221 |
$this->config = $config;
|
222 |
+
$this->module_url = $module_url;
|
223 |
$this->session_handler = $session_handler;
|
224 |
$this->refund_processor = $refund_processor;
|
225 |
+
$this->state = $state;
|
226 |
+
$this->transaction_url_provider = $transaction_url_provider;
|
227 |
+
$this->payment_token_repository = $payment_token_repository;
|
228 |
+
$this->purchase_unit_factory = $purchase_unit_factory;
|
229 |
+
$this->shipping_preference_factory = $shipping_preference_factory;
|
230 |
+
$this->payer_factory = $payer_factory;
|
231 |
+
$this->order_endpoint = $order_endpoint;
|
232 |
+
$this->subscription_helper = $subscription_helper;
|
233 |
+
$this->logger = $logger;
|
234 |
$this->environment = $environment;
|
235 |
+
$this->payments_endpoint = $payments_endpoint;
|
236 |
|
237 |
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
238 |
$this->supports = array( 'refunds' );
|
282 |
'process_admin_options',
|
283 |
)
|
284 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
}
|
286 |
|
287 |
/**
|
304 |
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
305 |
}
|
306 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
307 |
/**
|
308 |
* Replace WooCommerce credit card field label.
|
309 |
*
|
404 |
return $this->is_enabled();
|
405 |
}
|
406 |
|
407 |
+
/**
|
408 |
+
* Process payment for a WooCommerce order.
|
409 |
+
*
|
410 |
+
* @param int $order_id The WooCommerce order id.
|
411 |
+
*
|
412 |
+
* @return array
|
413 |
+
*/
|
414 |
+
public function process_payment( $order_id ) {
|
415 |
+
$wc_order = wc_get_order( $order_id );
|
416 |
+
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
417 |
+
return $this->handle_payment_failure(
|
418 |
+
null,
|
419 |
+
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
420 |
+
);
|
421 |
+
}
|
422 |
+
|
423 |
+
/**
|
424 |
+
* If customer has chosen a saved credit card payment.
|
425 |
+
*/
|
426 |
+
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
427 |
+
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
428 |
+
if ( $saved_credit_card && ! isset( $change_payment ) ) {
|
429 |
+
|
430 |
+
$user_id = (int) $wc_order->get_customer_id();
|
431 |
+
$customer = new \WC_Customer( $user_id );
|
432 |
+
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
433 |
+
|
434 |
+
$selected_token = null;
|
435 |
+
foreach ( $tokens as $token ) {
|
436 |
+
if ( $token->id() === $saved_credit_card ) {
|
437 |
+
$selected_token = $token;
|
438 |
+
break;
|
439 |
+
}
|
440 |
+
}
|
441 |
+
|
442 |
+
if ( ! $selected_token ) {
|
443 |
+
return $this->handle_payment_failure(
|
444 |
+
$wc_order,
|
445 |
+
new GatewayGenericException( new Exception( 'Saved card token not found.' ) )
|
446 |
+
);
|
447 |
+
}
|
448 |
+
|
449 |
+
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
450 |
+
$payer = $this->payer_factory->from_customer( $customer );
|
451 |
+
|
452 |
+
$shipping_preference = $this->shipping_preference_factory->from_state(
|
453 |
+
$purchase_unit,
|
454 |
+
''
|
455 |
+
);
|
456 |
+
|
457 |
+
try {
|
458 |
+
$order = $this->order_endpoint->create(
|
459 |
+
array( $purchase_unit ),
|
460 |
+
$shipping_preference,
|
461 |
+
$payer,
|
462 |
+
$selected_token
|
463 |
+
);
|
464 |
+
|
465 |
+
$this->add_paypal_meta( $wc_order, $order, $this->environment );
|
466 |
+
|
467 |
+
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
468 |
+
return $this->handle_payment_failure(
|
469 |
+
$wc_order,
|
470 |
+
new GatewayGenericException( new Exception( "Unexpected status for order {$order->id()} using a saved card: {$order->status()->name()}." ) )
|
471 |
+
);
|
472 |
+
}
|
473 |
+
|
474 |
+
if ( ! in_array(
|
475 |
+
$order->intent(),
|
476 |
+
array( 'CAPTURE', 'AUTHORIZE' ),
|
477 |
+
true
|
478 |
+
) ) {
|
479 |
+
return $this->handle_payment_failure(
|
480 |
+
$wc_order,
|
481 |
+
new GatewayGenericException( new Exception( "Could neither capture nor authorize order {$order->id()} using a saved card. Status: {$order->status()->name()}. Intent: {$order->intent()}." ) )
|
482 |
+
);
|
483 |
+
}
|
484 |
+
|
485 |
+
if ( $order->intent() === 'AUTHORIZE' ) {
|
486 |
+
$order = $this->order_endpoint->authorize( $order );
|
487 |
+
|
488 |
+
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
489 |
+
}
|
490 |
+
|
491 |
+
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
492 |
+
if ( $transaction_id ) {
|
493 |
+
$this->update_transaction_id( $transaction_id, $wc_order );
|
494 |
+
}
|
495 |
+
|
496 |
+
$this->handle_new_order_status( $order, $wc_order );
|
497 |
+
|
498 |
+
if ( $this->is_free_trial_order( $wc_order ) ) {
|
499 |
+
$this->authorized_payments_processor->void_authorizations( $order );
|
500 |
+
$wc_order->payment_complete();
|
501 |
+
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
502 |
+
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
503 |
+
}
|
504 |
+
|
505 |
+
return $this->handle_payment_success( $wc_order );
|
506 |
+
} catch ( RuntimeException $error ) {
|
507 |
+
return $this->handle_payment_failure( $wc_order, $error );
|
508 |
+
}
|
509 |
+
}
|
510 |
+
|
511 |
+
/**
|
512 |
+
* If customer has chosen change Subscription payment.
|
513 |
+
*/
|
514 |
+
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
515 |
+
if ( $saved_credit_card ) {
|
516 |
+
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
517 |
+
|
518 |
+
return $this->handle_payment_success( $wc_order );
|
519 |
+
}
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* If the WC_Order is paid through the approved webhook.
|
524 |
+
*/
|
525 |
+
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
526 |
+
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
527 |
+
return $this->handle_payment_success( $wc_order );
|
528 |
+
}
|
529 |
+
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
530 |
+
|
531 |
+
try {
|
532 |
+
if ( ! $this->order_processor->process( $wc_order ) ) {
|
533 |
+
return $this->handle_payment_failure(
|
534 |
+
$wc_order,
|
535 |
+
new Exception(
|
536 |
+
$this->order_processor->last_error()
|
537 |
+
)
|
538 |
+
);
|
539 |
+
}
|
540 |
+
|
541 |
+
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
542 |
+
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
543 |
+
}
|
544 |
+
|
545 |
+
return $this->handle_payment_success( $wc_order );
|
546 |
+
} catch ( PayPalApiException $error ) {
|
547 |
+
return $this->handle_payment_failure(
|
548 |
+
$wc_order,
|
549 |
+
new Exception(
|
550 |
+
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
551 |
+
$error->getCode(),
|
552 |
+
$error
|
553 |
+
)
|
554 |
+
);
|
555 |
+
} catch ( RuntimeException $error ) {
|
556 |
+
return $this->handle_payment_failure( $wc_order, $error );
|
557 |
+
}
|
558 |
+
}
|
559 |
|
560 |
/**
|
561 |
* Process refund.
|
647 |
}
|
648 |
|
649 |
/**
|
650 |
+
* Returns the settings renderer.
|
651 |
*
|
652 |
+
* @return SettingsRenderer
|
653 |
*/
|
654 |
+
protected function settings_renderer(): SettingsRenderer {
|
655 |
+
return $this->settings_renderer;
|
656 |
}
|
657 |
}
|
modules/ppcp-wc-gateway/src/Gateway/GatewaySettingsRendererTrait.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Adds generate_ppcp_html method for rendering settings.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare( strict_types=1 );
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
+
|
12 |
+
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Trait GatewaySettingsRendererTrait
|
16 |
+
*/
|
17 |
+
trait GatewaySettingsRendererTrait {
|
18 |
+
/**
|
19 |
+
* Renders the settings.
|
20 |
+
*
|
21 |
+
* @return string
|
22 |
+
*/
|
23 |
+
public function generate_ppcp_html(): string {
|
24 |
+
ob_start();
|
25 |
+
$this->settings_renderer()->render();
|
26 |
+
$content = ob_get_contents();
|
27 |
+
ob_end_clean();
|
28 |
+
return $content;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Returns the settings renderer.
|
33 |
+
*
|
34 |
+
* @return SettingsRenderer
|
35 |
+
*/
|
36 |
+
abstract protected function settings_renderer(): SettingsRenderer;
|
37 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/Messages.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Common messages.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class Messages
|
14 |
+
*/
|
15 |
+
class Messages {
|
16 |
+
/**
|
17 |
+
* The generic payment failure message.
|
18 |
+
*
|
19 |
+
* @return string
|
20 |
+
*/
|
21 |
+
public static function generic_payment_error_message(): string {
|
22 |
+
return apply_filters(
|
23 |
+
'woocommerce_paypal_payments_generic_payment_error_message',
|
24 |
+
__( 'Failed to process the payment. Please try again or contact the shop admin.', 'woocommerce-paypal-payments' )
|
25 |
+
);
|
26 |
+
}
|
27 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXO.php
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* OXXO integration.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
11 |
+
|
12 |
+
use WC_Order;
|
13 |
+
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Class OXXO.
|
17 |
+
*/
|
18 |
+
class OXXO {
|
19 |
+
|
20 |
+
/**
|
21 |
+
* The checkout helper.
|
22 |
+
*
|
23 |
+
* @var CheckoutHelper
|
24 |
+
*/
|
25 |
+
protected $checkout_helper;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* The module URL.
|
29 |
+
*
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
+
protected $module_url;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* The asset version.
|
36 |
+
*
|
37 |
+
* @var string
|
38 |
+
*/
|
39 |
+
protected $asset_version;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* OXXO constructor.
|
43 |
+
*
|
44 |
+
* @param CheckoutHelper $checkout_helper The checkout helper.
|
45 |
+
* @param string $module_url The module URL.
|
46 |
+
* @param string $asset_version The asset version.
|
47 |
+
*/
|
48 |
+
public function __construct(
|
49 |
+
CheckoutHelper $checkout_helper,
|
50 |
+
string $module_url,
|
51 |
+
string $asset_version
|
52 |
+
) {
|
53 |
+
|
54 |
+
$this->checkout_helper = $checkout_helper;
|
55 |
+
$this->module_url = $module_url;
|
56 |
+
$this->asset_version = $asset_version;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Initializes OXXO integration.
|
61 |
+
*/
|
62 |
+
public function init(): void {
|
63 |
+
|
64 |
+
add_filter(
|
65 |
+
'woocommerce_available_payment_gateways',
|
66 |
+
function ( array $methods ): array {
|
67 |
+
|
68 |
+
if ( ! $this->checkout_allowed_for_oxxo() ) {
|
69 |
+
unset( $methods[ OXXOGateway::ID ] );
|
70 |
+
}
|
71 |
+
|
72 |
+
return $methods;
|
73 |
+
}
|
74 |
+
);
|
75 |
+
|
76 |
+
add_action(
|
77 |
+
'wp_enqueue_scripts',
|
78 |
+
array( $this, 'register_assets' )
|
79 |
+
);
|
80 |
+
|
81 |
+
add_filter(
|
82 |
+
'woocommerce_thankyou_order_received_text',
|
83 |
+
function( string $message, WC_Order $order ) {
|
84 |
+
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' ) ?? '';
|
85 |
+
|
86 |
+
$button = '';
|
87 |
+
if ( $payer_action ) {
|
88 |
+
$button = '<p><a id="ppcp-oxxo-payer-action" class="button" href="' . $payer_action . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
89 |
+
}
|
90 |
+
|
91 |
+
return $message . ' ' . $button;
|
92 |
+
},
|
93 |
+
10,
|
94 |
+
2
|
95 |
+
);
|
96 |
+
|
97 |
+
add_action(
|
98 |
+
'woocommerce_email_before_order_table',
|
99 |
+
function ( WC_Order $order, bool $sent_to_admin ) {
|
100 |
+
if (
|
101 |
+
! $sent_to_admin
|
102 |
+
&& $order->get_payment_method() === OXXOGateway::ID
|
103 |
+
&& $order->has_status( 'on-hold' )
|
104 |
+
) {
|
105 |
+
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' ) ?? '';
|
106 |
+
if ( $payer_action ) {
|
107 |
+
echo '<p><a class="button" href="' . esc_url( $payer_action ) . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
108 |
+
}
|
109 |
+
}
|
110 |
+
},
|
111 |
+
10,
|
112 |
+
2
|
113 |
+
);
|
114 |
+
|
115 |
+
add_filter(
|
116 |
+
'ppcp_payment_capture_reversed_webhook_update_status_note',
|
117 |
+
function( string $note, WC_Order $wc_order, string $event_type ): string {
|
118 |
+
if ( $wc_order->get_payment_method() === OXXOGateway::ID && $event_type === 'PAYMENT.CAPTURE.DENIED' ) {
|
119 |
+
$note = __( 'OXXO voucher has expired or the buyer didn\'t complete the payment successfully.', 'woocommerce-paypal-payments' );
|
120 |
+
}
|
121 |
+
|
122 |
+
return $note;
|
123 |
+
},
|
124 |
+
10,
|
125 |
+
3
|
126 |
+
);
|
127 |
+
|
128 |
+
add_action(
|
129 |
+
'add_meta_boxes',
|
130 |
+
function( string $post_type ) {
|
131 |
+
if ( $post_type === 'shop_order' ) {
|
132 |
+
$post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_STRING );
|
133 |
+
$order = wc_get_order( $post_id );
|
134 |
+
if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() === OXXOGateway::ID ) {
|
135 |
+
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' );
|
136 |
+
if ( $payer_action ) {
|
137 |
+
add_meta_box(
|
138 |
+
'ppcp_oxxo_payer_action',
|
139 |
+
__( 'OXXO Voucher/Ticket', 'woocommerce-paypal-payments' ),
|
140 |
+
function() use ( $payer_action ) {
|
141 |
+
echo '<p><a class="button" href="' . esc_url( $payer_action ) . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
142 |
+
},
|
143 |
+
$post_type,
|
144 |
+
'side',
|
145 |
+
'high'
|
146 |
+
);
|
147 |
+
}
|
148 |
+
}
|
149 |
+
}
|
150 |
+
}
|
151 |
+
);
|
152 |
+
|
153 |
+
add_action(
|
154 |
+
'woocommerce_order_details_before_order_table_items',
|
155 |
+
function( WC_Order $order ) {
|
156 |
+
if ( $order->get_payment_method() === OXXOGateway::ID ) {
|
157 |
+
$payer_action = $order->get_meta( 'ppcp_oxxo_payer_action' );
|
158 |
+
if ( $payer_action ) {
|
159 |
+
echo '<p><a class="button" href="' . esc_url( $payer_action ) . '" target="_blank">' . esc_html__( 'See OXXO voucher', 'woocommerce-paypal-payments' ) . '</a></p>';
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
163 |
+
);
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Checks if checkout is allowed for OXXO.
|
168 |
+
*
|
169 |
+
* @return bool
|
170 |
+
*/
|
171 |
+
private function checkout_allowed_for_oxxo(): bool {
|
172 |
+
if ( 'MXN' !== get_woocommerce_currency() ) {
|
173 |
+
return false;
|
174 |
+
}
|
175 |
+
|
176 |
+
$billing_country = filter_input( INPUT_POST, 'country', FILTER_SANITIZE_STRING ) ?? null;
|
177 |
+
if ( $billing_country && 'MX' !== $billing_country ) {
|
178 |
+
return false;
|
179 |
+
}
|
180 |
+
|
181 |
+
if ( ! $this->checkout_helper->is_checkout_amount_allowed( 0, 10000 ) ) {
|
182 |
+
return false;
|
183 |
+
}
|
184 |
+
|
185 |
+
return true;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Register OXXO assets.
|
190 |
+
*/
|
191 |
+
public function register_assets(): void {
|
192 |
+
$gateway_settings = get_option( 'woocommerce_ppcp-oxxo-gateway_settings' );
|
193 |
+
$gateway_enabled = $gateway_settings['enabled'] ?? '';
|
194 |
+
if ( $gateway_enabled === 'yes' && is_checkout() ) {
|
195 |
+
wp_enqueue_script(
|
196 |
+
'ppcp-oxxo',
|
197 |
+
trailingslashit( $this->module_url ) . 'assets/js/oxxo.js',
|
198 |
+
array(),
|
199 |
+
$this->asset_version,
|
200 |
+
true
|
201 |
+
);
|
202 |
+
}
|
203 |
+
|
204 |
+
wp_localize_script(
|
205 |
+
'ppcp-oxxo',
|
206 |
+
'OXXOConfig',
|
207 |
+
array(
|
208 |
+
'oxxo_endpoint' => \WC_AJAX::get_endpoint( 'ppc-oxxo' ),
|
209 |
+
'oxxo_nonce' => wp_create_nonce( 'ppc-oxxo' ),
|
210 |
+
'error' => array(
|
211 |
+
'generic' => __(
|
212 |
+
'Something went wrong. Please try again or choose another payment source.',
|
213 |
+
'woocommerce-paypal-payments'
|
214 |
+
),
|
215 |
+
'js_validation' => __(
|
216 |
+
'Required form fields are not filled or invalid.',
|
217 |
+
'woocommerce-paypal-payments'
|
218 |
+
),
|
219 |
+
),
|
220 |
+
)
|
221 |
+
);
|
222 |
+
}
|
223 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOEndpoint.php
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handles OXXO payer action.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\Onboarding\Endpoint
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
11 |
+
|
12 |
+
use Psr\Log\LoggerInterface;
|
13 |
+
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
14 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
15 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
16 |
+
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
17 |
+
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
18 |
+
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
19 |
+
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* OXXOEndpoint constructor.
|
23 |
+
*/
|
24 |
+
class OXXOEndpoint implements EndpointInterface {
|
25 |
+
|
26 |
+
|
27 |
+
/**
|
28 |
+
* The request data
|
29 |
+
*
|
30 |
+
* @var RequestData
|
31 |
+
*/
|
32 |
+
protected $request_data;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* The purchase unit factory.
|
36 |
+
*
|
37 |
+
* @var PurchaseUnitFactory
|
38 |
+
*/
|
39 |
+
protected $purchase_unit_factory;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* The shipping preference factory.
|
43 |
+
*
|
44 |
+
* @var ShippingPreferenceFactory
|
45 |
+
*/
|
46 |
+
protected $shipping_preference_factory;
|
47 |
+
|
48 |
+
/**
|
49 |
+
* The order endpoint.
|
50 |
+
*
|
51 |
+
* @var OrderEndpoint
|
52 |
+
*/
|
53 |
+
protected $order_endpoint;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* The logger.
|
57 |
+
*
|
58 |
+
* @var LoggerInterface
|
59 |
+
*/
|
60 |
+
protected $logger;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* OXXOEndpoint constructor
|
64 |
+
*
|
65 |
+
* @param RequestData $request_data The request data.
|
66 |
+
* @param OrderEndpoint $order_endpoint The order endpoint.
|
67 |
+
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
68 |
+
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping preference factory.
|
69 |
+
* @param LoggerInterface $logger The logger.
|
70 |
+
*/
|
71 |
+
public function __construct(
|
72 |
+
RequestData $request_data,
|
73 |
+
OrderEndpoint $order_endpoint,
|
74 |
+
PurchaseUnitFactory $purchase_unit_factory,
|
75 |
+
ShippingPreferenceFactory $shipping_preference_factory,
|
76 |
+
LoggerInterface $logger
|
77 |
+
) {
|
78 |
+
$this->request_data = $request_data;
|
79 |
+
$this->purchase_unit_factory = $purchase_unit_factory;
|
80 |
+
$this->shipping_preference_factory = $shipping_preference_factory;
|
81 |
+
$this->order_endpoint = $order_endpoint;
|
82 |
+
$this->logger = $logger;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* The nonce
|
87 |
+
*
|
88 |
+
* @return string
|
89 |
+
*/
|
90 |
+
public static function nonce(): string {
|
91 |
+
return 'ppc-oxxo';
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Handles the request.
|
96 |
+
*
|
97 |
+
* @return bool
|
98 |
+
*/
|
99 |
+
public function handle_request(): bool {
|
100 |
+
$purchase_unit = $this->purchase_unit_factory->from_wc_cart();
|
101 |
+
$payer_action = '';
|
102 |
+
|
103 |
+
try {
|
104 |
+
$shipping_preference = $this->shipping_preference_factory->from_state(
|
105 |
+
$purchase_unit,
|
106 |
+
'checkout'
|
107 |
+
);
|
108 |
+
|
109 |
+
$order = $this->order_endpoint->create( array( $purchase_unit ), $shipping_preference );
|
110 |
+
|
111 |
+
$payment_source = array(
|
112 |
+
'oxxo' => array(
|
113 |
+
'name' => 'John Doe',
|
114 |
+
'email' => 'foo@bar.com',
|
115 |
+
'country_code' => 'MX',
|
116 |
+
),
|
117 |
+
);
|
118 |
+
|
119 |
+
$payment_method = $this->order_endpoint->confirm_payment_source( $order->id(), $payment_source );
|
120 |
+
|
121 |
+
foreach ( $payment_method->links as $link ) {
|
122 |
+
if ( $link->rel === 'payer-action' ) {
|
123 |
+
$payer_action = $link->href;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
} catch ( RuntimeException $exception ) {
|
127 |
+
$error = $exception->getMessage();
|
128 |
+
|
129 |
+
if ( is_a( $exception, PayPalApiException::class ) && is_array( $exception->details() ) ) {
|
130 |
+
$details = '';
|
131 |
+
foreach ( $exception->details() as $detail ) {
|
132 |
+
$issue = $detail->issue ?? '';
|
133 |
+
$field = $detail->field ?? '';
|
134 |
+
$description = $detail->description ?? '';
|
135 |
+
$details .= $issue . ' ' . $field . ' ' . $description . '<br>';
|
136 |
+
}
|
137 |
+
|
138 |
+
$error = $details;
|
139 |
+
}
|
140 |
+
|
141 |
+
$this->logger->error( $error );
|
142 |
+
wc_add_notice( $error, 'error' );
|
143 |
+
|
144 |
+
wp_send_json_error( 'Could not get OXXO payer action.' );
|
145 |
+
return false;
|
146 |
+
}
|
147 |
+
|
148 |
+
WC()->session->set( 'ppcp_payer_action', $payer_action );
|
149 |
+
|
150 |
+
wp_send_json_success(
|
151 |
+
array( 'payer_action' => $payer_action )
|
152 |
+
);
|
153 |
+
|
154 |
+
return true;
|
155 |
+
}
|
156 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The OXXO Gateway
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO;
|
11 |
+
|
12 |
+
use Psr\Log\LoggerInterface;
|
13 |
+
use WC_Payment_Gateway;
|
14 |
+
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
15 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
16 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
17 |
+
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
18 |
+
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Class OXXOGateway.
|
22 |
+
*/
|
23 |
+
class OXXOGateway extends WC_Payment_Gateway {
|
24 |
+
const ID = 'ppcp-oxxo-gateway';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* The order endpoint.
|
28 |
+
*
|
29 |
+
* @var OrderEndpoint
|
30 |
+
*/
|
31 |
+
protected $order_endpoint;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* The purchase unit factory.
|
35 |
+
*
|
36 |
+
* @var PurchaseUnitFactory
|
37 |
+
*/
|
38 |
+
protected $purchase_unit_factory;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* The shipping preference factory.
|
42 |
+
*
|
43 |
+
* @var ShippingPreferenceFactory
|
44 |
+
*/
|
45 |
+
protected $shipping_preference_factory;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* The URL to the module.
|
49 |
+
*
|
50 |
+
* @var string
|
51 |
+
*/
|
52 |
+
private $module_url;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* The logger.
|
56 |
+
*
|
57 |
+
* @var LoggerInterface
|
58 |
+
*/
|
59 |
+
protected $logger;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* OXXOGateway constructor.
|
63 |
+
*
|
64 |
+
* @param OrderEndpoint $order_endpoint The order endpoint.
|
65 |
+
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
66 |
+
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping preference factory.
|
67 |
+
* @param string $module_url The URL to the module.
|
68 |
+
* @param LoggerInterface $logger The logger.
|
69 |
+
*/
|
70 |
+
public function __construct(
|
71 |
+
OrderEndpoint $order_endpoint,
|
72 |
+
PurchaseUnitFactory $purchase_unit_factory,
|
73 |
+
ShippingPreferenceFactory $shipping_preference_factory,
|
74 |
+
string $module_url,
|
75 |
+
LoggerInterface $logger
|
76 |
+
) {
|
77 |
+
$this->id = self::ID;
|
78 |
+
|
79 |
+
$this->method_title = __( 'OXXO', 'woocommerce-paypal-payments' );
|
80 |
+
$this->method_description = __( 'OXXO is a Mexican chain of convenience stores.', 'woocommerce-paypal-payments' );
|
81 |
+
|
82 |
+
$this->title = $this->get_option( 'title', $this->method_title );
|
83 |
+
$this->description = $this->get_option( 'description', __( 'OXXO allows you to pay bills and online purchases in-store with cash.', 'woocommerce-paypal-payments' ) );
|
84 |
+
|
85 |
+
$this->init_form_fields();
|
86 |
+
$this->init_settings();
|
87 |
+
|
88 |
+
add_action(
|
89 |
+
'woocommerce_update_options_payment_gateways_' . $this->id,
|
90 |
+
array(
|
91 |
+
$this,
|
92 |
+
'process_admin_options',
|
93 |
+
)
|
94 |
+
);
|
95 |
+
|
96 |
+
$this->order_endpoint = $order_endpoint;
|
97 |
+
$this->purchase_unit_factory = $purchase_unit_factory;
|
98 |
+
$this->shipping_preference_factory = $shipping_preference_factory;
|
99 |
+
$this->module_url = $module_url;
|
100 |
+
$this->logger = $logger;
|
101 |
+
|
102 |
+
$this->icon = esc_url( $this->module_url ) . 'assets/images/oxxo.svg';
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Initialize the form fields.
|
107 |
+
*/
|
108 |
+
public function init_form_fields() {
|
109 |
+
$this->form_fields = array(
|
110 |
+
'enabled' => array(
|
111 |
+
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
112 |
+
'type' => 'checkbox',
|
113 |
+
'label' => __( 'OXXO', 'woocommerce-paypal-payments' ),
|
114 |
+
'default' => 'no',
|
115 |
+
'desc_tip' => true,
|
116 |
+
'description' => __( 'Enable/Disable OXXO payment gateway.', 'woocommerce-paypal-payments' ),
|
117 |
+
),
|
118 |
+
'title' => array(
|
119 |
+
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
120 |
+
'type' => 'text',
|
121 |
+
'default' => $this->title,
|
122 |
+
'desc_tip' => true,
|
123 |
+
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
124 |
+
),
|
125 |
+
'description' => array(
|
126 |
+
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
127 |
+
'type' => 'text',
|
128 |
+
'default' => $this->description,
|
129 |
+
'desc_tip' => true,
|
130 |
+
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
131 |
+
),
|
132 |
+
);
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Processes the order.
|
137 |
+
*
|
138 |
+
* @param int $order_id The WC order ID.
|
139 |
+
* @return array
|
140 |
+
*/
|
141 |
+
public function process_payment( $order_id ) {
|
142 |
+
$wc_order = wc_get_order( $order_id );
|
143 |
+
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
144 |
+
$payer_action = '';
|
145 |
+
|
146 |
+
try {
|
147 |
+
$shipping_preference = $this->shipping_preference_factory->from_state(
|
148 |
+
$purchase_unit,
|
149 |
+
'checkout'
|
150 |
+
);
|
151 |
+
|
152 |
+
$order = $this->order_endpoint->create( array( $purchase_unit ), $shipping_preference );
|
153 |
+
$payment_source = array(
|
154 |
+
'oxxo' => array(
|
155 |
+
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
156 |
+
'email' => $wc_order->get_billing_email(),
|
157 |
+
'country_code' => $wc_order->get_billing_country(),
|
158 |
+
),
|
159 |
+
);
|
160 |
+
$payment_method = $this->order_endpoint->confirm_payment_source( $order->id(), $payment_source );
|
161 |
+
foreach ( $payment_method->links as $link ) {
|
162 |
+
if ( $link->rel === 'payer-action' ) {
|
163 |
+
$payer_action = $link->href;
|
164 |
+
$wc_order->add_meta_data( 'ppcp_oxxo_payer_action', $payer_action );
|
165 |
+
$wc_order->save_meta_data();
|
166 |
+
}
|
167 |
+
}
|
168 |
+
} catch ( RuntimeException $exception ) {
|
169 |
+
$error = $exception->getMessage();
|
170 |
+
|
171 |
+
if ( is_a( $exception, PayPalApiException::class ) && is_array( $exception->details() ) ) {
|
172 |
+
$details = '';
|
173 |
+
foreach ( $exception->details() as $detail ) {
|
174 |
+
$issue = $detail->issue ?? '';
|
175 |
+
$field = $detail->field ?? '';
|
176 |
+
$description = $detail->description ?? '';
|
177 |
+
$details .= $issue . ' ' . $field . ' ' . $description . '<br>';
|
178 |
+
}
|
179 |
+
|
180 |
+
$error = $details;
|
181 |
+
}
|
182 |
+
|
183 |
+
$this->logger->error( $error );
|
184 |
+
wc_add_notice( $error, 'error' );
|
185 |
+
|
186 |
+
$wc_order->update_status(
|
187 |
+
'failed',
|
188 |
+
$error
|
189 |
+
);
|
190 |
+
|
191 |
+
return array(
|
192 |
+
'result' => 'failure',
|
193 |
+
'redirect' => wc_get_checkout_url(),
|
194 |
+
);
|
195 |
+
}
|
196 |
+
|
197 |
+
WC()->cart->empty_cart();
|
198 |
+
|
199 |
+
$result = array(
|
200 |
+
'result' => 'success',
|
201 |
+
'redirect' => $this->get_return_url( $wc_order ),
|
202 |
+
);
|
203 |
+
|
204 |
+
if ( $payer_action ) {
|
205 |
+
$result['payer_action'] = $payer_action;
|
206 |
+
}
|
207 |
+
|
208 |
+
return $result;
|
209 |
+
}
|
210 |
+
}
|
modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php
CHANGED
@@ -9,18 +9,21 @@ declare(strict_types=1);
|
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
|
|
|
12 |
use Psr\Log\LoggerInterface;
|
13 |
-
use
|
14 |
-
use WooCommerce\PayPalCommerce\ApiClient\
|
15 |
-
use WooCommerce\PayPalCommerce\ApiClient\
|
|
|
16 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
17 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
18 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|
|
19 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
20 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
|
|
21 |
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
23 |
-
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
24 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
25 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
26 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
@@ -32,7 +35,7 @@ use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
|
32 |
*/
|
33 |
class PayPalGateway extends \WC_Payment_Gateway {
|
34 |
|
35 |
-
use ProcessPaymentTrait;
|
36 |
|
37 |
const ID = 'ppcp-gateway';
|
38 |
const INTENT_META_KEY = '_ppcp_paypal_intent';
|
@@ -63,13 +66,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
63 |
*/
|
64 |
protected $order_processor;
|
65 |
|
66 |
-
/**
|
67 |
-
* The processor for authorized payments.
|
68 |
-
*
|
69 |
-
* @var AuthorizedPaymentsProcessor
|
70 |
-
*/
|
71 |
-
protected $authorized_payments_processor;
|
72 |
-
|
73 |
/**
|
74 |
* The settings.
|
75 |
*
|
@@ -119,27 +115,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
119 |
*/
|
120 |
protected $payment_token_repository;
|
121 |
|
122 |
-
/**
|
123 |
-
* The shipping_preference factory.
|
124 |
-
*
|
125 |
-
* @var ShippingPreferenceFactory
|
126 |
-
*/
|
127 |
-
private $shipping_preference_factory;
|
128 |
-
|
129 |
-
/**
|
130 |
-
* The payments endpoint
|
131 |
-
*
|
132 |
-
* @var PaymentsEndpoint
|
133 |
-
*/
|
134 |
-
protected $payments_endpoint;
|
135 |
-
|
136 |
-
/**
|
137 |
-
* The order endpoint.
|
138 |
-
*
|
139 |
-
* @var OrderEndpoint
|
140 |
-
*/
|
141 |
-
protected $order_endpoint;
|
142 |
-
|
143 |
/**
|
144 |
* Whether the plugin is in onboarded state.
|
145 |
*
|
@@ -178,30 +153,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
178 |
/**
|
179 |
* PayPalGateway constructor.
|
180 |
*
|
181 |
-
* @param SettingsRenderer
|
182 |
-
* @param FundingSourceRenderer
|
183 |
-
* @param OrderProcessor
|
184 |
-
* @param
|
185 |
-
* @param
|
186 |
-
* @param
|
187 |
-
* @param
|
188 |
-
* @param
|
189 |
-
* @param
|
190 |
-
* @param
|
191 |
-
* @param
|
192 |
-
* @param
|
193 |
-
* @param
|
194 |
-
* @param
|
195 |
-
* @param LoggerInterface $logger The logger.
|
196 |
-
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
197 |
-
* @param OrderEndpoint $order_endpoint The order endpoint.
|
198 |
-
* @param string $api_shop_country The api shop country.
|
199 |
*/
|
200 |
public function __construct(
|
201 |
SettingsRenderer $settings_renderer,
|
202 |
FundingSourceRenderer $funding_source_renderer,
|
203 |
OrderProcessor $order_processor,
|
204 |
-
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
205 |
ContainerInterface $config,
|
206 |
SessionHandler $session_handler,
|
207 |
RefundProcessor $refund_processor,
|
@@ -211,37 +181,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
211 |
string $page_id,
|
212 |
Environment $environment,
|
213 |
PaymentTokenRepository $payment_token_repository,
|
214 |
-
ShippingPreferenceFactory $shipping_preference_factory,
|
215 |
LoggerInterface $logger,
|
216 |
-
PaymentsEndpoint $payments_endpoint,
|
217 |
-
OrderEndpoint $order_endpoint,
|
218 |
string $api_shop_country
|
219 |
) {
|
220 |
-
|
221 |
-
$this->
|
222 |
-
$this->
|
223 |
-
$this->
|
224 |
-
$this->
|
225 |
-
$this->
|
226 |
-
$this->
|
227 |
-
$this->
|
228 |
-
$this->
|
229 |
-
$this->
|
230 |
-
$this->page_id
|
231 |
-
$this->environment
|
232 |
-
$this->onboarded
|
233 |
-
$this->
|
234 |
-
$this->
|
235 |
-
$this->
|
236 |
-
$this->shipping_preference_factory = $shipping_preference_factory;
|
237 |
-
$this->settings_renderer = $settings_renderer;
|
238 |
-
$this->config = $config;
|
239 |
-
$this->session_handler = $session_handler;
|
240 |
-
$this->refund_processor = $refund_processor;
|
241 |
-
$this->transaction_url_provider = $transaction_url_provider;
|
242 |
-
$this->page_id = $page_id;
|
243 |
-
$this->environment = $environment;
|
244 |
-
$this->logger = $logger;
|
245 |
|
246 |
if ( $this->onboarded ) {
|
247 |
$this->supports = array( 'refunds' );
|
@@ -291,13 +249,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
291 |
'process_admin_options',
|
292 |
)
|
293 |
);
|
294 |
-
$this->subscription_helper = $subscription_helper;
|
295 |
-
$this->payment_token_repository = $payment_token_repository;
|
296 |
-
$this->logger = $logger;
|
297 |
-
$this->payments_endpoint = $payments_endpoint;
|
298 |
-
$this->order_endpoint = $order_endpoint;
|
299 |
-
$this->state = $state;
|
300 |
-
$this->api_shop_country = $api_shop_country;
|
301 |
}
|
302 |
|
303 |
/**
|
@@ -306,7 +257,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
306 |
* @return bool
|
307 |
*/
|
308 |
public function needs_setup(): bool {
|
309 |
-
|
310 |
return ! $this->onboarded;
|
311 |
}
|
312 |
|
@@ -334,20 +284,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
334 |
}
|
335 |
}
|
336 |
|
337 |
-
/**
|
338 |
-
* Renders the settings.
|
339 |
-
*
|
340 |
-
* @return string
|
341 |
-
*/
|
342 |
-
public function generate_ppcp_html(): string {
|
343 |
-
|
344 |
-
ob_start();
|
345 |
-
$this->settings_renderer->render( false );
|
346 |
-
$content = ob_get_contents();
|
347 |
-
ob_end_clean();
|
348 |
-
return $content;
|
349 |
-
}
|
350 |
-
|
351 |
/**
|
352 |
* Defines the method title. If we are on the credit card tab in the settings, we want to change this.
|
353 |
*
|
@@ -450,6 +386,130 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
450 |
}
|
451 |
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
452 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
453 |
/**
|
454 |
* Process refund.
|
455 |
*
|
@@ -503,11 +563,11 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|
503 |
}
|
504 |
|
505 |
/**
|
506 |
-
* Returns the
|
507 |
*
|
508 |
-
* @return
|
509 |
*/
|
510 |
-
protected function
|
511 |
-
return $this->
|
512 |
}
|
513 |
}
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
|
12 |
+
use Exception;
|
13 |
use Psr\Log\LoggerInterface;
|
14 |
+
use WC_Order;
|
15 |
+
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
16 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
17 |
+
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
18 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
19 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
20 |
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
21 |
+
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
22 |
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
23 |
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
24 |
+
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
25 |
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
26 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
|
|
27 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
28 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
29 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
35 |
*/
|
36 |
class PayPalGateway extends \WC_Payment_Gateway {
|
37 |
|
38 |
+
use ProcessPaymentTrait, FreeTrialHandlerTrait, GatewaySettingsRendererTrait;
|
39 |
|
40 |
const ID = 'ppcp-gateway';
|
41 |
const INTENT_META_KEY = '_ppcp_paypal_intent';
|
66 |
*/
|
67 |
protected $order_processor;
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
/**
|
70 |
* The settings.
|
71 |
*
|
115 |
*/
|
116 |
protected $payment_token_repository;
|
117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
/**
|
119 |
* Whether the plugin is in onboarded state.
|
120 |
*
|
153 |
/**
|
154 |
* PayPalGateway constructor.
|
155 |
*
|
156 |
+
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
157 |
+
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
158 |
+
* @param OrderProcessor $order_processor The Order Processor.
|
159 |
+
* @param ContainerInterface $config The settings.
|
160 |
+
* @param SessionHandler $session_handler The Session Handler.
|
161 |
+
* @param RefundProcessor $refund_processor The Refund Processor.
|
162 |
+
* @param State $state The state.
|
163 |
+
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
164 |
+
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
165 |
+
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
166 |
+
* @param Environment $environment The environment.
|
167 |
+
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
168 |
+
* @param LoggerInterface $logger The logger.
|
169 |
+
* @param string $api_shop_country The api shop country.
|
|
|
|
|
|
|
|
|
170 |
*/
|
171 |
public function __construct(
|
172 |
SettingsRenderer $settings_renderer,
|
173 |
FundingSourceRenderer $funding_source_renderer,
|
174 |
OrderProcessor $order_processor,
|
|
|
175 |
ContainerInterface $config,
|
176 |
SessionHandler $session_handler,
|
177 |
RefundProcessor $refund_processor,
|
181 |
string $page_id,
|
182 |
Environment $environment,
|
183 |
PaymentTokenRepository $payment_token_repository,
|
|
|
184 |
LoggerInterface $logger,
|
|
|
|
|
185 |
string $api_shop_country
|
186 |
) {
|
187 |
+
$this->id = self::ID;
|
188 |
+
$this->settings_renderer = $settings_renderer;
|
189 |
+
$this->funding_source_renderer = $funding_source_renderer;
|
190 |
+
$this->order_processor = $order_processor;
|
191 |
+
$this->config = $config;
|
192 |
+
$this->session_handler = $session_handler;
|
193 |
+
$this->refund_processor = $refund_processor;
|
194 |
+
$this->state = $state;
|
195 |
+
$this->transaction_url_provider = $transaction_url_provider;
|
196 |
+
$this->subscription_helper = $subscription_helper;
|
197 |
+
$this->page_id = $page_id;
|
198 |
+
$this->environment = $environment;
|
199 |
+
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
200 |
+
$this->payment_token_repository = $payment_token_repository;
|
201 |
+
$this->logger = $logger;
|
202 |
+
$this->api_shop_country = $api_shop_country;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
|
204 |
if ( $this->onboarded ) {
|
205 |
$this->supports = array( 'refunds' );
|
249 |
'process_admin_options',
|
250 |
)
|
251 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
}
|
253 |
|
254 |
/**
|
257 |
* @return bool
|
258 |
*/
|
259 |
public function needs_setup(): bool {
|
|
|
260 |
return ! $this->onboarded;
|
261 |
}
|
262 |
|
284 |
}
|
285 |
}
|
286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
/**
|
288 |
* Defines the method title. If we are on the credit card tab in the settings, we want to change this.
|
289 |
*
|
386 |
}
|
387 |
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
388 |
|
389 |
+
/**
|
390 |
+
* Process payment for a WooCommerce order.
|
391 |
+
*
|
392 |
+
* @param int $order_id The WooCommerce order id.
|
393 |
+
*
|
394 |
+
* @return array
|
395 |
+
*/
|
396 |
+
public function process_payment( $order_id ) {
|
397 |
+
$wc_order = wc_get_order( $order_id );
|
398 |
+
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
399 |
+
return $this->handle_payment_failure(
|
400 |
+
null,
|
401 |
+
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
402 |
+
);
|
403 |
+
}
|
404 |
+
|
405 |
+
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
406 |
+
|
407 |
+
if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
408 |
+
$user_id = (int) $wc_order->get_customer_id();
|
409 |
+
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
410 |
+
if ( ! array_filter(
|
411 |
+
$tokens,
|
412 |
+
function ( PaymentToken $token ): bool {
|
413 |
+
return isset( $token->source()->paypal );
|
414 |
+
}
|
415 |
+
) ) {
|
416 |
+
return $this->handle_payment_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
417 |
+
}
|
418 |
+
|
419 |
+
$wc_order->payment_complete();
|
420 |
+
|
421 |
+
return $this->handle_payment_success( $wc_order );
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* If customer has chosen change Subscription payment.
|
426 |
+
*/
|
427 |
+
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
428 |
+
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
429 |
+
if ( $saved_paypal_payment ) {
|
430 |
+
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
431 |
+
|
432 |
+
return $this->handle_payment_success( $wc_order );
|
433 |
+
}
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* If the WC_Order is paid through the approved webhook.
|
438 |
+
*/
|
439 |
+
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
440 |
+
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
441 |
+
return $this->handle_payment_success( $wc_order );
|
442 |
+
}
|
443 |
+
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
444 |
+
|
445 |
+
try {
|
446 |
+
if ( ! $this->order_processor->process( $wc_order ) ) {
|
447 |
+
return $this->handle_payment_failure(
|
448 |
+
$wc_order,
|
449 |
+
new Exception(
|
450 |
+
$this->order_processor->last_error()
|
451 |
+
)
|
452 |
+
);
|
453 |
+
}
|
454 |
+
|
455 |
+
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
456 |
+
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
457 |
+
}
|
458 |
+
|
459 |
+
return $this->handle_payment_success( $wc_order );
|
460 |
+
} catch ( PayPalApiException $error ) {
|
461 |
+
$retry_keys_messages = array(
|
462 |
+
'INSTRUMENT_DECLINED' => __( 'Instrument declined.', 'woocommerce-paypal-payments' ),
|
463 |
+
'PAYER_ACTION_REQUIRED' => __( 'Payer action required, possibly overcharge.', 'woocommerce-paypal-payments' ),
|
464 |
+
);
|
465 |
+
$retry_errors = array_filter(
|
466 |
+
array_keys( $retry_keys_messages ),
|
467 |
+
function ( string $key ) use ( $error ): bool {
|
468 |
+
return $error->has_detail( $key );
|
469 |
+
}
|
470 |
+
);
|
471 |
+
if ( $retry_errors ) {
|
472 |
+
$retry_error_key = $retry_errors[0];
|
473 |
+
|
474 |
+
$wc_order->update_status(
|
475 |
+
'failed',
|
476 |
+
$retry_keys_messages[ $retry_error_key ] . ' ' . $error->details()[0]->description ?? ''
|
477 |
+
);
|
478 |
+
|
479 |
+
$this->session_handler->increment_insufficient_funding_tries();
|
480 |
+
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
481 |
+
return $this->handle_payment_failure(
|
482 |
+
null,
|
483 |
+
new Exception(
|
484 |
+
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
485 |
+
$error->getCode(),
|
486 |
+
$error
|
487 |
+
)
|
488 |
+
);
|
489 |
+
}
|
490 |
+
|
491 |
+
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
492 |
+
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
493 |
+
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
494 |
+
return array(
|
495 |
+
'result' => 'success',
|
496 |
+
'redirect' => $url,
|
497 |
+
);
|
498 |
+
}
|
499 |
+
|
500 |
+
return $this->handle_payment_failure(
|
501 |
+
$wc_order,
|
502 |
+
new Exception(
|
503 |
+
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
504 |
+
$error->getCode(),
|
505 |
+
$error
|
506 |
+
)
|
507 |
+
);
|
508 |
+
} catch ( RuntimeException $error ) {
|
509 |
+
return $this->handle_payment_failure( $wc_order, $error );
|
510 |
+
}
|
511 |
+
}
|
512 |
+
|
513 |
/**
|
514 |
* Process refund.
|
515 |
*
|
563 |
}
|
564 |
|
565 |
/**
|
566 |
+
* Returns the settings renderer.
|
567 |
*
|
568 |
+
* @return SettingsRenderer
|
569 |
*/
|
570 |
+
protected function settings_renderer(): SettingsRenderer {
|
571 |
+
return $this->settings_renderer;
|
572 |
}
|
573 |
}
|
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php
CHANGED
@@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory;
|
|
16 |
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
17 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
18 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
|
|
19 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
20 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
21 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
@@ -115,6 +116,13 @@ class PayUponInvoice {
|
|
115 |
*/
|
116 |
protected $pui_product_status;
|
117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
/**
|
119 |
* The capture factory.
|
120 |
*
|
@@ -137,6 +145,7 @@ class PayUponInvoice {
|
|
137 |
* @param string $current_ppcp_settings_page_id Current PayPal settings page id.
|
138 |
* @param PayUponInvoiceProductStatus $pui_product_status The PUI product status.
|
139 |
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
|
|
|
140 |
* @param CaptureFactory $capture_factory The capture factory.
|
141 |
*/
|
142 |
public function __construct(
|
@@ -152,6 +161,7 @@ class PayUponInvoice {
|
|
152 |
string $current_ppcp_settings_page_id,
|
153 |
PayUponInvoiceProductStatus $pui_product_status,
|
154 |
PayUponInvoiceHelper $pui_helper,
|
|
|
155 |
CaptureFactory $capture_factory
|
156 |
) {
|
157 |
$this->module_url = $module_url;
|
@@ -166,6 +176,7 @@ class PayUponInvoice {
|
|
166 |
$this->current_ppcp_settings_page_id = $current_ppcp_settings_page_id;
|
167 |
$this->pui_product_status = $pui_product_status;
|
168 |
$this->pui_helper = $pui_helper;
|
|
|
169 |
$this->capture_factory = $capture_factory;
|
170 |
}
|
171 |
|
@@ -298,7 +309,7 @@ class PayUponInvoice {
|
|
298 |
}
|
299 |
},
|
300 |
10,
|
301 |
-
|
302 |
);
|
303 |
|
304 |
add_filter(
|
@@ -360,7 +371,7 @@ class PayUponInvoice {
|
|
360 |
}
|
361 |
|
362 |
$birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING );
|
363 |
-
if ( ( $birth_date && ! $this->
|
364 |
$errors->add( 'validation', __( 'Invalid birth date.', 'woocommerce-paypal-payments' ) );
|
365 |
}
|
366 |
|
@@ -477,7 +488,7 @@ class PayUponInvoice {
|
|
477 |
if ( $post_type === 'shop_order' ) {
|
478 |
$post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_STRING );
|
479 |
$order = wc_get_order( $post_id );
|
480 |
-
if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() ===
|
481 |
$instructions = $order->get_meta( 'ppcp_ratepay_payment_instructions_payment_reference' );
|
482 |
if ( $instructions ) {
|
483 |
add_meta_box(
|
16 |
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
17 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
18 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
19 |
+
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
20 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
21 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
116 |
*/
|
117 |
protected $pui_product_status;
|
118 |
|
119 |
+
/**
|
120 |
+
* The checkout helper.
|
121 |
+
*
|
122 |
+
* @var CheckoutHelper
|
123 |
+
*/
|
124 |
+
protected $checkout_helper;
|
125 |
+
|
126 |
/**
|
127 |
* The capture factory.
|
128 |
*
|
145 |
* @param string $current_ppcp_settings_page_id Current PayPal settings page id.
|
146 |
* @param PayUponInvoiceProductStatus $pui_product_status The PUI product status.
|
147 |
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
|
148 |
+
* @param CheckoutHelper $checkout_helper The checkout helper.
|
149 |
* @param CaptureFactory $capture_factory The capture factory.
|
150 |
*/
|
151 |
public function __construct(
|
161 |
string $current_ppcp_settings_page_id,
|
162 |
PayUponInvoiceProductStatus $pui_product_status,
|
163 |
PayUponInvoiceHelper $pui_helper,
|
164 |
+
CheckoutHelper $checkout_helper,
|
165 |
CaptureFactory $capture_factory
|
166 |
) {
|
167 |
$this->module_url = $module_url;
|
176 |
$this->current_ppcp_settings_page_id = $current_ppcp_settings_page_id;
|
177 |
$this->pui_product_status = $pui_product_status;
|
178 |
$this->pui_helper = $pui_helper;
|
179 |
+
$this->checkout_helper = $checkout_helper;
|
180 |
$this->capture_factory = $capture_factory;
|
181 |
}
|
182 |
|
309 |
}
|
310 |
},
|
311 |
10,
|
312 |
+
2
|
313 |
);
|
314 |
|
315 |
add_filter(
|
371 |
}
|
372 |
|
373 |
$birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING );
|
374 |
+
if ( ( $birth_date && ! $this->checkout_helper->validate_birth_date( $birth_date ) ) || $birth_date === '' ) {
|
375 |
$errors->add( 'validation', __( 'Invalid birth date.', 'woocommerce-paypal-payments' ) );
|
376 |
}
|
377 |
|
488 |
if ( $post_type === 'shop_order' ) {
|
489 |
$post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_STRING );
|
490 |
$order = wc_get_order( $post_id );
|
491 |
+
if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() === PayUponInvoiceGateway::ID ) {
|
492 |
$instructions = $order->get_meta( 'ppcp_ratepay_payment_instructions_payment_reference' );
|
493 |
if ( $instructions ) {
|
494 |
add_meta_box(
|
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php
CHANGED
@@ -12,14 +12,13 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
|
|
12 |
use Psr\Log\LoggerInterface;
|
13 |
use RuntimeException;
|
14 |
use WC_Order;
|
15 |
-
use WC_Order_Item_Product;
|
16 |
use WC_Payment_Gateway;
|
17 |
-
use WC_Product;
|
18 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
|
19 |
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
20 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
21 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
|
|
23 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
24 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
25 |
|
@@ -81,6 +80,13 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|
81 |
*/
|
82 |
protected $pui_helper;
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
/**
|
85 |
* PayUponInvoiceGateway constructor.
|
86 |
*
|
@@ -91,6 +97,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|
91 |
* @param TransactionUrlProvider $transaction_url_provider The transaction URL provider.
|
92 |
* @param LoggerInterface $logger The logger.
|
93 |
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
|
|
|
94 |
*/
|
95 |
public function __construct(
|
96 |
PayUponInvoiceOrderEndpoint $order_endpoint,
|
@@ -99,7 +106,8 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|
99 |
Environment $environment,
|
100 |
TransactionUrlProvider $transaction_url_provider,
|
101 |
LoggerInterface $logger,
|
102 |
-
PayUponInvoiceHelper $pui_helper
|
|
|
103 |
) {
|
104 |
$this->id = self::ID;
|
105 |
|
@@ -128,6 +136,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|
128 |
$this->environment = $environment;
|
129 |
$this->transaction_url_provider = $transaction_url_provider;
|
130 |
$this->pui_helper = $pui_helper;
|
|
|
131 |
}
|
132 |
|
133 |
/**
|
@@ -198,7 +207,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|
198 |
|
199 |
$pay_for_order = filter_input( INPUT_GET, 'pay_for_order', FILTER_SANITIZE_STRING );
|
200 |
if ( 'true' === $pay_for_order ) {
|
201 |
-
if ( ! $this->
|
202 |
wc_add_notice( 'Invalid birth date.', 'error' );
|
203 |
return array(
|
204 |
'result' => 'failure',
|
12 |
use Psr\Log\LoggerInterface;
|
13 |
use RuntimeException;
|
14 |
use WC_Order;
|
|
|
15 |
use WC_Payment_Gateway;
|
|
|
16 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
|
17 |
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
18 |
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
19 |
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
20 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
21 |
+
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
22 |
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
23 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
24 |
|
80 |
*/
|
81 |
protected $pui_helper;
|
82 |
|
83 |
+
/**
|
84 |
+
* The checkout helper.
|
85 |
+
*
|
86 |
+
* @var CheckoutHelper
|
87 |
+
*/
|
88 |
+
protected $checkout_helper;
|
89 |
+
|
90 |
/**
|
91 |
* PayUponInvoiceGateway constructor.
|
92 |
*
|
97 |
* @param TransactionUrlProvider $transaction_url_provider The transaction URL provider.
|
98 |
* @param LoggerInterface $logger The logger.
|
99 |
* @param PayUponInvoiceHelper $pui_helper The PUI helper.
|
100 |
+
* @param CheckoutHelper $checkout_helper The checkout helper.
|
101 |
*/
|
102 |
public function __construct(
|
103 |
PayUponInvoiceOrderEndpoint $order_endpoint,
|
106 |
Environment $environment,
|
107 |
TransactionUrlProvider $transaction_url_provider,
|
108 |
LoggerInterface $logger,
|
109 |
+
PayUponInvoiceHelper $pui_helper,
|
110 |
+
CheckoutHelper $checkout_helper
|
111 |
) {
|
112 |
$this->id = self::ID;
|
113 |
|
136 |
$this->environment = $environment;
|
137 |
$this->transaction_url_provider = $transaction_url_provider;
|
138 |
$this->pui_helper = $pui_helper;
|
139 |
+
$this->checkout_helper = $checkout_helper;
|
140 |
}
|
141 |
|
142 |
/**
|
207 |
|
208 |
$pay_for_order = filter_input( INPUT_GET, 'pay_for_order', FILTER_SANITIZE_STRING );
|
209 |
if ( 'true' === $pay_for_order ) {
|
210 |
+
if ( ! $this->checkout_helper->validate_birth_date( $birth_date ) ) {
|
211 |
wc_add_notice( 'Invalid birth date.', 'error' );
|
212 |
return array(
|
213 |
'result' => 'failure',
|
modules/ppcp-wc-gateway/src/Gateway/ProcessPaymentTrait.php
CHANGED
@@ -10,279 +10,14 @@ declare( strict_types=1 );
|
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
|
12 |
use Exception;
|
13 |
-
use
|
14 |
-
use
|
15 |
-
use WooCommerce\PayPalCommerce\
|
16 |
-
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
17 |
-
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
18 |
-
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
19 |
-
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
20 |
-
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
21 |
-
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
22 |
-
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
23 |
|
24 |
/**
|
25 |
* Trait ProcessPaymentTrait
|
26 |
*/
|
27 |
trait ProcessPaymentTrait {
|
28 |
-
|
29 |
-
use OrderMetaTrait, PaymentsStatusHandlingTrait, TransactionIdHandlingTrait, FreeTrialHandlerTrait;
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Process a payment for an WooCommerce order.
|
33 |
-
*
|
34 |
-
* @param int $order_id The WooCommerce order id.
|
35 |
-
*
|
36 |
-
* @return array
|
37 |
-
*
|
38 |
-
* @throws RuntimeException When processing payment fails.
|
39 |
-
*/
|
40 |
-
public function process_payment( $order_id ) {
|
41 |
-
|
42 |
-
$failure_data = array(
|
43 |
-
'result' => 'failure',
|
44 |
-
'redirect' => wc_get_checkout_url(),
|
45 |
-
);
|
46 |
-
|
47 |
-
$wc_order = wc_get_order( $order_id );
|
48 |
-
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
49 |
-
wc_add_notice(
|
50 |
-
__( 'Couldn\'t find order to process', 'woocommerce-paypal-payments' ),
|
51 |
-
'error'
|
52 |
-
);
|
53 |
-
|
54 |
-
return $failure_data;
|
55 |
-
}
|
56 |
-
|
57 |
-
$payment_method = filter_input( INPUT_POST, 'payment_method', FILTER_SANITIZE_STRING );
|
58 |
-
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
59 |
-
|
60 |
-
/**
|
61 |
-
* If customer has chosen a saved credit card payment.
|
62 |
-
*/
|
63 |
-
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
64 |
-
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
65 |
-
if ( CreditCardGateway::ID === $payment_method && $saved_credit_card && ! isset( $change_payment ) ) {
|
66 |
-
|
67 |
-
$user_id = (int) $wc_order->get_customer_id();
|
68 |
-
$customer = new \WC_Customer( $user_id );
|
69 |
-
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
70 |
-
|
71 |
-
$selected_token = null;
|
72 |
-
foreach ( $tokens as $token ) {
|
73 |
-
if ( $token->id() === $saved_credit_card ) {
|
74 |
-
$selected_token = $token;
|
75 |
-
break;
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
if ( ! $selected_token ) {
|
80 |
-
return null;
|
81 |
-
}
|
82 |
-
|
83 |
-
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
84 |
-
$payer = $this->payer_factory->from_customer( $customer );
|
85 |
-
|
86 |
-
$shipping_preference = $this->shipping_preference_factory->from_state(
|
87 |
-
$purchase_unit,
|
88 |
-
''
|
89 |
-
);
|
90 |
-
|
91 |
-
try {
|
92 |
-
$order = $this->order_endpoint->create(
|
93 |
-
array( $purchase_unit ),
|
94 |
-
$shipping_preference,
|
95 |
-
$payer,
|
96 |
-
$selected_token
|
97 |
-
);
|
98 |
-
|
99 |
-
$this->add_paypal_meta( $wc_order, $order, $this->environment() );
|
100 |
-
|
101 |
-
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
102 |
-
$this->logger->warning( "Unexpected status for order {$order->id()} using a saved credit card: " . $order->status()->name() );
|
103 |
-
return null;
|
104 |
-
}
|
105 |
-
|
106 |
-
if ( ! in_array(
|
107 |
-
$order->intent(),
|
108 |
-
array( 'CAPTURE', 'AUTHORIZE' ),
|
109 |
-
true
|
110 |
-
) ) {
|
111 |
-
$this->logger->warning( "Could neither capture nor authorize order {$order->id()} using a saved credit card:" . 'Status: ' . $order->status()->name() . ' Intent: ' . $order->intent() );
|
112 |
-
return null;
|
113 |
-
}
|
114 |
-
|
115 |
-
if ( $order->intent() === 'AUTHORIZE' ) {
|
116 |
-
$order = $this->order_endpoint->authorize( $order );
|
117 |
-
|
118 |
-
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
119 |
-
}
|
120 |
-
|
121 |
-
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
122 |
-
if ( $transaction_id ) {
|
123 |
-
$this->update_transaction_id( $transaction_id, $wc_order );
|
124 |
-
}
|
125 |
-
|
126 |
-
$this->handle_new_order_status( $order, $wc_order );
|
127 |
-
|
128 |
-
if ( $this->is_free_trial_order( $wc_order ) ) {
|
129 |
-
$this->authorized_payments_processor->void_authorizations( $order );
|
130 |
-
$wc_order->payment_complete();
|
131 |
-
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
132 |
-
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
133 |
-
}
|
134 |
-
|
135 |
-
$this->session_handler->destroy_session_data();
|
136 |
-
return array(
|
137 |
-
'result' => 'success',
|
138 |
-
'redirect' => $this->get_return_url( $wc_order ),
|
139 |
-
);
|
140 |
-
} catch ( RuntimeException $error ) {
|
141 |
-
$this->handle_failure( $wc_order, $error );
|
142 |
-
return null;
|
143 |
-
}
|
144 |
-
}
|
145 |
-
|
146 |
-
if ( PayPalGateway::ID === $payment_method && 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
147 |
-
$user_id = (int) $wc_order->get_customer_id();
|
148 |
-
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
149 |
-
if ( ! array_filter(
|
150 |
-
$tokens,
|
151 |
-
function ( PaymentToken $token ): bool {
|
152 |
-
return isset( $token->source()->paypal );
|
153 |
-
}
|
154 |
-
) ) {
|
155 |
-
$this->handle_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
156 |
-
return null;
|
157 |
-
}
|
158 |
-
|
159 |
-
$wc_order->payment_complete();
|
160 |
-
|
161 |
-
$this->session_handler->destroy_session_data();
|
162 |
-
return array(
|
163 |
-
'result' => 'success',
|
164 |
-
'redirect' => $this->get_return_url( $wc_order ),
|
165 |
-
);
|
166 |
-
}
|
167 |
-
|
168 |
-
/**
|
169 |
-
* If customer has chosen change Subscription payment.
|
170 |
-
*/
|
171 |
-
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
172 |
-
if ( 'ppcp-credit-card-gateway' === $this->id && $saved_credit_card ) {
|
173 |
-
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
174 |
-
|
175 |
-
$this->session_handler->destroy_session_data();
|
176 |
-
return array(
|
177 |
-
'result' => 'success',
|
178 |
-
'redirect' => $this->get_return_url( $wc_order ),
|
179 |
-
);
|
180 |
-
}
|
181 |
-
|
182 |
-
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
183 |
-
if ( 'ppcp-gateway' === $this->id && $saved_paypal_payment ) {
|
184 |
-
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
185 |
-
|
186 |
-
$this->session_handler->destroy_session_data();
|
187 |
-
return array(
|
188 |
-
'result' => 'success',
|
189 |
-
'redirect' => $this->get_return_url( $wc_order ),
|
190 |
-
);
|
191 |
-
}
|
192 |
-
}
|
193 |
-
|
194 |
-
/**
|
195 |
-
* If the WC_Order is payed through the approved webhook.
|
196 |
-
*/
|
197 |
-
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
198 |
-
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
199 |
-
$this->session_handler->destroy_session_data();
|
200 |
-
return array(
|
201 |
-
'result' => 'success',
|
202 |
-
'redirect' => $this->get_return_url( $wc_order ),
|
203 |
-
);
|
204 |
-
}
|
205 |
-
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
206 |
-
|
207 |
-
try {
|
208 |
-
if ( $this->order_processor->process( $wc_order ) ) {
|
209 |
-
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
210 |
-
as_schedule_single_action(
|
211 |
-
time() + ( 1 * MINUTE_IN_SECONDS ),
|
212 |
-
'woocommerce_paypal_payments_check_saved_payment',
|
213 |
-
array(
|
214 |
-
'order_id' => $order_id,
|
215 |
-
'customer_id' => $wc_order->get_customer_id(),
|
216 |
-
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
217 |
-
)
|
218 |
-
);
|
219 |
-
}
|
220 |
-
|
221 |
-
WC()->cart->empty_cart();
|
222 |
-
$this->session_handler->destroy_session_data();
|
223 |
-
|
224 |
-
return array(
|
225 |
-
'result' => 'success',
|
226 |
-
'redirect' => $this->get_return_url( $wc_order ),
|
227 |
-
);
|
228 |
-
}
|
229 |
-
} catch ( PayPalApiException $error ) {
|
230 |
-
if ( $error->has_detail( 'INSTRUMENT_DECLINED' ) ) {
|
231 |
-
$wc_order->update_status(
|
232 |
-
'failed',
|
233 |
-
__( 'Instrument declined. ', 'woocommerce-paypal-payments' ) . $error->details()[0]->description ?? ''
|
234 |
-
);
|
235 |
-
|
236 |
-
$this->session_handler->increment_insufficient_funding_tries();
|
237 |
-
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
238 |
-
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
239 |
-
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
240 |
-
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
241 |
-
$this->session_handler->destroy_session_data();
|
242 |
-
wc_add_notice(
|
243 |
-
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
244 |
-
'error'
|
245 |
-
);
|
246 |
-
return $failure_data;
|
247 |
-
}
|
248 |
-
return array(
|
249 |
-
'result' => 'success',
|
250 |
-
'redirect' => $url,
|
251 |
-
);
|
252 |
-
}
|
253 |
-
|
254 |
-
$error_message = $error->getMessage();
|
255 |
-
if ( $error->issues() ) {
|
256 |
-
$error_message = implode(
|
257 |
-
array_map(
|
258 |
-
function( $issue ) {
|
259 |
-
return $issue->issue . ' ' . $issue->description . '<br/>';
|
260 |
-
},
|
261 |
-
$error->issues()
|
262 |
-
)
|
263 |
-
);
|
264 |
-
}
|
265 |
-
wc_add_notice( $error_message, 'error' );
|
266 |
-
|
267 |
-
$this->session_handler->destroy_session_data();
|
268 |
-
} catch ( RuntimeException $error ) {
|
269 |
-
$this->handle_failure( $wc_order, $error );
|
270 |
-
return $failure_data;
|
271 |
-
}
|
272 |
-
|
273 |
-
wc_add_notice(
|
274 |
-
$this->order_processor->last_error(),
|
275 |
-
'error'
|
276 |
-
);
|
277 |
-
|
278 |
-
$wc_order->update_status(
|
279 |
-
'failed',
|
280 |
-
__( 'Could not process order. ', 'woocommerce-paypal-payments' ) . $this->order_processor->last_error()
|
281 |
-
);
|
282 |
-
|
283 |
-
return $failure_data;
|
284 |
-
}
|
285 |
-
|
286 |
/**
|
287 |
* Checks if PayPal or Credit Card gateways are enabled.
|
288 |
*
|
@@ -311,29 +46,86 @@ trait ProcessPaymentTrait {
|
|
311 |
return false;
|
312 |
}
|
313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
/**
|
315 |
* Handles the payment failure.
|
316 |
*
|
317 |
-
* @param
|
318 |
-
* @param Exception
|
|
|
319 |
*/
|
320 |
-
protected function
|
321 |
-
$this->logger->error( 'Payment failed: ' . $
|
322 |
|
323 |
-
$wc_order
|
324 |
-
|
325 |
-
|
326 |
-
|
|
|
|
|
327 |
|
328 |
$this->session_handler->destroy_session_data();
|
329 |
|
330 |
wc_add_notice( $error->getMessage(), 'error' );
|
|
|
|
|
|
|
|
|
|
|
331 |
}
|
332 |
|
333 |
/**
|
334 |
-
*
|
335 |
*
|
336 |
-
* @
|
|
|
|
|
337 |
*/
|
338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
}
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
11 |
|
12 |
use Exception;
|
13 |
+
use Throwable;
|
14 |
+
use WC_Order;
|
15 |
+
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
/**
|
18 |
* Trait ProcessPaymentTrait
|
19 |
*/
|
20 |
trait ProcessPaymentTrait {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
/**
|
22 |
* Checks if PayPal or Credit Card gateways are enabled.
|
23 |
*
|
46 |
return false;
|
47 |
}
|
48 |
|
49 |
+
/**
|
50 |
+
* Scheduled the vaulted payment check.
|
51 |
+
*
|
52 |
+
* @param int $wc_order_id The WC order ID.
|
53 |
+
* @param int $customer_id The customer ID.
|
54 |
+
*/
|
55 |
+
protected function schedule_saved_payment_check( int $wc_order_id, int $customer_id ): void {
|
56 |
+
as_schedule_single_action(
|
57 |
+
time() + ( 1 * MINUTE_IN_SECONDS ),
|
58 |
+
'woocommerce_paypal_payments_check_saved_payment',
|
59 |
+
array(
|
60 |
+
'order_id' => $wc_order_id,
|
61 |
+
'customer_id' => $customer_id,
|
62 |
+
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
63 |
+
)
|
64 |
+
);
|
65 |
+
}
|
66 |
+
|
67 |
/**
|
68 |
* Handles the payment failure.
|
69 |
*
|
70 |
+
* @param WC_Order|null $wc_order The order.
|
71 |
+
* @param Exception $error The error causing the failure.
|
72 |
+
* @return array The data that can be returned by the gateway process_payment method.
|
73 |
*/
|
74 |
+
protected function handle_payment_failure( ?WC_Order $wc_order, Exception $error ): array {
|
75 |
+
$this->logger->error( 'Payment failed: ' . $this->format_exception( $error ) );
|
76 |
|
77 |
+
if ( $wc_order ) {
|
78 |
+
$wc_order->update_status(
|
79 |
+
'failed',
|
80 |
+
$this->format_exception( $error )
|
81 |
+
);
|
82 |
+
}
|
83 |
|
84 |
$this->session_handler->destroy_session_data();
|
85 |
|
86 |
wc_add_notice( $error->getMessage(), 'error' );
|
87 |
+
|
88 |
+
return array(
|
89 |
+
'result' => 'failure',
|
90 |
+
'redirect' => wc_get_checkout_url(),
|
91 |
+
);
|
92 |
}
|
93 |
|
94 |
/**
|
95 |
+
* Handles the payment completion.
|
96 |
*
|
97 |
+
* @param WC_Order|null $wc_order The order.
|
98 |
+
* @param string|null $url The redirect URL.
|
99 |
+
* @return array The data that can be returned by the gateway process_payment method.
|
100 |
*/
|
101 |
+
protected function handle_payment_success( ?WC_Order $wc_order, string $url = null ): array {
|
102 |
+
if ( ! $url ) {
|
103 |
+
$url = $this->get_return_url( $wc_order );
|
104 |
+
}
|
105 |
+
|
106 |
+
$this->session_handler->destroy_session_data();
|
107 |
+
|
108 |
+
return array(
|
109 |
+
'result' => 'success',
|
110 |
+
'redirect' => $url,
|
111 |
+
);
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Outputs the exception, including the inner exception.
|
116 |
+
*
|
117 |
+
* @param Throwable $exception The exception to format.
|
118 |
+
* @return string
|
119 |
+
*/
|
120 |
+
protected function format_exception( Throwable $exception ): string {
|
121 |
+
$output = $exception->getMessage() . ' ' . $exception->getFile() . ':' . $exception->getLine();
|
122 |
+
$prev = $exception->getPrevious();
|
123 |
+
if ( ! $prev ) {
|
124 |
+
return $output;
|
125 |
+
}
|
126 |
+
if ( $exception instanceof GatewayGenericException ) {
|
127 |
+
$output = '';
|
128 |
+
}
|
129 |
+
return $output . ' ' . $this->format_exception( $prev );
|
130 |
+
}
|
131 |
}
|
modules/ppcp-wc-gateway/src/Helper/CheckoutHelper.php
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The Checkout helper.
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\WcGateway\Helper;
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
11 |
+
|
12 |
+
use DateTime;
|
13 |
+
use WC_Order;
|
14 |
+
use WC_Order_Item_Product;
|
15 |
+
use WC_Product;
|
16 |
+
use WC_Product_Variable;
|
17 |
+
use WC_Product_Variation;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* CheckoutHelper class.
|
21 |
+
*/
|
22 |
+
class CheckoutHelper {
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Checks if amount is allowed within the given range.
|
26 |
+
*
|
27 |
+
* @param float $minimum Minimum amount.
|
28 |
+
* @param float $maximum Maximum amount.
|
29 |
+
* @return bool
|
30 |
+
*/
|
31 |
+
public function is_checkout_amount_allowed( float $minimum, float $maximum ): bool {
|
32 |
+
$cart = WC()->cart ?? null;
|
33 |
+
if ( $cart && ! is_checkout_pay_page() ) {
|
34 |
+
$cart_total = (float) $cart->get_total( 'numeric' );
|
35 |
+
if ( $cart_total < $minimum || $cart_total > $maximum ) {
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
|
39 |
+
$items = $cart->get_cart_contents();
|
40 |
+
foreach ( $items as $item ) {
|
41 |
+
$product = wc_get_product( $item['product_id'] );
|
42 |
+
if ( is_a( $product, WC_Product::class ) && ! $this->is_physical_product( $product ) ) {
|
43 |
+
return false;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
if ( is_wc_endpoint_url( 'order-pay' ) ) {
|
49 |
+
/**
|
50 |
+
* Needed for WordPress `query_vars`.
|
51 |
+
*
|
52 |
+
* @psalm-suppress InvalidGlobal
|
53 |
+
*/
|
54 |
+
global $wp;
|
55 |
+
|
56 |
+
if ( isset( $wp->query_vars['order-pay'] ) && absint( $wp->query_vars['order-pay'] ) > 0 ) {
|
57 |
+
$order_id = absint( $wp->query_vars['order-pay'] );
|
58 |
+
$order = wc_get_order( $order_id );
|
59 |
+
if ( is_a( $order, WC_Order::class ) ) {
|
60 |
+
$order_total = (float) $order->get_total();
|
61 |
+
if ( $order_total < $minimum || $order_total > $maximum ) {
|
62 |
+
return false;
|
63 |
+
}
|
64 |
+
|
65 |
+
foreach ( $order->get_items() as $item_id => $item ) {
|
66 |
+
if ( is_a( $item, WC_Order_Item_Product::class ) ) {
|
67 |
+
$product = wc_get_product( $item->get_product_id() );
|
68 |
+
if ( is_a( $product, WC_Product::class ) && ! $this->is_physical_product( $product ) ) {
|
69 |
+
return false;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
return true;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Ensures date is valid and at least 18 years back.
|
82 |
+
*
|
83 |
+
* @param string $date The date.
|
84 |
+
* @param string $format The date format.
|
85 |
+
* @return bool
|
86 |
+
*/
|
87 |
+
public function validate_birth_date( string $date, string $format = 'Y-m-d' ): bool {
|
88 |
+
$d = DateTime::createFromFormat( $format, $date );
|
89 |
+
if ( false === $d ) {
|
90 |
+
return false;
|
91 |
+
}
|
92 |
+
|
93 |
+
if ( $date !== $d->format( $format ) ) {
|
94 |
+
return false;
|
95 |
+
}
|
96 |
+
|
97 |
+
$date_time = strtotime( $date );
|
98 |
+
if ( $date_time && time() < strtotime( '+18 years', $date_time ) ) {
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
if ( $date_time < strtotime( '-100 years', time() ) ) {
|
102 |
+
return false;
|
103 |
+
}
|
104 |
+
|
105 |
+
return true;
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Ensures product is neither downloadable nor virtual.
|
110 |
+
*
|
111 |
+
* @param WC_Product $product WC product.
|
112 |
+
* @return bool
|
113 |
+
*/
|
114 |
+
public function is_physical_product( WC_Product $product ):bool {
|
115 |
+
if ( $product->is_downloadable() || $product->is_virtual() ) {
|
116 |
+
return false;
|
117 |
+
}
|
118 |
+
|
119 |
+
if ( is_a( $product, WC_Product_Variable::class ) ) {
|
120 |
+
foreach ( $product->get_available_variations( 'object' ) as $variation ) {
|
121 |
+
if ( is_a( $variation, WC_Product_Variation::class ) ) {
|
122 |
+
if ( true === $variation->is_downloadable() || true === $variation->is_virtual() ) {
|
123 |
+
return false;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
return true;
|
130 |
+
}
|
131 |
+
}
|
modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php
CHANGED
@@ -9,65 +9,25 @@ declare( strict_types=1 );
|
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
11 |
|
12 |
-
use DateTime;
|
13 |
-
use WC_Order;
|
14 |
-
use WC_Order_Item_Product;
|
15 |
-
use WC_Product;
|
16 |
-
use WC_Product_Variable;
|
17 |
-
use WC_Product_Variation;
|
18 |
-
|
19 |
/**
|
20 |
* Class PayUponInvoiceHelper
|
21 |
*/
|
22 |
class PayUponInvoiceHelper {
|
23 |
|
24 |
/**
|
25 |
-
*
|
26 |
*
|
27 |
-
* @
|
28 |
-
* @param string $format The date format.
|
29 |
-
* @return bool
|
30 |
*/
|
31 |
-
|
32 |
-
$d = DateTime::createFromFormat( $format, $date );
|
33 |
-
if ( false === $d ) {
|
34 |
-
return false;
|
35 |
-
}
|
36 |
-
|
37 |
-
if ( $date !== $d->format( $format ) ) {
|
38 |
-
return false;
|
39 |
-
}
|
40 |
-
|
41 |
-
$date_time = strtotime( $date );
|
42 |
-
if ( $date_time && time() < strtotime( '+18 years', $date_time ) ) {
|
43 |
-
return false;
|
44 |
-
}
|
45 |
-
|
46 |
-
return true;
|
47 |
-
}
|
48 |
|
49 |
/**
|
50 |
-
*
|
51 |
*
|
52 |
-
* @param
|
53 |
-
* @return bool
|
54 |
*/
|
55 |
-
public function
|
56 |
-
|
57 |
-
return false;
|
58 |
-
}
|
59 |
-
|
60 |
-
if ( is_a( $product, WC_Product_Variable::class ) ) {
|
61 |
-
foreach ( $product->get_available_variations( 'object' ) as $variation ) {
|
62 |
-
if ( is_a( $variation, WC_Product_Variation::class ) ) {
|
63 |
-
if ( true === $variation->is_downloadable() || true === $variation->is_virtual() ) {
|
64 |
-
return false;
|
65 |
-
}
|
66 |
-
}
|
67 |
-
}
|
68 |
-
}
|
69 |
-
|
70 |
-
return true;
|
71 |
}
|
72 |
|
73 |
/**
|
@@ -90,49 +50,8 @@ class PayUponInvoiceHelper {
|
|
90 |
return false;
|
91 |
}
|
92 |
|
93 |
-
$
|
94 |
-
|
95 |
-
$cart_total = (float) $cart->get_total( 'numeric' );
|
96 |
-
if ( $cart_total < 5 || $cart_total > 2500 ) {
|
97 |
-
return false;
|
98 |
-
}
|
99 |
-
|
100 |
-
$items = $cart->get_cart_contents();
|
101 |
-
foreach ( $items as $item ) {
|
102 |
-
$product = wc_get_product( $item['product_id'] );
|
103 |
-
if ( is_a( $product, WC_Product::class ) && ! $this->product_ready_for_pui( $product ) ) {
|
104 |
-
return false;
|
105 |
-
}
|
106 |
-
}
|
107 |
-
}
|
108 |
-
|
109 |
-
if ( is_wc_endpoint_url( 'order-pay' ) ) {
|
110 |
-
/**
|
111 |
-
* Needed for WordPress `query_vars`.
|
112 |
-
*
|
113 |
-
* @psalm-suppress InvalidGlobal
|
114 |
-
*/
|
115 |
-
global $wp;
|
116 |
-
|
117 |
-
if ( isset( $wp->query_vars['order-pay'] ) && absint( $wp->query_vars['order-pay'] ) > 0 ) {
|
118 |
-
$order_id = absint( $wp->query_vars['order-pay'] );
|
119 |
-
$order = wc_get_order( $order_id );
|
120 |
-
if ( is_a( $order, WC_Order::class ) ) {
|
121 |
-
$order_total = (float) $order->get_total();
|
122 |
-
if ( $order_total < 5 || $order_total > 2500 ) {
|
123 |
-
return false;
|
124 |
-
}
|
125 |
-
|
126 |
-
foreach ( $order->get_items() as $item_id => $item ) {
|
127 |
-
if ( is_a( $item, WC_Order_Item_Product::class ) ) {
|
128 |
-
$product = wc_get_product( $item->get_product_id() );
|
129 |
-
if ( is_a( $product, WC_Product::class ) && ! $this->product_ready_for_pui( $product ) ) {
|
130 |
-
return false;
|
131 |
-
}
|
132 |
-
}
|
133 |
-
}
|
134 |
-
}
|
135 |
-
}
|
136 |
}
|
137 |
|
138 |
return true;
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
/**
|
13 |
* Class PayUponInvoiceHelper
|
14 |
*/
|
15 |
class PayUponInvoiceHelper {
|
16 |
|
17 |
/**
|
18 |
+
* The checkout helper.
|
19 |
*
|
20 |
+
* @var CheckoutHelper
|
|
|
|
|
21 |
*/
|
22 |
+
protected $checkout_helper;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
/**
|
25 |
+
* PayUponInvoiceHelper constructor.
|
26 |
*
|
27 |
+
* @param CheckoutHelper $checkout_helper The checkout helper.
|
|
|
28 |
*/
|
29 |
+
public function __construct( CheckoutHelper $checkout_helper ) {
|
30 |
+
$this->checkout_helper = $checkout_helper;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
/**
|
50 |
return false;
|
51 |
}
|
52 |
|
53 |
+
if ( ! $this->checkout_helper->is_checkout_amount_allowed( 5, 2500 ) ) {
|
54 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
return true;
|
modules/ppcp-wc-gateway/src/Notice/{DccWithoutPayPalAdminNotice.php → GatewayWithoutPayPalAdminNotice.php}
RENAMED
@@ -1,6 +1,6 @@
|
|
1 |
<?php
|
2 |
/**
|
3 |
-
* Creates the admin message about the
|
4 |
*
|
5 |
* @package WooCommerce\PayPalCommerce\WcGateway\Notice
|
6 |
*/
|
@@ -9,14 +9,21 @@ declare(strict_types=1);
|
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Notice;
|
11 |
|
|
|
12 |
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
13 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
14 |
use Psr\Container\ContainerInterface;
|
15 |
|
16 |
/**
|
17 |
-
* Creates the admin message about the
|
18 |
*/
|
19 |
-
class
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
/**
|
22 |
* The state.
|
@@ -49,17 +56,20 @@ class DccWithoutPayPalAdminNotice {
|
|
49 |
/**
|
50 |
* ConnectAdminNotice constructor.
|
51 |
*
|
|
|
52 |
* @param State $state The state.
|
53 |
* @param ContainerInterface $settings The settings.
|
54 |
* @param bool $is_payments_page Whether the current page is the WC payment page.
|
55 |
* @param bool $is_ppcp_settings_page Whether the current page is the PPCP settings page.
|
56 |
*/
|
57 |
public function __construct(
|
|
|
58 |
State $state,
|
59 |
ContainerInterface $settings,
|
60 |
bool $is_payments_page,
|
61 |
bool $is_ppcp_settings_page
|
62 |
) {
|
|
|
63 |
$this->state = $state;
|
64 |
$this->settings = $settings;
|
65 |
$this->is_payments_page = $is_payments_page;
|
@@ -76,12 +86,20 @@ class DccWithoutPayPalAdminNotice {
|
|
76 |
return null;
|
77 |
}
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
$message = sprintf(
|
80 |
-
/* translators: %1$s the gateway name. */
|
81 |
__(
|
82 |
-
'
|
83 |
'woocommerce-paypal-payments'
|
84 |
),
|
|
|
85 |
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' )
|
86 |
);
|
87 |
return new Message( $message, 'warning' );
|
@@ -93,9 +111,29 @@ class DccWithoutPayPalAdminNotice {
|
|
93 |
* @return bool
|
94 |
*/
|
95 |
protected function should_display(): bool {
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
}
|
101 |
}
|
1 |
<?php
|
2 |
/**
|
3 |
+
* Creates the admin message about the gateway being enabled without the PayPal gateway.
|
4 |
*
|
5 |
* @package WooCommerce\PayPalCommerce\WcGateway\Notice
|
6 |
*/
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Notice;
|
11 |
|
12 |
+
use WC_Payment_Gateway;
|
13 |
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
14 |
use WooCommerce\PayPalCommerce\Onboarding\State;
|
15 |
use Psr\Container\ContainerInterface;
|
16 |
|
17 |
/**
|
18 |
+
* Creates the admin message about the gateway being enabled without the PayPal gateway.
|
19 |
*/
|
20 |
+
class GatewayWithoutPayPalAdminNotice {
|
21 |
+
/**
|
22 |
+
* The gateway ID.
|
23 |
+
*
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
private $id;
|
27 |
|
28 |
/**
|
29 |
* The state.
|
56 |
/**
|
57 |
* ConnectAdminNotice constructor.
|
58 |
*
|
59 |
+
* @param string $id The gateway ID.
|
60 |
* @param State $state The state.
|
61 |
* @param ContainerInterface $settings The settings.
|
62 |
* @param bool $is_payments_page Whether the current page is the WC payment page.
|
63 |
* @param bool $is_ppcp_settings_page Whether the current page is the PPCP settings page.
|
64 |
*/
|
65 |
public function __construct(
|
66 |
+
string $id,
|
67 |
State $state,
|
68 |
ContainerInterface $settings,
|
69 |
bool $is_payments_page,
|
70 |
bool $is_ppcp_settings_page
|
71 |
) {
|
72 |
+
$this->id = $id;
|
73 |
$this->state = $state;
|
74 |
$this->settings = $settings;
|
75 |
$this->is_payments_page = $is_payments_page;
|
86 |
return null;
|
87 |
}
|
88 |
|
89 |
+
$gateway = $this->get_gateway();
|
90 |
+
if ( ! $gateway ) {
|
91 |
+
return null;
|
92 |
+
}
|
93 |
+
|
94 |
+
$name = $gateway->get_method_title();
|
95 |
+
|
96 |
$message = sprintf(
|
97 |
+
/* translators: %1$s the gateway name, %2$s URL. */
|
98 |
__(
|
99 |
+
'%1$s cannot be used without the PayPal gateway. <a href="%2$s">Enable the PayPal gateway</a>.',
|
100 |
'woocommerce-paypal-payments'
|
101 |
),
|
102 |
+
$name,
|
103 |
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' )
|
104 |
);
|
105 |
return new Message( $message, 'warning' );
|
111 |
* @return bool
|
112 |
*/
|
113 |
protected function should_display(): bool {
|
114 |
+
if ( State::STATE_ONBOARDED !== $this->state->current_state() ||
|
115 |
+
( ! $this->is_payments_page && ! $this->is_ppcp_settings_page ) ) {
|
116 |
+
return false;
|
117 |
+
}
|
118 |
+
if ( $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' ) ) {
|
119 |
+
return false;
|
120 |
+
}
|
121 |
+
|
122 |
+
$gateway = $this->get_gateway();
|
123 |
+
|
124 |
+
return $gateway && wc_string_to_bool( $gateway->get_option( 'enabled' ) );
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Returns the gateway object or null.
|
129 |
+
*
|
130 |
+
* @return WC_Payment_Gateway|null
|
131 |
+
*/
|
132 |
+
protected function get_gateway(): ?WC_Payment_Gateway {
|
133 |
+
$gateways = WC()->payment_gateways->payment_gateways();
|
134 |
+
if ( ! isset( $gateways[ $this->id ] ) ) {
|
135 |
+
return null;
|
136 |
+
}
|
137 |
+
return $gateways[ $this->id ];
|
138 |
}
|
139 |
}
|
modules/ppcp-wc-gateway/src/Settings/PageMatcherTrait.php
CHANGED
@@ -9,6 +9,7 @@ declare(strict_types=1);
|
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
11 |
|
|
|
12 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
13 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
14 |
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
@@ -34,6 +35,7 @@ trait PageMatcherTrait {
|
|
34 |
$gateway_page_id_map = array(
|
35 |
PayPalGateway::ID => 'paypal',
|
36 |
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
|
|
|
37 |
WebhooksStatusPage::ID => WebhooksStatusPage::ID,
|
38 |
);
|
39 |
return array_key_exists( $current_page_id, $gateway_page_id_map )
|
9 |
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
11 |
|
12 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
13 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
14 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
15 |
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
35 |
$gateway_page_id_map = array(
|
36 |
PayPalGateway::ID => 'paypal',
|
37 |
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
|
38 |
+
CardButtonGateway::ID => CardButtonGateway::ID,
|
39 |
WebhooksStatusPage::ID => WebhooksStatusPage::ID,
|
40 |
);
|
41 |
return array_key_exists( $current_page_id, $gateway_page_id_map )
|
modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php
CHANGED
@@ -10,8 +10,6 @@ declare( strict_types=1 );
|
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
13 |
-
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
14 |
-
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
15 |
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
16 |
|
17 |
/**
|
@@ -29,21 +27,21 @@ class SectionsRenderer {
|
|
29 |
protected $page_id;
|
30 |
|
31 |
/**
|
32 |
-
*
|
33 |
*
|
34 |
-
* @var string
|
35 |
*/
|
36 |
-
protected $
|
37 |
|
38 |
/**
|
39 |
* SectionsRenderer constructor.
|
40 |
*
|
41 |
-
* @param string
|
42 |
-
* @param string $
|
43 |
*/
|
44 |
-
public function __construct( string $page_id,
|
45 |
-
$this->page_id
|
46 |
-
$this->
|
47 |
}
|
48 |
|
49 |
/**
|
@@ -58,30 +56,22 @@ class SectionsRenderer {
|
|
58 |
/**
|
59 |
* Renders the Sections tab.
|
60 |
*/
|
61 |
-
public function render() {
|
62 |
if ( ! $this->should_render() ) {
|
63 |
return;
|
64 |
}
|
65 |
|
66 |
-
$sections = array(
|
67 |
-
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
68 |
-
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
69 |
-
PayUponInvoiceGateway::ID => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
|
70 |
-
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
|
71 |
-
);
|
72 |
-
|
73 |
-
if ( 'DE' !== $this->api_shop_country ) {
|
74 |
-
unset( $sections[ PayUponInvoiceGateway::ID ] );
|
75 |
-
}
|
76 |
-
|
77 |
echo '<ul class="subsubsub">';
|
78 |
|
79 |
-
$array_keys = array_keys( $sections );
|
80 |
|
81 |
-
foreach ( $sections as $id => $label ) {
|
82 |
-
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=
|
83 |
-
if (
|
84 |
-
|
|
|
|
|
|
|
85 |
}
|
86 |
echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $this->page_id === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
|
87 |
}
|
10 |
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
11 |
|
12 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
|
|
|
|
13 |
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
14 |
|
15 |
/**
|
27 |
protected $page_id;
|
28 |
|
29 |
/**
|
30 |
+
* Key - page/gateway ID, value - displayed text.
|
31 |
*
|
32 |
+
* @var array<string, string>
|
33 |
*/
|
34 |
+
protected $sections;
|
35 |
|
36 |
/**
|
37 |
* SectionsRenderer constructor.
|
38 |
*
|
39 |
+
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
40 |
+
* @param array<string, string> $sections Key - page/gateway ID, value - displayed text.
|
41 |
*/
|
42 |
+
public function __construct( string $page_id, array $sections ) {
|
43 |
+
$this->page_id = $page_id;
|
44 |
+
$this->sections = $sections;
|
45 |
}
|
46 |
|
47 |
/**
|
56 |
/**
|
57 |
* Renders the Sections tab.
|
58 |
*/
|
59 |
+
public function render(): void {
|
60 |
if ( ! $this->should_render() ) {
|
61 |
return;
|
62 |
}
|
63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
echo '<ul class="subsubsub">';
|
65 |
|
66 |
+
$array_keys = array_keys( $this->sections );
|
67 |
|
68 |
+
foreach ( $this->sections as $id => $label ) {
|
69 |
+
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=' . $id );
|
70 |
+
if ( in_array( $id, array( CreditCardGateway::ID, WebhooksStatusPage::ID ), true ) ) {
|
71 |
+
// We need section=ppcp-gateway for the webhooks page because it is not a gateway,
|
72 |
+
// and for DCC because otherwise it will not render the page if gateway is not available (country/currency).
|
73 |
+
// Other gateways render fields differently, and their pages are not expected to work when gateway is not available.
|
74 |
+
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id );
|
75 |
}
|
76 |
echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $this->page_id === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
|
77 |
}
|
modules/ppcp-wc-gateway/src/WCGatewayModule.php
CHANGED
@@ -29,7 +29,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
|
29 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
30 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
31 |
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
32 |
-
use WooCommerce\PayPalCommerce\WcGateway\Notice\
|
33 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
34 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
35 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
@@ -164,11 +164,15 @@ class WCGatewayModule implements ModuleInterface {
|
|
164 |
$notices[] = $connect_message;
|
165 |
}
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
$
|
|
|
|
|
|
|
|
|
172 |
}
|
173 |
|
174 |
$authorize_order_action = $c->get( 'wcgateway.notice.authorize-order-action' );
|
@@ -231,6 +235,10 @@ class WCGatewayModule implements ModuleInterface {
|
|
231 |
if ( 'DE' === $c->get( 'api.shop.country' ) && 'EUR' === $c->get( 'api.shop.currency' ) ) {
|
232 |
( $c->get( 'wcgateway.pay-upon-invoice' ) )->init();
|
233 |
}
|
|
|
|
|
|
|
|
|
234 |
}
|
235 |
);
|
236 |
|
@@ -260,6 +268,18 @@ class WCGatewayModule implements ModuleInterface {
|
|
260 |
10,
|
261 |
2
|
262 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
}
|
264 |
|
265 |
/**
|
@@ -284,10 +304,18 @@ class WCGatewayModule implements ModuleInterface {
|
|
284 |
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
285 |
}
|
286 |
|
|
|
|
|
|
|
|
|
287 |
if ( 'DE' === $container->get( 'api.shop.country' ) && 'EUR' === $container->get( 'api.shop.currency' ) ) {
|
288 |
$methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' );
|
289 |
}
|
290 |
|
|
|
|
|
|
|
|
|
291 |
return (array) $methods;
|
292 |
}
|
293 |
);
|
29 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
30 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
31 |
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
32 |
+
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
|
33 |
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
34 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
35 |
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
164 |
$notices[] = $connect_message;
|
165 |
}
|
166 |
|
167 |
+
foreach ( array(
|
168 |
+
$c->get( 'wcgateway.notice.dcc-without-paypal' ),
|
169 |
+
$c->get( 'wcgateway.notice.card-button-without-paypal' ),
|
170 |
+
) as $gateway_without_paypal_notice ) {
|
171 |
+
assert( $gateway_without_paypal_notice instanceof GatewayWithoutPayPalAdminNotice );
|
172 |
+
$message = $gateway_without_paypal_notice->message();
|
173 |
+
if ( $message ) {
|
174 |
+
$notices[] = $message;
|
175 |
+
}
|
176 |
}
|
177 |
|
178 |
$authorize_order_action = $c->get( 'wcgateway.notice.authorize-order-action' );
|
235 |
if ( 'DE' === $c->get( 'api.shop.country' ) && 'EUR' === $c->get( 'api.shop.currency' ) ) {
|
236 |
( $c->get( 'wcgateway.pay-upon-invoice' ) )->init();
|
237 |
}
|
238 |
+
|
239 |
+
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === true ) {
|
240 |
+
( $c->get( 'wcgateway.oxxo' ) )->init();
|
241 |
+
}
|
242 |
}
|
243 |
);
|
244 |
|
268 |
10,
|
269 |
2
|
270 |
);
|
271 |
+
|
272 |
+
add_action(
|
273 |
+
'wc_ajax_ppc-oxxo',
|
274 |
+
static function () use ( $c ) {
|
275 |
+
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === false ) {
|
276 |
+
return;
|
277 |
+
}
|
278 |
+
|
279 |
+
$endpoint = $c->get( 'wcgateway.endpoint.oxxo' );
|
280 |
+
$endpoint->handle_request();
|
281 |
+
}
|
282 |
+
);
|
283 |
}
|
284 |
|
285 |
/**
|
304 |
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
305 |
}
|
306 |
|
307 |
+
if ( $container->get( 'wcgateway.settings.allow_card_button_gateway' ) ) {
|
308 |
+
$methods[] = $container->get( 'wcgateway.card-button-gateway' );
|
309 |
+
}
|
310 |
+
|
311 |
if ( 'DE' === $container->get( 'api.shop.country' ) && 'EUR' === $container->get( 'api.shop.currency' ) ) {
|
312 |
$methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' );
|
313 |
}
|
314 |
|
315 |
+
if ( defined( 'PPCP_FLAG_OXXO' ) && PPCP_FLAG_OXXO === true ) {
|
316 |
+
$methods[] = $container->get( 'wcgateway.oxxo-gateway' );
|
317 |
+
}
|
318 |
+
|
319 |
return (array) $methods;
|
320 |
}
|
321 |
);
|
modules/ppcp-wc-gateway/webpack.config.js
CHANGED
@@ -8,6 +8,7 @@ module.exports = {
|
|
8 |
entry: {
|
9 |
'gateway-settings': path.resolve('./resources/js/gateway-settings.js'),
|
10 |
'pay-upon-invoice': path.resolve('./resources/js/pay-upon-invoice.js'),
|
|
|
11 |
},
|
12 |
output: {
|
13 |
path: path.resolve(__dirname, 'assets/'),
|
8 |
entry: {
|
9 |
'gateway-settings': path.resolve('./resources/js/gateway-settings.js'),
|
10 |
'pay-upon-invoice': path.resolve('./resources/js/pay-upon-invoice.js'),
|
11 |
+
'oxxo': path.resolve('./resources/js/oxxo.js'),
|
12 |
},
|
13 |
output: {
|
14 |
path: path.resolve(__dirname, 'assets/'),
|
modules/ppcp-webhooks/services.php
CHANGED
@@ -20,6 +20,8 @@ use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
|
|
20 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
|
21 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
|
22 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
|
|
|
|
|
23 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureRefunded;
|
24 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureReversed;
|
25 |
use Psr\Container\ContainerInterface;
|
@@ -78,6 +80,7 @@ return array(
|
|
78 |
new PaymentCaptureCompleted( $logger, $prefix, $order_endpoint ),
|
79 |
new VaultPaymentTokenCreated( $logger, $prefix, $authorized_payments_processor ),
|
80 |
new VaultCreditCardCreated( $logger, $prefix ),
|
|
|
81 |
);
|
82 |
},
|
83 |
|
20 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
|
21 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
|
22 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
|
23 |
+
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureDenied;
|
24 |
+
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCapturePending;
|
25 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureRefunded;
|
26 |
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureReversed;
|
27 |
use Psr\Container\ContainerInterface;
|
80 |
new PaymentCaptureCompleted( $logger, $prefix, $order_endpoint ),
|
81 |
new VaultPaymentTokenCreated( $logger, $prefix, $authorized_payments_processor ),
|
82 |
new VaultCreditCardCreated( $logger, $prefix ),
|
83 |
+
new PaymentCapturePending( $logger ),
|
84 |
);
|
85 |
},
|
86 |
|
modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php
CHANGED
@@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
13 |
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
14 |
use Psr\Log\LoggerInterface;
|
|
|
15 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
16 |
|
17 |
/**
|
@@ -189,7 +190,7 @@ class CheckoutOrderApproved implements RequestHandler {
|
|
189 |
}
|
190 |
|
191 |
foreach ( $wc_orders as $wc_order ) {
|
192 |
-
if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() ) {
|
193 |
continue;
|
194 |
}
|
195 |
|
12 |
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
13 |
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
14 |
use Psr\Log\LoggerInterface;
|
15 |
+
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
16 |
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
17 |
|
18 |
/**
|
190 |
}
|
191 |
|
192 |
foreach ( $wc_orders as $wc_order ) {
|
193 |
+
if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() || OXXOGateway::ID === $wc_order->get_payment_method() ) {
|
194 |
continue;
|
195 |
}
|
196 |
|
modules/ppcp-webhooks/src/Handler/PaymentCapturePending.php
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handles the Webhook PAYMENT.CAPTURE.PENDING
|
4 |
+
*
|
5 |
+
* @package WooCommerce\PayPalCommerce\Webhooks\Handler
|
6 |
+
*/
|
7 |
+
|
8 |
+
declare(strict_types=1);
|
9 |
+
|
10 |
+
namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
11 |
+
|
12 |
+
use Psr\Log\LoggerInterface;
|
13 |
+
use WP_REST_Request;
|
14 |
+
use WP_REST_Response;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Class PaymentCaptureCompleted
|
18 |
+
*/
|
19 |
+
class PaymentCapturePending implements RequestHandler {
|
20 |
+
|
21 |
+
use PrefixTrait;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* The logger.
|
25 |
+
*
|
26 |
+
* @var LoggerInterface
|
27 |
+
*/
|
28 |
+
private $logger;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* PaymentCaptureCompleted constructor.
|
32 |
+
*
|
33 |
+
* @param LoggerInterface $logger The logger.
|
34 |
+
*/
|
35 |
+
public function __construct(
|
36 |
+
LoggerInterface $logger
|
37 |
+
) {
|
38 |
+
$this->logger = $logger;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* The event types a handler handles.
|
43 |
+
*
|
44 |
+
* @return string[]
|
45 |
+
*/
|
46 |
+
public function event_types(): array {
|
47 |
+
return array( 'PAYMENT.CAPTURE.PENDING' );
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Whether a handler is responsible for a given request or not.
|
52 |
+
*
|
53 |
+
* @param \WP_REST_Request $request The request.
|
54 |
+
*
|
55 |
+
* @return bool
|
56 |
+
*/
|
57 |
+
public function responsible_for_request( \WP_REST_Request $request ): bool {
|
58 |
+
return in_array( $request['event_type'], $this->event_types(), true );
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Responsible for handling the request.
|
63 |
+
*
|
64 |
+
* @param WP_REST_Request $request The request.
|
65 |
+
*
|
66 |
+
* @return WP_REST_Response
|
67 |
+
*/
|
68 |
+
public function handle_request( WP_REST_Request $request ): WP_REST_Response {
|
69 |
+
$response = array( 'success' => false );
|
70 |
+
$order_id = $request['resource'] !== null && isset( $request['resource']['custom_id'] )
|
71 |
+
? $this->sanitize_custom_id( $request['resource']['custom_id'] )
|
72 |
+
: 0;
|
73 |
+
if ( ! $order_id ) {
|
74 |
+
$message = sprintf(
|
75 |
+
// translators: %s is the PayPal webhook Id.
|
76 |
+
__(
|
77 |
+
'No order for webhook event %s was found.',
|
78 |
+
'woocommerce-paypal-payments'
|
79 |
+
),
|
80 |
+
$request['id'] !== null && isset( $request['id'] ) ? $request['id'] : ''
|
81 |
+
);
|
82 |
+
$this->logger->log(
|
83 |
+
'warning',
|
84 |
+
$message,
|
85 |
+
array(
|
86 |
+
'request' => $request,
|
87 |
+
)
|
88 |
+
);
|
89 |
+
$response['message'] = $message;
|
90 |
+
return new WP_REST_Response( $response );
|
91 |
+
}
|
92 |
+
|
93 |
+
$resource = $request['resource'];
|
94 |
+
if ( ! is_array( $resource ) ) {
|
95 |
+
$message = 'Resource data not found in webhook request.';
|
96 |
+
$this->logger->warning( $message, array( 'request' => $request ) );
|
97 |
+
$response['message'] = $message;
|
98 |
+
return new WP_REST_Response( $response );
|
99 |
+
}
|
100 |
+
|
101 |
+
$wc_order = wc_get_order( $order_id );
|
102 |
+
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
103 |
+
$message = sprintf(
|
104 |
+
'WC order for PayPal ID %s not found.',
|
105 |
+
$request['resource'] !== null && isset( $request['resource']['id'] ) ? $request['resource']['id'] : ''
|
106 |
+
);
|
107 |
+
|
108 |
+
$this->logger->warning( $message );
|
109 |
+
|
110 |
+
$response['message'] = $message;
|
111 |
+
return new WP_REST_Response( $response );
|
112 |
+
}
|
113 |
+
|
114 |
+
if ( $wc_order->get_status() === 'pending' ) {
|
115 |
+
$wc_order->update_status( 'on-hold', __( 'Payment initiation was successful, and is waiting for the buyer to complete the payment.', 'woocommerce-paypal-payments' ) );
|
116 |
+
|
117 |
+
}
|
118 |
+
|
119 |
+
$response['success'] = true;
|
120 |
+
return new WP_REST_Response( $response );
|
121 |
+
}
|
122 |
+
}
|
modules/ppcp-webhooks/src/Handler/PaymentCaptureRefunded.php
CHANGED
@@ -46,7 +46,7 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|
46 |
* @return string[]
|
47 |
*/
|
48 |
public function event_types(): array {
|
49 |
-
return array( 'PAYMENT.CAPTURE.REFUNDED' );
|
50 |
}
|
51 |
|
52 |
/**
|
46 |
* @return string[]
|
47 |
*/
|
48 |
public function event_types(): array {
|
49 |
+
return array( 'PAYMENT.CAPTURE.REFUNDED', 'PAYMENT.AUTHORIZATION.VOIDED' );
|
50 |
}
|
51 |
|
52 |
/**
|
modules/ppcp-webhooks/src/Handler/PaymentCaptureReversed.php
CHANGED
@@ -112,12 +112,17 @@ class PaymentCaptureReversed implements RequestHandler {
|
|
112 |
return rest_ensure_response( $response );
|
113 |
}
|
114 |
|
|
|
|
|
|
|
|
|
|
|
115 |
/**
|
116 |
* The WooCommerce order.
|
117 |
*
|
118 |
* @var \WC_Order $wc_order
|
119 |
*/
|
120 |
-
$response['success'] = (bool) $wc_order->update_status( 'cancelled' );
|
121 |
|
122 |
$message = $response['success'] ? sprintf(
|
123 |
// translators: %1$s is the order id.
|
112 |
return rest_ensure_response( $response );
|
113 |
}
|
114 |
|
115 |
+
/**
|
116 |
+
* Allows adding an update status note.
|
117 |
+
*/
|
118 |
+
$note = apply_filters( 'ppcp_payment_capture_reversed_webhook_update_status_note', '', $wc_order, $request['event_type'] );
|
119 |
+
|
120 |
/**
|
121 |
* The WooCommerce order.
|
122 |
*
|
123 |
* @var \WC_Order $wc_order
|
124 |
*/
|
125 |
+
$response['success'] = (bool) $wc_order->update_status( 'cancelled', $note );
|
126 |
|
127 |
$message = $response['success'] ? sprintf(
|
128 |
// translators: %1$s is the order id.
|
readme.txt
CHANGED
@@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell,
|
|
4 |
Requires at least: 5.3
|
5 |
Tested up to: 6.0
|
6 |
Requires PHP: 7.1
|
7 |
-
Stable tag: 1.9.
|
8 |
License: GPLv2
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -81,6 +81,19 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|
81 |
|
82 |
== Changelog ==
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
= 1.9.1 =
|
85 |
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
86 |
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
4 |
Requires at least: 5.3
|
5 |
Tested up to: 6.0
|
6 |
Requires PHP: 7.1
|
7 |
+
Stable tag: 1.9.2
|
8 |
License: GPLv2
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
81 |
|
82 |
== Changelog ==
|
83 |
|
84 |
+
= 1.9.2 =
|
85 |
+
* Fix - Do not allow birth date older than 100 years for PUI. #743
|
86 |
+
* Fix - Store the customer id for vaulted payment method in usermeta to not lose vaulted methods after the invoice prefix change. #698
|
87 |
+
* Fix - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
|
88 |
+
* Fix - Voiding authorization at PayPal did not update the status/order notes. #712
|
89 |
+
* Fix - PayPal scripts were loading on pages without smart buttons or Pay Later messaging. #750
|
90 |
+
* Fix - Do not show links for unavailable gateways settings pages. #753
|
91 |
+
* Fix - The smart buttons were not loaded on single product page if a subscription product exists in the cart. #703
|
92 |
+
* Fix - DCC was causing other gateways to disappear after checkout validation error. #757
|
93 |
+
* Fix - Buttons not loading on single product page with default settings when product is in cart. #777
|
94 |
+
* Enhancement - Improve Checkout Field Validation Message. #739
|
95 |
+
* Enhancement - Handle PAYER_ACTION_REQUIRED error. #759
|
96 |
+
|
97 |
= 1.9.1 =
|
98 |
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
99 |
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
vendor/autoload.php
CHANGED
@@ -4,4 +4,4 @@
|
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
-
return
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
+
return ComposerAutoloaderInita666fe7b7b5a2bfddefb2ffdba48c7b2::getLoader();
|
vendor/composer/autoload_real.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
-
class
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf
|
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
-
spl_autoload_register(array('
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
-
spl_autoload_unregister(array('
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
-
call_user_func(\Composer\Autoload\
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
@@ -51,19 +51,19 @@ class ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf
|
|
51 |
$loader->register(true);
|
52 |
|
53 |
if ($useStaticLoader) {
|
54 |
-
$includeFiles = Composer\Autoload\
|
55 |
} else {
|
56 |
$includeFiles = require __DIR__ . '/autoload_files.php';
|
57 |
}
|
58 |
foreach ($includeFiles as $fileIdentifier => $file) {
|
59 |
-
|
60 |
}
|
61 |
|
62 |
return $loader;
|
63 |
}
|
64 |
}
|
65 |
|
66 |
-
function
|
67 |
{
|
68 |
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
69 |
require $file;
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class ComposerAutoloaderInita666fe7b7b5a2bfddefb2ffdba48c7b2
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
+
spl_autoload_register(array('ComposerAutoloaderInita666fe7b7b5a2bfddefb2ffdba48c7b2', 'loadClassLoader'), true, true);
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
+
spl_autoload_unregister(array('ComposerAutoloaderInita666fe7b7b5a2bfddefb2ffdba48c7b2', 'loadClassLoader'));
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
+
call_user_func(\Composer\Autoload\ComposerStaticInita666fe7b7b5a2bfddefb2ffdba48c7b2::getInitializer($loader));
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
51 |
$loader->register(true);
|
52 |
|
53 |
if ($useStaticLoader) {
|
54 |
+
$includeFiles = Composer\Autoload\ComposerStaticInita666fe7b7b5a2bfddefb2ffdba48c7b2::$files;
|
55 |
} else {
|
56 |
$includeFiles = require __DIR__ . '/autoload_files.php';
|
57 |
}
|
58 |
foreach ($includeFiles as $fileIdentifier => $file) {
|
59 |
+
composerRequirea666fe7b7b5a2bfddefb2ffdba48c7b2($fileIdentifier, $file);
|
60 |
}
|
61 |
|
62 |
return $loader;
|
63 |
}
|
64 |
}
|
65 |
|
66 |
+
function composerRequirea666fe7b7b5a2bfddefb2ffdba48c7b2($fileIdentifier, $file)
|
67 |
{
|
68 |
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
69 |
require $file;
|
vendor/composer/autoload_static.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
-
class
|
8 |
{
|
9 |
public static $files = array (
|
10 |
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
@@ -173,9 +173,9 @@ class ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf
|
|
173 |
public static function getInitializer(ClassLoader $loader)
|
174 |
{
|
175 |
return \Closure::bind(function () use ($loader) {
|
176 |
-
$loader->prefixLengthsPsr4 =
|
177 |
-
$loader->prefixDirsPsr4 =
|
178 |
-
$loader->classMap =
|
179 |
|
180 |
}, null, ClassLoader::class);
|
181 |
}
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
+
class ComposerStaticInita666fe7b7b5a2bfddefb2ffdba48c7b2
|
8 |
{
|
9 |
public static $files = array (
|
10 |
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
173 |
public static function getInitializer(ClassLoader $loader)
|
174 |
{
|
175 |
return \Closure::bind(function () use ($loader) {
|
176 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInita666fe7b7b5a2bfddefb2ffdba48c7b2::$prefixLengthsPsr4;
|
177 |
+
$loader->prefixDirsPsr4 = ComposerStaticInita666fe7b7b5a2bfddefb2ffdba48c7b2::$prefixDirsPsr4;
|
178 |
+
$loader->classMap = ComposerStaticInita666fe7b7b5a2bfddefb2ffdba48c7b2::$classMap;
|
179 |
|
180 |
}, null, ClassLoader::class);
|
181 |
}
|
woocommerce-paypal-payments.php
CHANGED
@@ -3,13 +3,13 @@
|
|
3 |
* Plugin Name: WooCommerce PayPal Payments
|
4 |
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
|
5 |
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
|
6 |
-
* Version: 1.9.
|
7 |
* Author: WooCommerce
|
8 |
* Author URI: https://woocommerce.com/
|
9 |
* License: GPL-2.0
|
10 |
* Requires PHP: 7.1
|
11 |
* WC requires at least: 3.9
|
12 |
-
* WC tested up to: 6.
|
13 |
* Text Domain: woocommerce-paypal-payments
|
14 |
*
|
15 |
* @package WooCommerce\PayPalCommerce
|
@@ -24,6 +24,8 @@ define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' );
|
|
24 |
define( 'PAYPAL_INTEGRATION_DATE', '2022-04-13' );
|
25 |
|
26 |
define( 'PPCP_FLAG_SUBSCRIPTION', true );
|
|
|
|
|
27 |
|
28 |
! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' );
|
29 |
! defined( 'CONNECT_WOO_SANDBOX_CLIENT_ID' ) && define( 'CONNECT_WOO_SANDBOX_CLIENT_ID', 'AYmOHbt1VHg-OZ_oihPdzKEVbU3qg0qXonBcAztuzniQRaKE0w1Hr762cSFwd4n8wxOl-TCWohEa0XM_' );
|
3 |
* Plugin Name: WooCommerce PayPal Payments
|
4 |
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
|
5 |
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
|
6 |
+
* Version: 1.9.2
|
7 |
* Author: WooCommerce
|
8 |
* Author URI: https://woocommerce.com/
|
9 |
* License: GPL-2.0
|
10 |
* Requires PHP: 7.1
|
11 |
* WC requires at least: 3.9
|
12 |
+
* WC tested up to: 6.7
|
13 |
* Text Domain: woocommerce-paypal-payments
|
14 |
*
|
15 |
* @package WooCommerce\PayPalCommerce
|
24 |
define( 'PAYPAL_INTEGRATION_DATE', '2022-04-13' );
|
25 |
|
26 |
define( 'PPCP_FLAG_SUBSCRIPTION', true );
|
27 |
+
define( 'PPCP_FLAG_OXXO', apply_filters( 'woocommerce_paypal_payments_enable_oxxo_feature', false ) );
|
28 |
+
define( 'PPCP_FLAG_SEPARATE_APM_BUTTONS', apply_filters( 'woocommerce_paypal_payments_enable_separate_apm_buttons_feature', false ) );
|
29 |
|
30 |
! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' );
|
31 |
! defined( 'CONNECT_WOO_SANDBOX_CLIENT_ID' ) && define( 'CONNECT_WOO_SANDBOX_CLIENT_ID', 'AYmOHbt1VHg-OZ_oihPdzKEVbU3qg0qXonBcAztuzniQRaKE0w1Hr762cSFwd4n8wxOl-TCWohEa0XM_' );
|