WooCommerce PayPal Payments - Version 1.9.2

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 Icon 128x128 WooCommerce PayPal Payments
Version 1.9.2
Comparing to
See all releases

Code changes from version 1.9.1 to 1.9.2

Files changed (60) hide show
  1. changelog.txt +13 -0
  2. modules/ppcp-api-client/services.php +54 -0
  3. modules/ppcp-api-client/src/Endpoint/IdentityToken.php +1 -1
  4. modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php +48 -1
  5. modules/ppcp-api-client/src/Entity/Payer.php +36 -19
  6. modules/ppcp-api-client/src/Exception/PayPalApiException.php +0 -9
  7. modules/ppcp-api-client/src/Factory/AmountFactory.php +2 -1
  8. modules/ppcp-api-client/src/Repository/CustomerRepository.php +1 -1
  9. modules/ppcp-button/assets/js/button.js +1 -1
  10. modules/ppcp-button/resources/js/button.js +40 -6
  11. modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +5 -2
  12. modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +1 -3
  13. modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +13 -4
  14. modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js +7 -3
  15. modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +1 -3
  16. modules/ppcp-button/resources/js/modules/Helper/CheckoutMethodState.js +2 -0
  17. modules/ppcp-button/resources/js/modules/Renderer/Renderer.js +75 -12
  18. modules/ppcp-button/services.php +1 -0
  19. modules/ppcp-button/src/Assets/SmartButton.php +109 -56
  20. modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +39 -4
  21. modules/ppcp-session/src/Cancellation/CancelController.php +4 -0
  22. modules/ppcp-subscription/services.php +5 -1
  23. modules/ppcp-subscription/src/RenewalHandler.php +81 -15
  24. modules/ppcp-vaulting/src/PaymentTokenChecker.php +2 -1
  25. modules/ppcp-wc-gateway/assets/images/oxxo.svg +18 -0
  26. modules/ppcp-wc-gateway/assets/js/oxxo.js +1 -0
  27. modules/ppcp-wc-gateway/resources/js/oxxo.js +18 -0
  28. modules/ppcp-wc-gateway/services.php +209 -63
  29. modules/ppcp-wc-gateway/src/CardBillingMode.php +19 -0
  30. modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +14 -20
  31. modules/ppcp-wc-gateway/src/Endpoint/ReturnUrlEndpoint.php +8 -2
  32. modules/ppcp-wc-gateway/src/Exception/GatewayGenericException.php +32 -0
  33. modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php +364 -0
  34. modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +180 -33
  35. modules/ppcp-wc-gateway/src/Gateway/GatewaySettingsRendererTrait.php +37 -0
  36. modules/ppcp-wc-gateway/src/Gateway/Messages.php +27 -0
  37. modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXO.php +223 -0
  38. modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOEndpoint.php +156 -0
  39. modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php +210 -0
  40. modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +166 -106
  41. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +14 -3
  42. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +13 -4
  43. modules/ppcp-wc-gateway/src/Gateway/ProcessPaymentTrait.php +71 -279
  44. modules/ppcp-wc-gateway/src/Helper/CheckoutHelper.php +131 -0
  45. modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php +9 -90
  46. modules/ppcp-wc-gateway/src/Notice/{DccWithoutPayPalAdminNotice.php → GatewayWithoutPayPalAdminNotice.php} +47 -9
  47. modules/ppcp-wc-gateway/src/Settings/PageMatcherTrait.php +2 -0
  48. modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +17 -27
  49. modules/ppcp-wc-gateway/src/WCGatewayModule.php +34 -6
  50. modules/ppcp-wc-gateway/webpack.config.js +1 -0
  51. modules/ppcp-webhooks/services.php +3 -0
  52. modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +2 -1
  53. modules/ppcp-webhooks/src/Handler/PaymentCapturePending.php +122 -0
  54. modules/ppcp-webhooks/src/Handler/PaymentCaptureRefunded.php +1 -1
  55. modules/ppcp-webhooks/src/Handler/PaymentCaptureReversed.php +6 -1
  56. readme.txt +14 -1
  57. vendor/autoload.php +1 -1
  58. vendor/composer/autoload_real.php +7 -7
  59. vendor/composer/autoload_static.php +4 -4
  60. 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() ) && ! empty( $payer->name() ) ) {
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 $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,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->address() ) {
 
 
 
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()->to_array();
182
  }
183
- if ( $this->tax_info() ) {
184
- $payer['tax_info'] = $this->tax_info()->to_array();
185
  }
186
- if ( $this->birthdate() ) {
187
- $payer['birth_date'] = $this->birthdate()->format( 'Y-m-d' );
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
- CreditCardGateway::ID === $order->get_payment_method()
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
- const buttonsSpinner = new Spinner('.ppc-button-wrapper');
 
 
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
- if (jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible').length) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  errorHandler.clear();
43
- errorHandler.message(PayPalCommerceGateway.labels.error.js_validation);
 
 
 
 
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 isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
157
  const isCards = currentPaymentMethod === PaymentMethods.CARDS;
158
 
159
- setVisible(ORDER_BUTTON_SELECTOR, !isPaypal && !isCards, true);
160
 
161
- if (isPaypal) {
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: getCurrentPaymentMethod(),
38
- funding_source: window.ppcpFundingSource,
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
- this.gateway.button.wrapper,
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
- this.gateway.button.wrapper,
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.gateway.button.mini_cart_wrapper,
36
- this.gateway.hosted_fields.mini_cart_wrapper,
37
- this.actionHandler.configuration()
 
 
 
 
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
- this.gateway.button.wrapper,
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, defaultConfig, onSmartButtonClick, onSmartButtonsInit) {
3
- this.defaultConfig = defaultConfig;
4
  this.creditCardRenderer = creditCardRenderer;
5
  this.onSmartButtonClick = onSmartButtonClick;
6
  this.onSmartButtonsInit = onSmartButtonsInit;
 
 
7
  }
8
 
9
- render(wrapper, hostedFieldsWrapper, contextConfig) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- this.renderButtons(wrapper, contextConfig);
12
- this.creditCardRenderer.render(hostedFieldsWrapper, contextConfig);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
 
15
- renderButtons(wrapper, contextConfig) {
16
- if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper) || 'undefined' === typeof paypal.Buttons ) {
17
  return;
18
  }
19
 
20
- const style = wrapper === this.defaultConfig.button.wrapper ? this.defaultConfig.button.style : this.defaultConfig.button.mini_cart_style;
21
- paypal.Buttons({
 
 
 
22
  style,
23
  ...contextConfig,
24
  onClick: this.onSmartButtonClick,
25
  onInit: this.onSmartButtonsInit,
26
- }).render(wrapper);
 
 
 
 
 
 
 
27
  }
28
 
29
- isAlreadyRendered(wrapper) {
30
- return document.querySelector(wrapper).hasChildNodes();
 
 
 
 
 
 
 
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
- array(
425
- $this,
426
- 'button_renderer',
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
- add_action( $this->checkout_button_renderer_hook(), array( $this, 'button_renderer' ), 10 );
461
 
462
- $not_enabled_on_cart = $this->settings->has( 'button_cart_enabled' ) &&
463
- ! $this->settings->get( 'button_cart_enabled' );
464
- add_action(
465
- $this->proceed_to_checkout_button_renderer_hook(),
466
- function() use ( $not_enabled_on_cart ) {
467
- if ( ! is_cart() || $not_enabled_on_cart || $this->is_free_trial_cart() || $this->is_cart_price_total_zero() ) {
468
- return;
 
 
 
 
 
 
469
  }
 
470
 
471
- $this->button_renderer();
472
- },
473
- 20
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['ppcp-gateway'] ) ) {
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' => '#ppcp-hosted-fields',
835
- 'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
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' => $this->dcc_applies->valid_cards(),
851
- 'contingency' => $this->get_3ds_contingency(),
852
  ),
853
  'messages' => $this->message_values(),
854
  'labels' => array(
855
- 'error' => array(
856
- 'generic' => __(
857
  'Something went wrong. Please try again or choose another payment source.',
858
  'woocommerce-paypal-payments'
859
  ),
860
- 'js_validation' => __(
861
- 'Required form fields are not filled or invalid.',
862
- 'woocommerce-paypal-payments'
 
 
 
 
 
 
 
 
 
 
 
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
- unset( $localize['button']['mini_cart_style']['tagline'] );
874
  }
875
  if ( $this->style_for_context( 'layout', $this->context() ) !== 'horizontal' ) {
876
- unset( $localize['button']['style']['tagline'] );
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 = ( $this->settings->has( 'intent' ) ) ? $this->settings->get( 'intent' ) : 'capture';
 
 
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' => ( $this->subscription_helper->cart_contains_subscription() || $this->subscription_helper->current_product_is_subscription() )
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
- if ( is_checkout() && $is_dcc_enabled ) {
 
 
 
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
- && $this->settings->has( 'button_product_enabled' )
1053
- && $this->settings->get( 'button_product_enabled' )
1054
- || $this->settings->has( 'message_product_enabled' )
 
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
- && $this->settings->has( 'button_cart_enabled' )
1067
- && $this->settings->get( 'button_cart_enabled' )
1068
- || $this->settings->has( 'message_product_enabled' )
 
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 === $payment_method
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
- $this->parsed_request_data['funding_source'] ?? ''
339
  );
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  try {
342
  return $this->api_endpoint->create(
343
  array( $this->purchase_unit ),
344
  $shipping_preference,
345
- $this->payer( $this->parsed_request_data, $wc_order ),
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
- $this->payer( $this->parsed_request_data, $wc_order ),
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 $logger The logger.
87
- * @param PaymentTokenRepository $repository The payment token repository.
88
- * @param OrderEndpoint $order_endpoint The order endpoint.
89
- * @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
90
- * @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
91
- * @param PayerFactory $payer_factory The payer factory.
92
- * @param Environment $environment The 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 = $logger;
105
- $this->repository = $repository;
106
- $this->order_endpoint = $order_endpoint;
107
- $this->purchase_unit_factory = $purchase_unit_factory;
108
- $this->shipping_preference_factory = $shipping_preference_factory;
109
- $this->payer_factory = $payer_factory;
110
- $this->environment = $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 ( CreditCardGateway::ID === $wc_order->get_payment_method()
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_&amp;_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\DccWithoutPayPalAdminNotice;
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' => static function ( ContainerInterface $container ): PayPalGateway {
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' => static function ( ContainerInterface $container ): CreditCardGateway {
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.disabler' => static function ( ContainerInterface $container ): DisableGateways {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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' => static function ( ContainerInterface $container ): bool {
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' => static function ( ContainerInterface $container ): bool {
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' => static function ( ContainerInterface $container ): string {
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' => static function ( ContainerInterface $container ): Settings {
168
  return new Settings();
169
  },
170
- 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
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' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice {
176
- $state = $container->get( 'onboarding.state' );
177
- $settings = $container->get( 'wcgateway.settings' );
178
- $is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' );
179
- $is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
180
- return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page );
 
 
 
 
 
 
 
 
 
 
 
181
  },
182
- 'wcgateway.notice.authorize-order-action' =>
183
  static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
184
  return new AuthorizeOrderActionNotice();
185
  },
186
- 'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
187
  return new SectionsRenderer(
188
  $container->get( 'wcgateway.current-ppcp-settings-page-id' ),
189
- $container->get( 'api.shop.country' )
190
  );
191
  },
192
- 'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  $settings = $container->get( 'wcgateway.settings' );
194
  return new SettingsStatus( $settings );
195
  },
196
- 'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
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' => static function ( ContainerInterface $container ): SettingsListener {
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' => static function ( ContainerInterface $container ): OrderProcessor {
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' => static function ( ContainerInterface $container ): RefundProcessor {
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' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
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' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
286
  $column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
287
  return new RenderAuthorizeAction( $column );
288
  },
289
- 'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
290
  $column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
291
  return new PaymentStatusOrderDetail( $column );
292
  },
293
- 'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
294
  $settings = $container->get( 'wcgateway.settings' );
295
  return new OrderTablePaymentStatusColumn( $settings );
296
  },
297
- 'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
298
  return new FeesRenderer();
299
  },
300
 
301
- 'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
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' => static function( ContainerInterface $container ): array {
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' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
2096
 
2097
  return new CheckoutPayPalAddressPreset(
2098
  $container->get( 'session.handler' )
2099
  );
2100
  },
2101
- 'wcgateway.url' => static function ( ContainerInterface $container ): string {
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' => static function( ContainerInterface $container ): string {
2108
  return 'modules/ppcp-wc-gateway/';
2109
  },
2110
- 'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
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' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
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' => static function ( ContainerInterface $container ): string {
2128
  return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
2129
  },
2130
 
2131
- 'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
2132
  return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
2133
  },
2134
 
2135
- 'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
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' => static function ( ContainerInterface $container ) : DCCProductStatus {
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' => static function ( ContainerInterface $container ): MessagesDisclaimers {
2150
  return new MessagesDisclaimers(
2151
  $container->get( 'api.shop.country' )
2152
  );
2153
  },
2154
 
2155
- 'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
2156
  return new FundingSourceRenderer(
2157
  $container->get( 'wcgateway.settings' )
2158
  );
2159
  },
2160
- 'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
 
 
 
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' => static function ( ContainerInterface $container ): PaymentSourceFactory {
2170
  return new PaymentSourceFactory();
2171
  },
2172
- 'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
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' => static function ( ContainerInterface $container ): FraudNetSessionId {
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' => static function ( ContainerInterface $container ): 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' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
2198
- return new PayUponInvoiceHelper();
 
 
2199
  },
2200
- 'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
2201
  return new PayUponInvoiceProductStatus(
2202
  $container->get( 'wcgateway.settings' ),
2203
  $container->get( 'api.endpoint.partners' )
2204
  );
2205
  },
2206
- 'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
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.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2224
  $settings = $container->get( 'wcgateway.settings' );
2225
 
2226
  /**
@@ -2232,7 +2350,7 @@ return array(
2232
  );
2233
  },
2234
 
2235
- 'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
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' => static function ( ContainerInterface $container ): string {
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' => static function ( ContainerInterface $container ): string {
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->disable_both_gateways() ) {
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 both gateways should be disabled or not.
91
  *
92
  * @return bool
93
  */
94
- private function disable_both_gateways() : bool {
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
- if ( ! $order->payment_source() || ! $order->payment_source()->card() ) {
127
- return false;
 
 
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 environment.
504
  *
505
- * @return Environment
506
  */
507
- protected function environment(): Environment {
508
- return $this->environment;
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 WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
14
- use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
15
- use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
 
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 $settings_renderer The Settings Renderer.
182
- * @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
183
- * @param OrderProcessor $order_processor The Order Processor.
184
- * @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
185
- * @param ContainerInterface $config The settings.
186
- * @param SessionHandler $session_handler The Session Handler.
187
- * @param RefundProcessor $refund_processor The Refund Processor.
188
- * @param State $state The state.
189
- * @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
190
- * @param SubscriptionHelper $subscription_helper The subscription helper.
191
- * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
192
- * @param Environment $environment The environment.
193
- * @param PaymentTokenRepository $payment_token_repository The payment token repository.
194
- * @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
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->id = self::ID;
222
- $this->order_processor = $order_processor;
223
- $this->authorized_payments_processor = $authorized_payments_processor;
224
- $this->settings_renderer = $settings_renderer;
225
- $this->funding_source_renderer = $funding_source_renderer;
226
- $this->config = $config;
227
- $this->session_handler = $session_handler;
228
- $this->refund_processor = $refund_processor;
229
- $this->transaction_url_provider = $transaction_url_provider;
230
- $this->page_id = $page_id;
231
- $this->environment = $environment;
232
- $this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
233
- $this->id = self::ID;
234
- $this->order_processor = $order_processor;
235
- $this->authorized_payments = $authorized_payments_processor;
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 environment.
507
  *
508
- * @return Environment
509
  */
510
- protected function environment(): Environment {
511
- return $this->environment;
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
- 3
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->pui_helper->validate_birth_date( $birth_date ) ) || $birth_date === '' ) {
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() === 'ppcp-pay-upon-invoice-gateway' ) {
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->pui_helper->validate_birth_date( $birth_date ) ) {
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 WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
14
- use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
15
- use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
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 \WC_Order $wc_order The order.
318
- * @param Exception $error The error causing the failure.
 
319
  */
320
- protected function handle_failure( \WC_Order $wc_order, Exception $error ): void {
321
- $this->logger->error( 'Payment failed: ' . $error->getMessage() );
322
 
323
- $wc_order->update_status(
324
- 'failed',
325
- __( 'Could not process order. ', 'woocommerce-paypal-payments' ) . $error->getMessage()
326
- );
 
 
327
 
328
  $this->session_handler->destroy_session_data();
329
 
330
  wc_add_notice( $error->getMessage(), 'error' );
 
 
 
 
 
331
  }
332
 
333
  /**
334
- * Returns the environment.
335
  *
336
- * @return Environment
 
 
337
  */
338
- abstract protected function environment(): Environment;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- * Ensures date is valid and at least 18 years back.
26
  *
27
- * @param string $date The date.
28
- * @param string $format The date format.
29
- * @return bool
30
  */
31
- public function validate_birth_date( string $date, string $format = 'Y-m-d' ): bool {
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
- * Ensures product is ready for PUI.
51
  *
52
- * @param WC_Product $product WC product.
53
- * @return bool
54
  */
55
- public function product_ready_for_pui( WC_Product $product ):bool {
56
- if ( $product->is_downloadable() || $product->is_virtual() ) {
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
- $cart = WC()->cart ?? null;
94
- if ( $cart && ! is_checkout_pay_page() ) {
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 DCC gateway being enabled without the PayPal gateway.
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 DCC gateway being enabled without the PayPal gateway.
18
  */
19
- class DccWithoutPayPalAdminNotice {
 
 
 
 
 
 
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
- 'PayPal Card Processing cannot be used without the PayPal gateway. <a href="%1$s">Enable the PayPal Gateway</a>.',
83
  'woocommerce-paypal-payments'
84
  ),
 
85
  admin_url( 'admin.php?page=wc-settings&tab=checkout&section=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
- return State::STATE_ONBOARDED === $this->state->current_state()
97
- && ( $this->is_payments_page || $this->is_ppcp_settings_page )
98
- && ( $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) )
99
- && ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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&section=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
- * The api shop country.
33
  *
34
- * @var string
35
  */
36
- protected $api_shop_country;
37
 
38
  /**
39
  * SectionsRenderer constructor.
40
  *
41
- * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
42
- * @param string $api_shop_country The api shop country.
43
  */
44
- public function __construct( string $page_id, string $api_shop_country ) {
45
- $this->page_id = $page_id;
46
- $this->api_shop_country = $api_shop_country;
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&section=ppcp-gateway&' . self::KEY . '=' . $id );
83
- if ( PayUponInvoiceGateway::ID === $id ) {
84
- $url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-pay-upon-invoice-gateway' );
 
 
 
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&section=' . $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&section=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\DccWithoutPayPalAdminNotice;
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
- $dcc_without_paypal_notice = $c->get( 'wcgateway.notice.dcc-without-paypal' );
168
- assert( $dcc_without_paypal_notice instanceof DccWithoutPayPalAdminNotice );
169
- $dcc_without_paypal_message = $dcc_without_paypal_notice->message();
170
- if ( $dcc_without_paypal_message ) {
171
- $notices[] = $dcc_without_paypal_message;
 
 
 
 
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.1
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 ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf::getLoader();
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 ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf
6
  {
7
  private static $loader;
8
 
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf
22
  return self::$loader;
23
  }
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
- spl_autoload_unregister(array('ComposerAutoloaderInit34be0cba1171aaff174d64d2b76a07cf', '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\ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf::getInitializer($loader));
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\ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf::$files;
55
  } else {
56
  $includeFiles = require __DIR__ . '/autoload_files.php';
57
  }
58
  foreach ($includeFiles as $fileIdentifier => $file) {
59
- composerRequire34be0cba1171aaff174d64d2b76a07cf($fileIdentifier, $file);
60
  }
61
 
62
  return $loader;
63
  }
64
  }
65
 
66
- function composerRequire34be0cba1171aaff174d64d2b76a07cf($fileIdentifier, $file)
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 ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf
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 = ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf::$prefixLengthsPsr4;
177
- $loader->prefixDirsPsr4 = ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf::$prefixDirsPsr4;
178
- $loader->classMap = ComposerStaticInit34be0cba1171aaff174d64d2b76a07cf::$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.1
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.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_' );