WooCommerce PayPal Payments - Version 1.9.0

Version Description

  • Add - New Feature - Pay Upon Invoice (Germany only) #608
  • Fix - Order not approved: payment via vaulted PayPal account fails #677
  • Fix - Cant' refund : "ERROR Refund failed: No country given for address." #639
  • Fix - Something went wrong error in Virtual products when using vaulted payment #673
  • Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669
  • Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
  • Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
  • Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
  • Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
  • Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523
  • Fix - Order details are sometimes empty in PayPal dashboard #689
  • Fix - Incorrect TAX details on PayPal order overview #541
  • Fix - Fatal error: Uncaught Error: Call to a member function get_name() on bool #622
  • Fix - DCC causes checkout continuation state after checkout validation error #695
  • Enhancement - Improve checkout validation & order creation #513
Download this release

Release Info

Developer automattic
Plugin Icon 128x128 WooCommerce PayPal Payments
Version 1.9.0
Comparing to
See all releases

Code changes from version 1.8.1 to 1.9.0

Files changed (70) hide show
  1. bootstrap.php +4 -2
  2. changelog.txt +19 -2
  3. modules/ppcp-api-client/services.php +4 -0
  4. modules/ppcp-api-client/src/Endpoint/PayUponInvoiceOrderEndpoint.php +260 -0
  5. modules/ppcp-api-client/src/Endpoint/RequestTrait.php +4 -2
  6. modules/ppcp-api-client/src/Entity/Item.php +26 -4
  7. modules/ppcp-api-client/src/Entity/OrderStatus.php +10 -10
  8. modules/ppcp-api-client/src/Entity/PurchaseUnit.php +11 -4
  9. modules/ppcp-api-client/src/Factory/AddressFactory.php +1 -6
  10. modules/ppcp-api-client/src/Factory/AmountFactory.php +9 -36
  11. modules/ppcp-api-client/src/Factory/ItemFactory.php +10 -22
  12. modules/ppcp-api-client/src/Factory/PayerFactory.php +10 -0
  13. modules/ppcp-api-client/src/Helper/Cache.php +3 -2
  14. modules/ppcp-api-client/src/Helper/OrderHelper.php +34 -0
  15. modules/ppcp-api-client/src/Repository/PartnerReferralsData.php +47 -40
  16. modules/ppcp-button/assets/js/button.js +1 -1
  17. modules/ppcp-button/resources/js/button.js +15 -0
  18. modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +5 -3
  19. modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +4 -0
  20. modules/ppcp-button/resources/js/modules/Renderer/MessageRenderer.js +9 -0
  21. modules/ppcp-button/services.php +26 -15
  22. modules/ppcp-button/src/Assets/SmartButton.php +109 -41
  23. modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php +13 -3
  24. modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +5 -6
  25. modules/ppcp-button/src/Endpoint/RequestData.php +3 -9
  26. modules/ppcp-onboarding/assets/js/onboarding.js +32 -0
  27. modules/ppcp-onboarding/services.php +27 -3
  28. modules/ppcp-onboarding/src/Assets/OnboardingAssets.php +2 -0
  29. modules/ppcp-onboarding/src/Endpoint/LoginSellerEndpoint.php +2 -0
  30. modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php +143 -0
  31. modules/ppcp-onboarding/src/OnboardingModule.php +8 -0
  32. modules/ppcp-onboarding/src/OnboardingRESTController.php +1 -0
  33. modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php +38 -5
  34. modules/ppcp-onboarding/src/Render/OnboardingRenderer.php +20 -1
  35. modules/ppcp-session/src/Cancellation/CancelController.php +8 -1
  36. modules/ppcp-wc-gateway/assets/js/pay-upon-invoice.js +1 -0
  37. modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +55 -0
  38. modules/ppcp-wc-gateway/services.php +133 -44
  39. modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +29 -2
  40. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php +59 -0
  41. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php +46 -0
  42. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php +41 -0
  43. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +515 -0
  44. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +274 -0
  45. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php +322 -0
  46. modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +59 -0
  47. modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php +140 -0
  48. modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php +106 -0
  49. modules/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php +1 -0
  50. modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php +2 -0
  51. modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php +19 -9
  52. modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +23 -5
  53. modules/ppcp-wc-gateway/src/Settings/SettingsListener.php +28 -1
  54. modules/ppcp-wc-gateway/src/WCGatewayModule.php +43 -1
  55. modules/ppcp-wc-gateway/webpack.config.js +1 -0
  56. modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +5 -0
  57. modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php +5 -0
  58. modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php +7 -2
  59. readme.txt +19 -2
  60. vendor/autoload.php +1 -1
  61. vendor/composer/autoload_classmap.php +1 -0
  62. vendor/composer/autoload_real.php +7 -7
  63. vendor/composer/autoload_static.php +5 -4
  64. vendor/composer/installed.json +7 -7
  65. vendor/symfony/polyfill-php80/Php80.php +11 -1
  66. vendor/symfony/polyfill-php80/PhpToken.php +103 -0
  67. vendor/symfony/polyfill-php80/README.md +4 -3
  68. vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php +7 -0
  69. vendor/symfony/polyfill-php80/composer.json +1 -1
  70. woocommerce-paypal-payments.php +6 -3
bootstrap.php CHANGED
@@ -20,8 +20,10 @@ return function (
20
  ): ContainerInterface {
21
  $modules = ( require "$root_dir/modules.php" )( $root_dir );
22
 
23
- // Use this filter to add custom module or remove some of existing ones.
24
- // Modules able to access container, add services and modify existing ones.
 
 
25
  $modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
26
 
27
  $providers = array_map(
20
  ): ContainerInterface {
21
  $modules = ( require "$root_dir/modules.php" )( $root_dir );
22
 
23
+ /**
24
+ * Use this filter to add custom module or remove some of existing ones.
25
+ * Modules able to access container, add services and modify existing ones.
26
+ */
27
  $modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
28
 
29
  $providers = array_map(
changelog.txt CHANGED
@@ -1,5 +1,22 @@
1
  *** Changelog ***
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  = 1.8.1 - 2022-05-31 =
4
  * Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
5
  * Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
@@ -19,8 +36,8 @@
19
  = 1.8.0 - 2022-05-03 =
20
  * Add - Allow free trial subscriptions #580
21
  * Fix - The Card Processing does not appear as an available payment method when manually creating an order #562
22
- * Fix - Express buttons & Pay Later visible on variable Subscription products /w disabled vaulting #281
23
- * Fix - Pay for order (guest) failing when no email address available #535
24
  * Fix - Emoji in product description causing INVALID_STRING_LENGTH error #491
25
  * Enhancement - Change cart total amount that is sent to PayPal gateway #486
26
  * Enhancement - Include dark Visa and Mastercard gateway icon list for PayPal Card Processing #566
1
  *** Changelog ***
2
 
3
+ = 1.9.0 - 2022-07-04 =
4
+ * Add - New Feature - Pay Upon Invoice (Germany only) #608
5
+ * Fix - Order not approved: payment via vaulted PayPal account fails #677
6
+ * Fix - Cant' refund : "ERROR Refund failed: No country given for address." #639
7
+ * Fix - Something went wrong error in Virtual products when using vaulted payment #673
8
+ * Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669
9
+ * Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
10
+ * Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
11
+ * Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
12
+ * Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
13
+ * Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523
14
+ * Fix - Order details are sometimes empty in PayPal dashboard #689
15
+ * Fix - Incorrect TAX details on PayPal order overview #541
16
+ * Fix - Fatal error: Uncaught Error: Call to a member function get_name() on bool #622
17
+ * Fix - DCC causes checkout continuation state after checkout validation error #695
18
+ * Enhancement - Improve checkout validation & order creation #513
19
+
20
  = 1.8.1 - 2022-05-31 =
21
  * Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
22
  * Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
36
  = 1.8.0 - 2022-05-03 =
37
  * Add - Allow free trial subscriptions #580
38
  * Fix - The Card Processing does not appear as an available payment method when manually creating an order #562
39
+ * Fix - Express buttons & Pay Later visible on variable Subscription products /w disabled vaulting #281
40
+ * Fix - Pay for order (guest) failing when no email address available #535
41
  * Fix - Emoji in product description causing INVALID_STRING_LENGTH error #491
42
  * Enhancement - Change cart total amount that is sent to PayPal gateway #486
43
  * Enhancement - Include dark Visa and Mastercard gateway icon list for PayPal Card Processing #566
modules/ppcp-api-client/services.php CHANGED
@@ -47,6 +47,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
47
  use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
48
  use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
49
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
 
50
  use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
51
  use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
52
  use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
@@ -671,4 +672,7 @@ return array(
671
  'SE',
672
  );
673
  },
 
 
 
674
  );
47
  use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
48
  use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
49
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
50
+ use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
51
  use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
52
  use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
53
  use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
672
  'SE',
673
  );
674
  },
675
+ 'api.order-helper' => static function( ContainerInterface $container ): OrderHelper {
676
+ return new OrderHelper();
677
+ },
678
  );
modules/ppcp-api-client/src/Endpoint/PayUponInvoiceOrderEndpoint.php ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Create order for PUI.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
11
+
12
+ use Psr\Log\LoggerInterface;
13
+ use RuntimeException;
14
+ use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
15
+ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
16
+ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
17
+ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
18
+ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
19
+ use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
20
+ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
21
+ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSource;
22
+ use WP_Error;
23
+
24
+ /**
25
+ * Class OrderEndpoint.
26
+ */
27
+ class PayUponInvoiceOrderEndpoint {
28
+
29
+ use RequestTrait;
30
+
31
+ /**
32
+ * The host.
33
+ *
34
+ * @var string
35
+ */
36
+ protected $host;
37
+
38
+ /**
39
+ * The bearer.
40
+ *
41
+ * @var Bearer
42
+ */
43
+ protected $bearer;
44
+
45
+ /**
46
+ * The order factory.
47
+ *
48
+ * @var OrderFactory
49
+ */
50
+ protected $order_factory;
51
+
52
+ /**
53
+ * The FraudNet entity.
54
+ *
55
+ * @var FraudNet
56
+ */
57
+ protected $fraudnet;
58
+
59
+ /**
60
+ * The logger.
61
+ *
62
+ * @var LoggerInterface
63
+ */
64
+ protected $logger;
65
+
66
+ /**
67
+ * OrderEndpoint constructor.
68
+ *
69
+ * @param string $host The host.
70
+ * @param Bearer $bearer The bearer.
71
+ * @param OrderFactory $order_factory The order factory.
72
+ * @param FraudNet $fraudnet FrauNet entity.
73
+ * @param LoggerInterface $logger The logger.
74
+ */
75
+ public function __construct(
76
+ string $host,
77
+ Bearer $bearer,
78
+ OrderFactory $order_factory,
79
+ FraudNet $fraudnet,
80
+ LoggerInterface $logger
81
+ ) {
82
+ $this->host = $host;
83
+ $this->bearer = $bearer;
84
+ $this->order_factory = $order_factory;
85
+ $this->logger = $logger;
86
+ $this->fraudnet = $fraudnet;
87
+ }
88
+
89
+ /**
90
+ * Creates an order.
91
+ *
92
+ * @param PurchaseUnit[] $items The purchase unit items for the order.
93
+ * @param PaymentSource $payment_source The payment source.
94
+ * @return Order
95
+ * @throws RuntimeException When there is a problem with the payment source.
96
+ * @throws PayPalApiException When there is a problem creating the order.
97
+ */
98
+ public function create( array $items, PaymentSource $payment_source ): Order {
99
+
100
+ $data = array(
101
+ 'intent' => 'CAPTURE',
102
+ 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
103
+ 'purchase_units' => array_map(
104
+ static function ( PurchaseUnit $item ): array {
105
+ return $item->to_array();
106
+ },
107
+ $items
108
+ ),
109
+ 'payment_source' => array(
110
+ 'pay_upon_invoice' => $payment_source->to_array(),
111
+ ),
112
+ );
113
+
114
+ $data = $this->ensure_tax( $data );
115
+ $data = $this->ensure_tax_rate( $data );
116
+ $data = $this->ensure_shipping( $data, $payment_source->to_array() );
117
+
118
+ $bearer = $this->bearer->bearer();
119
+ $url = trailingslashit( $this->host ) . 'v2/checkout/orders';
120
+ $args = array(
121
+ 'method' => 'POST',
122
+ 'headers' => array(
123
+ 'Authorization' => 'Bearer ' . $bearer->token(),
124
+ 'Content-Type' => 'application/json',
125
+ 'Prefer' => 'return=representation',
126
+ 'PayPal-Client-Metadata-Id' => $this->fraudnet->session_id(),
127
+ 'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
128
+ ),
129
+ 'body' => wp_json_encode( $data ),
130
+ );
131
+
132
+ $response = $this->request( $url, $args );
133
+ if ( $response instanceof WP_Error ) {
134
+ throw new RuntimeException( $response->get_error_message() );
135
+ }
136
+
137
+ $json = json_decode( $response['body'] );
138
+ $status_code = (int) wp_remote_retrieve_response_code( $response );
139
+ if ( ! in_array( $status_code, array( 200, 201 ), true ) ) {
140
+ $issue = $json->details[0]->issue ?? null;
141
+
142
+ $site_country_code = explode( '-', get_bloginfo( 'language' ) )[0] ?? '';
143
+ if ( 'PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED' === $issue ) {
144
+ if ( 'de' === $site_country_code ) {
145
+ throw new RuntimeException( 'Die Kombination aus Ihrem Namen und Ihrer Anschrift konnte nicht validiert werden. Bitte korrigieren Sie Ihre Daten und versuchen Sie es erneut. Weitere Informationen finden Sie in den Ratepay <a href="https://www.ratepay.com/legal-payment-dataprivacy/?lang=de" target="_blank">Datenschutzbestimmungen</a> oder nutzen Sie das Ratepay <a href="https://www.ratepay.com/kontakt/" target="_blank">Kontaktformular</a>.' );
146
+ } else {
147
+ throw new RuntimeException( 'The combination of your name and address could not be validated. Please correct your data and try again. You can find further information in the <a href="https://www.ratepay.com/en/ratepay-data-privacy-statement/" target="_blank">Ratepay Data Privacy Statement</a> or you can contact Ratepay using this <a href="https://www.ratepay.com/en/contact/" target="_blank">contact form</a>.' );
148
+ }
149
+ }
150
+ if ( 'PAYMENT_SOURCE_DECLINED_BY_PROCESSOR' === $issue ) {
151
+ if ( 'de' === $site_country_code ) {
152
+ throw new RuntimeException( 'Die gewählte Zahlungsart kann nicht genutzt werden. Diese Entscheidung basiert auf einem automatisierten <a href="https://www.ratepay.com/legal-payment-dataprivacy/?lang=de" target="_blank">Datenverarbeitungsverfahren</a>. Weitere Informationen finden Sie in den Ratepay Datenschutzbestimmungen oder nutzen Sie das Ratepay <a href="https://www.ratepay.com/kontakt/" target="_blank">Kontaktformular</a>.' );
153
+ } else {
154
+ throw new RuntimeException( 'It is not possible to use the selected payment method. This decision is based on automated data processing. You can find further information in the <a href="https://www.ratepay.com/en/ratepay-data-privacy-statement/" target="_blank">Ratepay Data Privacy Statement</a> or you can contact Ratepay using this <a href="https://www.ratepay.com/en/contact/" target="_blank">contact form</a>.' );
155
+ }
156
+ }
157
+
158
+ throw new PayPalApiException( $json, $status_code );
159
+ }
160
+
161
+ return $this->order_factory->from_paypal_response( $json );
162
+ }
163
+
164
+ /**
165
+ * Get Ratepay payment instructions from PayPal order.
166
+ *
167
+ * @param string $id The PayPal order ID.
168
+ * @return array
169
+ * @throws RuntimeException When there is a problem getting the order.
170
+ * @throws PayPalApiException When there is a problem getting the order.
171
+ */
172
+ public function order_payment_instructions( string $id ): array {
173
+ $bearer = $this->bearer->bearer();
174
+ $url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id;
175
+ $args = array(
176
+ 'headers' => array(
177
+ 'Authorization' => 'Bearer ' . $bearer->token(),
178
+ 'Content-Type' => 'application/json',
179
+ 'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
180
+ ),
181
+ );
182
+
183
+ $response = $this->request( $url, $args );
184
+ if ( $response instanceof WP_Error ) {
185
+ throw new RuntimeException( $response->get_error_message() );
186
+ }
187
+
188
+ $json = json_decode( $response['body'] );
189
+ $status_code = (int) wp_remote_retrieve_response_code( $response );
190
+ if ( 200 !== $status_code ) {
191
+ throw new PayPalApiException( $json, $status_code );
192
+ }
193
+
194
+ return array(
195
+ $json->payment_source->pay_upon_invoice->payment_reference,
196
+ $json->payment_source->pay_upon_invoice->deposit_bank_details,
197
+ );
198
+ }
199
+
200
+ /**
201
+ * Ensures items contains tax.
202
+ *
203
+ * @param array $data The data.
204
+ * @return array
205
+ */
206
+ private function ensure_tax( array $data ): array {
207
+ $items_count = count( $data['purchase_units'][0]['items'] );
208
+
209
+ for ( $i = 0; $i < $items_count; $i++ ) {
210
+ if ( ! isset( $data['purchase_units'][0]['items'][ $i ]['tax'] ) ) {
211
+ $data['purchase_units'][0]['items'][ $i ]['tax'] = array(
212
+ 'currency_code' => 'EUR',
213
+ 'value' => '0.00',
214
+ );
215
+ }
216
+ }
217
+
218
+ return $data;
219
+ }
220
+
221
+ /**
222
+ * Ensures items contains tax rate.
223
+ *
224
+ * @param array $data The data.
225
+ * @return array
226
+ */
227
+ private function ensure_tax_rate( array $data ): array {
228
+ $items_count = count( $data['purchase_units'][0]['items'] );
229
+
230
+ for ( $i = 0; $i < $items_count; $i++ ) {
231
+ if ( ! isset( $data['purchase_units'][0]['items'][ $i ]['tax_rate'] ) ) {
232
+ $data['purchase_units'][0]['items'][ $i ]['tax_rate'] = '0.00';
233
+ }
234
+ }
235
+
236
+ return $data;
237
+ }
238
+
239
+ /**
240
+ * Ensures purchase units contains shipping by using payment source data.
241
+ *
242
+ * @param array $data The data.
243
+ * @param array $payment_source The payment source.
244
+ * @return array
245
+ */
246
+ private function ensure_shipping( array $data, array $payment_source ): array {
247
+ if ( isset( $data['purchase_units'][0]['shipping'] ) ) {
248
+ return $data;
249
+ }
250
+
251
+ $given_name = $payment_source['name']['given_name'] ?? '';
252
+ $surname = $payment_source['name']['surname'] ?? '';
253
+ $address = $payment_source['billing_address'] ?? array();
254
+
255
+ $data['purchase_units'][0]['shipping']['name'] = array( 'full_name' => $given_name . ' ' . $surname );
256
+ $data['purchase_units'][0]['shipping']['address'] = $address;
257
+
258
+ return $data;
259
+ }
260
+ }
modules/ppcp-api-client/src/Endpoint/RequestTrait.php CHANGED
@@ -87,9 +87,11 @@ trait RequestTrait {
87
  if ( isset( $response['response'] ) ) {
88
  $output .= 'Response: ' . wc_print_r( $response['response'], true ) . "\n";
89
 
90
- if ( isset( $response['body'] )
 
91
  && isset( $response['response']['code'] )
92
- && ! in_array( $response['response']['code'], array( 200, 201, 202, 204 ), true ) ) {
 
93
  $output .= 'Response Body: ' . wc_print_r( $response['body'], true ) . "\n";
94
  }
95
  }
87
  if ( isset( $response['response'] ) ) {
88
  $output .= 'Response: ' . wc_print_r( $response['response'], true ) . "\n";
89
 
90
+ if (
91
+ isset( $response['body'] )
92
  && isset( $response['response']['code'] )
93
+ && ! in_array( $response['response']['code'], array( 200, 201, 202, 204 ), true )
94
+ ) {
95
  $output .= 'Response Body: ' . wc_print_r( $response['body'], true ) . "\n";
96
  }
97
  }
modules/ppcp-api-client/src/Entity/Item.php CHANGED
@@ -14,7 +14,6 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
14
  */
15
  class Item {
16
 
17
-
18
  const PHYSICAL_GOODS = 'PHYSICAL_GOODS';
19
  const DIGITAL_GOODS = 'DIGITAL_GOODS';
20
 
@@ -67,6 +66,13 @@ class Item {
67
  */
68
  private $category;
69
 
 
 
 
 
 
 
 
70
  /**
71
  * Item constructor.
72
  *
@@ -77,6 +83,7 @@ class Item {
77
  * @param Money|null $tax The tax.
78
  * @param string $sku The SKU.
79
  * @param string $category The category.
 
80
  */
81
  public function __construct(
82
  string $name,
@@ -85,7 +92,8 @@ class Item {
85
  string $description = '',
86
  Money $tax = null,
87
  string $sku = '',
88
- string $category = 'PHYSICAL_GOODS'
 
89
  ) {
90
 
91
  $this->name = $name;
@@ -94,8 +102,9 @@ class Item {
94
  $this->description = $description;
95
  $this->tax = $tax;
96
  $this->sku = $sku;
97
- $this->category = ( self::DIGITAL_GOODS === $category ) ?
98
- self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
 
99
  }
100
 
101
  /**
@@ -161,6 +170,15 @@ class Item {
161
  return $this->category;
162
  }
163
 
 
 
 
 
 
 
 
 
 
164
  /**
165
  * Returns the object as array.
166
  *
@@ -180,6 +198,10 @@ class Item {
180
  $item['tax'] = $this->tax()->to_array();
181
  }
182
 
 
 
 
 
183
  return $item;
184
  }
185
  }
14
  */
15
  class Item {
16
 
 
17
  const PHYSICAL_GOODS = 'PHYSICAL_GOODS';
18
  const DIGITAL_GOODS = 'DIGITAL_GOODS';
19
 
66
  */
67
  private $category;
68
 
69
+ /**
70
+ * The tax rate.
71
+ *
72
+ * @var float
73
+ */
74
+ protected $tax_rate;
75
+
76
  /**
77
  * Item constructor.
78
  *
83
  * @param Money|null $tax The tax.
84
  * @param string $sku The SKU.
85
  * @param string $category The category.
86
+ * @param float $tax_rate The tax rate.
87
  */
88
  public function __construct(
89
  string $name,
92
  string $description = '',
93
  Money $tax = null,
94
  string $sku = '',
95
+ string $category = 'PHYSICAL_GOODS',
96
+ float $tax_rate = 0
97
  ) {
98
 
99
  $this->name = $name;
102
  $this->description = $description;
103
  $this->tax = $tax;
104
  $this->sku = $sku;
105
+ $this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
106
+ $this->category = $category;
107
+ $this->tax_rate = $tax_rate;
108
  }
109
 
110
  /**
170
  return $this->category;
171
  }
172
 
173
+ /**
174
+ * Returns the tax rate.
175
+ *
176
+ * @return float
177
+ */
178
+ public function tax_rate():float {
179
+ return round( (float) $this->tax_rate, 2 );
180
+ }
181
+
182
  /**
183
  * Returns the object as array.
184
  *
198
  $item['tax'] = $this->tax()->to_array();
199
  }
200
 
201
+ if ( $this->tax_rate() ) {
202
+ $item['tax_rate'] = (string) $this->tax_rate();
203
+ }
204
+
205
  return $item;
206
  }
207
  }
modules/ppcp-api-client/src/Entity/OrderStatus.php CHANGED
@@ -15,21 +15,21 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
15
  * Class OrderStatus
16
  */
17
  class OrderStatus {
18
-
19
-
20
- const INTERNAL = 'INTERNAL';
21
- const CREATED = 'CREATED';
22
- const SAVED = 'SAVED';
23
- const APPROVED = 'APPROVED';
24
- const VOIDED = 'VOIDED';
25
- const COMPLETED = 'COMPLETED';
26
- const VALID_STATI = array(
27
  self::INTERNAL,
28
  self::CREATED,
29
  self::SAVED,
30
  self::APPROVED,
31
  self::VOIDED,
32
  self::COMPLETED,
 
33
  );
34
 
35
  /**
@@ -46,7 +46,7 @@ class OrderStatus {
46
  * @throws RuntimeException When the status is not valid.
47
  */
48
  public function __construct( string $status ) {
49
- if ( ! in_array( $status, self::VALID_STATI, true ) ) {
50
  throw new RuntimeException(
51
  sprintf(
52
  // translators: %s is the current status.
15
  * Class OrderStatus
16
  */
17
  class OrderStatus {
18
+ const INTERNAL = 'INTERNAL';
19
+ const CREATED = 'CREATED';
20
+ const SAVED = 'SAVED';
21
+ const APPROVED = 'APPROVED';
22
+ const VOIDED = 'VOIDED';
23
+ const COMPLETED = 'COMPLETED';
24
+ const PENDING_APPROVAL = 'PENDING_APPROVAL';
25
+ const VALID_STATUS = array(
 
26
  self::INTERNAL,
27
  self::CREATED,
28
  self::SAVED,
29
  self::APPROVED,
30
  self::VOIDED,
31
  self::COMPLETED,
32
+ self::PENDING_APPROVAL,
33
  );
34
 
35
  /**
46
  * @throws RuntimeException When the status is not valid.
47
  */
48
  public function __construct( string $status ) {
49
+ if ( ! in_array( $status, self::VALID_STATUS, true ) ) {
50
  throw new RuntimeException(
51
  sprintf(
52
  // translators: %s is the current status.
modules/ppcp-api-client/src/Entity/PurchaseUnit.php CHANGED
@@ -343,8 +343,14 @@ class PurchaseUnit {
343
  }
344
  }
345
 
346
- $tax_total = $breakdown->tax_total();
347
- if ( $tax_total ) {
 
 
 
 
 
 
348
  $remaining_tax_total = array_reduce(
349
  $items,
350
  function ( float $total, Item $item ): float {
@@ -393,8 +399,9 @@ class PurchaseUnit {
393
  $amount_total += $insurance->value();
394
  }
395
 
396
- $amount_value = $amount->value();
397
- $needs_to_ditch = (string) $amount_total !== (string) $amount_value;
 
398
  return $needs_to_ditch;
399
  }
400
  }
343
  }
344
  }
345
 
346
+ $tax_total = $breakdown->tax_total();
347
+ $items_with_tax = array_filter(
348
+ $this->items,
349
+ function ( Item $item ): bool {
350
+ return null !== $item->tax();
351
+ }
352
+ );
353
+ if ( $tax_total && ! empty( $items_with_tax ) ) {
354
  $remaining_tax_total = array_reduce(
355
  $items,
356
  function ( float $total, Item $item ): float {
399
  $amount_total += $insurance->value();
400
  }
401
 
402
+ $amount_str = (string) $amount->to_array()['value'];
403
+ $amount_total_str = (string) ( new Money( $amount_total, $amount->currency_code() ) )->to_array()['value'];
404
+ $needs_to_ditch = $amount_str !== $amount_total_str;
405
  return $needs_to_ditch;
406
  }
407
  }
modules/ppcp-api-client/src/Factory/AddressFactory.php CHANGED
@@ -69,13 +69,8 @@ class AddressFactory {
69
  * @throws RuntimeException When JSON object is malformed.
70
  */
71
  public function from_paypal_response( \stdClass $data ): Address {
72
- if ( ! isset( $data->country_code ) ) {
73
- throw new RuntimeException(
74
- __( 'No country given for address.', 'woocommerce-paypal-payments' )
75
- );
76
- }
77
  return new Address(
78
- $data->country_code,
79
  ( isset( $data->address_line_1 ) ) ? $data->address_line_1 : '',
80
  ( isset( $data->address_line_2 ) ) ? $data->address_line_2 : '',
81
  ( isset( $data->admin_area_1 ) ) ? $data->admin_area_1 : '',
69
  * @throws RuntimeException When JSON object is malformed.
70
  */
71
  public function from_paypal_response( \stdClass $data ): Address {
 
 
 
 
 
72
  return new Address(
73
+ ( isset( $data->country_code ) ) ? $data->country_code : '',
74
  ( isset( $data->address_line_1 ) ) ? $data->address_line_1 : '',
75
  ( isset( $data->address_line_2 ) ) ? $data->address_line_2 : '',
76
  ( isset( $data->admin_area_1 ) ) ? $data->admin_area_1 : '',
modules/ppcp-api-client/src/Factory/AmountFactory.php CHANGED
@@ -69,30 +69,22 @@ class AmountFactory {
69
  public function from_wc_cart( \WC_Cart $cart ): Amount {
70
  $total = new Money( (float) $cart->get_total( 'numeric' ), $this->currency );
71
 
72
- $total_fees_amount = 0;
73
- $fees = WC()->session->get( 'ppcp_fees' );
74
- if ( $fees ) {
75
- foreach ( WC()->session->get( 'ppcp_fees' ) as $fee ) {
76
- $total_fees_amount += (float) $fee->amount;
77
- }
78
- }
79
-
80
- $item_total = $cart->get_cart_contents_total() + $cart->get_discount_total() + $total_fees_amount;
81
- $item_total = new Money( (float) $item_total, $this->currency );
82
  $shipping = new Money(
83
- (float) $cart->get_shipping_total() + $cart->get_shipping_tax(),
84
  $this->currency
85
  );
86
 
87
  $taxes = new Money(
88
- $cart->get_subtotal_tax(),
89
  $this->currency
90
  );
91
 
92
  $discount = null;
93
  if ( $cart->get_discount_total() ) {
94
  $discount = new Money(
95
- (float) $cart->get_discount_total() + $cart->get_discount_tax(),
96
  $this->currency
97
  );
98
  }
@@ -126,7 +118,7 @@ class AmountFactory {
126
 
127
  $discount_value = array_sum(
128
  array(
129
- (float) $order->get_total_discount( false ), // Only coupons.
130
  $this->discounts_from_items( $items ),
131
  )
132
  );
@@ -138,13 +130,6 @@ class AmountFactory {
138
  );
139
  }
140
 
141
- $items = array_filter(
142
- $items,
143
- function ( Item $item ): bool {
144
- return $item->unit_amount()->value() > 0;
145
- }
146
- );
147
-
148
  $total_value = (float) $order->get_total();
149
  if ( (
150
  CreditCardGateway::ID === $order->get_payment_method()
@@ -157,27 +142,15 @@ class AmountFactory {
157
  $total = new Money( $total_value, $currency );
158
 
159
  $item_total = new Money(
160
- (float) array_reduce(
161
- $items,
162
- static function ( float $total, Item $item ): float {
163
- return $total + $item->quantity() * $item->unit_amount()->value();
164
- },
165
- 0
166
- ),
167
  $currency
168
  );
169
  $shipping = new Money(
170
- (float) $order->get_shipping_total() + (float) $order->get_shipping_tax(),
171
  $currency
172
  );
173
  $taxes = new Money(
174
- (float) array_reduce(
175
- $items,
176
- static function ( float $total, Item $item ): float {
177
- return $total + $item->quantity() * $item->tax()->value();
178
- },
179
- 0
180
- ),
181
  $currency
182
  );
183
 
69
  public function from_wc_cart( \WC_Cart $cart ): Amount {
70
  $total = new Money( (float) $cart->get_total( 'numeric' ), $this->currency );
71
 
72
+ $item_total = (float) $cart->get_subtotal() + (float) $cart->get_fee_total();
73
+ $item_total = new Money( $item_total, $this->currency );
 
 
 
 
 
 
 
 
74
  $shipping = new Money(
75
+ (float) $cart->get_shipping_total(),
76
  $this->currency
77
  );
78
 
79
  $taxes = new Money(
80
+ (float) $cart->get_total_tax(),
81
  $this->currency
82
  );
83
 
84
  $discount = null;
85
  if ( $cart->get_discount_total() ) {
86
  $discount = new Money(
87
+ (float) $cart->get_discount_total(),
88
  $this->currency
89
  );
90
  }
118
 
119
  $discount_value = array_sum(
120
  array(
121
+ (float) $order->get_total_discount(), // Only coupons.
122
  $this->discounts_from_items( $items ),
123
  )
124
  );
130
  );
131
  }
132
 
 
 
 
 
 
 
 
133
  $total_value = (float) $order->get_total();
134
  if ( (
135
  CreditCardGateway::ID === $order->get_payment_method()
142
  $total = new Money( $total_value, $currency );
143
 
144
  $item_total = new Money(
145
+ (float) $order->get_subtotal() + (float) $order->get_total_fees(),
 
 
 
 
 
 
146
  $currency
147
  );
148
  $shipping = new Money(
149
+ (float) $order->get_shipping_total(),
150
  $currency
151
  );
152
  $taxes = new Money(
153
+ (float) $order->get_total_tax(),
 
 
 
 
 
 
154
  $currency
155
  );
156
 
modules/ppcp-api-client/src/Factory/ItemFactory.php CHANGED
@@ -53,17 +53,13 @@ class ItemFactory {
53
  */
54
  $quantity = (int) $item['quantity'];
55
 
56
- $price = (float) wc_get_price_including_tax( $product );
57
- $price_without_tax = (float) wc_get_price_excluding_tax( $product );
58
- $price_without_tax_rounded = round( $price_without_tax, 2 );
59
- $tax = round( $price - $price_without_tax_rounded, 2 );
60
- $tax = new Money( $tax, $this->currency );
61
  return new Item(
62
  mb_substr( $product->get_name(), 0, 127 ),
63
- new Money( $price_without_tax_rounded, $this->currency ),
64
  $quantity,
65
  substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ) ?: '',
66
- $tax,
67
  $product->get_sku(),
68
  ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
69
  );
@@ -81,7 +77,7 @@ class ItemFactory {
81
  new Money( (float) $fee->amount, $this->currency ),
82
  1,
83
  '',
84
- new Money( (float) $fee->tax, $this->currency )
85
  );
86
  },
87
  $fees_from_session
@@ -124,28 +120,20 @@ class ItemFactory {
124
  * @return Item
125
  */
126
  private function from_wc_order_line_item( \WC_Order_Item_Product $item, \WC_Order $order ): Item {
127
- /**
128
- * The WooCommerce product.
129
- *
130
- * @var WC_Product $product
131
- */
132
  $product = $item->get_product();
133
  $currency = $order->get_currency();
134
  $quantity = (int) $item->get_quantity();
135
- $price = (float) $order->get_item_subtotal( $item, true );
136
  $price_without_tax = (float) $order->get_item_subtotal( $item, false );
137
  $price_without_tax_rounded = round( $price_without_tax, 2 );
138
- $tax = round( $price - $price_without_tax_rounded, 2 );
139
- $tax = new Money( $tax, $currency );
140
 
141
  return new Item(
142
- mb_substr( $product->get_name(), 0, 127 ),
143
  new Money( $price_without_tax_rounded, $currency ),
144
  $quantity,
145
- substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ) ?: '',
146
- $tax,
147
- $product->get_sku(),
148
- ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
149
  );
150
  }
151
 
@@ -163,7 +151,7 @@ class ItemFactory {
163
  new Money( (float) $item->get_amount(), $order->get_currency() ),
164
  $item->get_quantity(),
165
  '',
166
- new Money( (float) $item->get_total_tax(), $order->get_currency() )
167
  );
168
  }
169
 
53
  */
54
  $quantity = (int) $item['quantity'];
55
 
56
+ $price = (float) $item['line_subtotal'] / (float) $item['quantity'];
 
 
 
 
57
  return new Item(
58
  mb_substr( $product->get_name(), 0, 127 ),
59
+ new Money( $price, $this->currency ),
60
  $quantity,
61
  substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ) ?: '',
62
+ null,
63
  $product->get_sku(),
64
  ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
65
  );
77
  new Money( (float) $fee->amount, $this->currency ),
78
  1,
79
  '',
80
+ null
81
  );
82
  },
83
  $fees_from_session
120
  * @return Item
121
  */
122
  private function from_wc_order_line_item( \WC_Order_Item_Product $item, \WC_Order $order ): Item {
 
 
 
 
 
123
  $product = $item->get_product();
124
  $currency = $order->get_currency();
125
  $quantity = (int) $item->get_quantity();
 
126
  $price_without_tax = (float) $order->get_item_subtotal( $item, false );
127
  $price_without_tax_rounded = round( $price_without_tax, 2 );
 
 
128
 
129
  return new Item(
130
+ mb_substr( $item->get_name(), 0, 127 ),
131
  new Money( $price_without_tax_rounded, $currency ),
132
  $quantity,
133
+ substr( wp_strip_all_tags( $product instanceof WC_Product ? $product->get_description() : '' ), 0, 127 ) ?: '',
134
+ null,
135
+ $product instanceof WC_Product ? $product->get_sku() : '',
136
+ ( $product instanceof WC_Product && $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
137
  );
138
  }
139
 
151
  new Money( (float) $item->get_amount(), $order->get_currency() ),
152
  $item->get_quantity(),
153
  '',
154
+ null
155
  );
156
  }
157
 
modules/ppcp-api-client/src/Factory/PayerFactory.php CHANGED
@@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerName;
15
  use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerTaxInfo;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\Phone;
17
  use WooCommerce\PayPalCommerce\ApiClient\Entity\PhoneWithType;
 
18
 
19
  /**
20
  * Class PayerFactory
@@ -158,6 +159,7 @@ class PayerFactory {
158
  *
159
  * @param array $form_fields The checkout form fields.
160
  * @return Payer
 
161
  */
162
  public function from_checkout_form( array $form_fields ): Payer {
163
 
@@ -189,6 +191,14 @@ class PayerFactory {
189
  }
190
  }
191
 
 
 
 
 
 
 
 
 
192
  return new Payer(
193
  new PayerName( $first_name, $last_name ),
194
  $billing_email,
15
  use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerTaxInfo;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\Phone;
17
  use WooCommerce\PayPalCommerce\ApiClient\Entity\PhoneWithType;
18
+ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
19
 
20
  /**
21
  * Class PayerFactory
159
  *
160
  * @param array $form_fields The checkout form fields.
161
  * @return Payer
162
+ * @throws RuntimeException When invalid data.
163
  */
164
  public function from_checkout_form( array $form_fields ): Payer {
165
 
191
  }
192
  }
193
 
194
+ if ( ! is_email( $billing_email ) ) {
195
+ /*
196
+ phpcs:disable WordPress.WP.I18n.TextDomainMismatch
197
+ translators: %s: email address
198
+ */
199
+ throw new RuntimeException( sprintf( __( '%s is not a valid email address.', 'woocommerce' ), esc_html( $billing_email ) ) );
200
+ }
201
+
202
  return new Payer(
203
  new PayerName( $first_name, $last_name ),
204
  $billing_email,
modules/ppcp-api-client/src/Helper/Cache.php CHANGED
@@ -67,10 +67,11 @@ class Cache {
67
  *
68
  * @param string $key The key under which the value should be cached.
69
  * @param mixed $value The value to cache.
 
70
  *
71
  * @return bool
72
  */
73
- public function set( string $key, $value ): bool {
74
- return (bool) set_transient( $this->prefix . $key, $value );
75
  }
76
  }
67
  *
68
  * @param string $key The key under which the value should be cached.
69
  * @param mixed $value The value to cache.
70
+ * @param int $expiration Time until expiration in seconds.
71
  *
72
  * @return bool
73
  */
74
+ public function set( string $key, $value, int $expiration = 0 ): bool {
75
+ return (bool) set_transient( $this->prefix . $key, $value, $expiration );
76
  }
77
  }
modules/ppcp-api-client/src/Helper/OrderHelper.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PayPal order helper.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\ApiClient\Helper
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
11
+
12
+ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
13
+
14
+ /**
15
+ * Class OrderHelper
16
+ */
17
+ class OrderHelper {
18
+
19
+ /**
20
+ * Checks if order contains physical goods.
21
+ *
22
+ * @param Order $order PayPal order.
23
+ * @return bool
24
+ */
25
+ public function contains_physical_goods( Order $order ): bool {
26
+ foreach ( $order->purchase_units() as $unit ) {
27
+ if ( $unit->contains_physical_goods() ) {
28
+ return true;
29
+ }
30
+ }
31
+
32
+ return false;
33
+ }
34
+ }
modules/ppcp-api-client/src/Repository/PartnerReferralsData.php CHANGED
@@ -72,53 +72,60 @@ class PartnerReferralsData {
72
  * @return array
73
  */
74
  public function data(): array {
75
- return array(
76
- 'partner_config_override' => array(
77
- 'partner_logo_url' => 'https://connect.woocommerce.com/images/woocommerce_logo.png',
78
- /**
79
- * Returns the URL which will be opened at the end of onboarding.
80
- */
81
- 'return_url' => apply_filters(
82
- 'woocommerce_paypal_payments_partner_config_override_return_url',
83
- admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' )
84
- ),
85
- /**
86
- * Returns the description of the URL which will be opened at the end of onboarding.
87
- */
88
- 'return_url_description' => apply_filters(
89
- 'woocommerce_paypal_payments_partner_config_override_return_url_description',
90
- __( 'Return to your shop.', 'woocommerce-paypal-payments' )
 
 
 
 
 
 
 
91
  ),
92
- 'show_add_credit_card' => true,
93
- ),
94
- 'products' => $this->products,
95
- 'legal_consents' => array(
96
- array(
97
- 'type' => 'SHARE_DATA_CONSENT',
98
- 'granted' => true,
99
  ),
100
- ),
101
- 'operations' => array(
102
- array(
103
- 'operation' => 'API_INTEGRATION',
104
- 'api_integration_preference' => array(
105
- 'rest_api_integration' => array(
106
- 'integration_method' => 'PAYPAL',
107
- 'integration_type' => 'FIRST_PARTY',
108
- 'first_party_details' => array(
109
- 'features' => array(
110
- 'PAYMENT',
111
- 'FUTURE_PAYMENT',
112
- 'REFUND',
113
- 'ADVANCED_TRANSACTIONS_SEARCH',
114
- 'VAULT',
 
 
115
  ),
116
- 'seller_nonce' => $this->nonce(),
117
  ),
118
  ),
119
  ),
120
  ),
121
- ),
122
  );
123
  }
124
  }
72
  * @return array
73
  */
74
  public function data(): array {
75
+ /**
76
+ * Returns the partners referrals data.
77
+ */
78
+ return apply_filters(
79
+ 'ppcp_partner_referrals_data',
80
+ array(
81
+ 'partner_config_override' => array(
82
+ 'partner_logo_url' => 'https://connect.woocommerce.com/images/woocommerce_logo.png',
83
+ /**
84
+ * Returns the URL which will be opened at the end of onboarding.
85
+ */
86
+ 'return_url' => apply_filters(
87
+ 'woocommerce_paypal_payments_partner_config_override_return_url',
88
+ admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' )
89
+ ),
90
+ /**
91
+ * Returns the description of the URL which will be opened at the end of onboarding.
92
+ */
93
+ 'return_url_description' => apply_filters(
94
+ 'woocommerce_paypal_payments_partner_config_override_return_url_description',
95
+ __( 'Return to your shop.', 'woocommerce-paypal-payments' )
96
+ ),
97
+ 'show_add_credit_card' => true,
98
  ),
99
+ 'products' => $this->products,
100
+ 'legal_consents' => array(
101
+ array(
102
+ 'type' => 'SHARE_DATA_CONSENT',
103
+ 'granted' => true,
104
+ ),
 
105
  ),
106
+ 'operations' => array(
107
+ array(
108
+ 'operation' => 'API_INTEGRATION',
109
+ 'api_integration_preference' => array(
110
+ 'rest_api_integration' => array(
111
+ 'integration_method' => 'PAYPAL',
112
+ 'integration_type' => 'FIRST_PARTY',
113
+ 'first_party_details' => array(
114
+ 'features' => array(
115
+ 'PAYMENT',
116
+ 'FUTURE_PAYMENT',
117
+ 'REFUND',
118
+ 'ADVANCED_TRANSACTIONS_SEARCH',
119
+ 'VAULT',
120
+ 'TRACKING_SHIPMENT_READWRITE',
121
+ ),
122
+ 'seller_nonce' => $this->nonce(),
123
  ),
 
124
  ),
125
  ),
126
  ),
127
  ),
128
+ )
129
  );
130
  }
131
  }
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 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 return;\n }\n\n this.render();\n }\n\n shouldRender() {\n return document.querySelector('form.cart') !== null && !this.priceAmountIsZero();\n }\n\n priceAmountIsZero() {\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 const amount = parseFloat(priceText.replace(/([^\\d,\\.\\s]*)/g, ''));\n return amount === 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 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 }\n\n const amount = parseInt(priceText.replace(/([^\\d,\\.\\s]*)/g, ''));\n this.messages.renderWithAmount(amount);\n }, () => {\n this.renderer.hideButtons(this.gateway.button.wrapper);\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\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 formValues = jQuery(formSelector).serialize();\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: formValues,\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 return;\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 Object.values(styles).forEach(prop => {\n if (!styles[prop] || !isNaN(prop)) {\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\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 hostedFields.on('validityChange', event => {\n const formValid = Object.keys(event.fields).every(function (key) {\n return event.fields[key].isValid;\n });\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}\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}\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 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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Qy9ULFlBQVAsQ0FBb0IwVyxRQUFRLENBQUMsQ0FBRCxDQUE1QixFQUFpQ0EsUUFBUSxDQUFDLENBQUQsQ0FBekM7QUFDSCxHQUhMOztBQU1BLE1BQUluVSxxQkFBcUIsQ0FBQzBULGNBQXRCLENBQXFDVSxhQUF6QyxFQUF3RDtBQUNwRDdDLElBQUFBLDRCQUE0QixDQUFDQyxNQUFELEVBQVN4UixxQkFBcUIsQ0FBQzBULGNBQS9CLENBQTVCO0FBQ0E7QUFDSDs7QUFFRDFYLEVBQUFBLFFBQVEsQ0FBQzJDLElBQVQsQ0FBY29KLE1BQWQsQ0FBcUJ5SixNQUFyQjtBQUNILENBckZMIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0Vycm9ySGFuZGxlci5qcz9lNjVhIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvckNvbnRpbnVlLmpzP2M0NTQiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9QYXllckRhdGEuanM/MmFmMSIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGUuanM/ODBhMyIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQWN0aW9uSGFuZGxlci9DYXJ0QWN0aW9uSGFuZGxlci5qcz84MmNmIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL01pbmlDYXJ0Qm9vdHN0YXAuanM/ZDU1MiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvSGVscGVyL1VwZGF0ZUNhcnQuanM/ZTQyMiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvSGVscGVyL0J1dHRvbnNUb2dnbGVMaXN0ZW5lci5qcz9lMTkzIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9FbnRpdHkvUHJvZHVjdC5qcz85ZmZmIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9BY3Rpb25IYW5kbGVyL1NpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyLmpzP2Q5YjciLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvU2luZ2xlUHJvZHVjdEJvb3RzdGFwLmpzPzdjMTkiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2FydEJvb3RzdGFwLmpzPzVlOTQiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yUGF5Tm93LmpzPzkzMDUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvQ2hlY2tvdXRBY3Rpb25IYW5kbGVyLmpzPzg1MTUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9IaWRpbmcuanM/MWQzNiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9DaGVja291dEJvb3RzdGFwLmpzP2M4NTUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9TdWJzY3JpcHRpb25zLmpzP2I4NzAiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvUGF5Tm93Qm9vdHN0cmFwLmpzP2Q5ZjUiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL1JlbmRlcmVyL1JlbmRlcmVyLmpzP2ZhOTMiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9EY2NJbnB1dEZhY3RvcnkuanM/MmEyZiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvUmVuZGVyZXIvQ3JlZGl0Q2FyZFJlbmRlcmVyLmpzPzM4N2EiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0RhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIuanM/ZWUwYiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvUmVuZGVyZXIvTWVzc2FnZVJlbmRlcmVyLmpzP2NkMDIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9TcGlubmVyLmpzPzE3MDgiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvRnJlZVRyaWFsSGFuZGxlci5qcz9hYjc3Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvYnV0dG9uLmpzPzA2MGYiXSwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRXJyb3JIYW5kbGVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGdlbmVyaWNFcnJvclRleHQpXG4gICAge1xuICAgICAgICB0aGlzLmdlbmVyaWNFcnJvclRleHQgPSBnZW5lcmljRXJyb3JUZXh0O1xuICAgICAgICB0aGlzLndyYXBwZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcud29vY29tbWVyY2Utbm90aWNlcy13cmFwcGVyJyk7XG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigndWwud29vY29tbWVyY2UtZXJyb3InKTtcbiAgICB9XG5cbiAgICBnZW5lcmljRXJyb3IoKSB7XG4gICAgICAgIGlmICh0aGlzLndyYXBwZXIuY2xhc3NMaXN0LmNvbnRhaW5zKCdwcGNwLXBlcnNpc3QnKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5tZXNzYWdlKHRoaXMuZ2VuZXJpY0Vycm9yVGV4dClcbiAgICB9XG5cbiAgICBhcHBlbmRQcmVwYXJlZEVycm9yTWVzc2FnZUVsZW1lbnQoZXJyb3JNZXNzYWdlRWxlbWVudClcbiAgICB7XG4gICAgICAgIGlmKHRoaXMubWVzc2FnZXNMaXN0ID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnByZXBhcmVNZXNzYWdlc0xpc3QoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LnJlcGxhY2VXaXRoKGVycm9yTWVzc2FnZUVsZW1lbnQpO1xuICAgIH1cblxuICAgIG1lc3NhZ2UodGV4dCwgcGVyc2lzdCA9IGZhbHNlKVxuICAgIHtcbiAgICAgICAgaWYoISB0eXBlb2YgU3RyaW5nIHx8IHRleHQubGVuZ3RoID09PSAwKXtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQSBuZXcgbWVzc2FnZSB0ZXh0IG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYodGhpcy5tZXNzYWdlc0xpc3QgPT09IG51bGwpe1xuICAgICAgICAgICAgdGhpcy5wcmVwYXJlTWVzc2FnZXNMaXN0KCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGVyc2lzdCkge1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyLmNsYXNzTGlzdC5hZGQoJ3BwY3AtcGVyc2lzdCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyLmNsYXNzTGlzdC5yZW1vdmUoJ3BwY3AtcGVyc2lzdCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG1lc3NhZ2VOb2RlID0gdGhpcy5wcmVwYXJlTWVzc2FnZXNMaXN0SXRlbSh0ZXh0KTtcbiAgICAgICAgdGhpcy5tZXNzYWdlc0xpc3QuYXBwZW5kQ2hpbGQobWVzc2FnZU5vZGUpO1xuXG4gICAgICAgIGpRdWVyeS5zY3JvbGxfdG9fbm90aWNlcyhqUXVlcnkoJy53b29jb21tZXJjZS1ub3RpY2VzLXdyYXBwZXInKSlcbiAgICB9XG5cbiAgICBwcmVwYXJlTWVzc2FnZXNMaXN0KClcbiAgICB7XG4gICAgICAgIGlmKHRoaXMubWVzc2FnZXNMaXN0ID09PSBudWxsKXtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXNMaXN0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKTtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LnNldEF0dHJpYnV0ZSgnY2xhc3MnLCAnd29vY29tbWVyY2UtZXJyb3InKTtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LnNldEF0dHJpYnV0ZSgncm9sZScsICdhbGVydCcpO1xuICAgICAgICAgICAgdGhpcy53cmFwcGVyLmFwcGVuZENoaWxkKHRoaXMubWVzc2FnZXNMaXN0KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByZXBhcmVNZXNzYWdlc0xpc3RJdGVtKG1lc3NhZ2UpXG4gICAge1xuICAgICAgICBjb25zdCBsaSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7XG4gICAgICAgIGxpLmlubmVySFRNTCA9IG1lc3NhZ2U7XG5cbiAgICAgICAgcmV0dXJuIGxpO1xuICAgIH1cblxuICAgIHNhbml0aXplKHRleHQpXG4gICAge1xuICAgICAgICBjb25zdCB0ZXh0YXJlYSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RleHRhcmVhJyk7XG4gICAgICAgIHRleHRhcmVhLmlubmVySFRNTCA9IHRleHQ7XG4gICAgICAgIHJldHVybiB0ZXh0YXJlYS52YWx1ZS5yZXBsYWNlKCdFcnJvcjogJywgJycpO1xuICAgIH1cblxuICAgIGNsZWFyKClcbiAgICB7XG4gICAgICAgIGlmICh0aGlzLm1lc3NhZ2VzTGlzdCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tZXNzYWdlc0xpc3QuaW5uZXJIVE1MID0gJyc7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBFcnJvckhhbmRsZXI7XG4iLCJjb25zdCBvbkFwcHJvdmUgPSAoY29udGV4dCwgZXJyb3JIYW5kbGVyKSA9PiB7XG4gICAgcmV0dXJuIChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgIHJldHVybiBmZXRjaChjb250ZXh0LmNvbmZpZy5hamF4LmFwcHJvdmVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIG5vbmNlOiBjb250ZXh0LmNvbmZpZy5hamF4LmFwcHJvdmVfb3JkZXIubm9uY2UsXG4gICAgICAgICAgICAgICAgb3JkZXJfaWQ6ZGF0YS5vcmRlcklELFxuICAgICAgICAgICAgICAgIGZ1bmRpbmdfc291cmNlOiB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UsXG4gICAgICAgICAgICB9KVxuICAgICAgICB9KS50aGVuKChyZXMpPT57XG4gICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICAgICAgfSkudGhlbigoZGF0YSk9PntcbiAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIHJldHVybiBhY3Rpb25zLnJlc3RhcnQoKS5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsb2NhdGlvbi5ocmVmID0gY29udGV4dC5jb25maWcucmVkaXJlY3Q7XG4gICAgICAgIH0pO1xuXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBvbkFwcHJvdmU7XG4iLCJleHBvcnQgY29uc3QgcGF5ZXJEYXRhID0gKCkgPT4ge1xuICAgIGNvbnN0IHBheWVyID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LnBheWVyO1xuICAgIGlmICghIHBheWVyKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHBob25lID0gKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3Bob25lJykgfHwgdHlwZW9mIHBheWVyLnBob25lICE9PSAndW5kZWZpbmVkJykgP1xuICAgIHtcbiAgICAgICAgcGhvbmVfdHlwZTpcIkhPTUVcIixcbiAgICAgICAgICAgIHBob25lX251bWJlcjp7XG4gICAgICAgICAgICBuYXRpb25hbF9udW1iZXIgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcGhvbmUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19waG9uZScpLnZhbHVlIDogcGF5ZXIucGhvbmUucGhvbmVfbnVtYmVyLm5hdGlvbmFsX251bWJlclxuICAgICAgICB9XG4gICAgfSA6IG51bGw7XG4gICAgY29uc3QgcGF5ZXJEYXRhID0ge1xuICAgICAgICBlbWFpbF9hZGRyZXNzOihkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19lbWFpbCcpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2VtYWlsJykudmFsdWUgOiBwYXllci5lbWFpbF9hZGRyZXNzLFxuICAgICAgICBuYW1lIDoge1xuICAgICAgICAgICAgc3VybmFtZTogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2xhc3RfbmFtZScpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2xhc3RfbmFtZScpLnZhbHVlIDogcGF5ZXIubmFtZS5zdXJuYW1lLFxuICAgICAgICAgICAgZ2l2ZW5fbmFtZTogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2ZpcnN0X25hbWUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19maXJzdF9uYW1lJykudmFsdWUgOiBwYXllci5uYW1lLmdpdmVuX25hbWVcbiAgICAgICAgfSxcbiAgICAgICAgYWRkcmVzcyA6IHtcbiAgICAgICAgICAgIGNvdW50cnlfY29kZSA6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19jb3VudHJ5JykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfY291bnRyeScpLnZhbHVlIDogcGF5ZXIuYWRkcmVzcy5jb3VudHJ5X2NvZGUsXG4gICAgICAgICAgICBhZGRyZXNzX2xpbmVfMSA6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzEnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzEnKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRkcmVzc19saW5lXzEsXG4gICAgICAgICAgICBhZGRyZXNzX2xpbmVfMiA6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzInKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19hZGRyZXNzXzInKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRkcmVzc19saW5lXzIsXG4gICAgICAgICAgICBhZG1pbl9hcmVhXzEgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfc3RhdGUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19zdGF0ZScpLnZhbHVlIDogcGF5ZXIuYWRkcmVzcy5hZG1pbl9hcmVhXzEsXG4gICAgICAgICAgICBhZG1pbl9hcmVhXzIgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfY2l0eScpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2NpdHknKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRtaW5fYXJlYV8yLFxuICAgICAgICAgICAgcG9zdGFsX2NvZGUgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcG9zdGNvZGUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19wb3N0Y29kZScpLnZhbHVlIDogcGF5ZXIuYWRkcmVzcy5wb3N0YWxfY29kZVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIGlmIChwaG9uZSkge1xuICAgICAgICBwYXllckRhdGEucGhvbmUgPSBwaG9uZTtcbiAgICB9XG4gICAgcmV0dXJuIHBheWVyRGF0YTtcbn1cbiIsImV4cG9ydCBjb25zdCBQYXltZW50TWV0aG9kcyA9IHtcbiAgICBQQVlQQUw6ICdwcGNwLWdhdGV3YXknLFxuICAgIENBUkRTOiAncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5Jyxcbn07XG5cbmV4cG9ydCBjb25zdCBPUkRFUl9CVVRUT05fU0VMRUNUT1IgPSAnI3BsYWNlX29yZGVyJztcblxuZXhwb3J0IGNvbnN0IGdldEN1cnJlbnRQYXltZW50TWV0aG9kID0gKCkgPT4ge1xuICAgIGNvbnN0IGVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignaW5wdXRbbmFtZT1cInBheW1lbnRfbWV0aG9kXCJdOmNoZWNrZWQnKTtcbiAgICBpZiAoIWVsKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBlbC52YWx1ZTtcbn07XG5cbmV4cG9ydCBjb25zdCBpc1NhdmVkQ2FyZFNlbGVjdGVkID0gKCkgPT4ge1xuICAgIGNvbnN0IHNhdmVkQ2FyZExpc3QgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjc2F2ZWQtY3JlZGl0LWNhcmQnKTtcbiAgICByZXR1cm4gc2F2ZWRDYXJkTGlzdCAmJiBzYXZlZENhcmRMaXN0LnZhbHVlICE9PSAnJztcbn07XG4iLCJpbXBvcnQgb25BcHByb3ZlIGZyb20gJy4uL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yQ29udGludWUuanMnO1xuaW1wb3J0IHtwYXllckRhdGF9IGZyb20gXCIuLi9IZWxwZXIvUGF5ZXJEYXRhXCI7XG5pbXBvcnQge1BheW1lbnRNZXRob2RzfSBmcm9tIFwiLi4vSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcblxuY2xhc3MgQ2FydEFjdGlvbkhhbmRsZXIge1xuXG4gICAgY29uc3RydWN0b3IoY29uZmlnLCBlcnJvckhhbmRsZXIpIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyID0gZXJyb3JIYW5kbGVyO1xuICAgIH1cblxuICAgIGNvbmZpZ3VyYXRpb24oKSB7XG4gICAgICAgIGNvbnN0IGNyZWF0ZU9yZGVyID0gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBheWVyID0gcGF5ZXJEYXRhKCk7XG4gICAgICAgICAgICBjb25zdCBibkNvZGUgPSB0eXBlb2YgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gIT09ICd1bmRlZmluZWQnID9cbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIGZldGNoKHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICBub25jZTogdGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIubm9uY2UsXG4gICAgICAgICAgICAgICAgICAgIHB1cmNoYXNlX3VuaXRzOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgcGF5bWVudF9tZXRob2Q6IFBheW1lbnRNZXRob2RzLlBBWVBBTCxcbiAgICAgICAgICAgICAgICAgICAgZnVuZGluZ19zb3VyY2U6IHdpbmRvdy5wcGNwRnVuZGluZ1NvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgYm5fY29kZTpibkNvZGUsXG4gICAgICAgICAgICAgICAgICAgIHBheWVyLFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0OnRoaXMuY29uZmlnLmNvbnRleHRcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24ocmVzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBkYXRhLmRhdGEuaWQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY3JlYXRlT3JkZXIsXG4gICAgICAgICAgICBvbkFwcHJvdmU6IG9uQXBwcm92ZSh0aGlzLCB0aGlzLmVycm9ySGFuZGxlciksXG4gICAgICAgICAgICBvbkVycm9yOiAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IENhcnRBY3Rpb25IYW5kbGVyO1xuIiwiaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuaW1wb3J0IENhcnRBY3Rpb25IYW5kbGVyIGZyb20gJy4uL0FjdGlvbkhhbmRsZXIvQ2FydEFjdGlvbkhhbmRsZXInO1xuXG5jbGFzcyBNaW5pQ2FydEJvb3RzdGFwIHtcbiAgICBjb25zdHJ1Y3RvcihnYXRld2F5LCByZW5kZXJlcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgICAgIHRoaXMuYWN0aW9uSGFuZGxlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaW5pdCgpIHtcblxuICAgICAgICB0aGlzLmFjdGlvbkhhbmRsZXIgPSBuZXcgQ2FydEFjdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICBuZXcgRXJyb3JIYW5kbGVyKHRoaXMuZ2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyksXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMucmVuZGVyKCk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd3Y19mcmFnbWVudHNfbG9hZGVkIHdjX2ZyYWdtZW50c19yZWZyZXNoZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5idXR0b24ubWluaV9jYXJ0X3dyYXBwZXIpICE9PSBudWxsXG4gICAgICAgICAgICB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLm1pbmlfY2FydF93cmFwcGVyKSAhPT0gbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuYnV0dG9uLm1pbmlfY2FydF93cmFwcGVyLFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMubWluaV9jYXJ0X3dyYXBwZXIsXG4gICAgICAgICAgICB0aGlzLmFjdGlvbkhhbmRsZXIuY29uZmlndXJhdGlvbigpXG4gICAgICAgICk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBNaW5pQ2FydEJvb3RzdGFwO1xuIiwiaW1wb3J0IFByb2R1Y3QgZnJvbSBcIi4uL0VudGl0eS9Qcm9kdWN0XCI7XG5jbGFzcyBVcGRhdGVDYXJ0IHtcblxuICAgIGNvbnN0cnVjdG9yKGVuZHBvaW50LCBub25jZSlcbiAgICB7XG4gICAgICAgIHRoaXMuZW5kcG9pbnQgPSBlbmRwb2ludDtcbiAgICAgICAgdGhpcy5ub25jZSA9IG5vbmNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIG9uUmVzb2x2ZVxuICAgICAqIEBwYXJhbSB7UHJvZHVjdFtdfSBwcm9kdWN0c1xuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fVxuICAgICAqL1xuICAgIHVwZGF0ZShvblJlc29sdmUsIHByb2R1Y3RzKVxuICAgIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIGZldGNoKFxuICAgICAgICAgICAgICAgIHRoaXMuZW5kcG9pbnQsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMubm9uY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0cyxcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApLnRoZW4oXG4gICAgICAgICAgICAgICAgKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQuanNvbigpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICkudGhlbigocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCEgcmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KHJlc3VsdC5kYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXNvbHZlZCA9IG9uUmVzb2x2ZShyZXN1bHQuZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUocmVzb2x2ZWQpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgVXBkYXRlQ2FydDsiLCIvKipcbiAqIFdoZW4geW91IGNhbid0IGFkZCBzb21ldGhpbmcgdG8gdGhlIGNhcnQsIHRoZSBQYXlQYWwgYnV0dG9ucyBzaG91bGQgbm90IHNob3cuXG4gKiBUaGVyZWZvcmUgd2UgbGlzdGVuIGZvciBjaGFuZ2VzIG9uIHRoZSBhZGQgdG8gY2FydCBidXR0b24gYW5kIHNob3cvaGlkZSB0aGUgYnV0dG9ucyBhY2NvcmRpbmdseS5cbiAqL1xuXG5jbGFzcyBCdXR0b25zVG9nZ2xlTGlzdGVuZXIge1xuICAgIGNvbnN0cnVjdG9yKGVsZW1lbnQsIHNob3dDYWxsYmFjaywgaGlkZUNhbGxiYWNrKVxuICAgIHtcbiAgICAgICAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcbiAgICAgICAgdGhpcy5zaG93Q2FsbGJhY2sgPSBzaG93Q2FsbGJhY2s7XG4gICAgICAgIHRoaXMuaGlkZUNhbGxiYWNrID0gaGlkZUNhbGxiYWNrO1xuICAgICAgICB0aGlzLm9ic2VydmVyID0gbnVsbDtcbiAgICB9XG5cbiAgICBpbml0KClcbiAgICB7XG4gICAgICAgIGNvbnN0IGNvbmZpZyA9IHsgYXR0cmlidXRlcyA6IHRydWUgfTtcbiAgICAgICAgY29uc3QgY2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5lbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnZGlzYWJsZWQnKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuaGlkZUNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zaG93Q2FsbGJhY2soKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoY2FsbGJhY2spO1xuICAgICAgICB0aGlzLm9ic2VydmVyLm9ic2VydmUodGhpcy5lbGVtZW50LCBjb25maWcpO1xuICAgICAgICBjYWxsYmFjaygpO1xuICAgIH1cblxuICAgIGRpc2Nvbm5lY3QoKVxuICAgIHtcbiAgICAgICAgdGhpcy5vYnNlcnZlci5kaXNjb25uZWN0KCk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBCdXR0b25zVG9nZ2xlTGlzdGVuZXI7IiwiY2xhc3MgUHJvZHVjdCB7XG5cbiAgICBjb25zdHJ1Y3RvcihpZCwgcXVhbnRpdHksIHZhcmlhdGlvbnMpIHtcbiAgICAgICAgdGhpcy5pZCA9IGlkO1xuICAgICAgICB0aGlzLnF1YW50aXR5ID0gcXVhbnRpdHk7XG4gICAgICAgIHRoaXMudmFyaWF0aW9ucyA9IHZhcmlhdGlvbnM7XG4gICAgfVxuXG4gICAgZGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGlkOnRoaXMuaWQsXG4gICAgICAgICAgICBxdWFudGl0eTp0aGlzLnF1YW50aXR5LFxuICAgICAgICAgICAgdmFyaWF0aW9uczp0aGlzLnZhcmlhdGlvbnNcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUHJvZHVjdDsiLCJpbXBvcnQgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyIGZyb20gJy4uL0hlbHBlci9CdXR0b25zVG9nZ2xlTGlzdGVuZXInO1xuaW1wb3J0IFByb2R1Y3QgZnJvbSAnLi4vRW50aXR5L1Byb2R1Y3QnO1xuaW1wb3J0IG9uQXBwcm92ZSBmcm9tICcuLi9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvckNvbnRpbnVlJztcbmltcG9ydCB7cGF5ZXJEYXRhfSBmcm9tIFwiLi4vSGVscGVyL1BheWVyRGF0YVwiO1xuaW1wb3J0IHtQYXltZW50TWV0aG9kc30gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIFNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyIHtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBjb25maWcsXG4gICAgICAgIHVwZGF0ZUNhcnQsXG4gICAgICAgIHNob3dCdXR0b25DYWxsYmFjayxcbiAgICAgICAgaGlkZUJ1dHRvbkNhbGxiYWNrLFxuICAgICAgICBmb3JtRWxlbWVudCxcbiAgICAgICAgZXJyb3JIYW5kbGVyXG4gICAgKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLnVwZGF0ZUNhcnQgPSB1cGRhdGVDYXJ0O1xuICAgICAgICB0aGlzLnNob3dCdXR0b25DYWxsYmFjayA9IHNob3dCdXR0b25DYWxsYmFjaztcbiAgICAgICAgdGhpcy5oaWRlQnV0dG9uQ2FsbGJhY2sgPSBoaWRlQnV0dG9uQ2FsbGJhY2s7XG4gICAgICAgIHRoaXMuZm9ybUVsZW1lbnQgPSBmb3JtRWxlbWVudDtcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgfVxuXG4gICAgY29uZmlndXJhdGlvbigpXG4gICAge1xuXG4gICAgICAgIGlmICggdGhpcy5oYXNWYXJpYXRpb25zKCkgKSB7XG4gICAgICAgICAgICBjb25zdCBvYnNlcnZlciA9IG5ldyBCdXR0b25zVG9nZ2xlTGlzdGVuZXIoXG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtRWxlbWVudC5xdWVyeVNlbGVjdG9yKCcuc2luZ2xlX2FkZF90b19jYXJ0X2J1dHRvbicpLFxuICAgICAgICAgICAgICAgIHRoaXMuc2hvd0J1dHRvbkNhbGxiYWNrLFxuICAgICAgICAgICAgICAgIHRoaXMuaGlkZUJ1dHRvbkNhbGxiYWNrXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgb2JzZXJ2ZXIuaW5pdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyOiB0aGlzLmNyZWF0ZU9yZGVyKCksXG4gICAgICAgICAgICBvbkFwcHJvdmU6IG9uQXBwcm92ZSh0aGlzLCB0aGlzLmVycm9ySGFuZGxlciksXG4gICAgICAgICAgICBvbkVycm9yOiAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNyZWF0ZU9yZGVyKClcbiAgICB7XG4gICAgICAgIHZhciBnZXRQcm9kdWN0cyA9IG51bGw7XG4gICAgICAgIGlmICghIHRoaXMuaXNHcm91cGVkUHJvZHVjdCgpICkge1xuICAgICAgICAgICAgZ2V0UHJvZHVjdHMgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgaWQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdbbmFtZT1cImFkZC10by1jYXJ0XCJdJykudmFsdWU7XG4gICAgICAgICAgICAgICAgY29uc3QgcXR5ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW25hbWU9XCJxdWFudGl0eVwiXScpLnZhbHVlO1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhcmlhdGlvbnMgPSB0aGlzLnZhcmlhdGlvbnMoKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gW25ldyBQcm9kdWN0KGlkLCBxdHksIHZhcmlhdGlvbnMpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGdldFByb2R1Y3RzID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHByb2R1Y3RzID0gW107XG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtRWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKCdpbnB1dFt0eXBlPVwibnVtYmVyXCJdJykuZm9yRWFjaCgoZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoISBlbGVtZW50LnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWxlbWVudE5hbWUgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnbmFtZScpLm1hdGNoKC9xdWFudGl0eVxcWyhbXFxkXSopXFxdLyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50TmFtZS5sZW5ndGggIT09IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb25zdCBpZCA9IHBhcnNlSW50KGVsZW1lbnROYW1lWzFdKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcXVhbnRpdHkgPSBwYXJzZUludChlbGVtZW50LnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgcHJvZHVjdHMucHVzaChuZXcgUHJvZHVjdChpZCwgcXVhbnRpdHksIG51bGwpKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIHJldHVybiBwcm9kdWN0cztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjcmVhdGVPcmRlciA9IChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5jbGVhcigpO1xuXG4gICAgICAgICAgICBjb25zdCBvblJlc29sdmUgPSAocHVyY2hhc2VfdW5pdHMpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwYXllciA9IHBheWVyRGF0YSgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJuQ29kZSA9IHR5cGVvZiB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSAhPT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSA6ICcnO1xuICAgICAgICAgICAgICAgIHJldHVybiBmZXRjaCh0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5lbmRwb2ludCwge1xuICAgICAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHVyY2hhc2VfdW5pdHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXllcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGJuX2NvZGU6Ym5Db2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcGF5bWVudF9tZXRob2Q6IFBheW1lbnRNZXRob2RzLlBBWVBBTCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmRpbmdfc291cmNlOiB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0OnRoaXMuY29uZmlnLmNvbnRleHRcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAoZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGRhdGEuZGF0YS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5kYXRhLmlkO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgY29uc3QgcHJvbWlzZSA9IHRoaXMudXBkYXRlQ2FydC51cGRhdGUob25SZXNvbHZlLCBnZXRQcm9kdWN0cygpKTtcbiAgICAgICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gY3JlYXRlT3JkZXI7XG4gICAgfVxuXG4gICAgdmFyaWF0aW9ucygpXG4gICAge1xuXG4gICAgICAgIGlmICghIHRoaXMuaGFzVmFyaWF0aW9ucygpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gWy4uLnRoaXMuZm9ybUVsZW1lbnQucXVlcnlTZWxlY3RvckFsbChcIltuYW1lXj0nYXR0cmlidXRlXyddXCIpXS5tYXAoXG4gICAgICAgICAgICAoZWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6ZWxlbWVudC52YWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgbmFtZTplbGVtZW50Lm5hbWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBhdHRyaWJ1dGVzO1xuICAgIH1cblxuICAgIGhhc1ZhcmlhdGlvbnMoKVxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZm9ybUVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCd2YXJpYXRpb25zX2Zvcm0nKTtcbiAgICB9XG5cbiAgICBpc0dyb3VwZWRQcm9kdWN0KClcbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1FbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnZ3JvdXBlZF9mb3JtJyk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXI7XG4iLCJpbXBvcnQgRXJyb3JIYW5kbGVyIGZyb20gJy4uL0Vycm9ySGFuZGxlcic7XG5pbXBvcnQgVXBkYXRlQ2FydCBmcm9tIFwiLi4vSGVscGVyL1VwZGF0ZUNhcnRcIjtcbmltcG9ydCBTaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlciBmcm9tIFwiLi4vQWN0aW9uSGFuZGxlci9TaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlclwiO1xuXG5jbGFzcyBTaW5nbGVQcm9kdWN0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcykge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgICAgIHRoaXMubWVzc2FnZXMgPSBtZXNzYWdlcztcbiAgICB9XG5cblxuICAgIGhhbmRsZUNoYW5nZSgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5oaWRlQnV0dG9ucyh0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICB9XG5cbiAgICBpbml0KCkge1xuXG4gICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHRoaXMuaGFuZGxlQ2hhbmdlLmJpbmQodGhpcykpXG5cbiAgICAgICAgaWYgKCF0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcblxuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcblxuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0JykgIT09IG51bGwgJiYgIXRoaXMucHJpY2VBbW91bnRJc1plcm8oKTtcblxuICAgIH1cblxuICAgIHByaWNlQW1vdW50SXNaZXJvKCkge1xuXG4gICAgICAgIGxldCBwcmljZVRleHQgPSBcIjBcIjtcbiAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCBpbnMgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQgaW5zIC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKS5pbm5lclRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKSkge1xuICAgICAgICAgICAgcHJpY2VUZXh0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKS5pbm5lclRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnByb2R1Y3QgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcucHJvZHVjdCAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFtb3VudCA9IHBhcnNlRmxvYXQocHJpY2VUZXh0LnJlcGxhY2UoLyhbXlxcZCxcXC5cXHNdKikvZywgJycpKTtcbiAgICAgICAgcmV0dXJuIGFtb3VudCA9PT0gMDtcblxuICAgIH1cblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgY29uc3QgYWN0aW9uSGFuZGxlciA9IG5ldyBTaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlcihcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheSxcbiAgICAgICAgICAgIG5ldyBVcGRhdGVDYXJ0KFxuICAgICAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5hamF4LmNoYW5nZV9jYXJ0LmVuZHBvaW50LFxuICAgICAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5hamF4LmNoYW5nZV9jYXJ0Lm5vbmNlLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNob3dCdXR0b25zKHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcik7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zaG93QnV0dG9ucyh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKTtcbiAgICAgICAgICAgICAgICBsZXQgcHJpY2VUZXh0ID0gXCIwXCI7XG4gICAgICAgICAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCBpbnMgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICAgICAgICAgIHByaWNlVGV4dCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCBpbnMgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpLmlubmVyVGV4dDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKSkge1xuICAgICAgICAgICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpLmlubmVyVGV4dDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgYW1vdW50ID0gcGFyc2VJbnQocHJpY2VUZXh0LnJlcGxhY2UoLyhbXlxcZCxcXC5cXHNdKikvZywgJycpKTtcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnJlbmRlcldpdGhBbW91bnQoYW1vdW50KVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcik7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5oaWRlQnV0dG9ucyh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQnKSxcbiAgICAgICAgICAgIG5ldyBFcnJvckhhbmRsZXIodGhpcy5nYXRld2F5LmxhYmVscy5lcnJvci5nZW5lcmljKSxcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnJlbmRlcmVyLnJlbmRlcihcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcixcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIsXG4gICAgICAgICAgICBhY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKSxcbiAgICAgICAgKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFNpbmdsZVByb2R1Y3RCb290c3RhcDtcbiIsImltcG9ydCBDYXJ0QWN0aW9uSGFuZGxlciBmcm9tICcuLi9BY3Rpb25IYW5kbGVyL0NhcnRBY3Rpb25IYW5kbGVyJztcbmltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcblxuY2xhc3MgQ2FydEJvb3RzdHJhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIpIHtcbiAgICAgICAgdGhpcy5nYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2FydF90b3RhbHMgdXBkYXRlZF9jaGVja291dCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKSAhPT1cbiAgICAgICAgICAgIG51bGwgfHwgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKSAhPT1cbiAgICAgICAgICAgIG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBjb25zdCBhY3Rpb25IYW5kbGVyID0gbmV3IENhcnRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyLFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcixcbiAgICAgICAgICAgIGFjdGlvbkhhbmRsZXIuY29uZmlndXJhdGlvbigpLFxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ2FydEJvb3RzdHJhcDtcbiIsImNvbnN0IG9uQXBwcm92ZSA9IChjb250ZXh0LCBlcnJvckhhbmRsZXIsIHNwaW5uZXIpID0+IHtcbiAgICByZXR1cm4gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgc3Bpbm5lci5ibG9jaygpO1xuICAgICAgICBlcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICByZXR1cm4gZmV0Y2goY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBub25jZTogY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgIG9yZGVyX2lkOmRhdGEub3JkZXJJRCxcbiAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oKGRhdGEpPT57XG4gICAgICAgICAgICBzcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuZGF0YS5jb2RlID09PSAxMDApIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBhY3Rpb25zICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgYWN0aW9ucy5yZXN0YXJ0ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZXN0YXJ0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcGxhY2Vfb3JkZXInKS5jbGljaygpXG4gICAgICAgIH0pO1xuXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBvbkFwcHJvdmU7XG4iLCJpbXBvcnQgb25BcHByb3ZlIGZyb20gJy4uL09uQXBwcm92ZUhhbmRsZXIvb25BcHByb3ZlRm9yUGF5Tm93LmpzJztcbmltcG9ydCB7cGF5ZXJEYXRhfSBmcm9tIFwiLi4vSGVscGVyL1BheWVyRGF0YVwiO1xuaW1wb3J0IHtnZXRDdXJyZW50UGF5bWVudE1ldGhvZH0gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENoZWNrb3V0QWN0aW9uSGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3Rvcihjb25maWcsIGVycm9ySGFuZGxlciwgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgICAgIHRoaXMuc3Bpbm5lciA9IHNwaW5uZXI7XG4gICAgfVxuXG4gICAgY29uZmlndXJhdGlvbigpIHtcbiAgICAgICAgY29uc3Qgc3Bpbm5lciA9IHRoaXMuc3Bpbm5lcjtcbiAgICAgICAgY29uc3QgY3JlYXRlT3JkZXIgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGF5ZXIgPSBwYXllckRhdGEoKTtcbiAgICAgICAgICAgIGNvbnN0IGJuQ29kZSA9IHR5cGVvZiB0aGlzLmNvbmZpZy5ibl9jb2Rlc1t0aGlzLmNvbmZpZy5jb250ZXh0XSAhPT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdIDogJyc7XG5cbiAgICAgICAgICAgIGNvbnN0IGVycm9ySGFuZGxlciA9IHRoaXMuZXJyb3JIYW5kbGVyO1xuXG4gICAgICAgICAgICBjb25zdCBmb3JtU2VsZWN0b3IgPSB0aGlzLmNvbmZpZy5jb250ZXh0ID09PSAnY2hlY2tvdXQnID8gJ2Zvcm0uY2hlY2tvdXQnIDogJ2Zvcm0jb3JkZXJfcmV2aWV3JztcbiAgICAgICAgICAgIGNvbnN0IGZvcm1WYWx1ZXMgPSBqUXVlcnkoZm9ybVNlbGVjdG9yKS5zZXJpYWxpemUoKTtcblxuICAgICAgICAgICAgY29uc3QgY3JlYXRlYWNjb3VudCA9IGpRdWVyeSgnI2NyZWF0ZWFjY291bnQnKS5pcyhcIjpjaGVja2VkXCIpID8gdHJ1ZSA6IGZhbHNlO1xuXG4gICAgICAgICAgICByZXR1cm4gZmV0Y2godGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5ub25jZSxcbiAgICAgICAgICAgICAgICAgICAgcGF5ZXIsXG4gICAgICAgICAgICAgICAgICAgIGJuX2NvZGU6Ym5Db2RlLFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0OnRoaXMuY29uZmlnLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgIG9yZGVyX2lkOnRoaXMuY29uZmlnLm9yZGVyX2lkLFxuICAgICAgICAgICAgICAgICAgICBwYXltZW50X21ldGhvZDogZ2V0Q3VycmVudFBheW1lbnRNZXRob2QoKSxcbiAgICAgICAgICAgICAgICAgICAgZnVuZGluZ19zb3VyY2U6IHdpbmRvdy5wcGNwRnVuZGluZ1NvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgZm9ybTpmb3JtVmFsdWVzLFxuICAgICAgICAgICAgICAgICAgICBjcmVhdGVhY2NvdW50OiBjcmVhdGVhY2NvdW50XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAoZGF0YSkge1xuICAgICAgICAgICAgICAgIGlmICghZGF0YS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgICAgICAgICAvL2hhbmRsZSBib3RoIG1lc3NhZ2VzIHNlbnQgZnJvbSBXb29jb21tZXJjZSAoZGF0YS5tZXNzYWdlcykgYW5kIHRoaXMgcGx1Z2luIChkYXRhLmRhdGEubWVzc2FnZSlcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZihkYXRhLm1lc3NhZ2VzKSAhPT0gJ3VuZGVmaW5lZCcgKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBkb21QYXJzZXIgPSBuZXcgRE9NUGFyc2VyKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIuYXBwZW5kUHJlcGFyZWRFcnJvck1lc3NhZ2VFbGVtZW50KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbVBhcnNlci5wYXJzZUZyb21TdHJpbmcoZGF0YS5tZXNzYWdlcywgJ3RleHQvaHRtbCcpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5xdWVyeVNlbGVjdG9yKCd1bCcpXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmNsZWFyKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGF0YS5kYXRhLmRldGFpbHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5tZXNzYWdlKGRhdGEuZGF0YS5kZXRhaWxzLm1hcChkID0+IGAke2QuaXNzdWV9ICR7ZC5kZXNjcmlwdGlvbn1gKS5qb2luKCc8YnIvPicpLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZGF0YS5kYXRhLm1lc3NhZ2UsIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XG4gICAgICAgICAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKCd0eXBlJywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZSgnbmFtZScsICdwcGNwLXJlc3VtZS1vcmRlcicpO1xuICAgICAgICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZSgndmFsdWUnLCBkYXRhLmRhdGEucHVyY2hhc2VfdW5pdHNbMF0uY3VzdG9tX2lkKTtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1TZWxlY3RvcikuYXBwZW5kKGlucHV0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5kYXRhLmlkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyLFxuICAgICAgICAgICAgb25BcHByb3ZlOm9uQXBwcm92ZSh0aGlzLCB0aGlzLmVycm9ySGFuZGxlciwgdGhpcy5zcGlubmVyKSxcbiAgICAgICAgICAgIG9uQ2FuY2VsOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25FcnJvcjogKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIHNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDaGVja291dEFjdGlvbkhhbmRsZXI7XG4iLCJjb25zdCBnZXRFbGVtZW50ID0gKHNlbGVjdG9yT3JFbGVtZW50KSA9PiB7XG4gICAgaWYgKHR5cGVvZiBzZWxlY3Rvck9yRWxlbWVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3JPckVsZW1lbnQpO1xuICAgIH1cbiAgICByZXR1cm4gc2VsZWN0b3JPckVsZW1lbnQ7XG59XG5cbmV4cG9ydCBjb25zdCBpc1Zpc2libGUgPSAoZWxlbWVudCkgPT4ge1xuICAgIHJldHVybiAhIShlbGVtZW50Lm9mZnNldFdpZHRoIHx8IGVsZW1lbnQub2Zmc2V0SGVpZ2h0IHx8IGVsZW1lbnQuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGgpO1xufVxuXG5leHBvcnQgY29uc3Qgc2V0VmlzaWJsZSA9IChzZWxlY3Rvck9yRWxlbWVudCwgc2hvdywgaW1wb3J0YW50ID0gZmFsc2UpID0+IHtcbiAgICBjb25zdCBlbGVtZW50ID0gZ2V0RWxlbWVudChzZWxlY3Rvck9yRWxlbWVudCk7XG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50VmFsdWUgPSBlbGVtZW50LnN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ2Rpc3BsYXknKTtcblxuICAgIGlmICghc2hvdykge1xuICAgICAgICBpZiAoY3VycmVudFZhbHVlID09PSAnbm9uZScpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGVsZW1lbnQuc3R5bGUuc2V0UHJvcGVydHkoJ2Rpc3BsYXknLCAnbm9uZScsIGltcG9ydGFudCA/ICdpbXBvcnRhbnQnIDogJycpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChjdXJyZW50VmFsdWUgPT09ICdub25lJykge1xuICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgnZGlzcGxheScpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3RpbGwgbm90IHZpc2libGUgKGlmIHNvbWV0aGluZyBlbHNlIGFkZGVkIGRpc3BsYXk6IG5vbmUgaW4gQ1NTKVxuICAgICAgICBpZiAoIWlzVmlzaWJsZShlbGVtZW50KSkge1xuICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eSgnZGlzcGxheScsICdibG9jaycpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGhpZGUgPSAoc2VsZWN0b3JPckVsZW1lbnQsIGltcG9ydGFudCA9IGZhbHNlKSA9PiB7XG4gICAgc2V0VmlzaWJsZShzZWxlY3Rvck9yRWxlbWVudCwgZmFsc2UsIGltcG9ydGFudCk7XG59O1xuXG5leHBvcnQgY29uc3Qgc2hvdyA9IChzZWxlY3Rvck9yRWxlbWVudCkgPT4ge1xuICAgIHNldFZpc2libGUoc2VsZWN0b3JPckVsZW1lbnQsIHRydWUpO1xufTtcbiIsImltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcbmltcG9ydCBDaGVja291dEFjdGlvbkhhbmRsZXIgZnJvbSAnLi4vQWN0aW9uSGFuZGxlci9DaGVja291dEFjdGlvbkhhbmRsZXInO1xuaW1wb3J0IHsgc2V0VmlzaWJsZSB9IGZyb20gJy4uL0hlbHBlci9IaWRpbmcnO1xuaW1wb3J0IHtcbiAgICBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCxcbiAgICBpc1NhdmVkQ2FyZFNlbGVjdGVkLCBPUkRFUl9CVVRUT05fU0VMRUNUT1IsXG4gICAgUGF5bWVudE1ldGhvZHNcbn0gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENoZWNrb3V0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgICAgIHRoaXMubWVzc2FnZXMgPSBtZXNzYWdlcztcbiAgICAgICAgdGhpcy5zcGlubmVyID0gc3Bpbm5lcjtcblxuICAgICAgICB0aGlzLnN0YW5kYXJkT3JkZXJCdXR0b25TZWxlY3RvciA9IE9SREVSX0JVVFRPTl9TRUxFQ1RPUjtcblxuICAgICAgICB0aGlzLmJ1dHRvbkNoYW5nZU9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKGVsKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVVpKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG4gICAgICAgIHRoaXMucmVuZGVyKCk7XG5cbiAgICAgICAgLy8gVW5zZWxlY3Qgc2F2ZWQgY2FyZC5cbiAgICAgICAgLy8gV0Mgc2F2ZXMgZm9ybSB2YWx1ZXMsIHNvIHdpdGggb3VyIGN1cnJlbnQgVUkgaXQgd291bGQgYmUgYSBiaXQgd2VpcmRcbiAgICAgICAgLy8gaWYgdGhlIHVzZXIgcGFpZCB3aXRoIHNhdmVkLCB0aGVuIGFmdGVyIHNvbWUgdGltZSB0cmllcyB0byBwYXkgYWdhaW4sXG4gICAgICAgIC8vIGJ1dCB3YW50cyB0byBlbnRlciBhIG5ldyBjYXJkLCBhbmQgdG8gZG8gdGhhdCB0aGV5IGhhdmUgdG8gY2hvb3NlIOKAnFNlbGVjdCBwYXltZW504oCdIGluIHRoZSBsaXN0LlxuICAgICAgICBqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCcpLnZhbChqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCBvcHRpb246Zmlyc3QnKS52YWwoKSk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NoZWNrb3V0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKVxuICAgICAgICB9KTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2hlY2tvdXQgcGF5bWVudF9tZXRob2Rfc2VsZWN0ZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVVpKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudCkub24oJ2hvc3RlZF9maWVsZHNfbG9hZGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgalF1ZXJ5KCcjc2F2ZWQtY3JlZGl0LWNhcmQnKS5vbignY2hhbmdlJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG4gICAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5idXR0b24uY2FuY2VsX3dyYXBwZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpICE9PSBudWxsIHx8IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcikgIT09IG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyICsgJz5kaXYnKSkge1xuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyICsgJz5kaXYnKS5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJycpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFjdGlvbkhhbmRsZXIgPSBuZXcgQ2hlY2tvdXRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICAgICAgdGhpcy5zcGlubmVyXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIsXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyLFxuICAgICAgICAgICAgYWN0aW9uSGFuZGxlci5jb25maWd1cmF0aW9uKCksXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5idXR0b25DaGFuZ2VPYnNlcnZlci5vYnNlcnZlKFxuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLnN0YW5kYXJkT3JkZXJCdXR0b25TZWxlY3RvciksXG4gICAgICAgICAgICB7YXR0cmlidXRlczogdHJ1ZX1cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICB1cGRhdGVVaSgpIHtcbiAgICAgICAgY29uc3QgY3VycmVudFBheW1lbnRNZXRob2QgPSBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCgpO1xuICAgICAgICBjb25zdCBpc1BheXBhbCA9IGN1cnJlbnRQYXltZW50TWV0aG9kID09PSBQYXltZW50TWV0aG9kcy5QQVlQQUw7XG4gICAgICAgIGNvbnN0IGlzQ2FyZCA9IGN1cnJlbnRQYXltZW50TWV0aG9kID09PSBQYXltZW50TWV0aG9kcy5DQVJEUztcbiAgICAgICAgY29uc3QgaXNTYXZlZENhcmQgPSBpc0NhcmQgJiYgaXNTYXZlZENhcmRTZWxlY3RlZCgpO1xuICAgICAgICBjb25zdCBpc05vdE91ckdhdGV3YXkgPSAhaXNQYXlwYWwgJiYgIWlzQ2FyZDtcbiAgICAgICAgY29uc3QgaXNGcmVlVHJpYWwgPSBQYXlQYWxDb21tZXJjZUdhdGV3YXkuaXNfZnJlZV90cmlhbF9jYXJ0O1xuICAgICAgICBjb25zdCBoYXNWYXVsdGVkUGF5cGFsID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LnZhdWx0ZWRfcGF5cGFsX2VtYWlsICE9PSAnJztcblxuICAgICAgICBzZXRWaXNpYmxlKHRoaXMuc3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yLCAgKGlzUGF5cGFsICYmIGlzRnJlZVRyaWFsICYmIGhhc1ZhdWx0ZWRQYXlwYWwpIHx8IGlzTm90T3VyR2F0ZXdheSB8fCBpc1NhdmVkQ2FyZCwgdHJ1ZSk7XG4gICAgICAgIHNldFZpc2libGUoJy5wcGNwLXZhdWx0ZWQtcGF5cGFsLWRldGFpbHMnLCBpc1BheXBhbCk7XG4gICAgICAgIHNldFZpc2libGUodGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyLCBpc1BheXBhbCAmJiAhKGlzRnJlZVRyaWFsICYmIGhhc1ZhdWx0ZWRQYXlwYWwpKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkubWVzc2FnZXMud3JhcHBlciwgaXNQYXlwYWwgJiYgIWlzRnJlZVRyaWFsKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyLCBpc0NhcmQgJiYgIWlzU2F2ZWRDYXJkKTtcblxuICAgICAgICBpZiAoaXNQYXlwYWwgJiYgIWlzRnJlZVRyaWFsKSB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnJlbmRlcigpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQ2FyZCkge1xuICAgICAgICAgICAgaWYgKGlzU2F2ZWRDYXJkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGRpc2FibGVDcmVkaXRDYXJkRmllbGRzKCkge1xuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlclwiXScpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5XCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5JykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmNcIl0nKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInZhdWx0XCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5hdHRyKFwiZGlzYWJsZWRcIiwgdHJ1ZSlcbiAgICAgICAgdGhpcy5yZW5kZXJlci5kaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpXG4gICAgfVxuXG4gICAgZW5hYmxlQ3JlZGl0Q2FyZEZpZWxkcygpIHtcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXJcIl0nKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXInKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeVwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjXCJdJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJ2YXVsdFwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuYXR0cihcImRpc2FibGVkXCIsIGZhbHNlKVxuICAgICAgICB0aGlzLnJlbmRlcmVyLmVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKVxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ2hlY2tvdXRCb290c3RhcFxuIiwiZXhwb3J0IGNvbnN0IGlzQ2hhbmdlUGF5bWVudFBhZ2UgPSAoKSA9PiB7XG4gICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKVxuICAgIHJldHVybiB1cmxQYXJhbXMuaGFzKCdjaGFuZ2VfcGF5bWVudF9tZXRob2QnKTtcbn1cbiIsImltcG9ydCBDaGVja291dEJvb3RzdGFwIGZyb20gJy4vQ2hlY2tvdXRCb290c3RhcCdcbmltcG9ydCB7aXNDaGFuZ2VQYXltZW50UGFnZX0gZnJvbSBcIi4uL0hlbHBlci9TdWJzY3JpcHRpb25zXCI7XG5cbmNsYXNzIFBheU5vd0Jvb3RzdHJhcCBleHRlbmRzIENoZWNrb3V0Qm9vdHN0YXAge1xuICAgIGNvbnN0cnVjdG9yKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcikge1xuICAgICAgICBzdXBlcihnYXRld2F5LCByZW5kZXJlciwgbWVzc2FnZXMsIHNwaW5uZXIpXG4gICAgfVxuXG4gICAgdXBkYXRlVWkoKSB7XG4gICAgICAgIGlmIChpc0NoYW5nZVBheW1lbnRQYWdlKCkpIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgc3VwZXIudXBkYXRlVWkoKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFBheU5vd0Jvb3RzdHJhcDtcbiIsImNsYXNzIFJlbmRlcmVyIHtcbiAgICBjb25zdHJ1Y3RvcihjcmVkaXRDYXJkUmVuZGVyZXIsIGRlZmF1bHRDb25maWcsIG9uU21hcnRCdXR0b25DbGljaywgb25TbWFydEJ1dHRvbnNJbml0KSB7XG4gICAgICAgIHRoaXMuZGVmYXVsdENvbmZpZyA9IGRlZmF1bHRDb25maWc7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyID0gY3JlZGl0Q2FyZFJlbmRlcmVyO1xuICAgICAgICB0aGlzLm9uU21hcnRCdXR0b25DbGljayA9IG9uU21hcnRCdXR0b25DbGljaztcbiAgICAgICAgdGhpcy5vblNtYXJ0QnV0dG9uc0luaXQgPSBvblNtYXJ0QnV0dG9uc0luaXQ7XG4gICAgfVxuXG4gICAgcmVuZGVyKHdyYXBwZXIsIGhvc3RlZEZpZWxkc1dyYXBwZXIsIGNvbnRleHRDb25maWcpIHtcblxuICAgICAgICB0aGlzLnJlbmRlckJ1dHRvbnMod3JhcHBlciwgY29udGV4dENvbmZpZyk7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyLnJlbmRlcihob3N0ZWRGaWVsZHNXcmFwcGVyLCBjb250ZXh0Q29uZmlnKTtcbiAgICB9XG5cbiAgICByZW5kZXJCdXR0b25zKHdyYXBwZXIsIGNvbnRleHRDb25maWcpIHtcbiAgICAgICAgaWYgKCEgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKSB8fCB0aGlzLmlzQWxyZWFkeVJlbmRlcmVkKHdyYXBwZXIpIHx8ICd1bmRlZmluZWQnID09PSB0eXBlb2YgcGF5cGFsLkJ1dHRvbnMgKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzdHlsZSA9IHdyYXBwZXIgPT09IHRoaXMuZGVmYXVsdENvbmZpZy5idXR0b24ud3JhcHBlciA/IHRoaXMuZGVmYXVsdENvbmZpZy5idXR0b24uc3R5bGUgOiB0aGlzLmRlZmF1bHRDb25maWcuYnV0dG9uLm1pbmlfY2FydF9zdHlsZTtcbiAgICAgICAgcGF5cGFsLkJ1dHRvbnMoe1xuICAgICAgICAgICAgc3R5bGUsXG4gICAgICAgICAgICAuLi5jb250ZXh0Q29uZmlnLFxuICAgICAgICAgICAgb25DbGljazogdGhpcy5vblNtYXJ0QnV0dG9uQ2xpY2ssXG4gICAgICAgICAgICBvbkluaXQ6IHRoaXMub25TbWFydEJ1dHRvbnNJbml0LFxuICAgICAgICB9KS5yZW5kZXIod3JhcHBlcik7XG4gICAgfVxuXG4gICAgaXNBbHJlYWR5UmVuZGVyZWQod3JhcHBlcikge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKS5oYXNDaGlsZE5vZGVzKCk7XG4gICAgfVxuXG4gICAgaGlkZUJ1dHRvbnMoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBkb21FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihlbGVtZW50KTtcbiAgICAgICAgaWYgKCEgZG9tRWxlbWVudCApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBkb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHNob3dCdXR0b25zKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZG9tRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZWxlbWVudCk7XG4gICAgICAgIGlmICghIGRvbUVsZW1lbnQgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZG9tRWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgZGlzYWJsZUNyZWRpdENhcmRGaWVsZHMoKSB7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyLmRpc2FibGVGaWVsZHMoKTtcbiAgICB9XG5cbiAgICBlbmFibGVDcmVkaXRDYXJkRmllbGRzKCkge1xuICAgICAgICB0aGlzLmNyZWRpdENhcmRSZW5kZXJlci5lbmFibGVGaWVsZHMoKTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFJlbmRlcmVyO1xuIiwiY29uc3QgZGNjSW5wdXRGYWN0b3J5ID0gKG9yaWdpbmFsKSA9PiB7XG4gICAgY29uc3Qgc3R5bGVzID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUob3JpZ2luYWwpO1xuICAgIGNvbnN0IG5ld0VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgbmV3RWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2lkJywgb3JpZ2luYWwuaWQpO1xuICAgIE9iamVjdC52YWx1ZXMoc3R5bGVzKS5mb3JFYWNoKCAocHJvcCkgPT4ge1xuICAgICAgICBpZiAoISBzdHlsZXNbcHJvcF0gfHwgISBpc05hTihwcm9wKSApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBuZXdFbGVtZW50LnN0eWxlLnNldFByb3BlcnR5KHByb3AsJycgKyBzdHlsZXNbcHJvcF0pO1xuICAgIH0pO1xuICAgIHJldHVybiBuZXdFbGVtZW50O1xufVxuXG5leHBvcnQgZGVmYXVsdCBkY2NJbnB1dEZhY3Rvcnk7IiwiaW1wb3J0IGRjY0lucHV0RmFjdG9yeSBmcm9tIFwiLi4vSGVscGVyL0RjY0lucHV0RmFjdG9yeVwiO1xuaW1wb3J0IHtzaG93fSBmcm9tIFwiLi4vSGVscGVyL0hpZGluZ1wiO1xuXG5jbGFzcyBDcmVkaXRDYXJkUmVuZGVyZXIge1xuXG4gICAgY29uc3RydWN0b3IoZGVmYXVsdENvbmZpZywgZXJyb3JIYW5kbGVyLCBzcGlubmVyKSB7XG4gICAgICAgIHRoaXMuZGVmYXVsdENvbmZpZyA9IGRlZmF1bHRDb25maWc7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyID0gZXJyb3JIYW5kbGVyO1xuICAgICAgICB0aGlzLnNwaW5uZXIgPSBzcGlubmVyO1xuICAgICAgICB0aGlzLmNhcmRWYWxpZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmZvcm1WYWxpZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSA9IG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKHdyYXBwZXIsIGNvbnRleHRDb25maWcpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgKFxuICAgICAgICAgICAgICAgIHRoaXMuZGVmYXVsdENvbmZpZy5jb250ZXh0ICE9PSAnY2hlY2tvdXQnXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5kZWZhdWx0Q29uZmlnLmNvbnRleHQgIT09ICdwYXktbm93J1xuICAgICAgICAgICAgKVxuICAgICAgICAgICAgfHwgd3JhcHBlciA9PT0gbnVsbFxuICAgICAgICAgICAgfHwgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKSA9PT0gbnVsbFxuICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0eXBlb2YgcGF5cGFsLkhvc3RlZEZpZWxkcyA9PT0gJ3VuZGVmaW5lZCdcbiAgICAgICAgICAgIHx8ICEgcGF5cGFsLkhvc3RlZEZpZWxkcy5pc0VsaWdpYmxlKClcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCB3cmFwcGVyRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iod3JhcHBlcik7XG4gICAgICAgICAgICB3cmFwcGVyRWxlbWVudC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHdyYXBwZXJFbGVtZW50KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1dHRvblNlbGVjdG9yID0gd3JhcHBlciArICcgYnV0dG9uJztcblxuICAgICAgICBpZiAodGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnRlYXJkb3duKClcbiAgICAgICAgICAgICAgICAuY2F0Y2goZXJyID0+IGNvbnNvbGUuZXJyb3IoYEhvc3RlZCBmaWVsZHMgdGVhcmRvd24gZXJyb3I6ICR7ZXJyfWApKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGdhdGVXYXlCb3ggPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcucGF5bWVudF9ib3gucGF5bWVudF9tZXRob2RfcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5Jyk7XG4gICAgICAgIGlmKCEgZ2F0ZVdheUJveCkge1xuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgb2xkRGlzcGxheVN0eWxlID0gZ2F0ZVdheUJveC5zdHlsZS5kaXNwbGF5O1xuICAgICAgICBnYXRlV2F5Qm94LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuXG4gICAgICAgIGNvbnN0IGhpZGVEY2NHYXRld2F5ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3BwY3AtaGlkZS1kY2MnKTtcbiAgICAgICAgaWYgKGhpZGVEY2NHYXRld2F5KSB7XG4gICAgICAgICAgICBoaWRlRGNjR2F0ZXdheS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGhpZGVEY2NHYXRld2F5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNhcmROdW1iZXJGaWVsZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXInKTtcblxuICAgICAgICBjb25zdCBzdHlsZXNSYXcgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShjYXJkTnVtYmVyRmllbGQpO1xuICAgICAgICBsZXQgc3R5bGVzID0ge307XG4gICAgICAgIE9iamVjdC52YWx1ZXMoc3R5bGVzUmF3KS5mb3JFYWNoKCAocHJvcCkgPT4ge1xuICAgICAgICAgICAgaWYgKCEgc3R5bGVzUmF3W3Byb3BdKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3R5bGVzW3Byb3BdID0gJycgKyBzdHlsZXNSYXdbcHJvcF07XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGNhcmROdW1iZXIgPSBkY2NJbnB1dEZhY3RvcnkoY2FyZE51bWJlckZpZWxkKTtcbiAgICAgICAgY2FyZE51bWJlckZpZWxkLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGNhcmROdW1iZXIsIGNhcmROdW1iZXJGaWVsZCk7XG5cbiAgICAgICAgY29uc3QgY2FyZEV4cGlyeUZpZWxkID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWV4cGlyeScpO1xuICAgICAgICBjb25zdCBjYXJkRXhwaXJ5ID0gZGNjSW5wdXRGYWN0b3J5KGNhcmRFeHBpcnlGaWVsZCk7XG4gICAgICAgIGNhcmRFeHBpcnlGaWVsZC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChjYXJkRXhwaXJ5LCBjYXJkRXhwaXJ5RmllbGQpO1xuXG4gICAgICAgIGNvbnN0IGNhcmRDb2RlRmllbGQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjJyk7XG4gICAgICAgIGNvbnN0IGNhcmRDb2RlID0gZGNjSW5wdXRGYWN0b3J5KGNhcmRDb2RlRmllbGQpO1xuICAgICAgICBjYXJkQ29kZUZpZWxkLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGNhcmRDb2RlLCBjYXJkQ29kZUZpZWxkKTtcblxuICAgICAgICBnYXRlV2F5Qm94LnN0eWxlLmRpc3BsYXkgPSBvbGREaXNwbGF5U3R5bGU7XG5cbiAgICAgICAgY29uc3QgZm9ybVdyYXBwZXIgPSAnLnBheW1lbnRfYm94IHBheW1lbnRfbWV0aG9kX3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheSc7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHRoaXMuZGVmYXVsdENvbmZpZy5lbmZvcmNlX3ZhdWx0XG4gICAgICAgICAgICAmJiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1XcmFwcGVyICsgJyAucHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpXG4gICAgICAgICkge1xuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihmb3JtV3JhcHBlciArICcgLnBwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5jaGVja2VkID0gdHJ1ZTtcbiAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVdyYXBwZXIgKyAnIC5wcGNwLWNyZWRpdC1jYXJkLXZhdWx0Jykuc2V0QXR0cmlidXRlKCdkaXNhYmxlZCcsIHRydWUpO1xuICAgICAgICB9XG4gICAgICAgIHBheXBhbC5Ib3N0ZWRGaWVsZHMucmVuZGVyKHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyOiBjb250ZXh0Q29uZmlnLmNyZWF0ZU9yZGVyLFxuICAgICAgICAgICAgc3R5bGVzOiB7XG4gICAgICAgICAgICAgICAgJ2lucHV0Jzogc3R5bGVzXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZmllbGRzOiB7XG4gICAgICAgICAgICAgICAgbnVtYmVyOiB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGVjdG9yOiAnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicsXG4gICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyOiB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5sYWJlbHMuY3JlZGl0X2NhcmRfbnVtYmVyLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgY3Z2OiB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGVjdG9yOiAnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWN2YycsXG4gICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyOiB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5sYWJlbHMuY3Z2LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZXhwaXJhdGlvbkRhdGU6IHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0b3I6ICcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5JyxcbiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI6IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5tbV95eSxcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pLnRoZW4oaG9zdGVkRmllbGRzID0+IHtcbiAgICAgICAgICAgIGRvY3VtZW50LmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFwiaG9zdGVkX2ZpZWxkc19sb2FkZWRcIikpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UgPSBob3N0ZWRGaWVsZHM7XG5cbiAgICAgICAgICAgIGhvc3RlZEZpZWxkcy5vbignaW5wdXRTdWJtaXRSZXF1ZXN0JywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuX3N1Ym1pdChjb250ZXh0Q29uZmlnKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaG9zdGVkRmllbGRzLm9uKCdjYXJkVHlwZUNoYW5nZScsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICggISBldmVudC5jYXJkcy5sZW5ndGggKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2FyZFZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgdmFsaWRDYXJkcyA9IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLnZhbGlkX2NhcmRzO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FyZFZhbGlkID0gdmFsaWRDYXJkcy5pbmRleE9mKGV2ZW50LmNhcmRzWzBdLnR5cGUpICE9PSAtMTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICBob3N0ZWRGaWVsZHMub24oJ3ZhbGlkaXR5Q2hhbmdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZm9ybVZhbGlkID0gT2JqZWN0LmtleXMoZXZlbnQuZmllbGRzKS5ldmVyeShmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBldmVudC5maWVsZHNba2V5XS5pc1ZhbGlkO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgdGhpcy5mb3JtVmFsaWQgPSBmb3JtVmFsaWQ7XG5cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBzaG93KGJ1dHRvblNlbGVjdG9yKTtcblxuICAgICAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iod3JhcHBlcikuZ2V0QXR0cmlidXRlKCdkYXRhLXBwY3Atc3Vic2NyaWJlZCcpICE9PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcihidXR0b25TZWxlY3RvcikuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgICAgICAgICAgICAgJ2NsaWNrJyxcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3N1Ym1pdChjb250ZXh0Q29uZmlnKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpLnNldEF0dHJpYnV0ZSgnZGF0YS1wcGNwLXN1YnNjcmliZWQnLCB0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3BheW1lbnRfbWV0aG9kX3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheScpLmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAgICAgICAnY2xpY2snLFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2xhYmVsW2Zvcj1wcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1udW1iZXJdJykuY2xpY2soKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKVxuICAgIH1cblxuICAgIGRpc2FibGVGaWVsZHMoKSB7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2Uuc2V0QXR0cmlidXRlKHtcbiAgICAgICAgICAgICAgICBmaWVsZDogJ251bWJlcicsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiAnZGlzYWJsZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2Uuc2V0QXR0cmlidXRlKHtcbiAgICAgICAgICAgICAgICBmaWVsZDogJ2N2dicsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiAnZGlzYWJsZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2Uuc2V0QXR0cmlidXRlKHtcbiAgICAgICAgICAgICAgICBmaWVsZDogJ2V4cGlyYXRpb25EYXRlJyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBlbmFibGVGaWVsZHMoKSB7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UucmVtb3ZlQXR0cmlidXRlKHtcbiAgICAgICAgICAgICAgICBmaWVsZDogJ251bWJlcicsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiAnZGlzYWJsZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UucmVtb3ZlQXR0cmlidXRlKHtcbiAgICAgICAgICAgICAgICBmaWVsZDogJ2N2dicsXG4gICAgICAgICAgICAgICAgYXR0cmlidXRlOiAnZGlzYWJsZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UucmVtb3ZlQXR0cmlidXRlKHtcbiAgICAgICAgICAgICAgICBmaWVsZDogJ2V4cGlyYXRpb25EYXRlJyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBfc3VibWl0KGNvbnRleHRDb25maWcpIHtcbiAgICAgICAgdGhpcy5zcGlubmVyLmJsb2NrKCk7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmNsZWFyKCk7XG5cbiAgICAgICAgaWYgKHRoaXMuZm9ybVZhbGlkICYmIHRoaXMuY2FyZFZhbGlkKSB7XG4gICAgICAgICAgICBjb25zdCBzYXZlX2NhcmQgPSB0aGlzLmRlZmF1bHRDb25maWcuY2FuX3NhdmVfdmF1bHRfdG9rZW4gPyB0cnVlIDogZmFsc2U7XG4gICAgICAgICAgICBsZXQgdmF1bHQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpID9cbiAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmNoZWNrZWQgOiBzYXZlX2NhcmQ7XG4gICAgICAgICAgICBpZiAodGhpcy5kZWZhdWx0Q29uZmlnLmVuZm9yY2VfdmF1bHQpIHtcbiAgICAgICAgICAgICAgICB2YXVsdCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBjb250aW5nZW5jeSA9IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmNvbnRpbmdlbmN5O1xuICAgICAgICAgICAgY29uc3QgaG9zdGVkRmllbGRzRGF0YSA9IHtcbiAgICAgICAgICAgICAgICB2YXVsdDogdmF1bHRcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoY29udGluZ2VuY3kgIT09ICdOT18zRF9TRUNVUkUnKSB7XG4gICAgICAgICAgICAgICAgaG9zdGVkRmllbGRzRGF0YS5jb250aW5nZW5jaWVzID0gW2NvbnRpbmdlbmN5XTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuZGVmYXVsdENvbmZpZy5wYXllcikge1xuICAgICAgICAgICAgICAgIGhvc3RlZEZpZWxkc0RhdGEuY2FyZGhvbGRlck5hbWUgPSB0aGlzLmRlZmF1bHRDb25maWcucGF5ZXIubmFtZS5naXZlbl9uYW1lICsgJyAnICsgdGhpcy5kZWZhdWx0Q29uZmlnLnBheWVyLm5hbWUuc3VybmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghaG9zdGVkRmllbGRzRGF0YS5jYXJkaG9sZGVyTmFtZSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpcnN0TmFtZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdiaWxsaW5nX2ZpcnN0X25hbWUnKSA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdiaWxsaW5nX2ZpcnN0X25hbWUnKS52YWx1ZSA6ICcnO1xuICAgICAgICAgICAgICAgIGNvbnN0IGxhc3ROYW1lID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JpbGxpbmdfbGFzdF9uYW1lJykgPyBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYmlsbGluZ19sYXN0X25hbWUnKS52YWx1ZSA6ICcnO1xuXG4gICAgICAgICAgICAgICAgaG9zdGVkRmllbGRzRGF0YS5jYXJkaG9sZGVyTmFtZSA9IGZpcnN0TmFtZSArICcgJyArIGxhc3ROYW1lO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zdWJtaXQoaG9zdGVkRmllbGRzRGF0YSkudGhlbigocGF5bG9hZCkgPT4ge1xuICAgICAgICAgICAgICAgIHBheWxvYWQub3JkZXJJRCA9IHBheWxvYWQub3JkZXJJZDtcbiAgICAgICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgICAgIHJldHVybiBjb250ZXh0Q29uZmlnLm9uQXBwcm92ZShwYXlsb2FkKTtcbiAgICAgICAgICAgIH0pLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5zcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5jbGVhcigpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGVyci5kZXRhaWxzKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLm1lc3NhZ2UoZXJyLmRldGFpbHMubWFwKGQgPT4gYCR7ZC5pc3N1ZX0gJHtkLmRlc2NyaXB0aW9ufWApLmpvaW4oJzxici8+JyksIHRydWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSAhIHRoaXMuY2FyZFZhbGlkID8gdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLmNhcmRfbm90X3N1cHBvcnRlZCA6IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5maWVsZHNfbm90X3ZhbGlkO1xuICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIubWVzc2FnZShtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IENyZWRpdENhcmRSZW5kZXJlcjtcbiIsImNvbnN0IHN0b3JhZ2VLZXkgPSAncHBjcC1kYXRhLWNsaWVudC1pZCc7XG5cbmNvbnN0IHZhbGlkYXRlVG9rZW4gPSAodG9rZW4sIHVzZXIpID0+IHtcbiAgICBpZiAoISB0b2tlbikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICh0b2tlbi51c2VyICE9PSB1c2VyKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgY3VycmVudFRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICBjb25zdCBpc0V4cGlyZWQgPSBjdXJyZW50VGltZSA+PSB0b2tlbi5leHBpcmF0aW9uICogMTAwMDtcbiAgICByZXR1cm4gISBpc0V4cGlyZWQ7XG59XG5cbmNvbnN0IHN0b3JlZFRva2VuRm9yVXNlciA9ICh1c2VyKSA9PiB7XG4gICAgY29uc3QgdG9rZW4gPSBKU09OLnBhcnNlKHNlc3Npb25TdG9yYWdlLmdldEl0ZW0oc3RvcmFnZUtleSkpO1xuICAgIGlmICh2YWxpZGF0ZVRva2VuKHRva2VuLCB1c2VyKSkge1xuICAgICAgICByZXR1cm4gdG9rZW4udG9rZW47XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuXG5jb25zdCBzdG9yZVRva2VuID0gKHRva2VuKSA9PiB7XG4gICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShzdG9yYWdlS2V5LCBKU09OLnN0cmluZ2lmeSh0b2tlbikpO1xufVxuXG5jb25zdCBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyID0gKHNjcmlwdCwgY29uZmlnKSA9PiB7XG4gICAgZmV0Y2goY29uZmlnLmVuZHBvaW50LCB7XG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBub25jZTogY29uZmlnLm5vbmNlXG4gICAgICAgIH0pXG4gICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICB9KS50aGVuKChkYXRhKT0+e1xuICAgICAgICBjb25zdCBpc1ZhbGlkID0gdmFsaWRhdGVUb2tlbihkYXRhLCBjb25maWcudXNlcik7XG4gICAgICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHN0b3JlVG9rZW4oZGF0YSk7XG4gICAgICAgIHNjcmlwdC5zZXRBdHRyaWJ1dGUoJ2RhdGEtY2xpZW50LXRva2VuJywgZGF0YS50b2tlbik7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKHNjcmlwdCk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXI7XG4iLCJjbGFzcyBNZXNzYWdlUmVuZGVyZXIge1xuXG4gICAgY29uc3RydWN0b3IoY29uZmlnKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIH1cblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgaWYgKCEgdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgcGF5cGFsLk1lc3NhZ2VzKHtcbiAgICAgICAgICAgIGFtb3VudDogdGhpcy5jb25maWcuYW1vdW50LFxuICAgICAgICAgICAgcGxhY2VtZW50OiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQsXG4gICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuc3R5bGVcbiAgICAgICAgfSkucmVuZGVyKHRoaXMuY29uZmlnLndyYXBwZXIpO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbigndXBkYXRlZF9jYXJ0X3RvdGFscycsICgpID0+IHtcbiAgICAgICAgICAgIHBheXBhbC5NZXNzYWdlcyh7XG4gICAgICAgICAgICAgICAgYW1vdW50OiB0aGlzLmNvbmZpZy5hbW91bnQsXG4gICAgICAgICAgICAgICAgcGxhY2VtZW50OiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQsXG4gICAgICAgICAgICAgICAgc3R5bGU6IHRoaXMuY29uZmlnLnN0eWxlXG4gICAgICAgICAgICB9KS5yZW5kZXIodGhpcy5jb25maWcud3JhcHBlcik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHJlbmRlcldpdGhBbW91bnQoYW1vdW50KSB7XG5cbiAgICAgICAgaWYgKCEgdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbmV3V3JhcHBlciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBuZXdXcmFwcGVyLnNldEF0dHJpYnV0ZSgnaWQnLCB0aGlzLmNvbmZpZy53cmFwcGVyLnJlcGxhY2UoJyMnLCAnJykpO1xuXG4gICAgICAgIGNvbnN0IHNpYmxpbmcgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpLm5leHRTaWJsaW5nO1xuICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpLnBhcmVudEVsZW1lbnQucmVtb3ZlQ2hpbGQoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKSk7XG4gICAgICAgIHNpYmxpbmcucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUobmV3V3JhcHBlciwgc2libGluZyk7XG4gICAgICAgIHBheXBhbC5NZXNzYWdlcyh7XG4gICAgICAgICAgICBhbW91bnQsXG4gICAgICAgICAgICBwbGFjZW1lbnQ6IHRoaXMuY29uZmlnLnBsYWNlbWVudCxcbiAgICAgICAgICAgIHN0eWxlOiB0aGlzLmNvbmZpZy5zdHlsZVxuICAgICAgICB9KS5yZW5kZXIodGhpcy5jb25maWcud3JhcHBlcik7XG4gICAgfVxuXG4gICAgc2hvdWxkUmVuZGVyKCkge1xuXG4gICAgICAgIGlmICh0eXBlb2YgcGF5cGFsLk1lc3NhZ2VzID09PSAndW5kZWZpbmVkJyB8fCB0eXBlb2YgdGhpcy5jb25maWcud3JhcHBlciA9PT0gJ3VuZGVmaW5lZCcgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCEgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IE1lc3NhZ2VSZW5kZXJlcjtcbiIsImNsYXNzIFNwaW5uZXIge1xuXG4gICAgY29uc3RydWN0b3IodGFyZ2V0ID0gJ2Zvcm0ud29vY29tbWVyY2UtY2hlY2tvdXQnKSB7XG4gICAgICAgIHRoaXMudGFyZ2V0ID0gdGFyZ2V0O1xuICAgIH1cblxuICAgIHNldFRhcmdldCh0YXJnZXQpIHtcbiAgICAgICAgdGhpcy50YXJnZXQgPSB0YXJnZXQ7XG4gICAgfVxuXG4gICAgYmxvY2soKSB7XG5cbiAgICAgICAgalF1ZXJ5KCB0aGlzLnRhcmdldCApLmJsb2NrKHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBvdmVybGF5Q1NTOiB7XG4gICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJyNmZmYnLFxuICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAuNlxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICB1bmJsb2NrKCkge1xuXG4gICAgICAgIGpRdWVyeSggdGhpcy50YXJnZXQgKS51bmJsb2NrKCk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBTcGlubmVyO1xuIiwiaW1wb3J0IHtQYXltZW50TWV0aG9kc30gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gXCIuLi9FcnJvckhhbmRsZXJcIjtcblxuY2xhc3MgRnJlZVRyaWFsSGFuZGxlciB7XG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgc3Bpbm5lcixcbiAgICAgICAgZXJyb3JIYW5kbGVyXG4gICAgKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLnNwaW5uZXIgPSBzcGlubmVyO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICB9XG5cbiAgICBoYW5kbGUoKVxuICAgIHtcbiAgICAgICAgdGhpcy5zcGlubmVyLmJsb2NrKCk7XG5cbiAgICAgICAgZmV0Y2godGhpcy5jb25maWcuYWpheC52YXVsdF9wYXlwYWwuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLmNvbmZpZy5hamF4LnZhdWx0X3BheXBhbC5ub25jZSxcbiAgICAgICAgICAgICAgICByZXR1cm5fdXJsOiBsb2NhdGlvbi5ocmVmXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgfSkudGhlbihyZXMgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oZGF0YSA9PiB7XG4gICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihkYXRhKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5tZXNzYWdlKGRhdGEuZGF0YS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxvY2F0aW9uLmhyZWYgPSBkYXRhLmRhdGEuYXBwcm92ZV9saW5rO1xuICAgICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgRnJlZVRyaWFsSGFuZGxlcjtcbiIsImltcG9ydCBNaW5pQ2FydEJvb3RzdGFwIGZyb20gJy4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL01pbmlDYXJ0Qm9vdHN0YXAnO1xuaW1wb3J0IFNpbmdsZVByb2R1Y3RCb290c3RhcCBmcm9tICcuL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9TaW5nbGVQcm9kdWN0Qm9vdHN0YXAnO1xuaW1wb3J0IENhcnRCb290c3RyYXAgZnJvbSAnLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2FydEJvb3RzdGFwJztcbmltcG9ydCBDaGVja291dEJvb3RzdGFwIGZyb20gJy4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL0NoZWNrb3V0Qm9vdHN0YXAnO1xuaW1wb3J0IFBheU5vd0Jvb3RzdHJhcCBmcm9tIFwiLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvUGF5Tm93Qm9vdHN0cmFwXCI7XG5pbXBvcnQgUmVuZGVyZXIgZnJvbSAnLi9tb2R1bGVzL1JlbmRlcmVyL1JlbmRlcmVyJztcbmltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi9tb2R1bGVzL0Vycm9ySGFuZGxlcic7XG5pbXBvcnQgQ3JlZGl0Q2FyZFJlbmRlcmVyIGZyb20gXCIuL21vZHVsZXMvUmVuZGVyZXIvQ3JlZGl0Q2FyZFJlbmRlcmVyXCI7XG5pbXBvcnQgZGF0YUNsaWVudElkQXR0cmlidXRlSGFuZGxlciBmcm9tIFwiLi9tb2R1bGVzL0RhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXJcIjtcbmltcG9ydCBNZXNzYWdlUmVuZGVyZXIgZnJvbSBcIi4vbW9kdWxlcy9SZW5kZXJlci9NZXNzYWdlUmVuZGVyZXJcIjtcbmltcG9ydCBTcGlubmVyIGZyb20gXCIuL21vZHVsZXMvSGVscGVyL1NwaW5uZXJcIjtcbmltcG9ydCB7XG4gICAgZ2V0Q3VycmVudFBheW1lbnRNZXRob2QsXG4gICAgT1JERVJfQlVUVE9OX1NFTEVDVE9SLFxuICAgIFBheW1lbnRNZXRob2RzXG59IGZyb20gXCIuL21vZHVsZXMvSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcbmltcG9ydCB7aGlkZSwgc2V0VmlzaWJsZX0gZnJvbSBcIi4vbW9kdWxlcy9IZWxwZXIvSGlkaW5nXCI7XG5pbXBvcnQge2lzQ2hhbmdlUGF5bWVudFBhZ2V9IGZyb20gXCIuL21vZHVsZXMvSGVscGVyL1N1YnNjcmlwdGlvbnNcIjtcbmltcG9ydCBGcmVlVHJpYWxIYW5kbGVyIGZyb20gXCIuL21vZHVsZXMvQWN0aW9uSGFuZGxlci9GcmVlVHJpYWxIYW5kbGVyXCI7XG5cbmNvbnN0IGJ1dHRvbnNTcGlubmVyID0gbmV3IFNwaW5uZXIoJy5wcGMtYnV0dG9uLXdyYXBwZXInKTtcbmNvbnN0IGNhcmRzU3Bpbm5lciA9IG5ldyBTcGlubmVyKCcjcHBjcC1ob3N0ZWQtZmllbGRzJyk7XG5cbmNvbnN0IGJvb3RzdHJhcCA9ICgpID0+IHtcbiAgICBjb25zdCBlcnJvckhhbmRsZXIgPSBuZXcgRXJyb3JIYW5kbGVyKFBheVBhbENvbW1lcmNlR2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyk7XG4gICAgY29uc3Qgc3Bpbm5lciA9IG5ldyBTcGlubmVyKCk7XG4gICAgY29uc3QgY3JlZGl0Q2FyZFJlbmRlcmVyID0gbmV3IENyZWRpdENhcmRSZW5kZXJlcihQYXlQYWxDb21tZXJjZUdhdGV3YXksIGVycm9ySGFuZGxlciwgc3Bpbm5lcik7XG5cbiAgICBjb25zdCBmcmVlVHJpYWxIYW5kbGVyID0gbmV3IEZyZWVUcmlhbEhhbmRsZXIoUGF5UGFsQ29tbWVyY2VHYXRld2F5LCBzcGlubmVyLCBlcnJvckhhbmRsZXIpO1xuXG4gICAgY29uc3Qgb25TbWFydEJ1dHRvbkNsaWNrID0gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgd2luZG93LnBwY3BGdW5kaW5nU291cmNlID0gZGF0YS5mdW5kaW5nU291cmNlO1xuXG4gICAgICAgIGNvbnN0IGZvcm0gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLndvb2NvbW1lcmNlLWNoZWNrb3V0Jyk7XG4gICAgICAgIGlmIChmb3JtKSB7XG4gICAgICAgICAgICBqUXVlcnkoJyNwcGNwLWZ1bmRpbmctc291cmNlLWZvcm0taW5wdXQnKS5yZW1vdmUoKTtcbiAgICAgICAgICAgIGZvcm0uaW5zZXJ0QWRqYWNlbnRIVE1MKFxuICAgICAgICAgICAgICAgICdiZWZvcmVlbmQnLFxuICAgICAgICAgICAgICAgIGA8aW5wdXQgdHlwZT1cImhpZGRlblwiIG5hbWU9XCJwcGNwLWZ1bmRpbmctc291cmNlXCIgdmFsdWU9XCIke2RhdGEuZnVuZGluZ1NvdXJjZX1cIiBpZD1cInBwY3AtZnVuZGluZy1zb3VyY2UtZm9ybS1pbnB1dFwiPmBcbiAgICAgICAgICAgIClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGlzRnJlZVRyaWFsID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LmlzX2ZyZWVfdHJpYWxfY2FydDtcbiAgICAgICAgaWYgKGlzRnJlZVRyaWFsICYmIGRhdGEuZnVuZGluZ1NvdXJjZSAhPT0gJ2NhcmQnKSB7XG4gICAgICAgICAgICBmcmVlVHJpYWxIYW5kbGVyLmhhbmRsZSgpO1xuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbnMucmVqZWN0KCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IG9uU21hcnRCdXR0b25zSW5pdCA9ICgpID0+IHtcbiAgICAgICAgYnV0dG9uc1NwaW5uZXIudW5ibG9jaygpO1xuICAgIH07XG4gICAgY29uc3QgcmVuZGVyZXIgPSBuZXcgUmVuZGVyZXIoY3JlZGl0Q2FyZFJlbmRlcmVyLCBQYXlQYWxDb21tZXJjZUdhdGV3YXksIG9uU21hcnRCdXR0b25DbGljaywgb25TbWFydEJ1dHRvbnNJbml0KTtcbiAgICBjb25zdCBtZXNzYWdlUmVuZGVyZXIgPSBuZXcgTWVzc2FnZVJlbmRlcmVyKFBheVBhbENvbW1lcmNlR2F0ZXdheS5tZXNzYWdlcyk7XG4gICAgY29uc3QgY29udGV4dCA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0O1xuICAgIGlmIChjb250ZXh0ID09PSAnbWluaS1jYXJ0JyB8fCBjb250ZXh0ID09PSAncHJvZHVjdCcpIHtcbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5taW5pX2NhcnRfYnV0dG9uc19lbmFibGVkID09PSAnMScpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pbmlDYXJ0Qm9vdHN0cmFwID0gbmV3IE1pbmlDYXJ0Qm9vdHN0YXAoXG4gICAgICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgICAgIHJlbmRlcmVyXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBtaW5pQ2FydEJvb3RzdHJhcC5pbml0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29udGV4dCA9PT0gJ3Byb2R1Y3QnICYmIFBheVBhbENvbW1lcmNlR2F0ZXdheS5zaW5nbGVfcHJvZHVjdF9idXR0b25zX2VuYWJsZWQgPT09ICcxJykge1xuICAgICAgICBjb25zdCBzaW5nbGVQcm9kdWN0Qm9vdHN0cmFwID0gbmV3IFNpbmdsZVByb2R1Y3RCb290c3RhcChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheSxcbiAgICAgICAgICAgIHJlbmRlcmVyLFxuICAgICAgICAgICAgbWVzc2FnZVJlbmRlcmVyLFxuICAgICAgICApO1xuXG4gICAgICAgIHNpbmdsZVByb2R1Y3RCb290c3RyYXAuaW5pdCgpO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0ID09PSAnY2FydCcpIHtcbiAgICAgICAgY29uc3QgY2FydEJvb3RzdHJhcCA9IG5ldyBDYXJ0Qm9vdHN0cmFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICk7XG5cbiAgICAgICAgY2FydEJvb3RzdHJhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdjaGVja291dCcpIHtcbiAgICAgICAgY29uc3QgY2hlY2tvdXRCb290c3RhcCA9IG5ldyBDaGVja291dEJvb3RzdGFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICAgICBtZXNzYWdlUmVuZGVyZXIsXG4gICAgICAgICAgICBzcGlubmVyXG4gICAgICAgICk7XG5cbiAgICAgICAgY2hlY2tvdXRCb290c3RhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdwYXktbm93JyApIHtcbiAgICAgICAgY29uc3QgcGF5Tm93Qm9vdHN0cmFwID0gbmV3IFBheU5vd0Jvb3RzdHJhcChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheSxcbiAgICAgICAgICAgIHJlbmRlcmVyLFxuICAgICAgICAgICAgbWVzc2FnZVJlbmRlcmVyLFxuICAgICAgICAgICAgc3Bpbm5lclxuICAgICAgICApO1xuICAgICAgICBwYXlOb3dCb290c3RyYXAuaW5pdCgpO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0ICE9PSAnY2hlY2tvdXQnKSB7XG4gICAgICAgIG1lc3NhZ2VSZW5kZXJlci5yZW5kZXIoKTtcbiAgICB9XG59O1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAnRE9NQ29udGVudExvYWRlZCcsXG4gICAgKCkgPT4ge1xuICAgICAgICBpZiAoIXR5cGVvZiAoUGF5UGFsQ29tbWVyY2VHYXRld2F5KSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignUGF5UGFsIGJ1dHRvbiBjb3VsZCBub3QgYmUgY29uZmlndXJlZC4nKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0ICE9PSAnY2hlY2tvdXQnXG4gICAgICAgICAgICAmJiBQYXlQYWxDb21tZXJjZUdhdGV3YXkuZGF0YV9jbGllbnRfaWQudXNlciA9PT0gMFxuICAgICAgICAgICAgJiYgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkLmhhc19zdWJzY3JpcHRpb25zXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU29tZXRpbWVzIFBheVBhbCBzY3JpcHQgdGFrZXMgbG9uZyB0aW1lIHRvIGxvYWQsXG4gICAgICAgIC8vIHNvIHdlIGFkZGl0aW9uYWxseSBoaWRlIHRoZSBzdGFuZGFyZCBvcmRlciBidXR0b24gaGVyZSB0byBhdm9pZCBmYWlsZWQgb3JkZXJzLlxuICAgICAgICAvLyBOb3JtYWxseSBpdCBpcyBoaWRkZW4gbGF0ZXIgYWZ0ZXIgdGhlIHNjcmlwdCBsb2FkLlxuICAgICAgICBjb25zdCBoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5ID0gKCkgPT4ge1xuICAgICAgICAgICAgLy8gb25seSBpbiBjaGVja291dCBhbmQgcGF5IG5vdyBwYWdlLCBvdGhlcndpc2UgaXQgbWF5IGJyZWFrIHRoaW5ncyAoZS5nLiBwYXltZW50IHZpYSBwcm9kdWN0IHBhZ2UpLFxuICAgICAgICAgICAgLy8gYW5kIGFsc28gdGhlIGxvYWRpbmcgc3Bpbm5lciBtYXkgbG9vayB3ZWlyZCBvbiBvdGhlciBwYWdlc1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICFbJ2NoZWNrb3V0JywgJ3BheS1ub3cnXS5pbmNsdWRlcyhQYXlQYWxDb21tZXJjZUdhdGV3YXkuY29udGV4dClcbiAgICAgICAgICAgICAgICB8fCBpc0NoYW5nZVBheW1lbnRQYWdlKClcbiAgICAgICAgICAgICAgICB8fCAoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmlzX2ZyZWVfdHJpYWxfY2FydCAmJiBQYXlQYWxDb21tZXJjZUdhdGV3YXkudmF1bHRlZF9wYXlwYWxfZW1haWwgIT09ICcnKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBjdXJyZW50UGF5bWVudE1ldGhvZCA9IGdldEN1cnJlbnRQYXltZW50TWV0aG9kKCk7XG4gICAgICAgICAgICBjb25zdCBpc1BheXBhbCA9IGN1cnJlbnRQYXltZW50TWV0aG9kID09PSBQYXltZW50TWV0aG9kcy5QQVlQQUw7XG4gICAgICAgICAgICBjb25zdCBpc0NhcmRzID0gY3VycmVudFBheW1lbnRNZXRob2QgPT09IFBheW1lbnRNZXRob2RzLkNBUkRTO1xuXG4gICAgICAgICAgICBzZXRWaXNpYmxlKE9SREVSX0JVVFRPTl9TRUxFQ1RPUiwgIWlzUGF5cGFsICYmICFpc0NhcmRzLCB0cnVlKTtcblxuICAgICAgICAgICAgaWYgKGlzUGF5cGFsKSB7XG4gICAgICAgICAgICAgICAgLy8gc3RvcHBlZCBhZnRlciB0aGUgZmlyc3QgcmVuZGVyaW5nIG9mIHRoZSBidXR0b25zLCBpbiBvbkluaXRcbiAgICAgICAgICAgICAgICBidXR0b25zU3Bpbm5lci5ibG9jaygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBidXR0b25zU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpc0NhcmRzKSB7XG4gICAgICAgICAgICAgICAgY2FyZHNTcGlubmVyLmJsb2NrKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhcmRzU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQpLm9uKCdob3N0ZWRfZmllbGRzX2xvYWRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIGNhcmRzU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGxldCBib290c3RyYXBwZWQgPSBmYWxzZTtcblxuICAgICAgICBoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5KCk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NoZWNrb3V0IHBheW1lbnRfbWV0aG9kX3NlbGVjdGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGJvb3RzdHJhcHBlZCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaGlkZU9yZGVyQnV0dG9uSWZQcGNwR2F0ZXdheSgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgICAgICAgc2NyaXB0LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGJvb3RzdHJhcHBlZCA9IHRydWU7XG5cbiAgICAgICAgICAgIGJvb3RzdHJhcCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgc2NyaXB0LnNldEF0dHJpYnV0ZSgnc3JjJywgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmJ1dHRvbi51cmwpO1xuICAgICAgICBPYmplY3QuZW50cmllcyhQYXlQYWxDb21tZXJjZUdhdGV3YXkuc2NyaXB0X2F0dHJpYnV0ZXMpLmZvckVhY2goXG4gICAgICAgICAgICAoa2V5VmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKGtleVZhbHVlWzBdLCBrZXlWYWx1ZVsxXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5kYXRhX2NsaWVudF9pZC5zZXRfYXR0cmlidXRlKSB7XG4gICAgICAgICAgICBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyKHNjcmlwdCwgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKHNjcmlwdCk7XG4gICAgfSxcbik7XG4iXSwibmFtZXMiOlsiRXJyb3JIYW5kbGVyIiwiY29uc3RydWN0b3IiLCJnZW5lcmljRXJyb3JUZXh0Iiwid3JhcHBlciIsImRvY3VtZW50IiwicXVlcnlTZWxlY3RvciIsIm1lc3NhZ2VzTGlzdCIsImdlbmVyaWNFcnJvciIsImNsYXNzTGlzdCIsImNvbnRhaW5zIiwiY2xlYXIiLCJtZXNzYWdlIiwiYXBwZW5kUHJlcGFyZWRFcnJvck1lc3NhZ2VFbGVtZW50IiwiZXJyb3JNZXNzYWdlRWxlbWVudCIsInByZXBhcmVNZXNzYWdlc0xpc3QiLCJyZXBsYWNlV2l0aCIsInRleHQiLCJwZXJzaXN0IiwiU3RyaW5nIiwibGVuZ3RoIiwiRXJyb3IiLCJhZGQiLCJyZW1vdmUiLCJtZXNzYWdlTm9kZSIsInByZXBhcmVNZXNzYWdlc0xpc3RJdGVtIiwiYXBwZW5kQ2hpbGQiLCJqUXVlcnkiLCJzY3JvbGxfdG9fbm90aWNlcyIsImNyZWF0ZUVsZW1lbnQiLCJzZXRBdHRyaWJ1dGUiLCJsaSIsImlubmVySFRNTCIsInNhbml0aXplIiwidGV4dGFyZWEiLCJ2YWx1ZSIsInJlcGxhY2UiLCJvbkFwcHJvdmUiLCJjb250ZXh0IiwiZXJyb3JIYW5kbGVyIiwiZGF0YSIsImFjdGlvbnMiLCJmZXRjaCIsImNvbmZpZyIsImFqYXgiLCJhcHByb3ZlX29yZGVyIiwiZW5kcG9pbnQiLCJtZXRob2QiLCJib2R5IiwiSlNPTiIsInN0cmluZ2lmeSIsIm5vbmNlIiwib3JkZXJfaWQiLCJvcmRlcklEIiwiZnVuZGluZ19zb3VyY2UiLCJ3aW5kb3ciLCJwcGNwRnVuZGluZ1NvdXJjZSIsInRoZW4iLCJyZXMiLCJqc29uIiwic3VjY2VzcyIsInJlc3RhcnQiLCJjYXRjaCIsImVyciIsImxvY2F0aW9uIiwiaHJlZiIsInJlZGlyZWN0IiwicGF5ZXJEYXRhIiwicGF5ZXIiLCJQYXlQYWxDb21tZXJjZUdhdGV3YXkiLCJwaG9uZSIsInBob25lX3R5cGUiLCJwaG9uZV9udW1iZXIiLCJuYXRpb25hbF9udW1iZXIiLCJlbWFpbF9hZGRyZXNzIiwibmFtZSIsInN1cm5hbWUiLCJnaXZlbl9uYW1lIiwiYWRkcmVzcyIsImNvdW50cnlfY29kZSIsImFkZHJlc3NfbGluZV8xIiwiYWRkcmVzc19saW5lXzIiLCJhZG1pbl9hcmVhXzEiLCJhZG1pbl9hcmVhXzIiLCJwb3N0YWxfY29kZSIsIlBheW1lbnRNZXRob2RzIiwiUEFZUEFMIiwiQ0FSRFMiLCJPUkRFUl9CVVRUT05fU0VMRUNUT1IiLCJnZXRDdXJyZW50UGF5bWVudE1ldGhvZCIsImVsIiwiaXNTYXZlZENhcmRTZWxlY3RlZCIsInNhdmVkQ2FyZExpc3QiLCJDYXJ0QWN0aW9uSGFuZGxlciIsImNvbmZpZ3VyYXRpb24iLCJjcmVhdGVPcmRlciIsImJuQ29kZSIsImJuX2NvZGVzIiwiY3JlYXRlX29yZGVyIiwicHVyY2hhc2VfdW5pdHMiLCJwYXltZW50X21ldGhvZCIsImJuX2NvZGUiLCJjb25zb2xlIiwiZXJyb3IiLCJpZCIsIm9uRXJyb3IiLCJNaW5pQ2FydEJvb3RzdGFwIiwiZ2F0ZXdheSIsInJlbmRlcmVyIiwiYWN0aW9uSGFuZGxlciIsImluaXQiLCJsYWJlbHMiLCJnZW5lcmljIiwicmVuZGVyIiwib24iLCJzaG91bGRSZW5kZXIiLCJidXR0b24iLCJtaW5pX2NhcnRfd3JhcHBlciIsImhvc3RlZF9maWVsZHMiLCJQcm9kdWN0IiwiVXBkYXRlQ2FydCIsInVwZGF0ZSIsIm9uUmVzb2x2ZSIsInByb2R1Y3RzIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJyZXN1bHQiLCJyZXNvbHZlZCIsIkJ1dHRvbnNUb2dnbGVMaXN0ZW5lciIsImVsZW1lbnQiLCJzaG93Q2FsbGJhY2siLCJoaWRlQ2FsbGJhY2siLCJvYnNlcnZlciIsImF0dHJpYnV0ZXMiLCJjYWxsYmFjayIsIk11dGF0aW9uT2JzZXJ2ZXIiLCJvYnNlcnZlIiwiZGlzY29ubmVjdCIsInF1YW50aXR5IiwidmFyaWF0aW9ucyIsIlNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyIiwidXBkYXRlQ2FydCIsInNob3dCdXR0b25DYWxsYmFjayIsImhpZGVCdXR0b25DYWxsYmFjayIsImZvcm1FbGVtZW50IiwiaGFzVmFyaWF0aW9ucyIsImdldFByb2R1Y3RzIiwiaXNHcm91cGVkUHJvZHVjdCIsInF0eSIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJmb3JFYWNoIiwiZWxlbWVudE5hbWUiLCJnZXRBdHRyaWJ1dGUiLCJtYXRjaCIsInBhcnNlSW50IiwicHVzaCIsInByb21pc2UiLCJtYXAiLCJTaW5nbGVQcm9kdWN0Qm9vdHN0YXAiLCJtZXNzYWdlcyIsImhhbmRsZUNoYW5nZSIsImhpZGVCdXR0b25zIiwiYWRkRXZlbnRMaXN0ZW5lciIsImJpbmQiLCJwcmljZUFtb3VudElzWmVybyIsInByaWNlVGV4dCIsImlubmVyVGV4dCIsImFtb3VudCIsInBhcnNlRmxvYXQiLCJjaGFuZ2VfY2FydCIsInNob3dCdXR0b25zIiwicmVuZGVyV2l0aEFtb3VudCIsIkNhcnRCb290c3RyYXAiLCJzcGlubmVyIiwiYmxvY2siLCJ1bmJsb2NrIiwiY29kZSIsImNsaWNrIiwiQ2hlY2tvdXRBY3Rpb25IYW5kbGVyIiwiZm9ybVNlbGVjdG9yIiwiZm9ybVZhbHVlcyIsInNlcmlhbGl6ZSIsImNyZWF0ZWFjY291bnQiLCJpcyIsImZvcm0iLCJkb21QYXJzZXIiLCJET01QYXJzZXIiLCJwYXJzZUZyb21TdHJpbmciLCJkZXRhaWxzIiwiZCIsImlzc3VlIiwiZGVzY3JpcHRpb24iLCJqb2luIiwiaW5wdXQiLCJjdXN0b21faWQiLCJhcHBlbmQiLCJvbkNhbmNlbCIsImdldEVsZW1lbnQiLCJzZWxlY3Rvck9yRWxlbWVudCIsImlzVmlzaWJsZSIsIm9mZnNldFdpZHRoIiwib2Zmc2V0SGVpZ2h0IiwiZ2V0Q2xpZW50UmVjdHMiLCJzZXRWaXNpYmxlIiwic2hvdyIsImltcG9ydGFudCIsImN1cnJlbnRWYWx1ZSIsInN0eWxlIiwiZ2V0UHJvcGVydHlWYWx1ZSIsInNldFByb3BlcnR5IiwicmVtb3ZlUHJvcGVydHkiLCJoaWRlIiwiQ2hlY2tvdXRCb290c3RhcCIsInN0YW5kYXJkT3JkZXJCdXR0b25TZWxlY3RvciIsImJ1dHRvbkNoYW5nZU9ic2VydmVyIiwidXBkYXRlVWkiLCJ2YWwiLCJjYW5jZWxfd3JhcHBlciIsImN1cnJlbnRQYXltZW50TWV0aG9kIiwiaXNQYXlwYWwiLCJpc0NhcmQiLCJpc1NhdmVkQ2FyZCIsImlzTm90T3VyR2F0ZXdheSIsImlzRnJlZVRyaWFsIiwiaXNfZnJlZV90cmlhbF9jYXJ0IiwiaGFzVmF1bHRlZFBheXBhbCIsInZhdWx0ZWRfcGF5cGFsX2VtYWlsIiwiZGlzYWJsZUNyZWRpdENhcmRGaWVsZHMiLCJlbmFibGVDcmVkaXRDYXJkRmllbGRzIiwiYWRkQ2xhc3MiLCJhdHRyIiwicmVtb3ZlQ2xhc3MiLCJpc0NoYW5nZVBheW1lbnRQYWdlIiwidXJsUGFyYW1zIiwiVVJMU2VhcmNoUGFyYW1zIiwic2VhcmNoIiwiaGFzIiwiUGF5Tm93Qm9vdHN0cmFwIiwiUmVuZGVyZXIiLCJjcmVkaXRDYXJkUmVuZGVyZXIiLCJkZWZhdWx0Q29uZmlnIiwib25TbWFydEJ1dHRvbkNsaWNrIiwib25TbWFydEJ1dHRvbnNJbml0IiwiaG9zdGVkRmllbGRzV3JhcHBlciIsImNvbnRleHRDb25maWciLCJyZW5kZXJCdXR0b25zIiwiaXNBbHJlYWR5UmVuZGVyZWQiLCJwYXlwYWwiLCJCdXR0b25zIiwibWluaV9jYXJ0X3N0eWxlIiwib25DbGljayIsIm9uSW5pdCIsImhhc0NoaWxkTm9kZXMiLCJkb21FbGVtZW50IiwiZGlzcGxheSIsImRpc2FibGVGaWVsZHMiLCJlbmFibGVGaWVsZHMiLCJkY2NJbnB1dEZhY3RvcnkiLCJvcmlnaW5hbCIsInN0eWxlcyIsImdldENvbXB1dGVkU3R5bGUiLCJuZXdFbGVtZW50IiwiT2JqZWN0IiwidmFsdWVzIiwicHJvcCIsImlzTmFOIiwiQ3JlZGl0Q2FyZFJlbmRlcmVyIiwiY2FyZFZhbGlkIiwiZm9ybVZhbGlkIiwiY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlIiwiSG9zdGVkRmllbGRzIiwiaXNFbGlnaWJsZSIsIndyYXBwZXJFbGVtZW50IiwicGFyZW50Tm9kZSIsInJlbW92ZUNoaWxkIiwiYnV0dG9uU2VsZWN0b3IiLCJ0ZWFyZG93biIsImdhdGVXYXlCb3giLCJvbGREaXNwbGF5U3R5bGUiLCJoaWRlRGNjR2F0ZXdheSIsImNhcmROdW1iZXJGaWVsZCIsInN0eWxlc1JhdyIsImNhcmROdW1iZXIiLCJyZXBsYWNlQ2hpbGQiLCJjYXJkRXhwaXJ5RmllbGQiLCJjYXJkRXhwaXJ5IiwiY2FyZENvZGVGaWVsZCIsImNhcmRDb2RlIiwiZm9ybVdyYXBwZXIiLCJlbmZvcmNlX3ZhdWx0IiwiY2hlY2tlZCIsImZpZWxkcyIsIm51bWJlciIsInNlbGVjdG9yIiwicGxhY2Vob2xkZXIiLCJjcmVkaXRfY2FyZF9udW1iZXIiLCJjdnYiLCJleHBpcmF0aW9uRGF0ZSIsIm1tX3l5IiwiaG9zdGVkRmllbGRzIiwiZGlzcGF0Y2hFdmVudCIsIkN1c3RvbUV2ZW50IiwiX3N1Ym1pdCIsImV2ZW50IiwiY2FyZHMiLCJ2YWxpZENhcmRzIiwidmFsaWRfY2FyZHMiLCJpbmRleE9mIiwidHlwZSIsImtleXMiLCJldmVyeSIsImtleSIsImlzVmFsaWQiLCJwcmV2ZW50RGVmYXVsdCIsImZpZWxkIiwiYXR0cmlidXRlIiwicmVtb3ZlQXR0cmlidXRlIiwic2F2ZV9jYXJkIiwiY2FuX3NhdmVfdmF1bHRfdG9rZW4iLCJ2YXVsdCIsImdldEVsZW1lbnRCeUlkIiwiY29udGluZ2VuY3kiLCJob3N0ZWRGaWVsZHNEYXRhIiwiY29udGluZ2VuY2llcyIsImNhcmRob2xkZXJOYW1lIiwiZmlyc3ROYW1lIiwibGFzdE5hbWUiLCJzdWJtaXQiLCJwYXlsb2FkIiwib3JkZXJJZCIsImNhcmRfbm90X3N1cHBvcnRlZCIsImZpZWxkc19ub3RfdmFsaWQiLCJzdG9yYWdlS2V5IiwidmFsaWRhdGVUb2tlbiIsInRva2VuIiwidXNlciIsImN1cnJlbnRUaW1lIiwiRGF0ZSIsImdldFRpbWUiLCJpc0V4cGlyZWQiLCJleHBpcmF0aW9uIiwic3RvcmVkVG9rZW5Gb3JVc2VyIiwicGFyc2UiLCJzZXNzaW9uU3RvcmFnZSIsImdldEl0ZW0iLCJzdG9yZVRva2VuIiwic2V0SXRlbSIsImRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIiLCJzY3JpcHQiLCJNZXNzYWdlUmVuZGVyZXIiLCJNZXNzYWdlcyIsInBsYWNlbWVudCIsIm5ld1dyYXBwZXIiLCJzaWJsaW5nIiwibmV4dFNpYmxpbmciLCJwYXJlbnRFbGVtZW50IiwiaW5zZXJ0QmVmb3JlIiwiU3Bpbm5lciIsInRhcmdldCIsInNldFRhcmdldCIsIm92ZXJsYXlDU1MiLCJiYWNrZ3JvdW5kIiwib3BhY2l0eSIsIkZyZWVUcmlhbEhhbmRsZXIiLCJoYW5kbGUiLCJ2YXVsdF9wYXlwYWwiLCJyZXR1cm5fdXJsIiwiYXBwcm92ZV9saW5rIiwiYnV0dG9uc1NwaW5uZXIiLCJjYXJkc1NwaW5uZXIiLCJib290c3RyYXAiLCJmcmVlVHJpYWxIYW5kbGVyIiwiZnVuZGluZ1NvdXJjZSIsImluc2VydEFkamFjZW50SFRNTCIsIm1lc3NhZ2VSZW5kZXJlciIsIm1pbmlfY2FydF9idXR0b25zX2VuYWJsZWQiLCJtaW5pQ2FydEJvb3RzdHJhcCIsInNpbmdsZV9wcm9kdWN0X2J1dHRvbnNfZW5hYmxlZCIsInNpbmdsZVByb2R1Y3RCb290c3RyYXAiLCJjYXJ0Qm9vdHN0cmFwIiwiY2hlY2tvdXRCb290c3RhcCIsInBheU5vd0Jvb3RzdHJhcCIsImRhdGFfY2xpZW50X2lkIiwiaGFzX3N1YnNjcmlwdGlvbnMiLCJoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5IiwiaW5jbHVkZXMiLCJpc0NhcmRzIiwiYm9vdHN0cmFwcGVkIiwidXJsIiwiZW50cmllcyIsInNjcmlwdF9hdHRyaWJ1dGVzIiwia2V5VmFsdWUiLCJzZXRfYXR0cmlidXRlIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///536\n")}},__webpack_exports__={};__webpack_modules__[536]()})();
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 priceAmountIsZero() {\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 const amount = parseFloat(priceText.replace(/([^\\d,\\.\\s]*)/g, ''));\n return amount === 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 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 }\n\n const amount = parseInt(priceText.replace(/([^\\d,\\.\\s]*)/g, ''));\n this.messages.renderWithAmount(amount);\n }, () => {\n this.renderer.hideButtons(this.gateway.button.wrapper);\n this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);\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 Object.values(styles).forEach(prop => {\n if (!styles[prop] || !isNaN(prop)) {\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\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 hostedFields.on('validityChange', event => {\n const formValid = Object.keys(event.fields).every(function (key) {\n return event.fields[key].isValid;\n });\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}\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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QUF4RCxDQUNLMFAsUUFBRCxJQUFjO0FBQ1ZqRCxJQUFBQSxNQUFNLENBQUNsVSxZQUFQLENBQW9CbVgsUUFBUSxDQUFDLENBQUQsQ0FBNUIsRUFBaUNBLFFBQVEsQ0FBQyxDQUFELENBQXpDO0FBQ0gsR0FITDs7QUFNQSxNQUFJNVUscUJBQXFCLENBQUNtVSxjQUF0QixDQUFxQ1UsYUFBekMsRUFBd0Q7QUFDcERuRCxJQUFBQSw0QkFBNEIsQ0FBQ0MsTUFBRCxFQUFTM1IscUJBQXFCLENBQUNtVSxjQUEvQixDQUE1QjtBQUNBO0FBQ0g7O0FBRURuWSxFQUFBQSxRQUFRLENBQUMyQyxJQUFULENBQWN3SixNQUFkLENBQXFCd0osTUFBckI7QUFDSCxDQXJGTCIsInNvdXJjZXMiOlsid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9FcnJvckhhbmRsZXIuanM/ZTY1YSIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvT25BcHByb3ZlSGFuZGxlci9vbkFwcHJvdmVGb3JDb250aW51ZS5qcz9jNDU0Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvUGF5ZXJEYXRhLmpzPzJhZjEiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlLmpzPzgwYTMiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0FjdGlvbkhhbmRsZXIvQ2FydEFjdGlvbkhhbmRsZXIuanM/ODJjZiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9NaW5pQ2FydEJvb3RzdGFwLmpzP2Q1NTIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9VcGRhdGVDYXJ0LmpzP2U0MjIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0hlbHBlci9CdXR0b25zVG9nZ2xlTGlzdGVuZXIuanM/ZTE5MyIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvRW50aXR5L1Byb2R1Y3QuanM/OWZmZiIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL21vZHVsZXMvQWN0aW9uSGFuZGxlci9TaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlci5qcz9kOWI3Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL1NpbmdsZVByb2R1Y3RCb290c3RhcC5qcz83YzE5Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL0NhcnRCb290c3RhcC5qcz81ZTk0Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvclBheU5vdy5qcz85MzA1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9BY3Rpb25IYW5kbGVyL0NoZWNrb3V0QWN0aW9uSGFuZGxlci5qcz84NTE1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvSGlkaW5nLmpzPzFkMzYiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2hlY2tvdXRCb290c3RhcC5qcz9jODU1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvU3Vic2NyaXB0aW9ucy5qcz9iODcwIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL1BheU5vd0Jvb3RzdHJhcC5qcz9kOWY1Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9SZW5kZXJlci9SZW5kZXJlci5qcz9mYTkzIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvRGNjSW5wdXRGYWN0b3J5LmpzPzJhMmYiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL1JlbmRlcmVyL0NyZWRpdENhcmRSZW5kZXJlci5qcz8zODdhIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9EYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyLmpzP2VlMGIiLCJ3ZWJwYWNrOi8vcHBjLWJ1dHRvbi8uL3Jlc291cmNlcy9qcy9tb2R1bGVzL1JlbmRlcmVyL01lc3NhZ2VSZW5kZXJlci5qcz9jZDAyIiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9IZWxwZXIvU3Bpbm5lci5qcz8xNzA4Iiwid2VicGFjazovL3BwYy1idXR0b24vLi9yZXNvdXJjZXMvanMvbW9kdWxlcy9BY3Rpb25IYW5kbGVyL0ZyZWVUcmlhbEhhbmRsZXIuanM/YWI3NyIsIndlYnBhY2s6Ly9wcGMtYnV0dG9uLy4vcmVzb3VyY2VzL2pzL2J1dHRvbi5qcz8wNjBmIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEVycm9ySGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3RvcihnZW5lcmljRXJyb3JUZXh0KVxuICAgIHtcbiAgICAgICAgdGhpcy5nZW5lcmljRXJyb3JUZXh0ID0gZ2VuZXJpY0Vycm9yVGV4dDtcbiAgICAgICAgdGhpcy53cmFwcGVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndvb2NvbW1lcmNlLW5vdGljZXMtd3JhcHBlcicpO1xuICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ3VsLndvb2NvbW1lcmNlLWVycm9yJyk7XG4gICAgfVxuXG4gICAgZ2VuZXJpY0Vycm9yKCkge1xuICAgICAgICBpZiAodGhpcy53cmFwcGVyLmNsYXNzTGlzdC5jb250YWlucygncHBjcC1wZXJzaXN0JykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNsZWFyKCk7XG4gICAgICAgIHRoaXMubWVzc2FnZSh0aGlzLmdlbmVyaWNFcnJvclRleHQpXG4gICAgfVxuXG4gICAgYXBwZW5kUHJlcGFyZWRFcnJvck1lc3NhZ2VFbGVtZW50KGVycm9yTWVzc2FnZUVsZW1lbnQpXG4gICAge1xuICAgICAgICBpZih0aGlzLm1lc3NhZ2VzTGlzdCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5wcmVwYXJlTWVzc2FnZXNMaXN0KCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdC5yZXBsYWNlV2l0aChlcnJvck1lc3NhZ2VFbGVtZW50KTtcbiAgICB9XG5cbiAgICBtZXNzYWdlKHRleHQsIHBlcnNpc3QgPSBmYWxzZSlcbiAgICB7XG4gICAgICAgIGlmKCEgdHlwZW9mIFN0cmluZyB8fCB0ZXh0Lmxlbmd0aCA9PT0gMCl7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0EgbmV3IG1lc3NhZ2UgdGV4dCBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZy4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKHRoaXMubWVzc2FnZXNMaXN0ID09PSBudWxsKXtcbiAgICAgICAgICAgIHRoaXMucHJlcGFyZU1lc3NhZ2VzTGlzdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBlcnNpc3QpIHtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlci5jbGFzc0xpc3QuYWRkKCdwcGNwLXBlcnNpc3QnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlci5jbGFzc0xpc3QucmVtb3ZlKCdwcGNwLXBlcnNpc3QnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBtZXNzYWdlTm9kZSA9IHRoaXMucHJlcGFyZU1lc3NhZ2VzTGlzdEl0ZW0odGV4dCk7XG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LmFwcGVuZENoaWxkKG1lc3NhZ2VOb2RlKTtcblxuICAgICAgICBqUXVlcnkuc2Nyb2xsX3RvX25vdGljZXMoalF1ZXJ5KCcud29vY29tbWVyY2Utbm90aWNlcy13cmFwcGVyJykpXG4gICAgfVxuXG4gICAgcHJlcGFyZU1lc3NhZ2VzTGlzdCgpXG4gICAge1xuICAgICAgICBpZih0aGlzLm1lc3NhZ2VzTGlzdCA9PT0gbnVsbCl7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3VsJyk7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdC5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgJ3dvb2NvbW1lcmNlLWVycm9yJyk7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzTGlzdC5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYWxlcnQnKTtcbiAgICAgICAgICAgIHRoaXMud3JhcHBlci5hcHBlbmRDaGlsZCh0aGlzLm1lc3NhZ2VzTGlzdCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcmVwYXJlTWVzc2FnZXNMaXN0SXRlbShtZXNzYWdlKVxuICAgIHtcbiAgICAgICAgY29uc3QgbGkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpO1xuICAgICAgICBsaS5pbm5lckhUTUwgPSBtZXNzYWdlO1xuXG4gICAgICAgIHJldHVybiBsaTtcbiAgICB9XG5cbiAgICBzYW5pdGl6ZSh0ZXh0KVxuICAgIHtcbiAgICAgICAgY29uc3QgdGV4dGFyZWEgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZXh0YXJlYScpO1xuICAgICAgICB0ZXh0YXJlYS5pbm5lckhUTUwgPSB0ZXh0O1xuICAgICAgICByZXR1cm4gdGV4dGFyZWEudmFsdWUucmVwbGFjZSgnRXJyb3I6ICcsICcnKTtcbiAgICB9XG5cbiAgICBjbGVhcigpXG4gICAge1xuICAgICAgICBpZiAodGhpcy5tZXNzYWdlc0xpc3QgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubWVzc2FnZXNMaXN0LmlubmVySFRNTCA9ICcnO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgRXJyb3JIYW5kbGVyO1xuIiwiY29uc3Qgb25BcHByb3ZlID0gKGNvbnRleHQsIGVycm9ySGFuZGxlcikgPT4ge1xuICAgIHJldHVybiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICByZXR1cm4gZmV0Y2goY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLmVuZHBvaW50LCB7XG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBub25jZTogY29udGV4dC5jb25maWcuYWpheC5hcHByb3ZlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgIG9yZGVyX2lkOmRhdGEub3JkZXJJRCxcbiAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgfSkudGhlbigocmVzKT0+e1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oKGRhdGEpPT57XG4gICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZXN0YXJ0KCkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbG9jYXRpb24uaHJlZiA9IGNvbnRleHQuY29uZmlnLnJlZGlyZWN0O1xuICAgICAgICB9KTtcblxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgb25BcHByb3ZlO1xuIiwiZXhwb3J0IGNvbnN0IHBheWVyRGF0YSA9ICgpID0+IHtcbiAgICBjb25zdCBwYXllciA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5wYXllcjtcbiAgICBpZiAoISBwYXllcikge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBwaG9uZSA9IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19waG9uZScpIHx8IHR5cGVvZiBwYXllci5waG9uZSAhPT0gJ3VuZGVmaW5lZCcpID9cbiAgICB7XG4gICAgICAgIHBob25lX3R5cGU6XCJIT01FXCIsXG4gICAgICAgICAgICBwaG9uZV9udW1iZXI6e1xuICAgICAgICAgICAgbmF0aW9uYWxfbnVtYmVyIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3Bob25lJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcGhvbmUnKS52YWx1ZSA6IHBheWVyLnBob25lLnBob25lX251bWJlci5uYXRpb25hbF9udW1iZXJcbiAgICAgICAgfVxuICAgIH0gOiBudWxsO1xuICAgIGNvbnN0IHBheWVyRGF0YSA9IHtcbiAgICAgICAgZW1haWxfYWRkcmVzczooZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfZW1haWwnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19lbWFpbCcpLnZhbHVlIDogcGF5ZXIuZW1haWxfYWRkcmVzcyxcbiAgICAgICAgbmFtZSA6IHtcbiAgICAgICAgICAgIHN1cm5hbWU6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19sYXN0X25hbWUnKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19sYXN0X25hbWUnKS52YWx1ZSA6IHBheWVyLm5hbWUuc3VybmFtZSxcbiAgICAgICAgICAgIGdpdmVuX25hbWU6IChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19maXJzdF9uYW1lJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfZmlyc3RfbmFtZScpLnZhbHVlIDogcGF5ZXIubmFtZS5naXZlbl9uYW1lXG4gICAgICAgIH0sXG4gICAgICAgIGFkZHJlc3MgOiB7XG4gICAgICAgICAgICBjb3VudHJ5X2NvZGUgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfY291bnRyeScpKSA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2NvdW50cnknKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuY291bnRyeV9jb2RlLFxuICAgICAgICAgICAgYWRkcmVzc19saW5lXzEgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18xJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18xJykudmFsdWUgOiBwYXllci5hZGRyZXNzLmFkZHJlc3NfbGluZV8xLFxuICAgICAgICAgICAgYWRkcmVzc19saW5lXzIgOiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18yJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfYWRkcmVzc18yJykudmFsdWUgOiBwYXllci5hZGRyZXNzLmFkZHJlc3NfbGluZV8yLFxuICAgICAgICAgICAgYWRtaW5fYXJlYV8xIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3N0YXRlJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfc3RhdGUnKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MuYWRtaW5fYXJlYV8xLFxuICAgICAgICAgICAgYWRtaW5fYXJlYV8yIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX2NpdHknKSkgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlsbGluZ19jaXR5JykudmFsdWUgOiBwYXllci5hZGRyZXNzLmFkbWluX2FyZWFfMixcbiAgICAgICAgICAgIHBvc3RhbF9jb2RlIDogKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNiaWxsaW5nX3Bvc3Rjb2RlJykpID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2JpbGxpbmdfcG9zdGNvZGUnKS52YWx1ZSA6IHBheWVyLmFkZHJlc3MucG9zdGFsX2NvZGVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAocGhvbmUpIHtcbiAgICAgICAgcGF5ZXJEYXRhLnBob25lID0gcGhvbmU7XG4gICAgfVxuICAgIHJldHVybiBwYXllckRhdGE7XG59XG4iLCJleHBvcnQgY29uc3QgUGF5bWVudE1ldGhvZHMgPSB7XG4gICAgUEFZUEFMOiAncHBjcC1nYXRld2F5JyxcbiAgICBDQVJEUzogJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheScsXG59O1xuXG5leHBvcnQgY29uc3QgT1JERVJfQlVUVE9OX1NFTEVDVE9SID0gJyNwbGFjZV9vcmRlcic7XG5cbmV4cG9ydCBjb25zdCBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCA9ICgpID0+IHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2lucHV0W25hbWU9XCJwYXltZW50X21ldGhvZFwiXTpjaGVja2VkJyk7XG4gICAgaWYgKCFlbCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gZWwudmFsdWU7XG59O1xuXG5leHBvcnQgY29uc3QgaXNTYXZlZENhcmRTZWxlY3RlZCA9ICgpID0+IHtcbiAgICBjb25zdCBzYXZlZENhcmRMaXN0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3NhdmVkLWNyZWRpdC1jYXJkJyk7XG4gICAgcmV0dXJuIHNhdmVkQ2FyZExpc3QgJiYgc2F2ZWRDYXJkTGlzdC52YWx1ZSAhPT0gJyc7XG59O1xuIiwiaW1wb3J0IG9uQXBwcm92ZSBmcm9tICcuLi9PbkFwcHJvdmVIYW5kbGVyL29uQXBwcm92ZUZvckNvbnRpbnVlLmpzJztcbmltcG9ydCB7cGF5ZXJEYXRhfSBmcm9tIFwiLi4vSGVscGVyL1BheWVyRGF0YVwiO1xuaW1wb3J0IHtQYXltZW50TWV0aG9kc30gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5cbmNsYXNzIENhcnRBY3Rpb25IYW5kbGVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGNvbmZpZywgZXJyb3JIYW5kbGVyKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICB9XG5cbiAgICBjb25maWd1cmF0aW9uKCkge1xuICAgICAgICBjb25zdCBjcmVhdGVPcmRlciA9IChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwYXllciA9IHBheWVyRGF0YSgpO1xuICAgICAgICAgICAgY29uc3QgYm5Db2RlID0gdHlwZW9mIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdICE9PSAndW5kZWZpbmVkJyA/XG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gOiAnJztcbiAgICAgICAgICAgIHJldHVybiBmZXRjaCh0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5lbmRwb2ludCwge1xuICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICBwdXJjaGFzZV91bml0czogW10sXG4gICAgICAgICAgICAgICAgICAgIHBheW1lbnRfbWV0aG9kOiBQYXltZW50TWV0aG9kcy5QQVlQQUwsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmRpbmdfc291cmNlOiB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgIGJuX2NvZGU6Ym5Db2RlLFxuICAgICAgICAgICAgICAgICAgICBwYXllcixcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dDp0aGlzLmNvbmZpZy5jb250ZXh0XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uKHJlcykge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoZGF0YS5kYXRhLm1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5kYXRhLmlkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNyZWF0ZU9yZGVyLFxuICAgICAgICAgICAgb25BcHByb3ZlOiBvbkFwcHJvdmUodGhpcywgdGhpcy5lcnJvckhhbmRsZXIpLFxuICAgICAgICAgICAgb25FcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDYXJ0QWN0aW9uSGFuZGxlcjtcbiIsImltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi4vRXJyb3JIYW5kbGVyJztcbmltcG9ydCBDYXJ0QWN0aW9uSGFuZGxlciBmcm9tICcuLi9BY3Rpb25IYW5kbGVyL0NhcnRBY3Rpb25IYW5kbGVyJztcblxuY2xhc3MgTWluaUNhcnRCb290c3RhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIpIHtcbiAgICAgICAgdGhpcy5nYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgICAgICB0aGlzLmFjdGlvbkhhbmRsZXIgPSBudWxsO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG5cbiAgICAgICAgdGhpcy5hY3Rpb25IYW5kbGVyID0gbmV3IENhcnRBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbignd2NfZnJhZ21lbnRzX2xvYWRlZCB3Y19mcmFnbWVudHNfcmVmcmVzaGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc2hvdWxkUmVuZGVyKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLm1pbmlfY2FydF93cmFwcGVyKSAhPT0gbnVsbFxuICAgICAgICAgICAgfHwgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy5taW5pX2NhcnRfd3JhcHBlcikgIT09IG51bGw7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LmJ1dHRvbi5taW5pX2NhcnRfd3JhcHBlcixcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLm1pbmlfY2FydF93cmFwcGVyLFxuICAgICAgICAgICAgdGhpcy5hY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKVxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgTWluaUNhcnRCb290c3RhcDtcbiIsImltcG9ydCBQcm9kdWN0IGZyb20gXCIuLi9FbnRpdHkvUHJvZHVjdFwiO1xuY2xhc3MgVXBkYXRlQ2FydCB7XG5cbiAgICBjb25zdHJ1Y3RvcihlbmRwb2ludCwgbm9uY2UpXG4gICAge1xuICAgICAgICB0aGlzLmVuZHBvaW50ID0gZW5kcG9pbnQ7XG4gICAgICAgIHRoaXMubm9uY2UgPSBub25jZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSBvblJlc29sdmVcbiAgICAgKiBAcGFyYW0ge1Byb2R1Y3RbXX0gcHJvZHVjdHNcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn1cbiAgICAgKi9cbiAgICB1cGRhdGUob25SZXNvbHZlLCBwcm9kdWN0cylcbiAgICB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBmZXRjaChcbiAgICAgICAgICAgICAgICB0aGlzLmVuZHBvaW50LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdHMsXG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKS50aGVuKFxuICAgICAgICAgICAgICAgIChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0Lmpzb24oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApLnRoZW4oKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghIHJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChyZXN1bHQuZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVzb2x2ZWQgPSBvblJlc29sdmUocmVzdWx0LmRhdGEpO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHJlc29sdmVkKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFVwZGF0ZUNhcnQ7IiwiLyoqXG4gKiBXaGVuIHlvdSBjYW4ndCBhZGQgc29tZXRoaW5nIHRvIHRoZSBjYXJ0LCB0aGUgUGF5UGFsIGJ1dHRvbnMgc2hvdWxkIG5vdCBzaG93LlxuICogVGhlcmVmb3JlIHdlIGxpc3RlbiBmb3IgY2hhbmdlcyBvbiB0aGUgYWRkIHRvIGNhcnQgYnV0dG9uIGFuZCBzaG93L2hpZGUgdGhlIGJ1dHRvbnMgYWNjb3JkaW5nbHkuXG4gKi9cblxuY2xhc3MgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyIHtcbiAgICBjb25zdHJ1Y3RvcihlbGVtZW50LCBzaG93Q2FsbGJhY2ssIGhpZGVDYWxsYmFjaylcbiAgICB7XG4gICAgICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgIHRoaXMuc2hvd0NhbGxiYWNrID0gc2hvd0NhbGxiYWNrO1xuICAgICAgICB0aGlzLmhpZGVDYWxsYmFjayA9IGhpZGVDYWxsYmFjaztcbiAgICAgICAgdGhpcy5vYnNlcnZlciA9IG51bGw7XG4gICAgfVxuXG4gICAgaW5pdCgpXG4gICAge1xuICAgICAgICBjb25zdCBjb25maWcgPSB7IGF0dHJpYnV0ZXMgOiB0cnVlIH07XG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuZWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2Rpc2FibGVkJykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhpZGVDYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuc2hvd0NhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGNhbGxiYWNrKTtcbiAgICAgICAgdGhpcy5vYnNlcnZlci5vYnNlcnZlKHRoaXMuZWxlbWVudCwgY29uZmlnKTtcbiAgICAgICAgY2FsbGJhY2soKTtcbiAgICB9XG5cbiAgICBkaXNjb25uZWN0KClcbiAgICB7XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyOyIsImNsYXNzIFByb2R1Y3Qge1xuXG4gICAgY29uc3RydWN0b3IoaWQsIHF1YW50aXR5LCB2YXJpYXRpb25zKSB7XG4gICAgICAgIHRoaXMuaWQgPSBpZDtcbiAgICAgICAgdGhpcy5xdWFudGl0eSA9IHF1YW50aXR5O1xuICAgICAgICB0aGlzLnZhcmlhdGlvbnMgPSB2YXJpYXRpb25zO1xuICAgIH1cblxuICAgIGRhdGEoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBpZDp0aGlzLmlkLFxuICAgICAgICAgICAgcXVhbnRpdHk6dGhpcy5xdWFudGl0eSxcbiAgICAgICAgICAgIHZhcmlhdGlvbnM6dGhpcy52YXJpYXRpb25zXG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IFByb2R1Y3Q7IiwiaW1wb3J0IEJ1dHRvbnNUb2dnbGVMaXN0ZW5lciBmcm9tICcuLi9IZWxwZXIvQnV0dG9uc1RvZ2dsZUxpc3RlbmVyJztcbmltcG9ydCBQcm9kdWN0IGZyb20gJy4uL0VudGl0eS9Qcm9kdWN0JztcbmltcG9ydCBvbkFwcHJvdmUgZnJvbSAnLi4vT25BcHByb3ZlSGFuZGxlci9vbkFwcHJvdmVGb3JDb250aW51ZSc7XG5pbXBvcnQge3BheWVyRGF0YX0gZnJvbSBcIi4uL0hlbHBlci9QYXllckRhdGFcIjtcbmltcG9ydCB7UGF5bWVudE1ldGhvZHN9IGZyb20gXCIuLi9IZWxwZXIvQ2hlY2tvdXRNZXRob2RTdGF0ZVwiO1xuXG5jbGFzcyBTaW5nbGVQcm9kdWN0QWN0aW9uSGFuZGxlciB7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgY29uZmlnLFxuICAgICAgICB1cGRhdGVDYXJ0LFxuICAgICAgICBzaG93QnV0dG9uQ2FsbGJhY2ssXG4gICAgICAgIGhpZGVCdXR0b25DYWxsYmFjayxcbiAgICAgICAgZm9ybUVsZW1lbnQsXG4gICAgICAgIGVycm9ySGFuZGxlclxuICAgICkge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy51cGRhdGVDYXJ0ID0gdXBkYXRlQ2FydDtcbiAgICAgICAgdGhpcy5zaG93QnV0dG9uQ2FsbGJhY2sgPSBzaG93QnV0dG9uQ2FsbGJhY2s7XG4gICAgICAgIHRoaXMuaGlkZUJ1dHRvbkNhbGxiYWNrID0gaGlkZUJ1dHRvbkNhbGxiYWNrO1xuICAgICAgICB0aGlzLmZvcm1FbGVtZW50ID0gZm9ybUVsZW1lbnQ7XG4gICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyID0gZXJyb3JIYW5kbGVyO1xuICAgIH1cblxuICAgIGNvbmZpZ3VyYXRpb24oKVxuICAgIHtcblxuICAgICAgICBpZiAoIHRoaXMuaGFzVmFyaWF0aW9ucygpICkge1xuICAgICAgICAgICAgY29uc3Qgb2JzZXJ2ZXIgPSBuZXcgQnV0dG9uc1RvZ2dsZUxpc3RlbmVyKFxuICAgICAgICAgICAgICAgIHRoaXMuZm9ybUVsZW1lbnQucXVlcnlTZWxlY3RvcignLnNpbmdsZV9hZGRfdG9fY2FydF9idXR0b24nKSxcbiAgICAgICAgICAgICAgICB0aGlzLnNob3dCdXR0b25DYWxsYmFjayxcbiAgICAgICAgICAgICAgICB0aGlzLmhpZGVCdXR0b25DYWxsYmFja1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIG9ic2VydmVyLmluaXQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjcmVhdGVPcmRlcjogdGhpcy5jcmVhdGVPcmRlcigpLFxuICAgICAgICAgICAgb25BcHByb3ZlOiBvbkFwcHJvdmUodGhpcywgdGhpcy5lcnJvckhhbmRsZXIpLFxuICAgICAgICAgICAgb25FcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjcmVhdGVPcmRlcigpXG4gICAge1xuICAgICAgICB2YXIgZ2V0UHJvZHVjdHMgPSBudWxsO1xuICAgICAgICBpZiAoISB0aGlzLmlzR3JvdXBlZFByb2R1Y3QoKSApIHtcbiAgICAgICAgICAgIGdldFByb2R1Y3RzID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlkID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW25hbWU9XCJhZGQtdG8tY2FydFwiXScpLnZhbHVlO1xuICAgICAgICAgICAgICAgIGNvbnN0IHF0eSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ1tuYW1lPVwicXVhbnRpdHlcIl0nKS52YWx1ZTtcbiAgICAgICAgICAgICAgICBjb25zdCB2YXJpYXRpb25zID0gdGhpcy52YXJpYXRpb25zKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtuZXcgUHJvZHVjdChpZCwgcXR5LCB2YXJpYXRpb25zKV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBnZXRQcm9kdWN0cyA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcm9kdWN0cyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMuZm9ybUVsZW1lbnQucXVlcnlTZWxlY3RvckFsbCgnaW5wdXRbdHlwZT1cIm51bWJlclwiXScpLmZvckVhY2goKGVsZW1lbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEgZWxlbWVudC52YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVsZW1lbnROYW1lID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ25hbWUnKS5tYXRjaCgvcXVhbnRpdHlcXFsoW1xcZF0qKVxcXS8pO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudE5hbWUubGVuZ3RoICE9PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaWQgPSBwYXJzZUludChlbGVtZW50TmFtZVsxXSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHF1YW50aXR5ID0gcGFyc2VJbnQoZWxlbWVudC52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIHByb2R1Y3RzLnB1c2gobmV3IFByb2R1Y3QoaWQsIHF1YW50aXR5LCBudWxsKSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICByZXR1cm4gcHJvZHVjdHM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY3JlYXRlT3JkZXIgPSAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICAgICAgY29uc3Qgb25SZXNvbHZlID0gKHB1cmNoYXNlX3VuaXRzKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGF5ZXIgPSBwYXllckRhdGEoKTtcbiAgICAgICAgICAgICAgICBjb25zdCBibkNvZGUgPSB0eXBlb2YgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gIT09ICd1bmRlZmluZWQnID9cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gOiAnJztcbiAgICAgICAgICAgICAgICByZXR1cm4gZmV0Y2godGhpcy5jb25maWcuYWpheC5jcmVhdGVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5ub25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHB1cmNoYXNlX3VuaXRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcGF5ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBibl9jb2RlOmJuQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBheW1lbnRfbWV0aG9kOiBQYXltZW50TWV0aG9kcy5QQVlQQUwsXG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dDp0aGlzLmNvbmZpZy5jb250ZXh0XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgICAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRhdGEuZGF0YS5pZDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGNvbnN0IHByb21pc2UgPSB0aGlzLnVwZGF0ZUNhcnQudXBkYXRlKG9uUmVzb2x2ZSwgZ2V0UHJvZHVjdHMoKSk7XG4gICAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZU9yZGVyO1xuICAgIH1cblxuICAgIHZhcmlhdGlvbnMoKVxuICAgIHtcblxuICAgICAgICBpZiAoISB0aGlzLmhhc1ZhcmlhdGlvbnMoKSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IFsuLi50aGlzLmZvcm1FbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXCJbbmFtZV49J2F0dHJpYnV0ZV8nXVwiKV0ubWFwKFxuICAgICAgICAgICAgKGVsZW1lbnQpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOmVsZW1lbnQudmFsdWUsXG4gICAgICAgICAgICAgICAgICAgIG5hbWU6ZWxlbWVudC5uYW1lXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gYXR0cmlidXRlcztcbiAgICB9XG5cbiAgICBoYXNWYXJpYXRpb25zKClcbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1FbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygndmFyaWF0aW9uc19mb3JtJyk7XG4gICAgfVxuXG4gICAgaXNHcm91cGVkUHJvZHVjdCgpXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtRWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2dyb3VwZWRfZm9ybScpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IFNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyO1xuIiwiaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuaW1wb3J0IFVwZGF0ZUNhcnQgZnJvbSBcIi4uL0hlbHBlci9VcGRhdGVDYXJ0XCI7XG5pbXBvcnQgU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXIgZnJvbSBcIi4uL0FjdGlvbkhhbmRsZXIvU2luZ2xlUHJvZHVjdEFjdGlvbkhhbmRsZXJcIjtcblxuY2xhc3MgU2luZ2xlUHJvZHVjdEJvb3RzdGFwIHtcbiAgICBjb25zdHJ1Y3RvcihnYXRld2F5LCByZW5kZXJlciwgbWVzc2FnZXMpIHtcbiAgICAgICAgdGhpcy5nYXRld2F5ID0gZ2F0ZXdheTtcbiAgICAgICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuICAgICAgICB0aGlzLm1lc3NhZ2VzID0gbWVzc2FnZXM7XG4gICAgfVxuXG5cbiAgICBoYW5kbGVDaGFuZ2UoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5oaWRlQnV0dG9ucyh0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKTtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKTtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXMuaGlkZU1lc3NhZ2VzKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH1cblxuICAgIGluaXQoKSB7XG5cbiAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0JykuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5oYW5kbGVDaGFuZ2UuYmluZCh0aGlzKSlcblxuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmVuZGVyKCkpIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcik7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLmhpZGVNZXNzYWdlcygpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcblxuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcblxuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0JykgIT09IG51bGwgJiYgIXRoaXMucHJpY2VBbW91bnRJc1plcm8oKTtcblxuICAgIH1cblxuICAgIHByaWNlQW1vdW50SXNaZXJvKCkge1xuXG4gICAgICAgIGxldCBwcmljZVRleHQgPSBcIjBcIjtcbiAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCBpbnMgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQgaW5zIC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKS5pbm5lclRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKSkge1xuICAgICAgICAgICAgcHJpY2VUZXh0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IC53b29jb21tZXJjZS1QcmljZS1hbW91bnQnKS5pbm5lclRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnByb2R1Y3QgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICBwcmljZVRleHQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcucHJvZHVjdCAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgcHJpY2VUZXh0ID0gcHJpY2VUZXh0LnJlcGxhY2UoLywvZywgJy4nKTtcbiAgICAgICAgY29uc3QgYW1vdW50ID0gcGFyc2VGbG9hdChwcmljZVRleHQucmVwbGFjZSgvKFteXFxkLFxcLlxcc10qKS9nLCAnJykpO1xuICAgICAgICByZXR1cm4gYW1vdW50ID09PSAwO1xuXG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBjb25zdCBhY3Rpb25IYW5kbGVyID0gbmV3IFNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LFxuICAgICAgICAgICAgbmV3IFVwZGF0ZUNhcnQoXG4gICAgICAgICAgICAgICAgdGhpcy5nYXRld2F5LmFqYXguY2hhbmdlX2NhcnQuZW5kcG9pbnQsXG4gICAgICAgICAgICAgICAgdGhpcy5nYXRld2F5LmFqYXguY2hhbmdlX2NhcnQubm9uY2UsXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2hvd0J1dHRvbnModGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNob3dCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgICAgIGxldCBwcmljZVRleHQgPSBcIjBcIjtcbiAgICAgICAgICAgICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IGlucyAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykpIHtcbiAgICAgICAgICAgICAgICAgICAgcHJpY2VUZXh0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignZm9ybS5jYXJ0IGlucyAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLmNhcnQgLndvb2NvbW1lcmNlLVByaWNlLWFtb3VudCcpKSB7XG4gICAgICAgICAgICAgICAgICAgIHByaWNlVGV4dCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCAud29vY29tbWVyY2UtUHJpY2UtYW1vdW50JykuaW5uZXJUZXh0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBhbW91bnQgPSBwYXJzZUludChwcmljZVRleHQucmVwbGFjZSgvKFteXFxkLFxcLlxcc10qKS9nLCAnJykpO1xuICAgICAgICAgICAgICAgIHRoaXMubWVzc2FnZXMucmVuZGVyV2l0aEFtb3VudChhbW91bnQpXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuaGlkZUJ1dHRvbnModGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmhpZGVCdXR0b25zKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2Zvcm0uY2FydCcpLFxuICAgICAgICAgICAgbmV3IEVycm9ySGFuZGxlcih0aGlzLmdhdGV3YXkubGFiZWxzLmVycm9yLmdlbmVyaWMpLFxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVuZGVyKFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5LmJ1dHRvbi53cmFwcGVyLFxuICAgICAgICAgICAgdGhpcy5nYXRld2F5Lmhvc3RlZF9maWVsZHMud3JhcHBlcixcbiAgICAgICAgICAgIGFjdGlvbkhhbmRsZXIuY29uZmlndXJhdGlvbigpLFxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgU2luZ2xlUHJvZHVjdEJvb3RzdGFwO1xuIiwiaW1wb3J0IENhcnRBY3Rpb25IYW5kbGVyIGZyb20gJy4uL0FjdGlvbkhhbmRsZXIvQ2FydEFjdGlvbkhhbmRsZXInO1xuaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuXG5jbGFzcyBDYXJ0Qm9vdHN0cmFwIHtcbiAgICBjb25zdHJ1Y3RvcihnYXRld2F5LCByZW5kZXJlcikge1xuICAgICAgICB0aGlzLmdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG4gICAgfVxuXG4gICAgaW5pdCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlbmRlcigpO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbigndXBkYXRlZF9jYXJ0X3RvdGFscyB1cGRhdGVkX2NoZWNrb3V0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc2hvdWxkUmVuZGVyKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIpICE9PVxuICAgICAgICAgICAgbnVsbCB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIpICE9PVxuICAgICAgICAgICAgbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGNvbnN0IGFjdGlvbkhhbmRsZXIgPSBuZXcgQ2FydEFjdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICBuZXcgRXJyb3JIYW5kbGVyKHRoaXMuZ2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyksXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW5kZXIoXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIsXG4gICAgICAgICAgICB0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyLFxuICAgICAgICAgICAgYWN0aW9uSGFuZGxlci5jb25maWd1cmF0aW9uKCksXG4gICAgICAgICk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDYXJ0Qm9vdHN0cmFwO1xuIiwiY29uc3Qgb25BcHByb3ZlID0gKGNvbnRleHQsIGVycm9ySGFuZGxlciwgc3Bpbm5lcikgPT4ge1xuICAgIHJldHVybiAoZGF0YSwgYWN0aW9ucykgPT4ge1xuICAgICAgICBzcGlubmVyLmJsb2NrKCk7XG4gICAgICAgIGVycm9ySGFuZGxlci5jbGVhcigpO1xuXG4gICAgICAgIHJldHVybiBmZXRjaChjb250ZXh0LmNvbmZpZy5hamF4LmFwcHJvdmVfb3JkZXIuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIG5vbmNlOiBjb250ZXh0LmNvbmZpZy5hamF4LmFwcHJvdmVfb3JkZXIubm9uY2UsXG4gICAgICAgICAgICAgICAgb3JkZXJfaWQ6ZGF0YS5vcmRlcklELFxuICAgICAgICAgICAgICAgIGZ1bmRpbmdfc291cmNlOiB3aW5kb3cucHBjcEZ1bmRpbmdTb3VyY2UsXG4gICAgICAgICAgICB9KVxuICAgICAgICB9KS50aGVuKChyZXMpPT57XG4gICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICAgICAgfSkudGhlbigoZGF0YSk9PntcbiAgICAgICAgICAgIHNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgaWYgKCFkYXRhLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5kYXRhLmNvZGUgPT09IDEwMCkge1xuICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIubWVzc2FnZShkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmdlbmVyaWNFcnJvcigpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGFjdGlvbnMgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBhY3Rpb25zLnJlc3RhcnQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBhY3Rpb25zLnJlc3RhcnQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEuZGF0YS5tZXNzYWdlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwbGFjZV9vcmRlcicpLmNsaWNrKClcbiAgICAgICAgfSk7XG5cbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IG9uQXBwcm92ZTtcbiIsImltcG9ydCBvbkFwcHJvdmUgZnJvbSAnLi4vT25BcHByb3ZlSGFuZGxlci9vbkFwcHJvdmVGb3JQYXlOb3cuanMnO1xuaW1wb3J0IHtwYXllckRhdGF9IGZyb20gXCIuLi9IZWxwZXIvUGF5ZXJEYXRhXCI7XG5pbXBvcnQge2dldEN1cnJlbnRQYXltZW50TWV0aG9kfSBmcm9tIFwiLi4vSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcblxuY2xhc3MgQ2hlY2tvdXRBY3Rpb25IYW5kbGVyIHtcblxuICAgIGNvbnN0cnVjdG9yKGNvbmZpZywgZXJyb3JIYW5kbGVyLCBzcGlubmVyKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICAgICAgdGhpcy5zcGlubmVyID0gc3Bpbm5lcjtcbiAgICB9XG5cbiAgICBjb25maWd1cmF0aW9uKCkge1xuICAgICAgICBjb25zdCBzcGlubmVyID0gdGhpcy5zcGlubmVyO1xuICAgICAgICBjb25zdCBjcmVhdGVPcmRlciA9IChkYXRhLCBhY3Rpb25zKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwYXllciA9IHBheWVyRGF0YSgpO1xuICAgICAgICAgICAgY29uc3QgYm5Db2RlID0gdHlwZW9mIHRoaXMuY29uZmlnLmJuX2NvZGVzW3RoaXMuY29uZmlnLmNvbnRleHRdICE9PSAndW5kZWZpbmVkJyA/XG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWcuYm5fY29kZXNbdGhpcy5jb25maWcuY29udGV4dF0gOiAnJztcblxuICAgICAgICAgICAgY29uc3QgZXJyb3JIYW5kbGVyID0gdGhpcy5lcnJvckhhbmRsZXI7XG5cbiAgICAgICAgICAgIGNvbnN0IGZvcm1TZWxlY3RvciA9IHRoaXMuY29uZmlnLmNvbnRleHQgPT09ICdjaGVja291dCcgPyAnZm9ybS5jaGVja291dCcgOiAnZm9ybSNvcmRlcl9yZXZpZXcnO1xuICAgICAgICAgICAgY29uc3QgZm9ybURhdGEgPSBuZXcgRm9ybURhdGEoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihmb3JtU2VsZWN0b3IpKTtcbiAgICAgICAgICAgIC8vIHdpbGwgbm90IGhhbmRsZSBmaWVsZHMgd2l0aCBtdWx0aXBsZSB2YWx1ZXMgKGNoZWNrYm94ZXMsIDxzZWxlY3QgbXVsdGlwbGU+KSwgYnV0IHdlIGRvIG5vdCBjYXJlIGFib3V0IHRoaXMgaGVyZVxuICAgICAgICAgICAgY29uc3QgZm9ybUpzb25PYmogPSBPYmplY3QuZnJvbUVudHJpZXMoZm9ybURhdGEpO1xuXG4gICAgICAgICAgICBjb25zdCBjcmVhdGVhY2NvdW50ID0galF1ZXJ5KCcjY3JlYXRlYWNjb3VudCcpLmlzKFwiOmNoZWNrZWRcIikgPyB0cnVlIDogZmFsc2U7XG5cbiAgICAgICAgICAgIHJldHVybiBmZXRjaCh0aGlzLmNvbmZpZy5hamF4LmNyZWF0ZV9vcmRlci5lbmRwb2ludCwge1xuICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHRoaXMuY29uZmlnLmFqYXguY3JlYXRlX29yZGVyLm5vbmNlLFxuICAgICAgICAgICAgICAgICAgICBwYXllcixcbiAgICAgICAgICAgICAgICAgICAgYm5fY29kZTpibkNvZGUsXG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6dGhpcy5jb25maWcuY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgb3JkZXJfaWQ6dGhpcy5jb25maWcub3JkZXJfaWQsXG4gICAgICAgICAgICAgICAgICAgIHBheW1lbnRfbWV0aG9kOiBnZXRDdXJyZW50UGF5bWVudE1ldGhvZCgpLFxuICAgICAgICAgICAgICAgICAgICBmdW5kaW5nX3NvdXJjZTogd2luZG93LnBwY3BGdW5kaW5nU291cmNlLFxuICAgICAgICAgICAgICAgICAgICBmb3JtOiBmb3JtSnNvbk9iaixcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlYWNjb3VudDogY3JlYXRlYWNjb3VudFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oKTtcbiAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgICAgICBzcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgICAgICAgICAgLy9oYW5kbGUgYm90aCBtZXNzYWdlcyBzZW50IGZyb20gV29vY29tbWVyY2UgKGRhdGEubWVzc2FnZXMpIGFuZCB0aGlzIHBsdWdpbiAoZGF0YS5kYXRhLm1lc3NhZ2UpXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YoZGF0YS5tZXNzYWdlcykgIT09ICd1bmRlZmluZWQnIClcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZG9tUGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JIYW5kbGVyLmFwcGVuZFByZXBhcmVkRXJyb3JNZXNzYWdlRWxlbWVudChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb21QYXJzZXIucGFyc2VGcm9tU3RyaW5nKGRhdGEubWVzc2FnZXMsICd0ZXh0L2h0bWwnKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucXVlcnlTZWxlY3RvcigndWwnKVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5jbGVhcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRhdGEuZGF0YS5kZXRhaWxzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvckhhbmRsZXIubWVzc2FnZShkYXRhLmRhdGEuZGV0YWlscy5tYXAoZCA9PiBgJHtkLmlzc3VlfSAke2QuZGVzY3JpcHRpb259YCkuam9pbignPGJyLz4nKSwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5tZXNzYWdlKGRhdGEuZGF0YS5tZXNzYWdlLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IGlucHV0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcbiAgICAgICAgICAgICAgICBpbnB1dC5zZXRBdHRyaWJ1dGUoJ3R5cGUnLCAnaGlkZGVuJyk7XG4gICAgICAgICAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKCduYW1lJywgJ3BwY3AtcmVzdW1lLW9yZGVyJyk7XG4gICAgICAgICAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKCd2YWx1ZScsIGRhdGEuZGF0YS5wdXJjaGFzZV91bml0c1swXS5jdXN0b21faWQpO1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVNlbGVjdG9yKS5hcHBlbmQoaW5wdXQpO1xuICAgICAgICAgICAgICAgIHJldHVybiBkYXRhLmRhdGEuaWQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY3JlYXRlT3JkZXIsXG4gICAgICAgICAgICBvbkFwcHJvdmU6b25BcHByb3ZlKHRoaXMsIHRoaXMuZXJyb3JIYW5kbGVyLCB0aGlzLnNwaW5uZXIpLFxuICAgICAgICAgICAgb25DYW5jZWw6ICgpID0+IHtcbiAgICAgICAgICAgICAgICBzcGlubmVyLnVuYmxvY2soKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkVycm9yOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuZ2VuZXJpY0Vycm9yKCk7XG4gICAgICAgICAgICAgICAgc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IENoZWNrb3V0QWN0aW9uSGFuZGxlcjtcbiIsImNvbnN0IGdldEVsZW1lbnQgPSAoc2VsZWN0b3JPckVsZW1lbnQpID0+IHtcbiAgICBpZiAodHlwZW9mIHNlbGVjdG9yT3JFbGVtZW50ID09PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihzZWxlY3Rvck9yRWxlbWVudCk7XG4gICAgfVxuICAgIHJldHVybiBzZWxlY3Rvck9yRWxlbWVudDtcbn1cblxuZXhwb3J0IGNvbnN0IGlzVmlzaWJsZSA9IChlbGVtZW50KSA9PiB7XG4gICAgcmV0dXJuICEhKGVsZW1lbnQub2Zmc2V0V2lkdGggfHwgZWxlbWVudC5vZmZzZXRIZWlnaHQgfHwgZWxlbWVudC5nZXRDbGllbnRSZWN0cygpLmxlbmd0aCk7XG59XG5cbmV4cG9ydCBjb25zdCBzZXRWaXNpYmxlID0gKHNlbGVjdG9yT3JFbGVtZW50LCBzaG93LCBpbXBvcnRhbnQgPSBmYWxzZSkgPT4ge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBnZXRFbGVtZW50KHNlbGVjdG9yT3JFbGVtZW50KTtcbiAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IGVsZW1lbnQuc3R5bGUuZ2V0UHJvcGVydHlWYWx1ZSgnZGlzcGxheScpO1xuXG4gICAgaWYgKCFzaG93KSB7XG4gICAgICAgIGlmIChjdXJyZW50VmFsdWUgPT09ICdub25lJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eSgnZGlzcGxheScsICdub25lJywgaW1wb3J0YW50ID8gJ2ltcG9ydGFudCcgOiAnJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGN1cnJlbnRWYWx1ZSA9PT0gJ25vbmUnKSB7XG4gICAgICAgICAgICBlbGVtZW50LnN0eWxlLnJlbW92ZVByb3BlcnR5KCdkaXNwbGF5Jyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzdGlsbCBub3QgdmlzaWJsZSAoaWYgc29tZXRoaW5nIGVsc2UgYWRkZWQgZGlzcGxheTogbm9uZSBpbiBDU1MpXG4gICAgICAgIGlmICghaXNWaXNpYmxlKGVsZW1lbnQpKSB7XG4gICAgICAgICAgICBlbGVtZW50LnN0eWxlLnNldFByb3BlcnR5KCdkaXNwbGF5JywgJ2Jsb2NrJyk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5leHBvcnQgY29uc3QgaGlkZSA9IChzZWxlY3Rvck9yRWxlbWVudCwgaW1wb3J0YW50ID0gZmFsc2UpID0+IHtcbiAgICBzZXRWaXNpYmxlKHNlbGVjdG9yT3JFbGVtZW50LCBmYWxzZSwgaW1wb3J0YW50KTtcbn07XG5cbmV4cG9ydCBjb25zdCBzaG93ID0gKHNlbGVjdG9yT3JFbGVtZW50KSA9PiB7XG4gICAgc2V0VmlzaWJsZShzZWxlY3Rvck9yRWxlbWVudCwgdHJ1ZSk7XG59O1xuIiwiaW1wb3J0IEVycm9ySGFuZGxlciBmcm9tICcuLi9FcnJvckhhbmRsZXInO1xuaW1wb3J0IENoZWNrb3V0QWN0aW9uSGFuZGxlciBmcm9tICcuLi9BY3Rpb25IYW5kbGVyL0NoZWNrb3V0QWN0aW9uSGFuZGxlcic7XG5pbXBvcnQgeyBzZXRWaXNpYmxlIH0gZnJvbSAnLi4vSGVscGVyL0hpZGluZyc7XG5pbXBvcnQge1xuICAgIGdldEN1cnJlbnRQYXltZW50TWV0aG9kLFxuICAgIGlzU2F2ZWRDYXJkU2VsZWN0ZWQsIE9SREVSX0JVVFRPTl9TRUxFQ1RPUixcbiAgICBQYXltZW50TWV0aG9kc1xufSBmcm9tIFwiLi4vSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcblxuY2xhc3MgQ2hlY2tvdXRCb290c3RhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIsIG1lc3NhZ2VzLCBzcGlubmVyKSB7XG4gICAgICAgIHRoaXMuZ2F0ZXdheSA9IGdhdGV3YXk7XG4gICAgICAgIHRoaXMucmVuZGVyZXIgPSByZW5kZXJlcjtcbiAgICAgICAgdGhpcy5tZXNzYWdlcyA9IG1lc3NhZ2VzO1xuICAgICAgICB0aGlzLnNwaW5uZXIgPSBzcGlubmVyO1xuXG4gICAgICAgIHRoaXMuc3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yID0gT1JERVJfQlVUVE9OX1NFTEVDVE9SO1xuXG4gICAgICAgIHRoaXMuYnV0dG9uQ2hhbmdlT2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcigoZWwpID0+IHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaW5pdCgpIHtcbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcblxuICAgICAgICAvLyBVbnNlbGVjdCBzYXZlZCBjYXJkLlxuICAgICAgICAvLyBXQyBzYXZlcyBmb3JtIHZhbHVlcywgc28gd2l0aCBvdXIgY3VycmVudCBVSSBpdCB3b3VsZCBiZSBhIGJpdCB3ZWlyZFxuICAgICAgICAvLyBpZiB0aGUgdXNlciBwYWlkIHdpdGggc2F2ZWQsIHRoZW4gYWZ0ZXIgc29tZSB0aW1lIHRyaWVzIHRvIHBheSBhZ2FpbixcbiAgICAgICAgLy8gYnV0IHdhbnRzIHRvIGVudGVyIGEgbmV3IGNhcmQsIGFuZCB0byBkbyB0aGF0IHRoZXkgaGF2ZSB0byBjaG9vc2Ug4oCcU2VsZWN0IHBheW1lbnTigJ0gaW4gdGhlIGxpc3QuXG4gICAgICAgIGpRdWVyeSgnI3NhdmVkLWNyZWRpdC1jYXJkJykudmFsKGpRdWVyeSgnI3NhdmVkLWNyZWRpdC1jYXJkIG9wdGlvbjpmaXJzdCcpLnZhbCgpKTtcblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQuYm9keSkub24oJ3VwZGF0ZWRfY2hlY2tvdXQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcigpXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGpRdWVyeShkb2N1bWVudC5ib2R5KS5vbigndXBkYXRlZF9jaGVja291dCBwYXltZW50X21ldGhvZF9zZWxlY3RlZCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVWkoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50KS5vbignaG9zdGVkX2ZpZWxkc19sb2FkZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICBqUXVlcnkoJyNzYXZlZC1jcmVkaXQtY2FyZCcpLm9uKCdjaGFuZ2UnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVVaSgpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy51cGRhdGVVaSgpO1xuICAgIH1cblxuICAgIHNob3VsZFJlbmRlcigpIHtcbiAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5nYXRld2F5LmJ1dHRvbi5jYW5jZWxfd3JhcHBlcikpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcikgIT09IG51bGwgfHwgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmdhdGV3YXkuaG9zdGVkX2ZpZWxkcy53cmFwcGVyKSAhPT0gbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIoKSB7XG4gICAgICAgIGlmICghdGhpcy5zaG91bGRSZW5kZXIoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIgKyAnPmRpdicpKSB7XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIgKyAnPmRpdicpLnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAnJyk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYWN0aW9uSGFuZGxlciA9IG5ldyBDaGVja291dEFjdGlvbkhhbmRsZXIoXG4gICAgICAgICAgICBQYXlQYWxDb21tZXJjZUdhdGV3YXksXG4gICAgICAgICAgICBuZXcgRXJyb3JIYW5kbGVyKHRoaXMuZ2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyksXG4gICAgICAgICAgICB0aGlzLnNwaW5uZXJcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnJlbmRlcmVyLnJlbmRlcihcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5idXR0b24ud3JhcHBlcixcbiAgICAgICAgICAgIHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIsXG4gICAgICAgICAgICBhY3Rpb25IYW5kbGVyLmNvbmZpZ3VyYXRpb24oKSxcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmJ1dHRvbkNoYW5nZU9ic2VydmVyLm9ic2VydmUoXG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuc3RhbmRhcmRPcmRlckJ1dHRvblNlbGVjdG9yKSxcbiAgICAgICAgICAgIHthdHRyaWJ1dGVzOiB0cnVlfVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHVwZGF0ZVVpKCkge1xuICAgICAgICBjb25zdCBjdXJyZW50UGF5bWVudE1ldGhvZCA9IGdldEN1cnJlbnRQYXltZW50TWV0aG9kKCk7XG4gICAgICAgIGNvbnN0IGlzUGF5cGFsID0gY3VycmVudFBheW1lbnRNZXRob2QgPT09IFBheW1lbnRNZXRob2RzLlBBWVBBTDtcbiAgICAgICAgY29uc3QgaXNDYXJkID0gY3VycmVudFBheW1lbnRNZXRob2QgPT09IFBheW1lbnRNZXRob2RzLkNBUkRTO1xuICAgICAgICBjb25zdCBpc1NhdmVkQ2FyZCA9IGlzQ2FyZCAmJiBpc1NhdmVkQ2FyZFNlbGVjdGVkKCk7XG4gICAgICAgIGNvbnN0IGlzTm90T3VyR2F0ZXdheSA9ICFpc1BheXBhbCAmJiAhaXNDYXJkO1xuICAgICAgICBjb25zdCBpc0ZyZWVUcmlhbCA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5pc19mcmVlX3RyaWFsX2NhcnQ7XG4gICAgICAgIGNvbnN0IGhhc1ZhdWx0ZWRQYXlwYWwgPSBQYXlQYWxDb21tZXJjZUdhdGV3YXkudmF1bHRlZF9wYXlwYWxfZW1haWwgIT09ICcnO1xuXG4gICAgICAgIHNldFZpc2libGUodGhpcy5zdGFuZGFyZE9yZGVyQnV0dG9uU2VsZWN0b3IsICAoaXNQYXlwYWwgJiYgaXNGcmVlVHJpYWwgJiYgaGFzVmF1bHRlZFBheXBhbCkgfHwgaXNOb3RPdXJHYXRld2F5IHx8IGlzU2F2ZWRDYXJkLCB0cnVlKTtcbiAgICAgICAgc2V0VmlzaWJsZSgnLnBwY3AtdmF1bHRlZC1wYXlwYWwtZGV0YWlscycsIGlzUGF5cGFsKTtcbiAgICAgICAgc2V0VmlzaWJsZSh0aGlzLmdhdGV3YXkuYnV0dG9uLndyYXBwZXIsIGlzUGF5cGFsICYmICEoaXNGcmVlVHJpYWwgJiYgaGFzVmF1bHRlZFBheXBhbCkpO1xuICAgICAgICBzZXRWaXNpYmxlKHRoaXMuZ2F0ZXdheS5tZXNzYWdlcy53cmFwcGVyLCBpc1BheXBhbCAmJiAhaXNGcmVlVHJpYWwpO1xuICAgICAgICBzZXRWaXNpYmxlKHRoaXMuZ2F0ZXdheS5ob3N0ZWRfZmllbGRzLndyYXBwZXIsIGlzQ2FyZCAmJiAhaXNTYXZlZENhcmQpO1xuXG4gICAgICAgIGlmIChpc1BheXBhbCAmJiAhaXNGcmVlVHJpYWwpIHtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXMucmVuZGVyKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNDYXJkKSB7XG4gICAgICAgICAgICBpZiAoaXNTYXZlZENhcmQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRpc2FibGVDcmVkaXRDYXJkRmllbGRzKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuZW5hYmxlQ3JlZGl0Q2FyZEZpZWxkcygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZGlzYWJsZUNyZWRpdENhcmRGaWVsZHMoKSB7XG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtbnVtYmVyXCJdJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtbnVtYmVyJykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1leHBpcnlcIl0nKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1leHBpcnknKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWN2Y1wiXScpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLWN2YycpLmFkZENsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwidmF1bHRcIl0nKS5hZGRDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuYWRkQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmF0dHIoXCJkaXNhYmxlZFwiLCB0cnVlKVxuICAgICAgICB0aGlzLnJlbmRlcmVyLmRpc2FibGVDcmVkaXRDYXJkRmllbGRzKClcbiAgICB9XG5cbiAgICBlbmFibGVDcmVkaXRDYXJkRmllbGRzKCkge1xuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlclwiXScpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnbGFiZWxbZm9yPVwicHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5XCJdJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5JykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCdsYWJlbFtmb3I9XCJwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmNcIl0nKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnKS5yZW1vdmVDbGFzcygncHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWZvcm0tZmllbGQtZGlzYWJsZWQnKVxuICAgICAgICBqUXVlcnkoJ2xhYmVsW2Zvcj1cInZhdWx0XCJdJykucmVtb3ZlQ2xhc3MoJ3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1mb3JtLWZpZWxkLWRpc2FibGVkJylcbiAgICAgICAgalF1ZXJ5KCcjcHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLnJlbW92ZUNsYXNzKCdwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktZm9ybS1maWVsZC1kaXNhYmxlZCcpXG4gICAgICAgIGpRdWVyeSgnI3BwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5hdHRyKFwiZGlzYWJsZWRcIiwgZmFsc2UpXG4gICAgICAgIHRoaXMucmVuZGVyZXIuZW5hYmxlQ3JlZGl0Q2FyZEZpZWxkcygpXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBDaGVja291dEJvb3RzdGFwXG4iLCJleHBvcnQgY29uc3QgaXNDaGFuZ2VQYXltZW50UGFnZSA9ICgpID0+IHtcbiAgICBjb25zdCB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpXG4gICAgcmV0dXJuIHVybFBhcmFtcy5oYXMoJ2NoYW5nZV9wYXltZW50X21ldGhvZCcpO1xufVxuIiwiaW1wb3J0IENoZWNrb3V0Qm9vdHN0YXAgZnJvbSAnLi9DaGVja291dEJvb3RzdGFwJ1xuaW1wb3J0IHtpc0NoYW5nZVBheW1lbnRQYWdlfSBmcm9tIFwiLi4vSGVscGVyL1N1YnNjcmlwdGlvbnNcIjtcblxuY2xhc3MgUGF5Tm93Qm9vdHN0cmFwIGV4dGVuZHMgQ2hlY2tvdXRCb290c3RhcCB7XG4gICAgY29uc3RydWN0b3IoZ2F0ZXdheSwgcmVuZGVyZXIsIG1lc3NhZ2VzLCBzcGlubmVyKSB7XG4gICAgICAgIHN1cGVyKGdhdGV3YXksIHJlbmRlcmVyLCBtZXNzYWdlcywgc3Bpbm5lcilcbiAgICB9XG5cbiAgICB1cGRhdGVVaSgpIHtcbiAgICAgICAgaWYgKGlzQ2hhbmdlUGF5bWVudFBhZ2UoKSkge1xuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBzdXBlci51cGRhdGVVaSgpO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUGF5Tm93Qm9vdHN0cmFwO1xuIiwiY2xhc3MgUmVuZGVyZXIge1xuICAgIGNvbnN0cnVjdG9yKGNyZWRpdENhcmRSZW5kZXJlciwgZGVmYXVsdENvbmZpZywgb25TbWFydEJ1dHRvbkNsaWNrLCBvblNtYXJ0QnV0dG9uc0luaXQpIHtcbiAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnID0gZGVmYXVsdENvbmZpZztcbiAgICAgICAgdGhpcy5jcmVkaXRDYXJkUmVuZGVyZXIgPSBjcmVkaXRDYXJkUmVuZGVyZXI7XG4gICAgICAgIHRoaXMub25TbWFydEJ1dHRvbkNsaWNrID0gb25TbWFydEJ1dHRvbkNsaWNrO1xuICAgICAgICB0aGlzLm9uU21hcnRCdXR0b25zSW5pdCA9IG9uU21hcnRCdXR0b25zSW5pdDtcbiAgICB9XG5cbiAgICByZW5kZXIod3JhcHBlciwgaG9zdGVkRmllbGRzV3JhcHBlciwgY29udGV4dENvbmZpZykge1xuXG4gICAgICAgIHRoaXMucmVuZGVyQnV0dG9ucyh3cmFwcGVyLCBjb250ZXh0Q29uZmlnKTtcbiAgICAgICAgdGhpcy5jcmVkaXRDYXJkUmVuZGVyZXIucmVuZGVyKGhvc3RlZEZpZWxkc1dyYXBwZXIsIGNvbnRleHRDb25maWcpO1xuICAgIH1cblxuICAgIHJlbmRlckJ1dHRvbnMod3JhcHBlciwgY29udGV4dENvbmZpZykge1xuICAgICAgICBpZiAoISBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpIHx8IHRoaXMuaXNBbHJlYWR5UmVuZGVyZWQod3JhcHBlcikgfHwgJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiBwYXlwYWwuQnV0dG9ucyApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHN0eWxlID0gd3JhcHBlciA9PT0gdGhpcy5kZWZhdWx0Q29uZmlnLmJ1dHRvbi53cmFwcGVyID8gdGhpcy5kZWZhdWx0Q29uZmlnLmJ1dHRvbi5zdHlsZSA6IHRoaXMuZGVmYXVsdENvbmZpZy5idXR0b24ubWluaV9jYXJ0X3N0eWxlO1xuICAgICAgICBwYXlwYWwuQnV0dG9ucyh7XG4gICAgICAgICAgICBzdHlsZSxcbiAgICAgICAgICAgIC4uLmNvbnRleHRDb25maWcsXG4gICAgICAgICAgICBvbkNsaWNrOiB0aGlzLm9uU21hcnRCdXR0b25DbGljayxcbiAgICAgICAgICAgIG9uSW5pdDogdGhpcy5vblNtYXJ0QnV0dG9uc0luaXQsXG4gICAgICAgIH0pLnJlbmRlcih3cmFwcGVyKTtcbiAgICB9XG5cbiAgICBpc0FscmVhZHlSZW5kZXJlZCh3cmFwcGVyKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpLmhhc0NoaWxkTm9kZXMoKTtcbiAgICB9XG5cbiAgICBoaWRlQnV0dG9ucyhlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGRvbUVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGVsZW1lbnQpO1xuICAgICAgICBpZiAoISBkb21FbGVtZW50ICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGRvbUVsZW1lbnQuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgc2hvd0J1dHRvbnMoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBkb21FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihlbGVtZW50KTtcbiAgICAgICAgaWYgKCEgZG9tRWxlbWVudCApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBkb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBkaXNhYmxlQ3JlZGl0Q2FyZEZpZWxkcygpIHtcbiAgICAgICAgdGhpcy5jcmVkaXRDYXJkUmVuZGVyZXIuZGlzYWJsZUZpZWxkcygpO1xuICAgIH1cblxuICAgIGVuYWJsZUNyZWRpdENhcmRGaWVsZHMoKSB7XG4gICAgICAgIHRoaXMuY3JlZGl0Q2FyZFJlbmRlcmVyLmVuYWJsZUZpZWxkcygpO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUmVuZGVyZXI7XG4iLCJjb25zdCBkY2NJbnB1dEZhY3RvcnkgPSAob3JpZ2luYWwpID0+IHtcbiAgICBjb25zdCBzdHlsZXMgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShvcmlnaW5hbCk7XG4gICAgY29uc3QgbmV3RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICBuZXdFbGVtZW50LnNldEF0dHJpYnV0ZSgnaWQnLCBvcmlnaW5hbC5pZCk7XG4gICAgT2JqZWN0LnZhbHVlcyhzdHlsZXMpLmZvckVhY2goIChwcm9wKSA9PiB7XG4gICAgICAgIGlmICghIHN0eWxlc1twcm9wXSB8fCAhIGlzTmFOKHByb3ApICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIG5ld0VsZW1lbnQuc3R5bGUuc2V0UHJvcGVydHkocHJvcCwnJyArIHN0eWxlc1twcm9wXSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIG5ld0VsZW1lbnQ7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGRjY0lucHV0RmFjdG9yeTsiLCJpbXBvcnQgZGNjSW5wdXRGYWN0b3J5IGZyb20gXCIuLi9IZWxwZXIvRGNjSW5wdXRGYWN0b3J5XCI7XG5pbXBvcnQge3Nob3d9IGZyb20gXCIuLi9IZWxwZXIvSGlkaW5nXCI7XG5cbmNsYXNzIENyZWRpdENhcmRSZW5kZXJlciB7XG5cbiAgICBjb25zdHJ1Y3RvcihkZWZhdWx0Q29uZmlnLCBlcnJvckhhbmRsZXIsIHNwaW5uZXIpIHtcbiAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnID0gZGVmYXVsdENvbmZpZztcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIgPSBlcnJvckhhbmRsZXI7XG4gICAgICAgIHRoaXMuc3Bpbm5lciA9IHNwaW5uZXI7XG4gICAgICAgIHRoaXMuY2FyZFZhbGlkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZm9ybVZhbGlkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlID0gbnVsbDtcbiAgICB9XG5cbiAgICByZW5kZXIod3JhcHBlciwgY29udGV4dENvbmZpZykge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICAoXG4gICAgICAgICAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnLmNvbnRleHQgIT09ICdjaGVja291dCdcbiAgICAgICAgICAgICAgICAmJiB0aGlzLmRlZmF1bHRDb25maWcuY29udGV4dCAhPT0gJ3BheS1ub3cnXG4gICAgICAgICAgICApXG4gICAgICAgICAgICB8fCB3cmFwcGVyID09PSBudWxsXG4gICAgICAgICAgICB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHdyYXBwZXIpID09PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHR5cGVvZiBwYXlwYWwuSG9zdGVkRmllbGRzID09PSAndW5kZWZpbmVkJ1xuICAgICAgICAgICAgfHwgISBwYXlwYWwuSG9zdGVkRmllbGRzLmlzRWxpZ2libGUoKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIGNvbnN0IHdyYXBwZXJFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKTtcbiAgICAgICAgICAgIHdyYXBwZXJFbGVtZW50LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQod3JhcHBlckVsZW1lbnQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYnV0dG9uU2VsZWN0b3IgPSB3cmFwcGVyICsgJyBidXR0b24nO1xuXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UudGVhcmRvd24oKVxuICAgICAgICAgICAgICAgIC5jYXRjaChlcnIgPT4gY29uc29sZS5lcnJvcihgSG9zdGVkIGZpZWxkcyB0ZWFyZG93biBlcnJvcjogJHtlcnJ9YCkpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50SG9zdGVkRmllbGRzSW5zdGFuY2UgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZ2F0ZVdheUJveCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5wYXltZW50X2JveC5wYXltZW50X21ldGhvZF9wcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXknKTtcbiAgICAgICAgaWYoISBnYXRlV2F5Qm94KSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBjb25zdCBvbGREaXNwbGF5U3R5bGUgPSBnYXRlV2F5Qm94LnN0eWxlLmRpc3BsYXk7XG4gICAgICAgIGdhdGVXYXlCb3guc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG5cbiAgICAgICAgY29uc3QgaGlkZURjY0dhdGV3YXkgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcHBjcC1oaWRlLWRjYycpO1xuICAgICAgICBpZiAoaGlkZURjY0dhdGV3YXkpIHtcbiAgICAgICAgICAgIGhpZGVEY2NHYXRld2F5LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoaGlkZURjY0dhdGV3YXkpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2FyZE51bWJlckZpZWxkID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3BwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcicpO1xuXG4gICAgICAgIGNvbnN0IHN0eWxlc1JhdyA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGNhcmROdW1iZXJGaWVsZCk7XG4gICAgICAgIGxldCBzdHlsZXMgPSB7fTtcbiAgICAgICAgT2JqZWN0LnZhbHVlcyhzdHlsZXNSYXcpLmZvckVhY2goIChwcm9wKSA9PiB7XG4gICAgICAgICAgICBpZiAoISBzdHlsZXNSYXdbcHJvcF0pIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzdHlsZXNbcHJvcF0gPSAnJyArIHN0eWxlc1Jhd1twcm9wXTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY2FyZE51bWJlciA9IGRjY0lucHV0RmFjdG9yeShjYXJkTnVtYmVyRmllbGQpO1xuICAgICAgICBjYXJkTnVtYmVyRmllbGQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoY2FyZE51bWJlciwgY2FyZE51bWJlckZpZWxkKTtcblxuICAgICAgICBjb25zdCBjYXJkRXhwaXJ5RmllbGQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtZXhwaXJ5Jyk7XG4gICAgICAgIGNvbnN0IGNhcmRFeHBpcnkgPSBkY2NJbnB1dEZhY3RvcnkoY2FyZEV4cGlyeUZpZWxkKTtcbiAgICAgICAgY2FyZEV4cGlyeUZpZWxkLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGNhcmRFeHBpcnksIGNhcmRFeHBpcnlGaWVsZCk7XG5cbiAgICAgICAgY29uc3QgY2FyZENvZGVGaWVsZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1jdmMnKTtcbiAgICAgICAgY29uc3QgY2FyZENvZGUgPSBkY2NJbnB1dEZhY3RvcnkoY2FyZENvZGVGaWVsZCk7XG4gICAgICAgIGNhcmRDb2RlRmllbGQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoY2FyZENvZGUsIGNhcmRDb2RlRmllbGQpO1xuXG4gICAgICAgIGdhdGVXYXlCb3guc3R5bGUuZGlzcGxheSA9IG9sZERpc3BsYXlTdHlsZTtcblxuICAgICAgICBjb25zdCBmb3JtV3JhcHBlciA9ICcucGF5bWVudF9ib3ggcGF5bWVudF9tZXRob2RfcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5JztcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5kZWZhdWx0Q29uZmlnLmVuZm9yY2VfdmF1bHRcbiAgICAgICAgICAgICYmIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZm9ybVdyYXBwZXIgKyAnIC5wcGNwLWNyZWRpdC1jYXJkLXZhdWx0JylcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGZvcm1XcmFwcGVyICsgJyAucHBjcC1jcmVkaXQtY2FyZC12YXVsdCcpLmNoZWNrZWQgPSB0cnVlO1xuICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihmb3JtV3JhcHBlciArICcgLnBwY3AtY3JlZGl0LWNhcmQtdmF1bHQnKS5zZXRBdHRyaWJ1dGUoJ2Rpc2FibGVkJywgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcGF5cGFsLkhvc3RlZEZpZWxkcy5yZW5kZXIoe1xuICAgICAgICAgICAgY3JlYXRlT3JkZXI6IGNvbnRleHRDb25maWcuY3JlYXRlT3JkZXIsXG4gICAgICAgICAgICBzdHlsZXM6IHtcbiAgICAgICAgICAgICAgICAnaW5wdXQnOiBzdHlsZXNcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmaWVsZHM6IHtcbiAgICAgICAgICAgICAgICBudW1iZXI6IHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0b3I6ICcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtbnVtYmVyJyxcbiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI6IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5jcmVkaXRfY2FyZF9udW1iZXIsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBjdnY6IHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0b3I6ICcjcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5LWNhcmQtY3ZjJyxcbiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI6IHRoaXMuZGVmYXVsdENvbmZpZy5ob3N0ZWRfZmllbGRzLmxhYmVscy5jdnYsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBleHBpcmF0aW9uRGF0ZToge1xuICAgICAgICAgICAgICAgICAgICBzZWxlY3RvcjogJyNwcGNwLWNyZWRpdC1jYXJkLWdhdGV3YXktY2FyZC1leHBpcnknLFxuICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcjogdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLm1tX3l5LFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihob3N0ZWRGaWVsZHMgPT4ge1xuICAgICAgICAgICAgZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoXCJob3N0ZWRfZmllbGRzX2xvYWRlZFwiKSk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSA9IGhvc3RlZEZpZWxkcztcblxuICAgICAgICAgICAgaG9zdGVkRmllbGRzLm9uKCdpbnB1dFN1Ym1pdFJlcXVlc3QnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fc3VibWl0KGNvbnRleHRDb25maWcpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBob3N0ZWRGaWVsZHMub24oJ2NhcmRUeXBlQ2hhbmdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCAhIGV2ZW50LmNhcmRzLmxlbmd0aCApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYXJkVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCB2YWxpZENhcmRzID0gdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMudmFsaWRfY2FyZHM7XG4gICAgICAgICAgICAgICAgdGhpcy5jYXJkVmFsaWQgPSB2YWxpZENhcmRzLmluZGV4T2YoZXZlbnQuY2FyZHNbMF0udHlwZSkgIT09IC0xO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIGhvc3RlZEZpZWxkcy5vbigndmFsaWRpdHlDaGFuZ2UnLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBmb3JtVmFsaWQgPSBPYmplY3Qua2V5cyhldmVudC5maWVsZHMpLmV2ZXJ5KGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGV2ZW50LmZpZWxkc1trZXldLmlzVmFsaWQ7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICB0aGlzLmZvcm1WYWxpZCA9IGZvcm1WYWxpZDtcblxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHNob3coYnV0dG9uU2VsZWN0b3IpO1xuXG4gICAgICAgICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih3cmFwcGVyKS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcHBjcC1zdWJzY3JpYmVkJykgIT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGJ1dHRvblNlbGVjdG9yKS5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICAgICAgICAnY2xpY2snLFxuICAgICAgICAgICAgICAgICAgICBldmVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fc3VibWl0KGNvbnRleHRDb25maWcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iod3JhcHBlcikuc2V0QXR0cmlidXRlKCdkYXRhLXBwY3Atc3Vic2NyaWJlZCcsIHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjcGF5bWVudF9tZXRob2RfcHBjcC1jcmVkaXQtY2FyZC1nYXRld2F5JykuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgICAgICdjbGljaycsXG4gICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignbGFiZWxbZm9yPXBwY3AtY3JlZGl0LWNhcmQtZ2F0ZXdheS1jYXJkLW51bWJlcl0nKS5jbGljaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICApXG4gICAgfVxuXG4gICAgZGlzYWJsZUZpZWxkcygpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zZXRBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnbnVtYmVyJyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zZXRBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnY3Z2JyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5zZXRBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnZXhwaXJhdGlvbkRhdGUnLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGVuYWJsZUZpZWxkcygpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5yZW1vdmVBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnbnVtYmVyJyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5yZW1vdmVBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnY3Z2JyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6ICdkaXNhYmxlZCdcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZS5yZW1vdmVBdHRyaWJ1dGUoe1xuICAgICAgICAgICAgICAgIGZpZWxkOiAnZXhwaXJhdGlvbkRhdGUnLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogJ2Rpc2FibGVkJ1xuICAgICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9zdWJtaXQoY29udGV4dENvbmZpZykge1xuICAgICAgICB0aGlzLnNwaW5uZXIuYmxvY2soKTtcbiAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIuY2xlYXIoKTtcblxuICAgICAgICBpZiAodGhpcy5mb3JtVmFsaWQgJiYgdGhpcy5jYXJkVmFsaWQpIHtcbiAgICAgICAgICAgIGNvbnN0IHNhdmVfY2FyZCA9IHRoaXMuZGVmYXVsdENvbmZpZy5jYW5fc2F2ZV92YXVsdF90b2tlbiA/IHRydWUgOiBmYWxzZTtcbiAgICAgICAgICAgIGxldCB2YXVsdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykgP1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwcGNwLWNyZWRpdC1jYXJkLXZhdWx0JykuY2hlY2tlZCA6IHNhdmVfY2FyZDtcbiAgICAgICAgICAgIGlmICh0aGlzLmRlZmF1bHRDb25maWcuZW5mb3JjZV92YXVsdCkge1xuICAgICAgICAgICAgICAgIHZhdWx0ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGNvbnRpbmdlbmN5ID0gdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMuY29udGluZ2VuY3k7XG4gICAgICAgICAgICBjb25zdCBob3N0ZWRGaWVsZHNEYXRhID0ge1xuICAgICAgICAgICAgICAgIHZhdWx0OiB2YXVsdFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChjb250aW5nZW5jeSAhPT0gJ05PXzNEX1NFQ1VSRScpIHtcbiAgICAgICAgICAgICAgICBob3N0ZWRGaWVsZHNEYXRhLmNvbnRpbmdlbmNpZXMgPSBbY29udGluZ2VuY3ldO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5kZWZhdWx0Q29uZmlnLnBheWVyKSB7XG4gICAgICAgICAgICAgICAgaG9zdGVkRmllbGRzRGF0YS5jYXJkaG9sZGVyTmFtZSA9IHRoaXMuZGVmYXVsdENvbmZpZy5wYXllci5uYW1lLmdpdmVuX25hbWUgKyAnICcgKyB0aGlzLmRlZmF1bHRDb25maWcucGF5ZXIubmFtZS5zdXJuYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFob3N0ZWRGaWVsZHNEYXRhLmNhcmRob2xkZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlyc3ROYW1lID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JpbGxpbmdfZmlyc3RfbmFtZScpID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JpbGxpbmdfZmlyc3RfbmFtZScpLnZhbHVlIDogJyc7XG4gICAgICAgICAgICAgICAgY29uc3QgbGFzdE5hbWUgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYmlsbGluZ19sYXN0X25hbWUnKSA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdiaWxsaW5nX2xhc3RfbmFtZScpLnZhbHVlIDogJyc7XG5cbiAgICAgICAgICAgICAgICBob3N0ZWRGaWVsZHNEYXRhLmNhcmRob2xkZXJOYW1lID0gZmlyc3ROYW1lICsgJyAnICsgbGFzdE5hbWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY3VycmVudEhvc3RlZEZpZWxkc0luc3RhbmNlLnN1Ym1pdChob3N0ZWRGaWVsZHNEYXRhKS50aGVuKChwYXlsb2FkKSA9PiB7XG4gICAgICAgICAgICAgICAgcGF5bG9hZC5vcmRlcklEID0gcGF5bG9hZC5vcmRlcklkO1xuICAgICAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHRDb25maWcub25BcHByb3ZlKHBheWxvYWQpO1xuICAgICAgICAgICAgfSkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGVyLmNsZWFyKCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoZXJyLmRldGFpbHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsZXIubWVzc2FnZShlcnIuZGV0YWlscy5tYXAoZCA9PiBgJHtkLmlzc3VlfSAke2QuZGVzY3JpcHRpb259YCkuam9pbignPGJyLz4nKSwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgY29uc3QgbWVzc2FnZSA9ICEgdGhpcy5jYXJkVmFsaWQgPyB0aGlzLmRlZmF1bHRDb25maWcuaG9zdGVkX2ZpZWxkcy5sYWJlbHMuY2FyZF9ub3Rfc3VwcG9ydGVkIDogdGhpcy5kZWZhdWx0Q29uZmlnLmhvc3RlZF9maWVsZHMubGFiZWxzLmZpZWxkc19ub3RfdmFsaWQ7XG4gICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5tZXNzYWdlKG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQ3JlZGl0Q2FyZFJlbmRlcmVyO1xuIiwiY29uc3Qgc3RvcmFnZUtleSA9ICdwcGNwLWRhdGEtY2xpZW50LWlkJztcblxuY29uc3QgdmFsaWRhdGVUb2tlbiA9ICh0b2tlbiwgdXNlcikgPT4ge1xuICAgIGlmICghIHRva2VuKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHRva2VuLnVzZXIgIT09IHVzZXIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBjdXJyZW50VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGlzRXhwaXJlZCA9IGN1cnJlbnRUaW1lID49IHRva2VuLmV4cGlyYXRpb24gKiAxMDAwO1xuICAgIHJldHVybiAhIGlzRXhwaXJlZDtcbn1cblxuY29uc3Qgc3RvcmVkVG9rZW5Gb3JVc2VyID0gKHVzZXIpID0+IHtcbiAgICBjb25zdCB0b2tlbiA9IEpTT04ucGFyc2Uoc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShzdG9yYWdlS2V5KSk7XG4gICAgaWYgKHZhbGlkYXRlVG9rZW4odG9rZW4sIHVzZXIpKSB7XG4gICAgICAgIHJldHVybiB0b2tlbi50b2tlbjtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5cbmNvbnN0IHN0b3JlVG9rZW4gPSAodG9rZW4pID0+IHtcbiAgICBzZXNzaW9uU3RvcmFnZS5zZXRJdGVtKHN0b3JhZ2VLZXksIEpTT04uc3RyaW5naWZ5KHRva2VuKSk7XG59XG5cbmNvbnN0IGRhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXIgPSAoc2NyaXB0LCBjb25maWcpID0+IHtcbiAgICBmZXRjaChjb25maWcuZW5kcG9pbnQsIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIG5vbmNlOiBjb25maWcubm9uY2VcbiAgICAgICAgfSlcbiAgICB9KS50aGVuKChyZXMpPT57XG4gICAgICAgIHJldHVybiByZXMuanNvbigpO1xuICAgIH0pLnRoZW4oKGRhdGEpPT57XG4gICAgICAgIGNvbnN0IGlzVmFsaWQgPSB2YWxpZGF0ZVRva2VuKGRhdGEsIGNvbmZpZy51c2VyKTtcbiAgICAgICAgaWYgKCFpc1ZhbGlkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3RvcmVUb2tlbihkYXRhKTtcbiAgICAgICAgc2NyaXB0LnNldEF0dHJpYnV0ZSgnZGF0YS1jbGllbnQtdG9rZW4nLCBkYXRhLnRva2VuKTtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmQoc2NyaXB0KTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgZGF0YUNsaWVudElkQXR0cmlidXRlSGFuZGxlcjtcbiIsImNsYXNzIE1lc3NhZ2VSZW5kZXJlciB7XG5cbiAgICBjb25zdHJ1Y3Rvcihjb25maWcpIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBpZiAoISB0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBwYXlwYWwuTWVzc2FnZXMoe1xuICAgICAgICAgICAgYW1vdW50OiB0aGlzLmNvbmZpZy5hbW91bnQsXG4gICAgICAgICAgICBwbGFjZW1lbnQ6IHRoaXMuY29uZmlnLnBsYWNlbWVudCxcbiAgICAgICAgICAgIHN0eWxlOiB0aGlzLmNvbmZpZy5zdHlsZVxuICAgICAgICB9KS5yZW5kZXIodGhpcy5jb25maWcud3JhcHBlcik7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NhcnRfdG90YWxzJywgKCkgPT4ge1xuICAgICAgICAgICAgcGF5cGFsLk1lc3NhZ2VzKHtcbiAgICAgICAgICAgICAgICBhbW91bnQ6IHRoaXMuY29uZmlnLmFtb3VudCxcbiAgICAgICAgICAgICAgICBwbGFjZW1lbnQ6IHRoaXMuY29uZmlnLnBsYWNlbWVudCxcbiAgICAgICAgICAgICAgICBzdHlsZTogdGhpcy5jb25maWcuc3R5bGVcbiAgICAgICAgICAgIH0pLnJlbmRlcih0aGlzLmNvbmZpZy53cmFwcGVyKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmVuZGVyV2l0aEFtb3VudChhbW91bnQpIHtcblxuICAgICAgICBpZiAoISB0aGlzLnNob3VsZFJlbmRlcigpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuZXdXcmFwcGVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIG5ld1dyYXBwZXIuc2V0QXR0cmlidXRlKCdpZCcsIHRoaXMuY29uZmlnLndyYXBwZXIucmVwbGFjZSgnIycsICcnKSk7XG5cbiAgICAgICAgY29uc3Qgc2libGluZyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5jb25maWcud3JhcHBlcikubmV4dFNpYmxpbmc7XG4gICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5jb25maWcud3JhcHBlcikucGFyZW50RWxlbWVudC5yZW1vdmVDaGlsZChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpKTtcbiAgICAgICAgc2libGluZy5wYXJlbnRFbGVtZW50Lmluc2VydEJlZm9yZShuZXdXcmFwcGVyLCBzaWJsaW5nKTtcbiAgICAgICAgcGF5cGFsLk1lc3NhZ2VzKHtcbiAgICAgICAgICAgIGFtb3VudCxcbiAgICAgICAgICAgIHBsYWNlbWVudDogdGhpcy5jb25maWcucGxhY2VtZW50LFxuICAgICAgICAgICAgc3R5bGU6IHRoaXMuY29uZmlnLnN0eWxlXG4gICAgICAgIH0pLnJlbmRlcih0aGlzLmNvbmZpZy53cmFwcGVyKTtcbiAgICB9XG5cbiAgICBzaG91bGRSZW5kZXIoKSB7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBwYXlwYWwuTWVzc2FnZXMgPT09ICd1bmRlZmluZWQnIHx8IHR5cGVvZiB0aGlzLmNvbmZpZy53cmFwcGVyID09PSAndW5kZWZpbmVkJyApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoISBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuY29uZmlnLndyYXBwZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaGlkZU1lc3NhZ2VzKCkge1xuICAgICAgICBjb25zdCBkb21FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcih0aGlzLmNvbmZpZy53cmFwcGVyKTtcbiAgICAgICAgaWYgKCEgZG9tRWxlbWVudCApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBkb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IE1lc3NhZ2VSZW5kZXJlcjtcbiIsImNsYXNzIFNwaW5uZXIge1xuXG4gICAgY29uc3RydWN0b3IodGFyZ2V0ID0gJ2Zvcm0ud29vY29tbWVyY2UtY2hlY2tvdXQnKSB7XG4gICAgICAgIHRoaXMudGFyZ2V0ID0gdGFyZ2V0O1xuICAgIH1cblxuICAgIHNldFRhcmdldCh0YXJnZXQpIHtcbiAgICAgICAgdGhpcy50YXJnZXQgPSB0YXJnZXQ7XG4gICAgfVxuXG4gICAgYmxvY2soKSB7XG5cbiAgICAgICAgalF1ZXJ5KCB0aGlzLnRhcmdldCApLmJsb2NrKHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBvdmVybGF5Q1NTOiB7XG4gICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJyNmZmYnLFxuICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAuNlxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICB1bmJsb2NrKCkge1xuXG4gICAgICAgIGpRdWVyeSggdGhpcy50YXJnZXQgKS51bmJsb2NrKCk7XG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBTcGlubmVyO1xuIiwiaW1wb3J0IHtQYXltZW50TWV0aG9kc30gZnJvbSBcIi4uL0hlbHBlci9DaGVja291dE1ldGhvZFN0YXRlXCI7XG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gXCIuLi9FcnJvckhhbmRsZXJcIjtcblxuY2xhc3MgRnJlZVRyaWFsSGFuZGxlciB7XG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgc3Bpbm5lcixcbiAgICAgICAgZXJyb3JIYW5kbGVyXG4gICAgKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLnNwaW5uZXIgPSBzcGlubmVyO1xuICAgICAgICB0aGlzLmVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlcjtcbiAgICB9XG5cbiAgICBoYW5kbGUoKVxuICAgIHtcbiAgICAgICAgdGhpcy5zcGlubmVyLmJsb2NrKCk7XG5cbiAgICAgICAgZmV0Y2godGhpcy5jb25maWcuYWpheC52YXVsdF9wYXlwYWwuZW5kcG9pbnQsIHtcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIG5vbmNlOiB0aGlzLmNvbmZpZy5hamF4LnZhdWx0X3BheXBhbC5ub25jZSxcbiAgICAgICAgICAgICAgICByZXR1cm5fdXJsOiBsb2NhdGlvbi5ocmVmXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgfSkudGhlbihyZXMgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5qc29uKCk7XG4gICAgICAgIH0pLnRoZW4oZGF0YSA9PiB7XG4gICAgICAgICAgICBpZiAoIWRhdGEuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIHRoaXMuc3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihkYXRhKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5tZXNzYWdlKGRhdGEuZGF0YS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcihkYXRhLmRhdGEubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxvY2F0aW9uLmhyZWYgPSBkYXRhLmRhdGEuYXBwcm92ZV9saW5rO1xuICAgICAgICB9KS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICB0aGlzLnNwaW5uZXIudW5ibG9jaygpO1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxlci5nZW5lcmljRXJyb3IoKTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgRnJlZVRyaWFsSGFuZGxlcjtcbiIsImltcG9ydCBNaW5pQ2FydEJvb3RzdGFwIGZyb20gJy4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL01pbmlDYXJ0Qm9vdHN0YXAnO1xuaW1wb3J0IFNpbmdsZVByb2R1Y3RCb290c3RhcCBmcm9tICcuL21vZHVsZXMvQ29udGV4dEJvb3RzdHJhcC9TaW5nbGVQcm9kdWN0Qm9vdHN0YXAnO1xuaW1wb3J0IENhcnRCb290c3RyYXAgZnJvbSAnLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvQ2FydEJvb3RzdGFwJztcbmltcG9ydCBDaGVja291dEJvb3RzdGFwIGZyb20gJy4vbW9kdWxlcy9Db250ZXh0Qm9vdHN0cmFwL0NoZWNrb3V0Qm9vdHN0YXAnO1xuaW1wb3J0IFBheU5vd0Jvb3RzdHJhcCBmcm9tIFwiLi9tb2R1bGVzL0NvbnRleHRCb290c3RyYXAvUGF5Tm93Qm9vdHN0cmFwXCI7XG5pbXBvcnQgUmVuZGVyZXIgZnJvbSAnLi9tb2R1bGVzL1JlbmRlcmVyL1JlbmRlcmVyJztcbmltcG9ydCBFcnJvckhhbmRsZXIgZnJvbSAnLi9tb2R1bGVzL0Vycm9ySGFuZGxlcic7XG5pbXBvcnQgQ3JlZGl0Q2FyZFJlbmRlcmVyIGZyb20gXCIuL21vZHVsZXMvUmVuZGVyZXIvQ3JlZGl0Q2FyZFJlbmRlcmVyXCI7XG5pbXBvcnQgZGF0YUNsaWVudElkQXR0cmlidXRlSGFuZGxlciBmcm9tIFwiLi9tb2R1bGVzL0RhdGFDbGllbnRJZEF0dHJpYnV0ZUhhbmRsZXJcIjtcbmltcG9ydCBNZXNzYWdlUmVuZGVyZXIgZnJvbSBcIi4vbW9kdWxlcy9SZW5kZXJlci9NZXNzYWdlUmVuZGVyZXJcIjtcbmltcG9ydCBTcGlubmVyIGZyb20gXCIuL21vZHVsZXMvSGVscGVyL1NwaW5uZXJcIjtcbmltcG9ydCB7XG4gICAgZ2V0Q3VycmVudFBheW1lbnRNZXRob2QsXG4gICAgT1JERVJfQlVUVE9OX1NFTEVDVE9SLFxuICAgIFBheW1lbnRNZXRob2RzXG59IGZyb20gXCIuL21vZHVsZXMvSGVscGVyL0NoZWNrb3V0TWV0aG9kU3RhdGVcIjtcbmltcG9ydCB7aGlkZSwgc2V0VmlzaWJsZX0gZnJvbSBcIi4vbW9kdWxlcy9IZWxwZXIvSGlkaW5nXCI7XG5pbXBvcnQge2lzQ2hhbmdlUGF5bWVudFBhZ2V9IGZyb20gXCIuL21vZHVsZXMvSGVscGVyL1N1YnNjcmlwdGlvbnNcIjtcbmltcG9ydCBGcmVlVHJpYWxIYW5kbGVyIGZyb20gXCIuL21vZHVsZXMvQWN0aW9uSGFuZGxlci9GcmVlVHJpYWxIYW5kbGVyXCI7XG5cbmNvbnN0IGJ1dHRvbnNTcGlubmVyID0gbmV3IFNwaW5uZXIoJy5wcGMtYnV0dG9uLXdyYXBwZXInKTtcbmNvbnN0IGNhcmRzU3Bpbm5lciA9IG5ldyBTcGlubmVyKCcjcHBjcC1ob3N0ZWQtZmllbGRzJyk7XG5cbmNvbnN0IGJvb3RzdHJhcCA9ICgpID0+IHtcbiAgICBjb25zdCBlcnJvckhhbmRsZXIgPSBuZXcgRXJyb3JIYW5kbGVyKFBheVBhbENvbW1lcmNlR2F0ZXdheS5sYWJlbHMuZXJyb3IuZ2VuZXJpYyk7XG4gICAgY29uc3Qgc3Bpbm5lciA9IG5ldyBTcGlubmVyKCk7XG4gICAgY29uc3QgY3JlZGl0Q2FyZFJlbmRlcmVyID0gbmV3IENyZWRpdENhcmRSZW5kZXJlcihQYXlQYWxDb21tZXJjZUdhdGV3YXksIGVycm9ySGFuZGxlciwgc3Bpbm5lcik7XG5cbiAgICBjb25zdCBmcmVlVHJpYWxIYW5kbGVyID0gbmV3IEZyZWVUcmlhbEhhbmRsZXIoUGF5UGFsQ29tbWVyY2VHYXRld2F5LCBzcGlubmVyLCBlcnJvckhhbmRsZXIpO1xuXG4gICAgY29uc3Qgb25TbWFydEJ1dHRvbkNsaWNrID0gKGRhdGEsIGFjdGlvbnMpID0+IHtcbiAgICAgICAgd2luZG93LnBwY3BGdW5kaW5nU291cmNlID0gZGF0YS5mdW5kaW5nU291cmNlO1xuXG4gICAgICAgIGlmIChQYXlQYWxDb21tZXJjZUdhdGV3YXkuYmFzaWNfY2hlY2tvdXRfdmFsaWRhdGlvbl9lbmFibGVkKSB7XG4gICAgICAgICAgICAvLyBUT0RPOiBxdWljayBmaXggdG8gZ2V0IHRoZSBlcnJvciBhYm91dCBlbXB0eSBmb3JtIGJlZm9yZSBhdHRlbXB0aW5nIFBheVBhbCBvcmRlclxuICAgICAgICAgICAgLy8gaXQgc2hvdWxkIHNvbHZlICM1MTMgZm9yIG1vc3Qgb2YgdGhlIHVzZXJzLCBidXQgcHJvcGVyIHNvbHV0aW9uIHNob3VsZCBiZSBpbXBsZW1lbnRlZCBsYXRlci5cbiAgICAgICAgICAgIGNvbnN0IHJlcXVpcmVkRmllbGRzID0galF1ZXJ5KCdmb3JtLndvb2NvbW1lcmNlLWNoZWNrb3V0IC52YWxpZGF0ZS1yZXF1aXJlZDp2aXNpYmxlIDppbnB1dCcpO1xuICAgICAgICAgICAgcmVxdWlyZWRGaWVsZHMuZWFjaCgoaSwgaW5wdXQpID0+IHtcbiAgICAgICAgICAgICAgICBqUXVlcnkoaW5wdXQpLnRyaWdnZXIoJ3ZhbGlkYXRlJyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChqUXVlcnkoJ2Zvcm0ud29vY29tbWVyY2UtY2hlY2tvdXQgLnZhbGlkYXRlLXJlcXVpcmVkLndvb2NvbW1lcmNlLWludmFsaWQ6dmlzaWJsZScpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5jbGVhcigpO1xuICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlci5tZXNzYWdlKFBheVBhbENvbW1lcmNlR2F0ZXdheS5sYWJlbHMuZXJyb3IuanNfdmFsaWRhdGlvbik7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5yZWplY3QoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGZvcm0gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdmb3JtLndvb2NvbW1lcmNlLWNoZWNrb3V0Jyk7XG4gICAgICAgIGlmIChmb3JtKSB7XG4gICAgICAgICAgICBqUXVlcnkoJyNwcGNwLWZ1bmRpbmctc291cmNlLWZvcm0taW5wdXQnKS5yZW1vdmUoKTtcbiAgICAgICAgICAgIGZvcm0uaW5zZXJ0QWRqYWNlbnRIVE1MKFxuICAgICAgICAgICAgICAgICdiZWZvcmVlbmQnLFxuICAgICAgICAgICAgICAgIGA8aW5wdXQgdHlwZT1cImhpZGRlblwiIG5hbWU9XCJwcGNwLWZ1bmRpbmctc291cmNlXCIgdmFsdWU9XCIke2RhdGEuZnVuZGluZ1NvdXJjZX1cIiBpZD1cInBwY3AtZnVuZGluZy1zb3VyY2UtZm9ybS1pbnB1dFwiPmBcbiAgICAgICAgICAgIClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGlzRnJlZVRyaWFsID0gUGF5UGFsQ29tbWVyY2VHYXRld2F5LmlzX2ZyZWVfdHJpYWxfY2FydDtcbiAgICAgICAgaWYgKGlzRnJlZVRyaWFsICYmIGRhdGEuZnVuZGluZ1NvdXJjZSAhPT0gJ2NhcmQnKSB7XG4gICAgICAgICAgICBmcmVlVHJpYWxIYW5kbGVyLmhhbmRsZSgpO1xuICAgICAgICAgICAgcmV0dXJuIGFjdGlvbnMucmVqZWN0KCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IG9uU21hcnRCdXR0b25zSW5pdCA9ICgpID0+IHtcbiAgICAgICAgYnV0dG9uc1NwaW5uZXIudW5ibG9jaygpO1xuICAgIH07XG4gICAgY29uc3QgcmVuZGVyZXIgPSBuZXcgUmVuZGVyZXIoY3JlZGl0Q2FyZFJlbmRlcmVyLCBQYXlQYWxDb21tZXJjZUdhdGV3YXksIG9uU21hcnRCdXR0b25DbGljaywgb25TbWFydEJ1dHRvbnNJbml0KTtcbiAgICBjb25zdCBtZXNzYWdlUmVuZGVyZXIgPSBuZXcgTWVzc2FnZVJlbmRlcmVyKFBheVBhbENvbW1lcmNlR2F0ZXdheS5tZXNzYWdlcyk7XG4gICAgY29uc3QgY29udGV4dCA9IFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0O1xuICAgIGlmIChjb250ZXh0ID09PSAnbWluaS1jYXJ0JyB8fCBjb250ZXh0ID09PSAncHJvZHVjdCcpIHtcbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5taW5pX2NhcnRfYnV0dG9uc19lbmFibGVkID09PSAnMScpIHtcbiAgICAgICAgICAgIGNvbnN0IG1pbmlDYXJ0Qm9vdHN0cmFwID0gbmV3IE1pbmlDYXJ0Qm9vdHN0YXAoXG4gICAgICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgICAgIHJlbmRlcmVyXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBtaW5pQ2FydEJvb3RzdHJhcC5pbml0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29udGV4dCA9PT0gJ3Byb2R1Y3QnICYmIFBheVBhbENvbW1lcmNlR2F0ZXdheS5zaW5nbGVfcHJvZHVjdF9idXR0b25zX2VuYWJsZWQgPT09ICcxJykge1xuICAgICAgICBjb25zdCBzaW5nbGVQcm9kdWN0Qm9vdHN0cmFwID0gbmV3IFNpbmdsZVByb2R1Y3RCb290c3RhcChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheSxcbiAgICAgICAgICAgIHJlbmRlcmVyLFxuICAgICAgICAgICAgbWVzc2FnZVJlbmRlcmVyLFxuICAgICAgICApO1xuXG4gICAgICAgIHNpbmdsZVByb2R1Y3RCb290c3RyYXAuaW5pdCgpO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0ID09PSAnY2FydCcpIHtcbiAgICAgICAgY29uc3QgY2FydEJvb3RzdHJhcCA9IG5ldyBDYXJ0Qm9vdHN0cmFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICk7XG5cbiAgICAgICAgY2FydEJvb3RzdHJhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdjaGVja291dCcpIHtcbiAgICAgICAgY29uc3QgY2hlY2tvdXRCb290c3RhcCA9IG5ldyBDaGVja291dEJvb3RzdGFwKFxuICAgICAgICAgICAgUGF5UGFsQ29tbWVyY2VHYXRld2F5LFxuICAgICAgICAgICAgcmVuZGVyZXIsXG4gICAgICAgICAgICBtZXNzYWdlUmVuZGVyZXIsXG4gICAgICAgICAgICBzcGlubmVyXG4gICAgICAgICk7XG5cbiAgICAgICAgY2hlY2tvdXRCb290c3RhcC5pbml0KCk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnRleHQgPT09ICdwYXktbm93JyApIHtcbiAgICAgICAgY29uc3QgcGF5Tm93Qm9vdHN0cmFwID0gbmV3IFBheU5vd0Jvb3RzdHJhcChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheSxcbiAgICAgICAgICAgIHJlbmRlcmVyLFxuICAgICAgICAgICAgbWVzc2FnZVJlbmRlcmVyLFxuICAgICAgICAgICAgc3Bpbm5lclxuICAgICAgICApO1xuICAgICAgICBwYXlOb3dCb290c3RyYXAuaW5pdCgpO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0ICE9PSAnY2hlY2tvdXQnKSB7XG4gICAgICAgIG1lc3NhZ2VSZW5kZXJlci5yZW5kZXIoKTtcbiAgICB9XG59O1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAnRE9NQ29udGVudExvYWRlZCcsXG4gICAgKCkgPT4ge1xuICAgICAgICBpZiAoIXR5cGVvZiAoUGF5UGFsQ29tbWVyY2VHYXRld2F5KSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignUGF5UGFsIGJ1dHRvbiBjb3VsZCBub3QgYmUgY29uZmlndXJlZC4nKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIFBheVBhbENvbW1lcmNlR2F0ZXdheS5jb250ZXh0ICE9PSAnY2hlY2tvdXQnXG4gICAgICAgICAgICAmJiBQYXlQYWxDb21tZXJjZUdhdGV3YXkuZGF0YV9jbGllbnRfaWQudXNlciA9PT0gMFxuICAgICAgICAgICAgJiYgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkLmhhc19zdWJzY3JpcHRpb25zXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU29tZXRpbWVzIFBheVBhbCBzY3JpcHQgdGFrZXMgbG9uZyB0aW1lIHRvIGxvYWQsXG4gICAgICAgIC8vIHNvIHdlIGFkZGl0aW9uYWxseSBoaWRlIHRoZSBzdGFuZGFyZCBvcmRlciBidXR0b24gaGVyZSB0byBhdm9pZCBmYWlsZWQgb3JkZXJzLlxuICAgICAgICAvLyBOb3JtYWxseSBpdCBpcyBoaWRkZW4gbGF0ZXIgYWZ0ZXIgdGhlIHNjcmlwdCBsb2FkLlxuICAgICAgICBjb25zdCBoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5ID0gKCkgPT4ge1xuICAgICAgICAgICAgLy8gb25seSBpbiBjaGVja291dCBhbmQgcGF5IG5vdyBwYWdlLCBvdGhlcndpc2UgaXQgbWF5IGJyZWFrIHRoaW5ncyAoZS5nLiBwYXltZW50IHZpYSBwcm9kdWN0IHBhZ2UpLFxuICAgICAgICAgICAgLy8gYW5kIGFsc28gdGhlIGxvYWRpbmcgc3Bpbm5lciBtYXkgbG9vayB3ZWlyZCBvbiBvdGhlciBwYWdlc1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICFbJ2NoZWNrb3V0JywgJ3BheS1ub3cnXS5pbmNsdWRlcyhQYXlQYWxDb21tZXJjZUdhdGV3YXkuY29udGV4dClcbiAgICAgICAgICAgICAgICB8fCBpc0NoYW5nZVBheW1lbnRQYWdlKClcbiAgICAgICAgICAgICAgICB8fCAoUGF5UGFsQ29tbWVyY2VHYXRld2F5LmlzX2ZyZWVfdHJpYWxfY2FydCAmJiBQYXlQYWxDb21tZXJjZUdhdGV3YXkudmF1bHRlZF9wYXlwYWxfZW1haWwgIT09ICcnKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBjdXJyZW50UGF5bWVudE1ldGhvZCA9IGdldEN1cnJlbnRQYXltZW50TWV0aG9kKCk7XG4gICAgICAgICAgICBjb25zdCBpc1BheXBhbCA9IGN1cnJlbnRQYXltZW50TWV0aG9kID09PSBQYXltZW50TWV0aG9kcy5QQVlQQUw7XG4gICAgICAgICAgICBjb25zdCBpc0NhcmRzID0gY3VycmVudFBheW1lbnRNZXRob2QgPT09IFBheW1lbnRNZXRob2RzLkNBUkRTO1xuXG4gICAgICAgICAgICBzZXRWaXNpYmxlKE9SREVSX0JVVFRPTl9TRUxFQ1RPUiwgIWlzUGF5cGFsICYmICFpc0NhcmRzLCB0cnVlKTtcblxuICAgICAgICAgICAgaWYgKGlzUGF5cGFsKSB7XG4gICAgICAgICAgICAgICAgLy8gc3RvcHBlZCBhZnRlciB0aGUgZmlyc3QgcmVuZGVyaW5nIG9mIHRoZSBidXR0b25zLCBpbiBvbkluaXRcbiAgICAgICAgICAgICAgICBidXR0b25zU3Bpbm5lci5ibG9jaygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBidXR0b25zU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpc0NhcmRzKSB7XG4gICAgICAgICAgICAgICAgY2FyZHNTcGlubmVyLmJsb2NrKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhcmRzU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBqUXVlcnkoZG9jdW1lbnQpLm9uKCdob3N0ZWRfZmllbGRzX2xvYWRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIGNhcmRzU3Bpbm5lci51bmJsb2NrKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGxldCBib290c3RyYXBwZWQgPSBmYWxzZTtcblxuICAgICAgICBoaWRlT3JkZXJCdXR0b25JZlBwY3BHYXRld2F5KCk7XG5cbiAgICAgICAgalF1ZXJ5KGRvY3VtZW50LmJvZHkpLm9uKCd1cGRhdGVkX2NoZWNrb3V0IHBheW1lbnRfbWV0aG9kX3NlbGVjdGVkJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGJvb3RzdHJhcHBlZCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaGlkZU9yZGVyQnV0dG9uSWZQcGNwR2F0ZXdheSgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgICAgICAgc2NyaXB0LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGJvb3RzdHJhcHBlZCA9IHRydWU7XG5cbiAgICAgICAgICAgIGJvb3RzdHJhcCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgc2NyaXB0LnNldEF0dHJpYnV0ZSgnc3JjJywgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmJ1dHRvbi51cmwpO1xuICAgICAgICBPYmplY3QuZW50cmllcyhQYXlQYWxDb21tZXJjZUdhdGV3YXkuc2NyaXB0X2F0dHJpYnV0ZXMpLmZvckVhY2goXG4gICAgICAgICAgICAoa2V5VmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKGtleVZhbHVlWzBdLCBrZXlWYWx1ZVsxXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKFBheVBhbENvbW1lcmNlR2F0ZXdheS5kYXRhX2NsaWVudF9pZC5zZXRfYXR0cmlidXRlKSB7XG4gICAgICAgICAgICBkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyKHNjcmlwdCwgUGF5UGFsQ29tbWVyY2VHYXRld2F5LmRhdGFfY2xpZW50X2lkKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKHNjcmlwdCk7XG4gICAgfSxcbik7XG4iXSwibmFtZXMiOlsiRXJyb3JIYW5kbGVyIiwiY29uc3RydWN0b3IiLCJnZW5lcmljRXJyb3JUZXh0Iiwid3JhcHBlciIsImRvY3VtZW50IiwicXVlcnlTZWxlY3RvciIsIm1lc3NhZ2VzTGlzdCIsImdlbmVyaWNFcnJvciIsImNsYXNzTGlzdCIsImNvbnRhaW5zIiwiY2xlYXIiLCJtZXNzYWdlIiwiYXBwZW5kUHJlcGFyZWRFcnJvck1lc3NhZ2VFbGVtZW50IiwiZXJyb3JNZXNzYWdlRWxlbWVudCIsInByZXBhcmVNZXNzYWdlc0xpc3QiLCJyZXBsYWNlV2l0aCIsInRleHQiLCJwZXJzaXN0IiwiU3RyaW5nIiwibGVuZ3RoIiwiRXJyb3IiLCJhZGQiLCJyZW1vdmUiLCJtZXNzYWdlTm9kZSIsInByZXBhcmVNZXNzYWdlc0xpc3RJdGVtIiwiYXBwZW5kQ2hpbGQiLCJqUXVlcnkiLCJzY3JvbGxfdG9fbm90aWNlcyIsImNyZWF0ZUVsZW1lbnQiLCJzZXRBdHRyaWJ1dGUiLCJsaSIsImlubmVySFRNTCIsInNhbml0aXplIiwidGV4dGFyZWEiLCJ2YWx1ZSIsInJlcGxhY2UiLCJvbkFwcHJvdmUiLCJjb250ZXh0IiwiZXJyb3JIYW5kbGVyIiwiZGF0YSIsImFjdGlvbnMiLCJmZXRjaCIsImNvbmZpZyIsImFqYXgiLCJhcHByb3ZlX29yZGVyIiwiZW5kcG9pbnQiLCJtZXRob2QiLCJib2R5IiwiSlNPTiIsInN0cmluZ2lmeSIsIm5vbmNlIiwib3JkZXJfaWQiLCJvcmRlcklEIiwiZnVuZGluZ19zb3VyY2UiLCJ3aW5kb3ciLCJwcGNwRnVuZGluZ1NvdXJjZSIsInRoZW4iLCJyZXMiLCJqc29uIiwic3VjY2VzcyIsInJlc3RhcnQiLCJjYXRjaCIsImVyciIsImxvY2F0aW9uIiwiaHJlZiIsInJlZGlyZWN0IiwicGF5ZXJEYXRhIiwicGF5ZXIiLCJQYXlQYWxDb21tZXJjZUdhdGV3YXkiLCJwaG9uZSIsInBob25lX3R5cGUiLCJwaG9uZV9udW1iZXIiLCJuYXRpb25hbF9udW1iZXIiLCJlbWFpbF9hZGRyZXNzIiwibmFtZSIsInN1cm5hbWUiLCJnaXZlbl9uYW1lIiwiYWRkcmVzcyIsImNvdW50cnlfY29kZSIsImFkZHJlc3NfbGluZV8xIiwiYWRkcmVzc19saW5lXzIiLCJhZG1pbl9hcmVhXzEiLCJhZG1pbl9hcmVhXzIiLCJwb3N0YWxfY29kZSIsIlBheW1lbnRNZXRob2RzIiwiUEFZUEFMIiwiQ0FSRFMiLCJPUkRFUl9CVVRUT05fU0VMRUNUT1IiLCJnZXRDdXJyZW50UGF5bWVudE1ldGhvZCIsImVsIiwiaXNTYXZlZENhcmRTZWxlY3RlZCIsInNhdmVkQ2FyZExpc3QiLCJDYXJ0QWN0aW9uSGFuZGxlciIsImNvbmZpZ3VyYXRpb24iLCJjcmVhdGVPcmRlciIsImJuQ29kZSIsImJuX2NvZGVzIiwiY3JlYXRlX29yZGVyIiwicHVyY2hhc2VfdW5pdHMiLCJwYXltZW50X21ldGhvZCIsImJuX2NvZGUiLCJjb25zb2xlIiwiZXJyb3IiLCJpZCIsIm9uRXJyb3IiLCJNaW5pQ2FydEJvb3RzdGFwIiwiZ2F0ZXdheSIsInJlbmRlcmVyIiwiYWN0aW9uSGFuZGxlciIsImluaXQiLCJsYWJlbHMiLCJnZW5lcmljIiwicmVuZGVyIiwib24iLCJzaG91bGRSZW5kZXIiLCJidXR0b24iLCJtaW5pX2NhcnRfd3JhcHBlciIsImhvc3RlZF9maWVsZHMiLCJQcm9kdWN0IiwiVXBkYXRlQ2FydCIsInVwZGF0ZSIsIm9uUmVzb2x2ZSIsInByb2R1Y3RzIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJyZXN1bHQiLCJyZXNvbHZlZCIsIkJ1dHRvbnNUb2dnbGVMaXN0ZW5lciIsImVsZW1lbnQiLCJzaG93Q2FsbGJhY2siLCJoaWRlQ2FsbGJhY2siLCJvYnNlcnZlciIsImF0dHJpYnV0ZXMiLCJjYWxsYmFjayIsIk11dGF0aW9uT2JzZXJ2ZXIiLCJvYnNlcnZlIiwiZGlzY29ubmVjdCIsInF1YW50aXR5IiwidmFyaWF0aW9ucyIsIlNpbmdsZVByb2R1Y3RBY3Rpb25IYW5kbGVyIiwidXBkYXRlQ2FydCIsInNob3dCdXR0b25DYWxsYmFjayIsImhpZGVCdXR0b25DYWxsYmFjayIsImZvcm1FbGVtZW50IiwiaGFzVmFyaWF0aW9ucyIsImdldFByb2R1Y3RzIiwiaXNHcm91cGVkUHJvZHVjdCIsInF0eSIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJmb3JFYWNoIiwiZWxlbWVudE5hbWUiLCJnZXRBdHRyaWJ1dGUiLCJtYXRjaCIsInBhcnNlSW50IiwicHVzaCIsInByb21pc2UiLCJtYXAiLCJTaW5nbGVQcm9kdWN0Qm9vdHN0YXAiLCJtZXNzYWdlcyIsImhhbmRsZUNoYW5nZSIsImhpZGVCdXR0b25zIiwiaGlkZU1lc3NhZ2VzIiwiYWRkRXZlbnRMaXN0ZW5lciIsImJpbmQiLCJwcmljZUFtb3VudElzWmVybyIsInByaWNlVGV4dCIsImlubmVyVGV4dCIsImFtb3VudCIsInBhcnNlRmxvYXQiLCJjaGFuZ2VfY2FydCIsInNob3dCdXR0b25zIiwicmVuZGVyV2l0aEFtb3VudCIsIkNhcnRCb290c3RyYXAiLCJzcGlubmVyIiwiYmxvY2siLCJ1bmJsb2NrIiwiY29kZSIsImNsaWNrIiwiQ2hlY2tvdXRBY3Rpb25IYW5kbGVyIiwiZm9ybVNlbGVjdG9yIiwiZm9ybURhdGEiLCJGb3JtRGF0YSIsImZvcm1Kc29uT2JqIiwiT2JqZWN0IiwiZnJvbUVudHJpZXMiLCJjcmVhdGVhY2NvdW50IiwiaXMiLCJmb3JtIiwiZG9tUGFyc2VyIiwiRE9NUGFyc2VyIiwicGFyc2VGcm9tU3RyaW5nIiwiZGV0YWlscyIsImQiLCJpc3N1ZSIsImRlc2NyaXB0aW9uIiwiam9pbiIsImlucHV0IiwiY3VzdG9tX2lkIiwiYXBwZW5kIiwib25DYW5jZWwiLCJnZXRFbGVtZW50Iiwic2VsZWN0b3JPckVsZW1lbnQiLCJpc1Zpc2libGUiLCJvZmZzZXRXaWR0aCIsIm9mZnNldEhlaWdodCIsImdldENsaWVudFJlY3RzIiwic2V0VmlzaWJsZSIsInNob3ciLCJpbXBvcnRhbnQiLCJjdXJyZW50VmFsdWUiLCJzdHlsZSIsImdldFByb3BlcnR5VmFsdWUiLCJzZXRQcm9wZXJ0eSIsInJlbW92ZVByb3BlcnR5IiwiaGlkZSIsIkNoZWNrb3V0Qm9vdHN0YXAiLCJzdGFuZGFyZE9yZGVyQnV0dG9uU2VsZWN0b3IiLCJidXR0b25DaGFuZ2VPYnNlcnZlciIsInVwZGF0ZVVpIiwidmFsIiwiY2FuY2VsX3dyYXBwZXIiLCJjdXJyZW50UGF5bWVudE1ldGhvZCIsImlzUGF5cGFsIiwiaXNDYXJkIiwiaXNTYXZlZENhcmQiLCJpc05vdE91ckdhdGV3YXkiLCJpc0ZyZWVUcmlhbCIsImlzX2ZyZWVfdHJpYWxfY2FydCIsImhhc1ZhdWx0ZWRQYXlwYWwiLCJ2YXVsdGVkX3BheXBhbF9lbWFpbCIsImRpc2FibGVDcmVkaXRDYXJkRmllbGRzIiwiZW5hYmxlQ3JlZGl0Q2FyZEZpZWxkcyIsImFkZENsYXNzIiwiYXR0ciIsInJlbW92ZUNsYXNzIiwiaXNDaGFuZ2VQYXltZW50UGFnZSIsInVybFBhcmFtcyIsIlVSTFNlYXJjaFBhcmFtcyIsInNlYXJjaCIsImhhcyIsIlBheU5vd0Jvb3RzdHJhcCIsIlJlbmRlcmVyIiwiY3JlZGl0Q2FyZFJlbmRlcmVyIiwiZGVmYXVsdENvbmZpZyIsIm9uU21hcnRCdXR0b25DbGljayIsIm9uU21hcnRCdXR0b25zSW5pdCIsImhvc3RlZEZpZWxkc1dyYXBwZXIiLCJjb250ZXh0Q29uZmlnIiwicmVuZGVyQnV0dG9ucyIsImlzQWxyZWFkeVJlbmRlcmVkIiwicGF5cGFsIiwiQnV0dG9ucyIsIm1pbmlfY2FydF9zdHlsZSIsIm9uQ2xpY2siLCJvbkluaXQiLCJoYXNDaGlsZE5vZGVzIiwiZG9tRWxlbWVudCIsImRpc3BsYXkiLCJkaXNhYmxlRmllbGRzIiwiZW5hYmxlRmllbGRzIiwiZGNjSW5wdXRGYWN0b3J5Iiwib3JpZ2luYWwiLCJzdHlsZXMiLCJnZXRDb21wdXRlZFN0eWxlIiwibmV3RWxlbWVudCIsInZhbHVlcyIsInByb3AiLCJpc05hTiIsIkNyZWRpdENhcmRSZW5kZXJlciIsImNhcmRWYWxpZCIsImZvcm1WYWxpZCIsImN1cnJlbnRIb3N0ZWRGaWVsZHNJbnN0YW5jZSIsIkhvc3RlZEZpZWxkcyIsImlzRWxpZ2libGUiLCJ3cmFwcGVyRWxlbWVudCIsInBhcmVudE5vZGUiLCJyZW1vdmVDaGlsZCIsImJ1dHRvblNlbGVjdG9yIiwidGVhcmRvd24iLCJnYXRlV2F5Qm94Iiwib2xkRGlzcGxheVN0eWxlIiwiaGlkZURjY0dhdGV3YXkiLCJjYXJkTnVtYmVyRmllbGQiLCJzdHlsZXNSYXciLCJjYXJkTnVtYmVyIiwicmVwbGFjZUNoaWxkIiwiY2FyZEV4cGlyeUZpZWxkIiwiY2FyZEV4cGlyeSIsImNhcmRDb2RlRmllbGQiLCJjYXJkQ29kZSIsImZvcm1XcmFwcGVyIiwiZW5mb3JjZV92YXVsdCIsImNoZWNrZWQiLCJmaWVsZHMiLCJudW1iZXIiLCJzZWxlY3RvciIsInBsYWNlaG9sZGVyIiwiY3JlZGl0X2NhcmRfbnVtYmVyIiwiY3Z2IiwiZXhwaXJhdGlvbkRhdGUiLCJtbV95eSIsImhvc3RlZEZpZWxkcyIsImRpc3BhdGNoRXZlbnQiLCJDdXN0b21FdmVudCIsIl9zdWJtaXQiLCJldmVudCIsImNhcmRzIiwidmFsaWRDYXJkcyIsInZhbGlkX2NhcmRzIiwiaW5kZXhPZiIsInR5cGUiLCJrZXlzIiwiZXZlcnkiLCJrZXkiLCJpc1ZhbGlkIiwicHJldmVudERlZmF1bHQiLCJmaWVsZCIsImF0dHJpYnV0ZSIsInJlbW92ZUF0dHJpYnV0ZSIsInNhdmVfY2FyZCIsImNhbl9zYXZlX3ZhdWx0X3Rva2VuIiwidmF1bHQiLCJnZXRFbGVtZW50QnlJZCIsImNvbnRpbmdlbmN5IiwiaG9zdGVkRmllbGRzRGF0YSIsImNvbnRpbmdlbmNpZXMiLCJjYXJkaG9sZGVyTmFtZSIsImZpcnN0TmFtZSIsImxhc3ROYW1lIiwic3VibWl0IiwicGF5bG9hZCIsIm9yZGVySWQiLCJjYXJkX25vdF9zdXBwb3J0ZWQiLCJmaWVsZHNfbm90X3ZhbGlkIiwic3RvcmFnZUtleSIsInZhbGlkYXRlVG9rZW4iLCJ0b2tlbiIsInVzZXIiLCJjdXJyZW50VGltZSIsIkRhdGUiLCJnZXRUaW1lIiwiaXNFeHBpcmVkIiwiZXhwaXJhdGlvbiIsInN0b3JlZFRva2VuRm9yVXNlciIsInBhcnNlIiwic2Vzc2lvblN0b3JhZ2UiLCJnZXRJdGVtIiwic3RvcmVUb2tlbiIsInNldEl0ZW0iLCJkYXRhQ2xpZW50SWRBdHRyaWJ1dGVIYW5kbGVyIiwic2NyaXB0IiwiTWVzc2FnZVJlbmRlcmVyIiwiTWVzc2FnZXMiLCJwbGFjZW1lbnQiLCJuZXdXcmFwcGVyIiwic2libGluZyIsIm5leHRTaWJsaW5nIiwicGFyZW50RWxlbWVudCIsImluc2VydEJlZm9yZSIsIlNwaW5uZXIiLCJ0YXJnZXQiLCJzZXRUYXJnZXQiLCJvdmVybGF5Q1NTIiwiYmFja2dyb3VuZCIsIm9wYWNpdHkiLCJGcmVlVHJpYWxIYW5kbGVyIiwiaGFuZGxlIiwidmF1bHRfcGF5cGFsIiwicmV0dXJuX3VybCIsImFwcHJvdmVfbGluayIsImJ1dHRvbnNTcGlubmVyIiwiY2FyZHNTcGlubmVyIiwiYm9vdHN0cmFwIiwiZnJlZVRyaWFsSGFuZGxlciIsImZ1bmRpbmdTb3VyY2UiLCJiYXNpY19jaGVja291dF92YWxpZGF0aW9uX2VuYWJsZWQiLCJyZXF1aXJlZEZpZWxkcyIsImVhY2giLCJpIiwidHJpZ2dlciIsImpzX3ZhbGlkYXRpb24iLCJpbnNlcnRBZGphY2VudEhUTUwiLCJtZXNzYWdlUmVuZGVyZXIiLCJtaW5pX2NhcnRfYnV0dG9uc19lbmFibGVkIiwibWluaUNhcnRCb290c3RyYXAiLCJzaW5nbGVfcHJvZHVjdF9idXR0b25zX2VuYWJsZWQiLCJzaW5nbGVQcm9kdWN0Qm9vdHN0cmFwIiwiY2FydEJvb3RzdHJhcCIsImNoZWNrb3V0Qm9vdHN0YXAiLCJwYXlOb3dCb290c3RyYXAiLCJkYXRhX2NsaWVudF9pZCIsImhhc19zdWJzY3JpcHRpb25zIiwiaGlkZU9yZGVyQnV0dG9uSWZQcGNwR2F0ZXdheSIsImluY2x1ZGVzIiwiaXNDYXJkcyIsImJvb3RzdHJhcHBlZCIsInVybCIsImVudHJpZXMiLCJzY3JpcHRfYXR0cmlidXRlcyIsImtleVZhbHVlIiwic2V0X2F0dHJpYnV0ZSJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///536\n")}},__webpack_exports__={};__webpack_modules__[536]()})();
modules/ppcp-button/resources/js/button.js CHANGED
@@ -31,6 +31,21 @@ const bootstrap = () => {
31
  const onSmartButtonClick = (data, actions) => {
32
  window.ppcpFundingSource = data.fundingSource;
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  const form = document.querySelector('form.woocommerce-checkout');
35
  if (form) {
36
  jQuery('#ppcp-funding-source-form-input').remove();
31
  const onSmartButtonClick = (data, actions) => {
32
  window.ppcpFundingSource = data.fundingSource;
33
 
34
+ if (PayPalCommerceGateway.basic_checkout_validation_enabled) {
35
+ // TODO: quick fix to get the error about empty form before attempting PayPal order
36
+ // it should solve #513 for most of the users, but proper solution should be implemented later.
37
+ const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
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
+ }
47
+ }
48
+
49
  const form = document.querySelector('form.woocommerce-checkout');
50
  if (form) {
51
  jQuery('#ppcp-funding-source-form-input').remove();
modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js CHANGED
@@ -20,7 +20,9 @@ class CheckoutActionHandler {
20
  const errorHandler = this.errorHandler;
21
 
22
  const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
23
- const formValues = jQuery(formSelector).serialize();
 
 
24
 
25
  const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
26
 
@@ -34,7 +36,7 @@ class CheckoutActionHandler {
34
  order_id:this.config.order_id,
35
  payment_method: getCurrentPaymentMethod(),
36
  funding_source: window.ppcpFundingSource,
37
- form:formValues,
38
  createaccount: createaccount
39
  })
40
  }).then(function (res) {
@@ -59,7 +61,7 @@ class CheckoutActionHandler {
59
  }
60
  }
61
 
62
- return;
63
  }
64
  const input = document.createElement('input');
65
  input.setAttribute('type', 'hidden');
20
  const errorHandler = this.errorHandler;
21
 
22
  const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
23
+ const formData = new FormData(document.querySelector(formSelector));
24
+ // will not handle fields with multiple values (checkboxes, <select multiple>), but we do not care about this here
25
+ const formJsonObj = Object.fromEntries(formData);
26
 
27
  const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
28
 
36
  order_id:this.config.order_id,
37
  payment_method: getCurrentPaymentMethod(),
38
  funding_source: window.ppcpFundingSource,
39
+ form: formJsonObj,
40
  createaccount: createaccount
41
  })
42
  }).then(function (res) {
61
  }
62
  }
63
 
64
+ throw new Error(data.data.message);
65
  }
66
  const input = document.createElement('input');
67
  input.setAttribute('type', 'hidden');
modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js CHANGED
@@ -14,6 +14,7 @@ class SingleProductBootstap {
14
  if (!this.shouldRender()) {
15
  this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
16
  this.renderer.hideButtons(this.gateway.button.wrapper);
 
17
  return;
18
  }
19
 
@@ -26,6 +27,7 @@ class SingleProductBootstap {
26
 
27
  if (!this.shouldRender()) {
28
  this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
 
29
  return;
30
  }
31
 
@@ -51,6 +53,8 @@ class SingleProductBootstap {
51
  else if (document.querySelector('.product .woocommerce-Price-amount')) {
52
  priceText = document.querySelector('.product .woocommerce-Price-amount').innerText;
53
  }
 
 
54
  const amount = parseFloat(priceText.replace(/([^\d,\.\s]*)/g, ''));
55
  return amount === 0;
56
 
14
  if (!this.shouldRender()) {
15
  this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
16
  this.renderer.hideButtons(this.gateway.button.wrapper);
17
+ this.messages.hideMessages();
18
  return;
19
  }
20
 
27
 
28
  if (!this.shouldRender()) {
29
  this.renderer.hideButtons(this.gateway.hosted_fields.wrapper);
30
+ this.messages.hideMessages();
31
  return;
32
  }
33
 
53
  else if (document.querySelector('.product .woocommerce-Price-amount')) {
54
  priceText = document.querySelector('.product .woocommerce-Price-amount').innerText;
55
  }
56
+
57
+ priceText = priceText.replace(/,/g, '.');
58
  const amount = parseFloat(priceText.replace(/([^\d,\.\s]*)/g, ''));
59
  return amount === 0;
60
 
modules/ppcp-button/resources/js/modules/Renderer/MessageRenderer.js CHANGED
@@ -53,5 +53,14 @@ class MessageRenderer {
53
  }
54
  return true;
55
  }
 
 
 
 
 
 
 
 
 
56
  }
57
  export default MessageRenderer;
53
  }
54
  return true;
55
  }
56
+
57
+ hideMessages() {
58
+ const domElement = document.querySelector(this.config.wrapper);
59
+ if (! domElement ) {
60
+ return false;
61
+ }
62
+ domElement.style.display = 'none';
63
+ return true;
64
+ }
65
  }
66
  export default MessageRenderer;
modules/ppcp-button/services.php CHANGED
@@ -27,7 +27,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Environment;
27
  use WooCommerce\PayPalCommerce\Onboarding\State;
28
 
29
  return array(
30
- 'button.client_id' => static function ( ContainerInterface $container ): string {
31
 
32
  $settings = $container->get( 'wcgateway.settings' );
33
  $client_id = $settings->has( 'client_id' ) ? $settings->get( 'client_id' ) : '';
@@ -45,7 +45,7 @@ return array(
45
  return $env->current_environment_is( Environment::SANDBOX ) ?
46
  CONNECT_WOO_SANDBOX_CLIENT_ID : CONNECT_WOO_CLIENT_ID;
47
  },
48
- 'button.smart-button' => static function ( ContainerInterface $container ): SmartButtonInterface {
49
 
50
  $state = $container->get( 'onboarding.state' );
51
  /**
@@ -88,19 +88,20 @@ return array(
88
  $settings_status,
89
  $currency,
90
  $container->get( 'wcgateway.all-funding-sources' ),
 
91
  $container->get( 'woocommerce.logger.woocommerce' )
92
  );
93
  },
94
- 'button.url' => static function ( ContainerInterface $container ): string {
95
  return plugins_url(
96
  '/modules/ppcp-button/',
97
  dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
98
  );
99
  },
100
- 'button.request-data' => static function ( ContainerInterface $container ): RequestData {
101
  return new RequestData();
102
  },
103
- 'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint {
104
  if ( ! \WC()->cart ) {
105
  throw new RuntimeException( 'cant initialize endpoint at this moment' );
106
  }
@@ -112,7 +113,7 @@ return array(
112
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
113
  return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger );
114
  },
115
- 'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
116
  $request_data = $container->get( 'button.request-data' );
117
  $cart_repository = $container->get( 'api.repository.cart' );
118
  $purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
@@ -136,7 +137,7 @@ return array(
136
  $logger
137
  );
138
  },
139
- 'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler {
140
 
141
  $state = $container->get( 'onboarding.state' );
142
  $order_processor = $container->get( 'wcgateway.order-processor' );
@@ -144,13 +145,14 @@ return array(
144
  $prefix = $container->get( 'api.prefix' );
145
  return new EarlyOrderHandler( $state, $order_processor, $session_handler, $prefix );
146
  },
147
- 'button.endpoint.approve-order' => static function ( ContainerInterface $container ): ApproveOrderEndpoint {
148
  $request_data = $container->get( 'button.request-data' );
149
  $order_endpoint = $container->get( 'api.endpoint.order' );
150
  $session_handler = $container->get( 'session.handler' );
151
  $three_d_secure = $container->get( 'button.helper.three-d-secure' );
152
  $settings = $container->get( 'wcgateway.settings' );
153
  $dcc_applies = $container->get( 'api.helpers.dccapplies' );
 
154
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
155
  return new ApproveOrderEndpoint(
156
  $request_data,
@@ -159,10 +161,11 @@ return array(
159
  $three_d_secure,
160
  $settings,
161
  $dcc_applies,
 
162
  $logger
163
  );
164
  },
165
- 'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
166
  $request_data = $container->get( 'button.request-data' );
167
  $identity_token = $container->get( 'api.endpoint.identity-token' );
168
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
@@ -172,31 +175,39 @@ return array(
172
  $logger
173
  );
174
  },
175
- 'button.endpoint.vault-paypal' => static function( ContainerInterface $container ) : StartPayPalVaultingEndpoint {
176
  return new StartPayPalVaultingEndpoint(
177
  $container->get( 'button.request-data' ),
178
  $container->get( 'api.endpoint.payment-token' ),
179
  $container->get( 'woocommerce.logger.woocommerce' )
180
  );
181
  },
182
- 'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
183
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
184
  return new ThreeDSecure( $logger );
185
  },
186
- 'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply {
187
  return new MessagesApply(
188
  $container->get( 'api.shop.country' )
189
  );
190
  },
191
 
192
- 'button.is-logged-in' => static function ( ContainerInterface $container ): bool {
193
  return is_user_logged_in();
194
  },
195
- 'button.registration-required' => static function ( ContainerInterface $container ): bool {
196
  return WC()->checkout()->is_registration_required();
197
  },
198
- 'button.current-user-must-register' => static function ( ContainerInterface $container ): bool {
199
  return ! $container->get( 'button.is-logged-in' ) &&
200
  $container->get( 'button.registration-required' );
201
  },
 
 
 
 
 
 
 
 
202
  );
27
  use WooCommerce\PayPalCommerce\Onboarding\State;
28
 
29
  return array(
30
+ 'button.client_id' => static function ( ContainerInterface $container ): string {
31
 
32
  $settings = $container->get( 'wcgateway.settings' );
33
  $client_id = $settings->has( 'client_id' ) ? $settings->get( 'client_id' ) : '';
45
  return $env->current_environment_is( Environment::SANDBOX ) ?
46
  CONNECT_WOO_SANDBOX_CLIENT_ID : CONNECT_WOO_CLIENT_ID;
47
  },
48
+ 'button.smart-button' => static function ( ContainerInterface $container ): SmartButtonInterface {
49
 
50
  $state = $container->get( 'onboarding.state' );
51
  /**
88
  $settings_status,
89
  $currency,
90
  $container->get( 'wcgateway.all-funding-sources' ),
91
+ $container->get( 'button.basic-checkout-validation-enabled' ),
92
  $container->get( 'woocommerce.logger.woocommerce' )
93
  );
94
  },
95
+ 'button.url' => static function ( ContainerInterface $container ): string {
96
  return plugins_url(
97
  '/modules/ppcp-button/',
98
  dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
99
  );
100
  },
101
+ 'button.request-data' => static function ( ContainerInterface $container ): RequestData {
102
  return new RequestData();
103
  },
104
+ 'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint {
105
  if ( ! \WC()->cart ) {
106
  throw new RuntimeException( 'cant initialize endpoint at this moment' );
107
  }
113
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
114
  return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger );
115
  },
116
+ 'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
117
  $request_data = $container->get( 'button.request-data' );
118
  $cart_repository = $container->get( 'api.repository.cart' );
119
  $purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
137
  $logger
138
  );
139
  },
140
+ 'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler {
141
 
142
  $state = $container->get( 'onboarding.state' );
143
  $order_processor = $container->get( 'wcgateway.order-processor' );
145
  $prefix = $container->get( 'api.prefix' );
146
  return new EarlyOrderHandler( $state, $order_processor, $session_handler, $prefix );
147
  },
148
+ 'button.endpoint.approve-order' => static function ( ContainerInterface $container ): ApproveOrderEndpoint {
149
  $request_data = $container->get( 'button.request-data' );
150
  $order_endpoint = $container->get( 'api.endpoint.order' );
151
  $session_handler = $container->get( 'session.handler' );
152
  $three_d_secure = $container->get( 'button.helper.three-d-secure' );
153
  $settings = $container->get( 'wcgateway.settings' );
154
  $dcc_applies = $container->get( 'api.helpers.dccapplies' );
155
+ $order_helper = $container->get( 'api.order-helper' );
156
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
157
  return new ApproveOrderEndpoint(
158
  $request_data,
161
  $three_d_secure,
162
  $settings,
163
  $dcc_applies,
164
+ $order_helper,
165
  $logger
166
  );
167
  },
168
+ 'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
169
  $request_data = $container->get( 'button.request-data' );
170
  $identity_token = $container->get( 'api.endpoint.identity-token' );
171
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
175
  $logger
176
  );
177
  },
178
+ 'button.endpoint.vault-paypal' => static function( ContainerInterface $container ) : StartPayPalVaultingEndpoint {
179
  return new StartPayPalVaultingEndpoint(
180
  $container->get( 'button.request-data' ),
181
  $container->get( 'api.endpoint.payment-token' ),
182
  $container->get( 'woocommerce.logger.woocommerce' )
183
  );
184
  },
185
+ 'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
186
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
187
  return new ThreeDSecure( $logger );
188
  },
189
+ 'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply {
190
  return new MessagesApply(
191
  $container->get( 'api.shop.country' )
192
  );
193
  },
194
 
195
+ 'button.is-logged-in' => static function ( ContainerInterface $container ): bool {
196
  return is_user_logged_in();
197
  },
198
+ 'button.registration-required' => static function ( ContainerInterface $container ): bool {
199
  return WC()->checkout()->is_registration_required();
200
  },
201
+ 'button.current-user-must-register' => static function ( ContainerInterface $container ): bool {
202
  return ! $container->get( 'button.is-logged-in' ) &&
203
  $container->get( 'button.registration-required' );
204
  },
205
+
206
+ 'button.basic-checkout-validation-enabled' => static function ( ContainerInterface $container ): bool {
207
+ /**
208
+ * The filter allowing to disable the basic client-side validation of the checkout form
209
+ * when the PayPal button is clicked.
210
+ */
211
+ return (bool) apply_filters( 'woocommerce_paypal_payments_basic_checkout_validation_enabled', true );
212
+ },
213
  );
modules/ppcp-button/src/Assets/SmartButton.php CHANGED
@@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Button\Assets;
12
  use Exception;
13
  use Psr\Log\LoggerInterface;
14
  use WC_Product;
 
15
  use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
16
  use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
17
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
@@ -143,6 +144,13 @@ class SmartButton implements SmartButtonInterface {
143
  */
144
  private $all_funding_sources;
145
 
 
 
 
 
 
 
 
146
  /**
147
  * The logger.
148
  *
@@ -175,6 +183,7 @@ class SmartButton implements SmartButtonInterface {
175
  * @param SettingsStatus $settings_status The Settings status helper.
176
  * @param string $currency 3-letter currency code of the shop.
177
  * @param array $all_funding_sources All existing funding sources.
 
178
  * @param LoggerInterface $logger The logger.
179
  */
180
  public function __construct(
@@ -193,25 +202,27 @@ class SmartButton implements SmartButtonInterface {
193
  SettingsStatus $settings_status,
194
  string $currency,
195
  array $all_funding_sources,
 
196
  LoggerInterface $logger
197
  ) {
198
 
199
- $this->module_url = $module_url;
200
- $this->version = $version;
201
- $this->session_handler = $session_handler;
202
- $this->settings = $settings;
203
- $this->payer_factory = $payer_factory;
204
- $this->client_id = $client_id;
205
- $this->request_data = $request_data;
206
- $this->dcc_applies = $dcc_applies;
207
- $this->subscription_helper = $subscription_helper;
208
- $this->messages_apply = $messages_apply;
209
- $this->environment = $environment;
210
- $this->payment_token_repository = $payment_token_repository;
211
- $this->settings_status = $settings_status;
212
- $this->currency = $currency;
213
- $this->all_funding_sources = $all_funding_sources;
214
- $this->logger = $logger;
 
215
  }
216
 
217
  /**
@@ -233,7 +244,6 @@ class SmartButton implements SmartButtonInterface {
233
  if (
234
  $this->settings->has( 'dcc_enabled' )
235
  && $this->settings->get( 'dcc_enabled' )
236
- && ! $this->session_handler->order()
237
  ) {
238
  add_action(
239
  $this->checkout_dcc_button_renderer_hook(),
@@ -680,8 +690,12 @@ class SmartButton implements SmartButtonInterface {
680
  return;
681
  }
682
 
683
- // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
 
 
 
684
  $label = 'checkout' === $this->context() ? apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ) : __( 'Pay for order', 'woocommerce' );
 
685
 
686
  printf(
687
  '<div id="%1$s" style="display:none;">
@@ -761,17 +775,17 @@ class SmartButton implements SmartButtonInterface {
761
 
762
  $this->request_data->enqueue_nonce_fix();
763
  $localize = array(
764
- 'script_attributes' => $this->attributes(),
765
- 'data_client_id' => array(
766
  'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(),
767
  'endpoint' => \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ),
768
  'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ),
769
  'user' => get_current_user_id(),
770
  'has_subscriptions' => $this->has_subscriptions(),
771
  ),
772
- 'redirect' => wc_get_checkout_url(),
773
- 'context' => $this->context(),
774
- 'ajax' => array(
775
  'change_cart' => array(
776
  'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ),
777
  'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ),
@@ -789,13 +803,13 @@ class SmartButton implements SmartButtonInterface {
789
  'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ),
790
  ),
791
  ),
792
- 'enforce_vault' => $this->has_subscriptions(),
793
- 'can_save_vault_token' => $this->can_save_vault_token(),
794
- 'is_free_trial_cart' => $is_free_trial_cart,
795
- 'vaulted_paypal_email' => ( is_checkout() && $is_free_trial_cart ) ? $this->get_vaulted_paypal_email() : '',
796
- 'bn_codes' => $this->bn_codes(),
797
- 'payer' => $this->payerData(),
798
- 'button' => array(
799
  'wrapper' => '#ppc-button',
800
  'mini_cart_wrapper' => '#ppc-button-minicart',
801
  'cancel_wrapper' => '#ppcp-cancel',
@@ -816,7 +830,7 @@ class SmartButton implements SmartButtonInterface {
816
  'tagline' => $this->style_for_context( 'tagline', $this->context() ),
817
  ),
818
  ),
819
- 'hosted_fields' => array(
820
  'wrapper' => '#ppcp-hosted-fields',
821
  'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
822
  'labels' => array(
@@ -836,18 +850,23 @@ class SmartButton implements SmartButtonInterface {
836
  'valid_cards' => $this->dcc_applies->valid_cards(),
837
  'contingency' => $this->get_3ds_contingency(),
838
  ),
839
- 'messages' => $this->message_values(),
840
- 'labels' => array(
841
  'error' => array(
842
- 'generic' => __(
843
  'Something went wrong. Please try again or choose another payment source.',
844
  'woocommerce-paypal-payments'
845
  ),
 
 
 
 
846
  ),
847
  ),
848
- 'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
849
- 'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ),
850
- 'mini_cart_buttons_enabled' => $this->settings->has( 'button_mini-cart_enabled' ) && $this->settings->get( 'button_mini-cart_enabled' ),
 
851
  );
852
 
853
  if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
@@ -922,9 +941,9 @@ class SmartButton implements SmartButtonInterface {
922
  }
923
 
924
  if ( $this->is_free_trial_cart() ) {
925
- $all_sources = $this->all_funding_sources;
926
  if ( $is_dcc_enabled ) {
927
- $all_sources = array_keys( array_diff_key( $all_sources, array( 'card' => '' ) ) );
928
  }
929
  $disable_funding = $all_sources;
930
  }
@@ -1068,7 +1087,7 @@ class SmartButton implements SmartButtonInterface {
1068
  if ( is_cart() ) {
1069
  $context = 'cart';
1070
  }
1071
- if ( is_checkout() && ! $this->session_handler->order() ) {
1072
  $context = 'checkout';
1073
  }
1074
  if ( is_checkout_pay_page() ) {
@@ -1077,6 +1096,23 @@ class SmartButton implements SmartButtonInterface {
1077
  return $context;
1078
  }
1079
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
  /**
1081
  * Whether DCC is enabled or not.
1082
  *
@@ -1252,9 +1288,25 @@ class SmartButton implements SmartButtonInterface {
1252
  /**
1253
  * The filter returning true if PayPal buttons/messages can be rendered for this product, or false otherwise.
1254
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1255
  return apply_filters(
1256
  'woocommerce_paypal_payments_product_supports_payment_request_button',
1257
- ! $product->is_type( array( 'external', 'grouped' ) ) && $product->is_in_stock(),
1258
  $product
1259
  );
1260
  }
@@ -1291,4 +1343,20 @@ class SmartButton implements SmartButtonInterface {
1291
  }
1292
  return '';
1293
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1294
  }
12
  use Exception;
13
  use Psr\Log\LoggerInterface;
14
  use WC_Product;
15
+ use WC_Product_Variation;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
17
  use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
144
  */
145
  private $all_funding_sources;
146
 
147
+ /**
148
+ * Whether the basic JS validation of the form iss enabled.
149
+ *
150
+ * @var bool
151
+ */
152
+ private $basic_checkout_validation_enabled;
153
+
154
  /**
155
  * The logger.
156
  *
183
  * @param SettingsStatus $settings_status The Settings status helper.
184
  * @param string $currency 3-letter currency code of the shop.
185
  * @param array $all_funding_sources All existing funding sources.
186
+ * @param bool $basic_checkout_validation_enabled Whether the basic JS validation of the form iss enabled.
187
  * @param LoggerInterface $logger The logger.
188
  */
189
  public function __construct(
202
  SettingsStatus $settings_status,
203
  string $currency,
204
  array $all_funding_sources,
205
+ bool $basic_checkout_validation_enabled,
206
  LoggerInterface $logger
207
  ) {
208
 
209
+ $this->module_url = $module_url;
210
+ $this->version = $version;
211
+ $this->session_handler = $session_handler;
212
+ $this->settings = $settings;
213
+ $this->payer_factory = $payer_factory;
214
+ $this->client_id = $client_id;
215
+ $this->request_data = $request_data;
216
+ $this->dcc_applies = $dcc_applies;
217
+ $this->subscription_helper = $subscription_helper;
218
+ $this->messages_apply = $messages_apply;
219
+ $this->environment = $environment;
220
+ $this->payment_token_repository = $payment_token_repository;
221
+ $this->settings_status = $settings_status;
222
+ $this->currency = $currency;
223
+ $this->all_funding_sources = $all_funding_sources;
224
+ $this->basic_checkout_validation_enabled = $basic_checkout_validation_enabled;
225
+ $this->logger = $logger;
226
  }
227
 
228
  /**
244
  if (
245
  $this->settings->has( 'dcc_enabled' )
246
  && $this->settings->get( 'dcc_enabled' )
 
247
  ) {
248
  add_action(
249
  $this->checkout_dcc_button_renderer_hook(),
690
  return;
691
  }
692
 
693
+ /**
694
+ * The WC filter returning the WC order button text.
695
+ * phpcs:disable WordPress.WP.I18n.TextDomainMismatch
696
+ */
697
  $label = 'checkout' === $this->context() ? apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ) : __( 'Pay for order', 'woocommerce' );
698
+ // phpcs:enable WordPress.WP.I18n.TextDomainMismatch
699
 
700
  printf(
701
  '<div id="%1$s" style="display:none;">
775
 
776
  $this->request_data->enqueue_nonce_fix();
777
  $localize = array(
778
+ 'script_attributes' => $this->attributes(),
779
+ 'data_client_id' => array(
780
  'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(),
781
  'endpoint' => \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ),
782
  'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ),
783
  'user' => get_current_user_id(),
784
  'has_subscriptions' => $this->has_subscriptions(),
785
  ),
786
+ 'redirect' => wc_get_checkout_url(),
787
+ 'context' => $this->context(),
788
+ 'ajax' => array(
789
  'change_cart' => array(
790
  'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ),
791
  'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ),
803
  'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ),
804
  ),
805
  ),
806
+ 'enforce_vault' => $this->has_subscriptions(),
807
+ 'can_save_vault_token' => $this->can_save_vault_token(),
808
+ 'is_free_trial_cart' => $is_free_trial_cart,
809
+ 'vaulted_paypal_email' => ( is_checkout() && $is_free_trial_cart ) ? $this->get_vaulted_paypal_email() : '',
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',
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(
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' ),
868
+ 'mini_cart_buttons_enabled' => $this->settings->has( 'button_mini-cart_enabled' ) && $this->settings->get( 'button_mini-cart_enabled' ),
869
+ 'basic_checkout_validation_enabled' => $this->basic_checkout_validation_enabled,
870
  );
871
 
872
  if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
941
  }
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;
949
  }
1087
  if ( is_cart() ) {
1088
  $context = 'cart';
1089
  }
1090
+ if ( is_checkout() && ! $this->is_paypal_continuation() ) {
1091
  $context = 'checkout';
1092
  }
1093
  if ( is_checkout_pay_page() ) {
1096
  return $context;
1097
  }
1098
 
1099
+ /**
1100
+ * Checks if PayPal payment was already initiated (on the product or cart pages).
1101
+ *
1102
+ * @return bool
1103
+ */
1104
+ private function is_paypal_continuation(): bool {
1105
+ $order = $this->session_handler->order();
1106
+ if ( ! $order ) {
1107
+ return false;
1108
+ }
1109
+ $source = $order->payment_source();
1110
+ if ( $source && $source->card() ) {
1111
+ return false; // Ignore for DCC.
1112
+ }
1113
+ return true;
1114
+ }
1115
+
1116
  /**
1117
  * Whether DCC is enabled or not.
1118
  *
1288
  /**
1289
  * The filter returning true if PayPal buttons/messages can be rendered for this product, or false otherwise.
1290
  */
1291
+
1292
+ $in_stock = $product->is_in_stock();
1293
+
1294
+ if ( $product->is_type( 'variable' ) ) {
1295
+ /**
1296
+ * The method is defined in WC_Product_Variable class.
1297
+ *
1298
+ * @psalm-suppress UndefinedMethod
1299
+ */
1300
+ $variations = $product->get_available_variations( 'objects' );
1301
+ $in_stock = $this->has_in_stock_variation( $variations );
1302
+ }
1303
+
1304
+ /**
1305
+ * Allows to filter if PayPal buttons/messages can be rendered for the given product.
1306
+ */
1307
  return apply_filters(
1308
  'woocommerce_paypal_payments_product_supports_payment_request_button',
1309
+ ! $product->is_type( array( 'external', 'grouped' ) ) && $in_stock,
1310
  $product
1311
  );
1312
  }
1343
  }
1344
  return '';
1345
  }
1346
+
1347
+ /**
1348
+ * Checks if variations contain any in stock variation.
1349
+ *
1350
+ * @param WC_Product_Variation[] $variations The list of variations.
1351
+ * @return bool True if any in stock variation, false otherwise.
1352
+ */
1353
+ protected function has_in_stock_variation( array $variations ): bool {
1354
+ foreach ( $variations as $variation ) {
1355
+ if ( $variation->is_in_stock() ) {
1356
+ return true;
1357
+ }
1358
+ }
1359
+
1360
+ return false;
1361
+ }
1362
  }
modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php CHANGED
@@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
17
  use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
 
19
  use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
20
  use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
21
  use WooCommerce\PayPalCommerce\Session\SessionHandler;
@@ -26,7 +27,6 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
26
  */
27
  class ApproveOrderEndpoint implements EndpointInterface {
28
 
29
-
30
  const ENDPOINT = 'ppc-approve-order';
31
 
32
  /**
@@ -71,6 +71,13 @@ class ApproveOrderEndpoint implements EndpointInterface {
71
  */
72
  private $dcc_applies;
73
 
 
 
 
 
 
 
 
74
  /**
75
  * The logger.
76
  *
@@ -87,6 +94,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
87
  * @param ThreeDSecure $three_d_secure The 3d secure helper object.
88
  * @param Settings $settings The settings.
89
  * @param DccApplies $dcc_applies The DCC applies object.
 
90
  * @param LoggerInterface $logger The logger.
91
  */
92
  public function __construct(
@@ -96,6 +104,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
96
  ThreeDSecure $three_d_secure,
97
  Settings $settings,
98
  DccApplies $dcc_applies,
 
99
  LoggerInterface $logger
100
  ) {
101
 
@@ -105,6 +114,7 @@ class ApproveOrderEndpoint implements EndpointInterface {
105
  $this->threed_secure = $three_d_secure;
106
  $this->settings = $settings;
107
  $this->dcc_applies = $dcc_applies;
 
108
  $this->logger = $logger;
109
  }
110
 
@@ -173,10 +183,10 @@ class ApproveOrderEndpoint implements EndpointInterface {
173
  wp_send_json_success( $order );
174
  }
175
 
176
- if ( ! $order->status()->is( OrderStatus::APPROVED ) ) {
177
  $message = sprintf(
178
  // translators: %s is the id of the order.
179
- __( 'Order %s is not approved yet.', 'woocommerce-paypal-payments' ),
180
  $data['order_id']
181
  );
182
 
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
17
  use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
19
+ use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
20
  use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
21
  use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
22
  use WooCommerce\PayPalCommerce\Session\SessionHandler;
27
  */
28
  class ApproveOrderEndpoint implements EndpointInterface {
29
 
 
30
  const ENDPOINT = 'ppc-approve-order';
31
 
32
  /**
71
  */
72
  private $dcc_applies;
73
 
74
+ /**
75
+ * The order helper.
76
+ *
77
+ * @var OrderHelper
78
+ */
79
+ protected $order_helper;
80
+
81
  /**
82
  * The logger.
83
  *
94
  * @param ThreeDSecure $three_d_secure The 3d secure helper object.
95
  * @param Settings $settings The settings.
96
  * @param DccApplies $dcc_applies The DCC applies object.
97
+ * @param OrderHelper $order_helper The order helper.
98
  * @param LoggerInterface $logger The logger.
99
  */
100
  public function __construct(
104
  ThreeDSecure $three_d_secure,
105
  Settings $settings,
106
  DccApplies $dcc_applies,
107
+ OrderHelper $order_helper,
108
  LoggerInterface $logger
109
  ) {
110
 
114
  $this->threed_secure = $three_d_secure;
115
  $this->settings = $settings;
116
  $this->dcc_applies = $dcc_applies;
117
+ $this->order_helper = $order_helper;
118
  $this->logger = $logger;
119
  }
120
 
183
  wp_send_json_success( $order );
184
  }
185
 
186
+ if ( $this->order_helper->contains_physical_goods( $order ) && ! $order->status()->is( OrderStatus::APPROVED ) && ! $order->status()->is( OrderStatus::CREATED ) ) {
187
  $message = sprintf(
188
  // translators: %s is the id of the order.
189
+ __( 'Order %s is not ready for processing yet.', 'woocommerce-paypal-payments' ),
190
  $data['order_id']
191
  );
192
 
modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php CHANGED
@@ -403,9 +403,9 @@ class CreateOrderEndpoint implements EndpointInterface {
403
  }
404
 
405
  if ( ! $payer && isset( $data['form'] ) ) {
406
- parse_str( $data['form'], $form_fields );
407
 
408
- if ( isset( $form_fields['billing_email'] ) && '' !== $form_fields['billing_email'] ) {
409
  return $this->payer_factory->from_checkout_form( $form_fields );
410
  }
411
  }
@@ -449,12 +449,11 @@ class CreateOrderEndpoint implements EndpointInterface {
449
  /**
450
  * Checks whether the terms input field is checked.
451
  *
452
- * @param string $form_values The form values.
453
  * @throws \RuntimeException When field is not checked.
454
  */
455
- private function validate_paynow_form( string $form_values ) {
456
- $parsed_values = wp_parse_args( $form_values );
457
- if ( isset( $parsed_values['terms-field'] ) && ! isset( $parsed_values['terms'] ) ) {
458
  throw new \RuntimeException(
459
  __( 'Please read and accept the terms and conditions to proceed with your order.', 'woocommerce-paypal-payments' )
460
  );
403
  }
404
 
405
  if ( ! $payer && isset( $data['form'] ) ) {
406
+ $form_fields = $data['form'];
407
 
408
+ if ( is_array( $form_fields ) && isset( $form_fields['billing_email'] ) && '' !== $form_fields['billing_email'] ) {
409
  return $this->payer_factory->from_checkout_form( $form_fields );
410
  }
411
  }
449
  /**
450
  * Checks whether the terms input field is checked.
451
  *
452
+ * @param array $form_fields The form fields.
453
  * @throws \RuntimeException When field is not checked.
454
  */
455
+ private function validate_paynow_form( array $form_fields ) {
456
+ if ( isset( $form_fields['terms-field'] ) && ! isset( $form_fields['terms'] ) ) {
 
457
  throw new \RuntimeException(
458
  __( 'Please read and accept the terms and conditions to proceed with your order.', 'woocommerce-paypal-payments' )
459
  );
modules/ppcp-button/src/Endpoint/RequestData.php CHANGED
@@ -81,15 +81,9 @@ class RequestData {
81
  $data = array();
82
  foreach ( (array) $assoc_array as $raw_key => $raw_value ) {
83
  if ( ! is_array( $raw_value ) ) {
84
- /**
85
- * The 'form' key is preserved for url encoded data and needs different
86
- * sanitization.
87
- */
88
- if ( 'form' !== $raw_key ) {
89
- $data[ sanitize_text_field( (string) $raw_key ) ] = sanitize_text_field( (string) $raw_value );
90
- } else {
91
- $data[ sanitize_text_field( (string) $raw_key ) ] = sanitize_text_field( urldecode( (string) $raw_value ) );
92
- }
93
  continue;
94
  }
95
  $data[ sanitize_text_field( (string) $raw_key ) ] = $this->sanitize( $raw_value );
81
  $data = array();
82
  foreach ( (array) $assoc_array as $raw_key => $raw_value ) {
83
  if ( ! is_array( $raw_value ) ) {
84
+ // Not sure if it is a good idea to sanitize everything at this level,
85
+ // but should be fine for now since we do not send any HTML or multi-line texts via ajax.
86
+ $data[ sanitize_text_field( (string) $raw_key ) ] = sanitize_text_field( (string) $raw_value );
 
 
 
 
 
 
87
  continue;
88
  }
89
  $data[ sanitize_text_field( (string) $raw_key ) ] = $this->sanitize( $raw_value );
modules/ppcp-onboarding/assets/js/onboarding.js CHANGED
@@ -70,6 +70,38 @@ const ppcp_onboarding = {
70
  },
71
  1000
72
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  },
74
 
75
  loginSeller: function(env, authCode, sharedId) {
70
  },
71
  1000
72
  );
73
+
74
+ const onboard_pui = document.querySelector('#ppcp-onboarding-pui');
75
+ onboard_pui?.addEventListener('click', (event) => {
76
+ event.preventDefault();
77
+ buttons.forEach((element) => {
78
+ element.removeAttribute('href');
79
+ });
80
+
81
+ fetch(PayPalCommerceGatewayOnboarding.pui_endpoint, {
82
+ method: 'POST',
83
+ body: JSON.stringify({
84
+ nonce: PayPalCommerceGatewayOnboarding.pui_nonce,
85
+ checked: onboard_pui.checked
86
+ })
87
+ }).then((res)=>{
88
+ return res.json();
89
+ }).then((data)=>{
90
+ if (!data.success) {
91
+ alert('Could not update signup buttons: ' + JSON.stringify(data));
92
+ return;
93
+ }
94
+
95
+ buttons.forEach((element) => {
96
+ for (let [key, value] of Object.entries(data.data.signup_links)) {
97
+ key = 'connect-to' + key.replace(/-/g, '');
98
+ if(key === element.id) {
99
+ element.setAttribute('href', value);
100
+ }
101
+ }
102
+ });
103
+ });
104
+ })
105
  },
106
 
107
  loginSeller: function(env, authCode, sharedId) {
modules/ppcp-onboarding/services.php CHANGED
@@ -18,6 +18,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnerReferrals;
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
19
  use WooCommerce\PayPalCommerce\Onboarding\Assets\OnboardingAssets;
20
  use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
 
21
  use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
22
  use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer;
23
  use WooCommerce\PayPalCommerce\Onboarding\OnboardingRESTController;
@@ -186,6 +187,16 @@ return array(
186
  $logger
187
  );
188
  },
 
 
 
 
 
 
 
 
 
 
189
  'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals {
190
 
191
  return new PartnerReferrals(
@@ -202,23 +213,36 @@ return array(
202
  $container->get( 'woocommerce.logger.woocommerce' )
203
  );
204
  },
 
 
 
 
 
 
 
 
 
 
 
205
  'onboarding.render' => static function ( ContainerInterface $container ) : OnboardingRenderer {
206
-
207
  $partner_referrals = $container->get( 'api.endpoint.partner-referrals-production' );
208
  $partner_referrals_sandbox = $container->get( 'api.endpoint.partner-referrals-sandbox' );
209
  $partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' );
210
  $settings = $container->get( 'wcgateway.settings' );
 
211
  return new OnboardingRenderer(
212
  $settings,
213
  $partner_referrals,
214
  $partner_referrals_sandbox,
215
- $partner_referrals_data
 
216
  );
217
  },
218
  'onboarding.render-options' => static function ( ContainerInterface $container ) : OnboardingOptionsRenderer {
219
  return new OnboardingOptionsRenderer(
220
  $container->get( 'onboarding.url' ),
221
- $container->get( 'api.shop.country' )
 
222
  );
223
  },
224
  'onboarding.rest' => static function( $container ) : OnboardingRESTController {
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
19
  use WooCommerce\PayPalCommerce\Onboarding\Assets\OnboardingAssets;
20
  use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
21
+ use WooCommerce\PayPalCommerce\Onboarding\Endpoint\PayUponInvoiceEndpoint;
22
  use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
23
  use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer;
24
  use WooCommerce\PayPalCommerce\Onboarding\OnboardingRESTController;
187
  $logger
188
  );
189
  },
190
+ 'onboarding.endpoint.pui' => static function( ContainerInterface $container ) : PayUponInvoiceEndpoint {
191
+ return new PayUponInvoiceEndpoint(
192
+ $container->get( 'wcgateway.settings' ),
193
+ $container->get( 'button.request-data' ),
194
+ $container->get( 'onboarding.signup-link-cache' ),
195
+ $container->get( 'onboarding.render' ),
196
+ $container->get( 'onboarding.signup-link-ids' ),
197
+ $container->get( 'woocommerce.logger.woocommerce' )
198
+ );
199
+ },
200
  'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals {
201
 
202
  return new PartnerReferrals(
213
  $container->get( 'woocommerce.logger.woocommerce' )
214
  );
215
  },
216
+ 'onboarding.signup-link-cache' => static function( ContainerInterface $container ): Cache {
217
+ return new Cache( 'ppcp-paypal-signup-link' );
218
+ },
219
+ 'onboarding.signup-link-ids' => static function ( ContainerInterface $container ): array {
220
+ return array(
221
+ 'production-ppcp',
222
+ 'production-express_checkout',
223
+ 'sandbox-ppcp',
224
+ 'sandbox-express_checkout',
225
+ );
226
+ },
227
  'onboarding.render' => static function ( ContainerInterface $container ) : OnboardingRenderer {
 
228
  $partner_referrals = $container->get( 'api.endpoint.partner-referrals-production' );
229
  $partner_referrals_sandbox = $container->get( 'api.endpoint.partner-referrals-sandbox' );
230
  $partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' );
231
  $settings = $container->get( 'wcgateway.settings' );
232
+ $signup_link_cache = $container->get( 'onboarding.signup-link-cache' );
233
  return new OnboardingRenderer(
234
  $settings,
235
  $partner_referrals,
236
  $partner_referrals_sandbox,
237
+ $partner_referrals_data,
238
+ $signup_link_cache
239
  );
240
  },
241
  'onboarding.render-options' => static function ( ContainerInterface $container ) : OnboardingOptionsRenderer {
242
  return new OnboardingOptionsRenderer(
243
  $container->get( 'onboarding.url' ),
244
+ $container->get( 'api.shop.country' ),
245
+ $container->get( 'wcgateway.settings' )
246
  );
247
  },
248
  'onboarding.rest' => static function( $container ) : OnboardingRESTController {
modules/ppcp-onboarding/src/Assets/OnboardingAssets.php CHANGED
@@ -145,6 +145,8 @@ class OnboardingAssets {
145
  'error_messages' => array(
146
  'no_credentials' => __( 'API credentials must be entered to save the settings.', 'woocommerce-paypal-payments' ),
147
  ),
 
 
148
  );
149
  }
150
 
145
  'error_messages' => array(
146
  'no_credentials' => __( 'API credentials must be entered to save the settings.', 'woocommerce-paypal-payments' ),
147
  ),
148
+ 'pui_endpoint' => \WC_AJAX::get_endpoint( 'ppc-pui' ),
149
+ 'pui_nonce' => wp_create_nonce( 'ppc-pui' ),
150
  );
151
  }
152
 
modules/ppcp-onboarding/src/Endpoint/LoginSellerEndpoint.php CHANGED
@@ -127,6 +127,7 @@ class LoginSellerEndpoint implements EndpointInterface {
127
  $is_sandbox = isset( $data['env'] ) && 'sandbox' === $data['env'];
128
  $this->settings->set( 'sandbox_on', $is_sandbox );
129
  $this->settings->set( 'products_dcc_enabled', null );
 
130
  $this->settings->persist();
131
 
132
  $endpoint = $is_sandbox ? $this->login_seller_sandbox : $this->login_seller_production;
@@ -144,6 +145,7 @@ class LoginSellerEndpoint implements EndpointInterface {
144
  }
145
  $this->settings->set( 'client_secret', $credentials->client_secret );
146
  $this->settings->set( 'client_id', $credentials->client_id );
 
147
 
148
  $accept_cards = (bool) ( $data['acceptCards'] ?? true );
149
  $funding_sources = array();
127
  $is_sandbox = isset( $data['env'] ) && 'sandbox' === $data['env'];
128
  $this->settings->set( 'sandbox_on', $is_sandbox );
129
  $this->settings->set( 'products_dcc_enabled', null );
130
+ $this->settings->set( 'products_pui_enabled', null );
131
  $this->settings->persist();
132
 
133
  $endpoint = $is_sandbox ? $this->login_seller_sandbox : $this->login_seller_production;
145
  }
146
  $this->settings->set( 'client_secret', $credentials->client_secret );
147
  $this->settings->set( 'client_id', $credentials->client_id );
148
+ $this->settings->persist();
149
 
150
  $accept_cards = (bool) ( $data['acceptCards'] ?? true );
151
  $funding_sources = array();
modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles the onboard with Pay Upon Invoice setting.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\Onboarding\Endpoint
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\Onboarding\Endpoint;
11
+
12
+ use Exception;
13
+ use Psr\Log\LoggerInterface;
14
+ use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
15
+ use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
16
+ use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
17
+ use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer;
18
+ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
19
+ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
20
+
21
+ /**
22
+ * Class PayUponInvoiceEndpoint
23
+ */
24
+ class PayUponInvoiceEndpoint implements EndpointInterface {
25
+
26
+ /**
27
+ * The settings.
28
+ *
29
+ * @var Settings
30
+ */
31
+ protected $settings;
32
+
33
+ /**
34
+ * The request data.
35
+ *
36
+ * @var RequestData
37
+ */
38
+ protected $request_data;
39
+
40
+ /**
41
+ * The signup link cache.
42
+ *
43
+ * @var Cache
44
+ */
45
+ protected $signup_link_cache;
46
+
47
+ /**
48
+ * The onboarding renderer.
49
+ *
50
+ * @var OnboardingRenderer
51
+ */
52
+ protected $onboarding_renderer;
53
+
54
+ /**
55
+ * Signup link ids.
56
+ *
57
+ * @var array
58
+ */
59
+ protected $signup_link_ids;
60
+
61
+ /**
62
+ * The logger.
63
+ *
64
+ * @var LoggerInterface
65
+ */
66
+ protected $logger;
67
+
68
+ /**
69
+ * PayUponInvoiceEndpoint constructor.
70
+ *
71
+ * @param Settings $settings The settings.
72
+ * @param RequestData $request_data The request data.
73
+ * @param Cache $signup_link_cache The signup link cache.
74
+ * @param OnboardingRenderer $onboarding_renderer The onboarding renderer.
75
+ * @param array $signup_link_ids Signup link ids.
76
+ * @param LoggerInterface $logger The logger.
77
+ */
78
+ public function __construct(
79
+ Settings $settings,
80
+ RequestData $request_data,
81
+ Cache $signup_link_cache,
82
+ OnboardingRenderer $onboarding_renderer,
83
+ array $signup_link_ids,
84
+ LoggerInterface $logger
85
+ ) {
86
+ $this->settings = $settings;
87
+ $this->request_data = $request_data;
88
+ $this->signup_link_cache = $signup_link_cache;
89
+ $this->onboarding_renderer = $onboarding_renderer;
90
+ $this->logger = $logger;
91
+ $this->signup_link_ids = $signup_link_ids;
92
+ }
93
+
94
+ /**
95
+ * The nonce.
96
+ *
97
+ * @return string
98
+ */
99
+ public static function nonce(): string {
100
+ return 'ppc-pui';
101
+ }
102
+
103
+ /**
104
+ * Handles the request.
105
+ *
106
+ * @return bool
107
+ * @throws NotFoundException When order not found or handling failed.
108
+ */
109
+ public function handle_request(): bool {
110
+ $signup_links = array();
111
+
112
+ try {
113
+ $data = $this->request_data->read_request( $this->nonce() );
114
+ $this->settings->set( 'ppcp-onboarding-pui', $data['checked'] );
115
+ $this->settings->persist();
116
+
117
+ foreach ( $this->signup_link_ids as $key ) {
118
+ if ( $this->signup_link_cache->has( $key ) ) {
119
+ $this->signup_link_cache->delete( $key );
120
+ }
121
+ }
122
+
123
+ foreach ( $this->signup_link_ids as $key ) {
124
+ $parts = explode( '-', $key );
125
+ $is_production = 'production' === $parts[0];
126
+ $products = 'ppcp' === $parts[1] ? array( 'PPCP' ) : array( 'EXPRESS_CHECKOUT' );
127
+ $signup_links[ $key ] = $this->onboarding_renderer->get_signup_link( $is_production, $products );
128
+ }
129
+ } catch ( Exception $exception ) {
130
+ $this->logger->error( $exception->getMessage() );
131
+ }
132
+
133
+ wp_send_json_success(
134
+ array(
135
+ 'onboarding_pui' => $this->settings->get( 'ppcp-onboarding-pui' ),
136
+ 'signup_links' => $signup_links,
137
+ )
138
+ );
139
+
140
+ return true;
141
+ }
142
+ }
143
+
modules/ppcp-onboarding/src/OnboardingModule.php CHANGED
@@ -96,6 +96,14 @@ class OnboardingModule implements ModuleInterface {
96
  }
97
  );
98
 
 
 
 
 
 
 
 
 
99
  // Initialize REST routes at the appropriate time.
100
  $rest_controller = $c->get( 'onboarding.rest' );
101
  add_action( 'rest_api_init', array( $rest_controller, 'register_routes' ) );
96
  }
97
  );
98
 
99
+ add_action(
100
+ 'wc_ajax_ppc-pui',
101
+ static function () use ( $c ) {
102
+ $endpoint = $c->get( 'onboarding.endpoint.pui' );
103
+ $endpoint->handle_request();
104
+ }
105
+ );
106
+
107
  // Initialize REST routes at the appropriate time.
108
  $rest_controller = $c->get( 'onboarding.rest' );
109
  add_action( 'rest_api_init', array( $rest_controller, 'register_routes' ) );
modules/ppcp-onboarding/src/OnboardingRESTController.php CHANGED
@@ -236,6 +236,7 @@ class OnboardingRESTController {
236
  }
237
 
238
  $settings->set( 'products_dcc_enabled', null );
 
239
 
240
  if ( ! $settings->persist() ) {
241
  return new \WP_Error(
236
  }
237
 
238
  $settings->set( 'products_dcc_enabled', null );
239
+ $settings->set( 'products_pui_enabled', null );
240
 
241
  if ( ! $settings->persist() ) {
242
  return new \WP_Error(
modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php CHANGED
@@ -9,6 +9,9 @@ declare(strict_types=1);
9
 
10
  namespace WooCommerce\PayPalCommerce\Onboarding\Render;
11
 
 
 
 
12
  /**
13
  * Class OnboardingRenderer
14
  */
@@ -27,15 +30,24 @@ class OnboardingOptionsRenderer {
27
  */
28
  private $country;
29
 
 
 
 
 
 
 
 
30
  /**
31
  * OnboardingOptionsRenderer constructor.
32
  *
33
- * @param string $module_url The module url (for assets).
34
- * @param string $country 2-letter country code of the shop.
 
35
  */
36
- public function __construct( string $module_url, string $country ) {
37
  $this->module_url = $module_url;
38
  $this->country = $country;
 
39
  }
40
 
41
  /**
@@ -56,8 +68,29 @@ class OnboardingOptionsRenderer {
56
  __( 'Securely accept all major credit & debit cards on the strength of the PayPal network', 'woocommerce-paypal-payments' ) . '
57
  </label>
58
  </li>
59
- <li>' . $this->render_dcc( $is_shop_supports_dcc ) . '</li>
60
- </ul>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
 
63
  /**
9
 
10
  namespace WooCommerce\PayPalCommerce\Onboarding\Render;
11
 
12
+ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
13
+ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
14
+
15
  /**
16
  * Class OnboardingRenderer
17
  */
30
  */
31
  private $country;
32
 
33
+ /**
34
+ * The settings.
35
+ *
36
+ * @var Settings
37
+ */
38
+ protected $settings;
39
+
40
  /**
41
  * OnboardingOptionsRenderer constructor.
42
  *
43
+ * @param string $module_url The module url (for assets).
44
+ * @param string $country 2-letter country code of the shop.
45
+ * @param Settings $settings The settings.
46
  */
47
+ public function __construct( string $module_url, string $country, Settings $settings ) {
48
  $this->module_url = $module_url;
49
  $this->country = $country;
50
+ $this->settings = $settings;
51
  }
52
 
53
  /**
68
  __( 'Securely accept all major credit & debit cards on the strength of the PayPal network', 'woocommerce-paypal-payments' ) . '
69
  </label>
70
  </li>
71
+ <li>' . $this->render_dcc( $is_shop_supports_dcc ) . '</li>' .
72
+ $this->render_pui_option()
73
+ . '</ul>';
74
+ }
75
+
76
+ /**
77
+ * Renders pui option.
78
+ *
79
+ * @return string
80
+ * @throws NotFoundException When setting is not found.
81
+ */
82
+ private function render_pui_option(): string {
83
+ if ( 'DE' === $this->country ) {
84
+ $checked = 'checked';
85
+ if ( $this->settings->has( 'ppcp-onboarding-pui' ) && $this->settings->get( 'ppcp-onboarding-pui' ) !== '1' ) {
86
+ $checked = '';
87
+ }
88
+ return '<li><label><input type="checkbox" id="ppcp-onboarding-pui" ' . $checked . '> ' .
89
+ __( 'Onboard with Pay Upon Invoice', 'woocommerce-paypal-payments' ) . '
90
+ </label></li>';
91
+ }
92
+
93
+ return '';
94
  }
95
 
96
  /**
modules/ppcp-onboarding/src/Render/OnboardingRenderer.php CHANGED
@@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Render;
11
 
12
  use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnerReferrals;
13
  use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
 
14
  use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
15
  use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
16
 
@@ -47,6 +48,13 @@ class OnboardingRenderer {
47
  */
48
  private $partner_referrals_data;
49
 
 
 
 
 
 
 
 
50
  /**
51
  * OnboardingRenderer constructor.
52
  *
@@ -54,17 +62,20 @@ class OnboardingRenderer {
54
  * @param PartnerReferrals $production_partner_referrals The PartnerReferrals for production.
55
  * @param PartnerReferrals $sandbox_partner_referrals The PartnerReferrals for sandbox.
56
  * @param PartnerReferralsData $partner_referrals_data The default partner referrals data.
 
57
  */
58
  public function __construct(
59
  Settings $settings,
60
  PartnerReferrals $production_partner_referrals,
61
  PartnerReferrals $sandbox_partner_referrals,
62
- PartnerReferralsData $partner_referrals_data
 
63
  ) {
64
  $this->settings = $settings;
65
  $this->production_partner_referrals = $production_partner_referrals;
66
  $this->sandbox_partner_referrals = $sandbox_partner_referrals;
67
  $this->partner_referrals_data = $partner_referrals_data;
 
68
  }
69
 
70
  /**
@@ -83,9 +94,17 @@ class OnboardingRenderer {
83
  ->with_products( $products )
84
  ->data();
85
 
 
 
 
 
 
 
86
  $url = $is_production ? $this->production_partner_referrals->signup_link( $data ) : $this->sandbox_partner_referrals->signup_link( $data );
87
  $url = add_query_arg( $args, $url );
88
 
 
 
89
  return $url;
90
  }
91
 
11
 
12
  use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnerReferrals;
13
  use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
14
+ use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
15
  use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
16
  use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
17
 
48
  */
49
  private $partner_referrals_data;
50
 
51
+ /**
52
+ * The cache
53
+ *
54
+ * @var Cache
55
+ */
56
+ protected $cache;
57
+
58
  /**
59
  * OnboardingRenderer constructor.
60
  *
62
  * @param PartnerReferrals $production_partner_referrals The PartnerReferrals for production.
63
  * @param PartnerReferrals $sandbox_partner_referrals The PartnerReferrals for sandbox.
64
  * @param PartnerReferralsData $partner_referrals_data The default partner referrals data.
65
+ * @param Cache $cache The cache.
66
  */
67
  public function __construct(
68
  Settings $settings,
69
  PartnerReferrals $production_partner_referrals,
70
  PartnerReferrals $sandbox_partner_referrals,
71
+ PartnerReferralsData $partner_referrals_data,
72
+ Cache $cache
73
  ) {
74
  $this->settings = $settings;
75
  $this->production_partner_referrals = $production_partner_referrals;
76
  $this->sandbox_partner_referrals = $sandbox_partner_referrals;
77
  $this->partner_referrals_data = $partner_referrals_data;
78
+ $this->cache = $cache;
79
  }
80
 
81
  /**
94
  ->with_products( $products )
95
  ->data();
96
 
97
+ $environment = $is_production ? 'production' : 'sandbox';
98
+ $product = 'PPCP' === $data['products'][0] ? 'ppcp' : 'express_checkout';
99
+ if ( $this->cache->has( $environment . '-' . $product ) ) {
100
+ return $this->cache->get( $environment . '-' . $product );
101
+ }
102
+
103
  $url = $is_production ? $this->production_partner_referrals->signup_link( $data ) : $this->sandbox_partner_referrals->signup_link( $data );
104
  $url = add_query_arg( $args, $url );
105
 
106
+ $this->cache->set( $environment . '-' . $product, $url, 3 * MONTH_IN_SECONDS );
107
+
108
  return $url;
109
  }
110
 
modules/ppcp-session/src/Cancellation/CancelController.php CHANGED
@@ -59,10 +59,17 @@ class CancelController {
59
  ) { // Input var ok.
60
  $this->session_handler->destroy_session_data();
61
  }
62
- if ( ! $this->session_handler->order() ) {
 
 
63
  return;
64
  }
65
 
 
 
 
 
 
66
  $url = add_query_arg( array( $param_name => wp_create_nonce( $nonce ) ), wc_get_checkout_url() );
67
  add_action(
68
  'woocommerce_review_order_after_submit',
59
  ) { // Input var ok.
60
  $this->session_handler->destroy_session_data();
61
  }
62
+
63
+ $order = $this->session_handler->order();
64
+ if ( ! $order ) {
65
  return;
66
  }
67
 
68
+ $source = $order->payment_source();
69
+ if ( $source && $source->card() ) {
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',
modules/ppcp-wc-gateway/assets/js/pay-upon-invoice.js ADDED
@@ -0,0 +1 @@
 
1
+ (()=>{var __webpack_modules__={493:()=>{eval("window.addEventListener('load', function () {\n function _loadBeaconJS(options) {\n var script = document.createElement('script');\n script.src = options.fnUrl;\n document.body.appendChild(script);\n }\n\n function _injectConfig() {\n var script = document.querySelector(\"[fncls='fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99']\");\n\n if (script) {\n if (script.parentNode) {\n script.parentNode.removeChild(script);\n }\n }\n\n script = document.createElement('script');\n script.id = 'fconfig';\n script.type = 'application/json';\n script.setAttribute('fncls', 'fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99');\n var configuration = {\n 'f': FraudNetConfig.f,\n 's': FraudNetConfig.s\n };\n\n if (FraudNetConfig.sandbox === '1') {\n configuration.sandbox = true;\n }\n\n script.text = JSON.stringify(configuration);\n document.body.appendChild(script);\n const payForOrderForm = document.forms.order_review;\n\n if (payForOrderForm) {\n const puiPayForOrderSessionId = document.createElement('input');\n puiPayForOrderSessionId.setAttribute('type', 'hidden');\n puiPayForOrderSessionId.setAttribute('name', 'pui_pay_for_order_session_id');\n puiPayForOrderSessionId.setAttribute('value', FraudNetConfig.f);\n payForOrderForm.appendChild(puiPayForOrderSessionId);\n }\n\n _loadBeaconJS({\n fnUrl: \"https://c.paypal.com/da/r/fb.js\"\n });\n }\n\n document.addEventListener('hosted_fields_loaded', event => {\n if (PAYPAL.asyncData && typeof PAYPAL.asyncData.initAndCollect === 'function') {\n PAYPAL.asyncData.initAndCollect();\n }\n\n _injectConfig();\n });\n\n _injectConfig();\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9wcGNwLXdjLWdhdGV3YXkvLi9yZXNvdXJjZXMvanMvcGF5LXVwb24taW52b2ljZS5qcz81YWVkIl0sIm5hbWVzIjpbIndpbmRvdyIsImFkZEV2ZW50TGlzdGVuZXIiLCJfbG9hZEJlYWNvbkpTIiwib3B0aW9ucyIsInNjcmlwdCIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsInNyYyIsImZuVXJsIiwiYm9keSIsImFwcGVuZENoaWxkIiwiX2luamVjdENvbmZpZyIsInF1ZXJ5U2VsZWN0b3IiLCJwYXJlbnROb2RlIiwicmVtb3ZlQ2hpbGQiLCJpZCIsInR5cGUiLCJzZXRBdHRyaWJ1dGUiLCJjb25maWd1cmF0aW9uIiwiRnJhdWROZXRDb25maWciLCJmIiwicyIsInNhbmRib3giLCJ0ZXh0IiwiSlNPTiIsInN0cmluZ2lmeSIsInBheUZvck9yZGVyRm9ybSIsImZvcm1zIiwib3JkZXJfcmV2aWV3IiwicHVpUGF5Rm9yT3JkZXJTZXNzaW9uSWQiLCJldmVudCIsIlBBWVBBTCIsImFzeW5jRGF0YSIsImluaXRBbmRDb2xsZWN0Il0sIm1hcHBpbmdzIjoiQUFBQUEsTUFBTSxDQUFDQyxnQkFBUCxDQUF3QixNQUF4QixFQUFnQyxZQUFXO0FBRXZDLFdBQVNDLGFBQVQsQ0FBdUJDLE9BQXZCLEVBQWdDO0FBQzVCLFFBQUlDLE1BQU0sR0FBR0MsUUFBUSxDQUFDQyxhQUFULENBQXVCLFFBQXZCLENBQWI7QUFDQUYsSUFBQUEsTUFBTSxDQUFDRyxHQUFQLEdBQWFKLE9BQU8sQ0FBQ0ssS0FBckI7QUFDQUgsSUFBQUEsUUFBUSxDQUFDSSxJQUFULENBQWNDLFdBQWQsQ0FBMEJOLE1BQTFCO0FBQ0g7O0FBRUQsV0FBU08sYUFBVCxHQUF5QjtBQUNyQixRQUFJUCxNQUFNLEdBQUdDLFFBQVEsQ0FBQ08sYUFBVCxDQUF1Qix5REFBdkIsQ0FBYjs7QUFDQSxRQUFJUixNQUFKLEVBQVk7QUFDUixVQUFJQSxNQUFNLENBQUNTLFVBQVgsRUFBdUI7QUFDbkJULFFBQUFBLE1BQU0sQ0FBQ1MsVUFBUCxDQUFrQkMsV0FBbEIsQ0FBOEJWLE1BQTlCO0FBQ0g7QUFDSjs7QUFFREEsSUFBQUEsTUFBTSxHQUFHQyxRQUFRLENBQUNDLGFBQVQsQ0FBdUIsUUFBdkIsQ0FBVDtBQUNBRixJQUFBQSxNQUFNLENBQUNXLEVBQVAsR0FBWSxTQUFaO0FBQ0FYLElBQUFBLE1BQU0sQ0FBQ1ksSUFBUCxHQUFjLGtCQUFkO0FBQ0FaLElBQUFBLE1BQU0sQ0FBQ2EsWUFBUCxDQUFvQixPQUFwQixFQUE2QiwrQ0FBN0I7QUFFQSxRQUFJQyxhQUFhLEdBQUc7QUFDaEIsV0FBS0MsY0FBYyxDQUFDQyxDQURKO0FBRWhCLFdBQUtELGNBQWMsQ0FBQ0U7QUFGSixLQUFwQjs7QUFJQSxRQUFHRixjQUFjLENBQUNHLE9BQWYsS0FBMkIsR0FBOUIsRUFBbUM7QUFDL0JKLE1BQUFBLGFBQWEsQ0FBQ0ksT0FBZCxHQUF3QixJQUF4QjtBQUNIOztBQUVEbEIsSUFBQUEsTUFBTSxDQUFDbUIsSUFBUCxHQUFjQyxJQUFJLENBQUNDLFNBQUwsQ0FBZVAsYUFBZixDQUFkO0FBQ0FiLElBQUFBLFFBQVEsQ0FBQ0ksSUFBVCxDQUFjQyxXQUFkLENBQTBCTixNQUExQjtBQUVBLFVBQU1zQixlQUFlLEdBQUdyQixRQUFRLENBQUNzQixLQUFULENBQWVDLFlBQXZDOztBQUNBLFFBQUdGLGVBQUgsRUFBb0I7QUFDaEIsWUFBTUcsdUJBQXVCLEdBQUd4QixRQUFRLENBQUNDLGFBQVQsQ0FBdUIsT0FBdkIsQ0FBaEM7QUFDQXVCLE1BQUFBLHVCQUF1QixDQUFDWixZQUF4QixDQUFxQyxNQUFyQyxFQUE2QyxRQUE3QztBQUNBWSxNQUFBQSx1QkFBdUIsQ0FBQ1osWUFBeEIsQ0FBcUMsTUFBckMsRUFBNkMsOEJBQTdDO0FBQ0FZLE1BQUFBLHVCQUF1QixDQUFDWixZQUF4QixDQUFxQyxPQUFyQyxFQUE4Q0UsY0FBYyxDQUFDQyxDQUE3RDtBQUNBTSxNQUFBQSxlQUFlLENBQUNoQixXQUFoQixDQUE0Qm1CLHVCQUE1QjtBQUNIOztBQUVEM0IsSUFBQUEsYUFBYSxDQUFDO0FBQUNNLE1BQUFBLEtBQUssRUFBRTtBQUFSLEtBQUQsQ0FBYjtBQUNIOztBQUVESCxFQUFBQSxRQUFRLENBQUNKLGdCQUFULENBQTBCLHNCQUExQixFQUFtRDZCLEtBQUQsSUFBVztBQUN6RCxRQUFJQyxNQUFNLENBQUNDLFNBQVAsSUFBb0IsT0FBT0QsTUFBTSxDQUFDQyxTQUFQLENBQWlCQyxjQUF4QixLQUEyQyxVQUFuRSxFQUErRTtBQUMzRUYsTUFBQUEsTUFBTSxDQUFDQyxTQUFQLENBQWlCQyxjQUFqQjtBQUNIOztBQUVEdEIsSUFBQUEsYUFBYTtBQUNoQixHQU5EOztBQVFBQSxFQUFBQSxhQUFhO0FBQ2hCLENBckREIiwic291cmNlc0NvbnRlbnQiOlsid2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBmdW5jdGlvbigpIHtcblxuICAgIGZ1bmN0aW9uIF9sb2FkQmVhY29uSlMob3B0aW9ucykge1xuICAgICAgICB2YXIgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7XG4gICAgICAgIHNjcmlwdC5zcmMgPSBvcHRpb25zLmZuVXJsO1xuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHNjcmlwdCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gX2luamVjdENvbmZpZygpIHtcbiAgICAgICAgdmFyIHNjcmlwdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCJbZm5jbHM9J2ZucGFyYW1zLWRlZGU3Y2M1LTE1ZmQtNGM3NS1hOWY0LTM2YzQzMGVlM2E5OSddXCIpO1xuICAgICAgICBpZiAoc2NyaXB0KSB7XG4gICAgICAgICAgICBpZiAoc2NyaXB0LnBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgICAgICBzY3JpcHQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChzY3JpcHQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7XG4gICAgICAgIHNjcmlwdC5pZCA9ICdmY29uZmlnJztcbiAgICAgICAgc2NyaXB0LnR5cGUgPSAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIHNjcmlwdC5zZXRBdHRyaWJ1dGUoJ2ZuY2xzJywgJ2ZucGFyYW1zLWRlZGU3Y2M1LTE1ZmQtNGM3NS1hOWY0LTM2YzQzMGVlM2E5OScpO1xuXG4gICAgICAgIHZhciBjb25maWd1cmF0aW9uID0ge1xuICAgICAgICAgICAgJ2YnOiBGcmF1ZE5ldENvbmZpZy5mLFxuICAgICAgICAgICAgJ3MnOiBGcmF1ZE5ldENvbmZpZy5zXG4gICAgICAgIH07XG4gICAgICAgIGlmKEZyYXVkTmV0Q29uZmlnLnNhbmRib3ggPT09ICcxJykge1xuICAgICAgICAgICAgY29uZmlndXJhdGlvbi5zYW5kYm94ID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNjcmlwdC50ZXh0ID0gSlNPTi5zdHJpbmdpZnkoY29uZmlndXJhdGlvbik7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoc2NyaXB0KTtcblxuICAgICAgICBjb25zdCBwYXlGb3JPcmRlckZvcm0gPSBkb2N1bWVudC5mb3Jtcy5vcmRlcl9yZXZpZXc7XG4gICAgICAgIGlmKHBheUZvck9yZGVyRm9ybSkge1xuICAgICAgICAgICAgY29uc3QgcHVpUGF5Rm9yT3JkZXJTZXNzaW9uSWQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbnB1dCcpO1xuICAgICAgICAgICAgcHVpUGF5Rm9yT3JkZXJTZXNzaW9uSWQuc2V0QXR0cmlidXRlKCd0eXBlJywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgcHVpUGF5Rm9yT3JkZXJTZXNzaW9uSWQuc2V0QXR0cmlidXRlKCduYW1lJywgJ3B1aV9wYXlfZm9yX29yZGVyX3Nlc3Npb25faWQnKTtcbiAgICAgICAgICAgIHB1aVBheUZvck9yZGVyU2Vzc2lvbklkLnNldEF0dHJpYnV0ZSgndmFsdWUnLCBGcmF1ZE5ldENvbmZpZy5mKTtcbiAgICAgICAgICAgIHBheUZvck9yZGVyRm9ybS5hcHBlbmRDaGlsZChwdWlQYXlGb3JPcmRlclNlc3Npb25JZCk7XG4gICAgICAgIH1cblxuICAgICAgICBfbG9hZEJlYWNvbkpTKHtmblVybDogXCJodHRwczovL2MucGF5cGFsLmNvbS9kYS9yL2ZiLmpzXCJ9KVxuICAgIH1cblxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2hvc3RlZF9maWVsZHNfbG9hZGVkJywgKGV2ZW50KSA9PiB7XG4gICAgICAgIGlmIChQQVlQQUwuYXN5bmNEYXRhICYmIHR5cGVvZiBQQVlQQUwuYXN5bmNEYXRhLmluaXRBbmRDb2xsZWN0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBQQVlQQUwuYXN5bmNEYXRhLmluaXRBbmRDb2xsZWN0KClcbiAgICAgICAgfVxuXG4gICAgICAgIF9pbmplY3RDb25maWcoKTtcbiAgICB9KTtcblxuICAgIF9pbmplY3RDb25maWcoKTtcbn0pXG5cbiJdLCJmaWxlIjoiNDkzLmpzIiwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///493\n")}},__webpack_exports__={};__webpack_modules__[493]()})();
modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ window.addEventListener('load', function() {
2
+
3
+ function _loadBeaconJS(options) {
4
+ var script = document.createElement('script');
5
+ script.src = options.fnUrl;
6
+ document.body.appendChild(script);
7
+ }
8
+
9
+ function _injectConfig() {
10
+ var script = document.querySelector("[fncls='fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99']");
11
+ if (script) {
12
+ if (script.parentNode) {
13
+ script.parentNode.removeChild(script);
14
+ }
15
+ }
16
+
17
+ script = document.createElement('script');
18
+ script.id = 'fconfig';
19
+ script.type = 'application/json';
20
+ script.setAttribute('fncls', 'fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99');
21
+
22
+ var configuration = {
23
+ 'f': FraudNetConfig.f,
24
+ 's': FraudNetConfig.s
25
+ };
26
+ if(FraudNetConfig.sandbox === '1') {
27
+ configuration.sandbox = true;
28
+ }
29
+
30
+ script.text = JSON.stringify(configuration);
31
+ document.body.appendChild(script);
32
+
33
+ const payForOrderForm = document.forms.order_review;
34
+ if(payForOrderForm) {
35
+ const puiPayForOrderSessionId = document.createElement('input');
36
+ puiPayForOrderSessionId.setAttribute('type', 'hidden');
37
+ puiPayForOrderSessionId.setAttribute('name', 'pui_pay_for_order_session_id');
38
+ puiPayForOrderSessionId.setAttribute('value', FraudNetConfig.f);
39
+ payForOrderForm.appendChild(puiPayForOrderSessionId);
40
+ }
41
+
42
+ _loadBeaconJS({fnUrl: "https://c.paypal.com/da/r/fb.js"})
43
+ }
44
+
45
+ document.addEventListener('hosted_fields_loaded', (event) => {
46
+ if (PAYPAL.asyncData && typeof PAYPAL.asyncData.initAndCollect === 'function') {
47
+ PAYPAL.asyncData.initAndCollect()
48
+ }
49
+
50
+ _injectConfig();
51
+ });
52
+
53
+ _injectConfig();
54
+ })
55
+
modules/ppcp-wc-gateway/services.php CHANGED
@@ -12,6 +12,7 @@ declare(strict_types=1);
12
  namespace WooCommerce\PayPalCommerce\WcGateway;
13
 
14
  use Psr\Container\ContainerInterface;
 
15
  use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
16
  use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
17
  use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
@@ -30,8 +31,16 @@ use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
30
  use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
31
  use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
32
  use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
 
 
 
 
 
 
33
  use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
34
  use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
 
 
35
  use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
36
  use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
37
  use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
@@ -46,7 +55,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
46
  use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
47
 
48
  return array(
49
- 'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
50
  $order_processor = $container->get( 'wcgateway.order-processor' );
51
  $settings_renderer = $container->get( 'wcgateway.settings.render' );
52
  $funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
@@ -63,6 +72,7 @@ return array(
63
  $order_endpoint = $container->get( 'api.endpoint.order' );
64
  $environment = $container->get( 'onboarding.environment' );
65
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
 
66
  return new PayPalGateway(
67
  $settings_renderer,
68
  $funding_source_renderer,
@@ -79,10 +89,11 @@ return array(
79
  $payment_token_repository,
80
  $logger,
81
  $payments_endpoint,
82
- $order_endpoint
 
83
  );
84
  },
85
- 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
86
  $order_processor = $container->get( 'wcgateway.order-processor' );
87
  $settings_renderer = $container->get( 'wcgateway.settings.render' );
88
  $authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
@@ -120,27 +131,27 @@ return array(
120
  $payments_endpoint
121
  );
122
  },
123
- 'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
124
  $session_handler = $container->get( 'session.handler' );
125
  $settings = $container->get( 'wcgateway.settings' );
126
  return new DisableGateways( $session_handler, $settings );
127
  },
128
- 'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
129
  $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
130
  $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
131
  return 'wc-settings' === $page && 'checkout' === $tab;
132
  },
133
 
134
- 'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
135
  if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
136
  return false;
137
  }
138
 
139
  $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
140
- return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID ), true );
141
  },
142
 
143
- 'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
144
  if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
145
  return '';
146
  }
@@ -151,33 +162,36 @@ return array(
151
  return $ppcp_tab ? $ppcp_tab : $section;
152
  },
153
 
154
- 'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
155
  return new Settings();
156
  },
157
- 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
158
  $state = $container->get( 'onboarding.state' );
159
  $settings = $container->get( 'wcgateway.settings' );
160
  return new ConnectAdminNotice( $state, $settings );
161
  },
162
- 'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice {
163
  $state = $container->get( 'onboarding.state' );
164
  $settings = $container->get( 'wcgateway.settings' );
165
  $is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' );
166
  $is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
167
  return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page );
168
  },
169
- 'wcgateway.notice.authorize-order-action' =>
170
  static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
171
  return new AuthorizeOrderActionNotice();
172
  },
173
- 'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
174
- return new SectionsRenderer( $container->get( 'wcgateway.current-ppcp-settings-page-id' ) );
 
 
 
175
  },
176
- 'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
177
  $settings = $container->get( 'wcgateway.settings' );
178
  return new SettingsStatus( $settings );
179
  },
180
- 'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
181
  $settings = $container->get( 'wcgateway.settings' );
182
  $state = $container->get( 'onboarding.state' );
183
  $fields = $container->get( 'wcgateway.settings.fields' );
@@ -197,7 +211,7 @@ return array(
197
  $page_id
198
  );
199
  },
200
- 'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
201
  $settings = $container->get( 'wcgateway.settings' );
202
  $fields = $container->get( 'wcgateway.settings.fields' );
203
  $webhook_registrar = $container->get( 'webhook.registrar' );
@@ -205,9 +219,21 @@ return array(
205
  $cache = new Cache( 'ppcp-paypal-bearer' );
206
  $bearer = $container->get( 'api.bearer' );
207
  $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
208
- return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer, $page_id );
 
 
 
 
 
 
 
 
 
 
 
 
209
  },
210
- 'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
211
 
212
  $session_handler = $container->get( 'session.handler' );
213
  $order_endpoint = $container->get( 'api.endpoint.order' );
@@ -218,6 +244,7 @@ return array(
218
  $environment = $container->get( 'onboarding.environment' );
219
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
220
  $subscription_helper = $container->get( 'subscription.helper' );
 
221
  return new OrderProcessor(
222
  $session_handler,
223
  $order_endpoint,
@@ -227,16 +254,17 @@ return array(
227
  $settings,
228
  $logger,
229
  $environment,
230
- $subscription_helper
 
231
  );
232
  },
233
- 'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
234
  $order_endpoint = $container->get( 'api.endpoint.order' );
235
  $payments_endpoint = $container->get( 'api.endpoint.payments' );
236
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
237
  return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger );
238
  },
239
- 'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
240
  $order_endpoint = $container->get( 'api.endpoint.order' );
241
  $payments_endpoint = $container->get( 'api.endpoint.payments' );
242
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
@@ -252,23 +280,23 @@ return array(
252
  $subscription_helper
253
  );
254
  },
255
- 'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
256
  $column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
257
  return new RenderAuthorizeAction( $column );
258
  },
259
- 'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
260
  $column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
261
  return new PaymentStatusOrderDetail( $column );
262
  },
263
- 'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
264
  $settings = $container->get( 'wcgateway.settings' );
265
  return new OrderTablePaymentStatusColumn( $settings );
266
  },
267
- 'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
268
  return new FeesRenderer();
269
  },
270
 
271
- 'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
272
 
273
  $state = $container->get( 'onboarding.state' );
274
  assert( $state instanceof State );
@@ -2044,7 +2072,7 @@ return array(
2044
  return $fields;
2045
  },
2046
 
2047
- 'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
2048
  return array(
2049
  'card' => _x( 'Credit or debit cards', 'Name of payment method', 'woocommerce-paypal-payments' ),
2050
  'credit' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
@@ -2062,28 +2090,28 @@ return array(
2062
  );
2063
  },
2064
 
2065
- 'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
2066
 
2067
  return new CheckoutPayPalAddressPreset(
2068
  $container->get( 'session.handler' )
2069
  );
2070
  },
2071
- 'wcgateway.url' => static function ( ContainerInterface $container ): string {
2072
  return plugins_url(
2073
  $container->get( 'wcgateway.relative-path' ),
2074
  dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
2075
  );
2076
  },
2077
- 'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
2078
  return 'modules/ppcp-wc-gateway/';
2079
  },
2080
- 'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
2081
  return plugin_dir_path(
2082
  dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
2083
  ) .
2084
  $container->get( 'wcgateway.relative-path' );
2085
  },
2086
- 'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
2087
  $gateway = $container->get( 'wcgateway.paypal-gateway' );
2088
  $endpoint = $container->get( 'api.endpoint.order' );
2089
  $prefix = $container->get( 'api.prefix' );
@@ -2094,41 +2122,102 @@ return array(
2094
  );
2095
  },
2096
 
2097
- 'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
2098
  return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
2099
  },
2100
 
2101
- 'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
2102
  return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
2103
  },
2104
 
2105
- 'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
2106
  $sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
2107
  $live_url_base = $container->get( 'wcgateway.transaction-url-live' );
2108
 
2109
  return new TransactionUrlProvider( $sandbox_url_base, $live_url_base );
2110
  },
2111
 
2112
- 'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
2113
 
2114
  $settings = $container->get( 'wcgateway.settings' );
2115
  $partner_endpoint = $container->get( 'api.endpoint.partners' );
2116
  return new DCCProductStatus( $settings, $partner_endpoint );
2117
  },
2118
 
2119
- 'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
2120
  return new MessagesDisclaimers(
2121
  $container->get( 'api.shop.country' )
2122
  );
2123
  },
2124
 
2125
- 'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
2126
  return new FundingSourceRenderer(
2127
  $container->get( 'wcgateway.settings' )
2128
  );
2129
  },
2130
-
2131
- 'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2132
  $settings = $container->get( 'wcgateway.settings' );
2133
 
2134
  /**
@@ -2140,7 +2229,7 @@ return array(
2140
  );
2141
  },
2142
 
2143
- 'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
2144
  try {
2145
  $token = $container->get( 'api.bearer' )->bearer();
2146
  return $token->vaulting_available();
@@ -2149,7 +2238,7 @@ return array(
2149
  }
2150
  },
2151
 
2152
- 'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
2153
  $vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' );
2154
 
2155
  if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) {
@@ -2171,7 +2260,7 @@ return array(
2171
  return $vaulting_label;
2172
  },
2173
 
2174
- 'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
2175
  $pay_later_label = '<span class="ppcp-pay-later-enabled-label">%s</span>';
2176
  $pay_later_label .= '<span class="ppcp-pay-later-disabled-label">';
2177
  $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' );
12
  namespace WooCommerce\PayPalCommerce\WcGateway;
13
 
14
  use Psr\Container\ContainerInterface;
15
+ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
17
  use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
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;
36
+ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSourceWebsiteId;
37
+ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFactory;
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;
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' );
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' );
76
  return new PayPalGateway(
77
  $settings_renderer,
78
  $funding_source_renderer,
89
  $payment_token_repository,
90
  $logger,
91
  $payments_endpoint,
92
+ $order_endpoint,
93
+ $api_shop_country
94
  );
95
  },
96
+ 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
97
  $order_processor = $container->get( 'wcgateway.order-processor' );
98
  $settings_renderer = $container->get( 'wcgateway.settings.render' );
99
  $authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
131
  $payments_endpoint
132
  );
133
  },
134
+ 'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
135
  $session_handler = $container->get( 'session.handler' );
136
  $settings = $container->get( 'wcgateway.settings' );
137
  return new DisableGateways( $session_handler, $settings );
138
  },
139
+ 'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
140
  $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
141
  $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
142
  return 'wc-settings' === $page && 'checkout' === $tab;
143
  },
144
 
145
+ 'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
146
  if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
147
  return false;
148
  }
149
 
150
  $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
151
+ return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID ), true );
152
  },
153
 
154
+ 'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
155
  if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
156
  return '';
157
  }
162
  return $ppcp_tab ? $ppcp_tab : $section;
163
  },
164
 
165
+ 'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
166
  return new Settings();
167
  },
168
+ 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
169
  $state = $container->get( 'onboarding.state' );
170
  $settings = $container->get( 'wcgateway.settings' );
171
  return new ConnectAdminNotice( $state, $settings );
172
  },
173
+ 'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice {
174
  $state = $container->get( 'onboarding.state' );
175
  $settings = $container->get( 'wcgateway.settings' );
176
  $is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' );
177
  $is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
178
  return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page );
179
  },
180
+ 'wcgateway.notice.authorize-order-action' =>
181
  static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
182
  return new AuthorizeOrderActionNotice();
183
  },
184
+ 'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
185
+ return new SectionsRenderer(
186
+ $container->get( 'wcgateway.current-ppcp-settings-page-id' ),
187
+ $container->get( 'api.shop.country' )
188
+ );
189
  },
190
+ 'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
191
  $settings = $container->get( 'wcgateway.settings' );
192
  return new SettingsStatus( $settings );
193
  },
194
+ 'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
195
  $settings = $container->get( 'wcgateway.settings' );
196
  $state = $container->get( 'onboarding.state' );
197
  $fields = $container->get( 'wcgateway.settings.fields' );
211
  $page_id
212
  );
213
  },
214
+ 'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
215
  $settings = $container->get( 'wcgateway.settings' );
216
  $fields = $container->get( 'wcgateway.settings.fields' );
217
  $webhook_registrar = $container->get( 'webhook.registrar' );
219
  $cache = new Cache( 'ppcp-paypal-bearer' );
220
  $bearer = $container->get( 'api.bearer' );
221
  $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
222
+ $signup_link_cache = $container->get( 'onboarding.signup-link-cache' );
223
+ $signup_link_ids = $container->get( 'onboarding.signup-link-ids' );
224
+ return new SettingsListener(
225
+ $settings,
226
+ $fields,
227
+ $webhook_registrar,
228
+ $cache,
229
+ $state,
230
+ $bearer,
231
+ $page_id,
232
+ $signup_link_cache,
233
+ $signup_link_ids
234
+ );
235
  },
236
+ 'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
237
 
238
  $session_handler = $container->get( 'session.handler' );
239
  $order_endpoint = $container->get( 'api.endpoint.order' );
244
  $environment = $container->get( 'onboarding.environment' );
245
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
246
  $subscription_helper = $container->get( 'subscription.helper' );
247
+ $order_helper = $container->get( 'api.order-helper' );
248
  return new OrderProcessor(
249
  $session_handler,
250
  $order_endpoint,
254
  $settings,
255
  $logger,
256
  $environment,
257
+ $subscription_helper,
258
+ $order_helper
259
  );
260
  },
261
+ 'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
262
  $order_endpoint = $container->get( 'api.endpoint.order' );
263
  $payments_endpoint = $container->get( 'api.endpoint.payments' );
264
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
265
  return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger );
266
  },
267
+ 'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
268
  $order_endpoint = $container->get( 'api.endpoint.order' );
269
  $payments_endpoint = $container->get( 'api.endpoint.payments' );
270
  $logger = $container->get( 'woocommerce.logger.woocommerce' );
280
  $subscription_helper
281
  );
282
  },
283
+ 'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
284
  $column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
285
  return new RenderAuthorizeAction( $column );
286
  },
287
+ 'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
288
  $column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
289
  return new PaymentStatusOrderDetail( $column );
290
  },
291
+ 'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
292
  $settings = $container->get( 'wcgateway.settings' );
293
  return new OrderTablePaymentStatusColumn( $settings );
294
  },
295
+ 'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
296
  return new FeesRenderer();
297
  },
298
 
299
+ 'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
300
 
301
  $state = $container->get( 'onboarding.state' );
302
  assert( $state instanceof State );
2072
  return $fields;
2073
  },
2074
 
2075
+ 'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
2076
  return array(
2077
  'card' => _x( 'Credit or debit cards', 'Name of payment method', 'woocommerce-paypal-payments' ),
2078
  'credit' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
2090
  );
2091
  },
2092
 
2093
+ 'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
2094
 
2095
  return new CheckoutPayPalAddressPreset(
2096
  $container->get( 'session.handler' )
2097
  );
2098
  },
2099
+ 'wcgateway.url' => static function ( ContainerInterface $container ): string {
2100
  return plugins_url(
2101
  $container->get( 'wcgateway.relative-path' ),
2102
  dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
2103
  );
2104
  },
2105
+ 'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
2106
  return 'modules/ppcp-wc-gateway/';
2107
  },
2108
+ 'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
2109
  return plugin_dir_path(
2110
  dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
2111
  ) .
2112
  $container->get( 'wcgateway.relative-path' );
2113
  },
2114
+ 'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
2115
  $gateway = $container->get( 'wcgateway.paypal-gateway' );
2116
  $endpoint = $container->get( 'api.endpoint.order' );
2117
  $prefix = $container->get( 'api.prefix' );
2122
  );
2123
  },
2124
 
2125
+ 'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
2126
  return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
2127
  },
2128
 
2129
+ 'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
2130
  return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
2131
  },
2132
 
2133
+ 'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
2134
  $sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
2135
  $live_url_base = $container->get( 'wcgateway.transaction-url-live' );
2136
 
2137
  return new TransactionUrlProvider( $sandbox_url_base, $live_url_base );
2138
  },
2139
 
2140
+ 'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
2141
 
2142
  $settings = $container->get( 'wcgateway.settings' );
2143
  $partner_endpoint = $container->get( 'api.endpoint.partners' );
2144
  return new DCCProductStatus( $settings, $partner_endpoint );
2145
  },
2146
 
2147
+ 'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
2148
  return new MessagesDisclaimers(
2149
  $container->get( 'api.shop.country' )
2150
  );
2151
  },
2152
 
2153
+ 'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
2154
  return new FundingSourceRenderer(
2155
  $container->get( 'wcgateway.settings' )
2156
  );
2157
  },
2158
+ 'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
2159
+ return new PayUponInvoiceOrderEndpoint(
2160
+ $container->get( 'api.host' ),
2161
+ $container->get( 'api.bearer' ),
2162
+ $container->get( 'api.factory.order' ),
2163
+ $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
2164
+ $container->get( 'woocommerce.logger.woocommerce' )
2165
+ );
2166
+ },
2167
+ 'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory {
2168
+ return new PaymentSourceFactory();
2169
+ },
2170
+ 'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
2171
+ return new PayUponInvoiceGateway(
2172
+ $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
2173
+ $container->get( 'api.factory.purchase-unit' ),
2174
+ $container->get( 'wcgateway.pay-upon-invoice-payment-source-factory' ),
2175
+ $container->get( 'onboarding.environment' ),
2176
+ $container->get( 'wcgateway.transaction-url-provider' ),
2177
+ $container->get( 'woocommerce.logger.woocommerce' ),
2178
+ $container->get( 'wcgateway.pay-upon-invoice-helper' )
2179
+ );
2180
+ },
2181
+ 'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
2182
+ return new FraudNetSessionId();
2183
+ },
2184
+ 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
2185
+ return new FraudNetSourceWebsiteId( $container->get( 'api.merchant_id' ) );
2186
+ },
2187
+ 'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
2188
+ $session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' );
2189
+ $source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' );
2190
+ return new FraudNet(
2191
+ (string) $session_id(),
2192
+ (string) $source_website_id()
2193
+ );
2194
+ },
2195
+ 'wcgateway.pay-upon-invoice-helper' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
2196
+ return new PayUponInvoiceHelper();
2197
+ },
2198
+ 'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
2199
+ return new PayUponInvoiceProductStatus(
2200
+ $container->get( 'wcgateway.settings' ),
2201
+ $container->get( 'api.endpoint.partners' )
2202
+ );
2203
+ },
2204
+ 'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
2205
+ return new PayUponInvoice(
2206
+ $container->get( 'wcgateway.url' ),
2207
+ $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
2208
+ $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
2209
+ $container->get( 'woocommerce.logger.woocommerce' ),
2210
+ $container->get( 'wcgateway.settings' ),
2211
+ $container->get( 'onboarding.environment' ),
2212
+ $container->get( 'ppcp.asset-version' ),
2213
+ $container->get( 'onboarding.state' ),
2214
+ $container->get( 'wcgateway.is-ppcp-settings-page' ),
2215
+ $container->get( 'wcgateway.current-ppcp-settings-page-id' ),
2216
+ $container->get( 'wcgateway.pay-upon-invoice-product-status' ),
2217
+ $container->get( 'wcgateway.pay-upon-invoice-helper' )
2218
+ );
2219
+ },
2220
+ 'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
2221
  $settings = $container->get( 'wcgateway.settings' );
2222
 
2223
  /**
2229
  );
2230
  },
2231
 
2232
+ 'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
2233
  try {
2234
  $token = $container->get( 'api.bearer' )->bearer();
2235
  return $token->vaulting_available();
2238
  }
2239
  },
2240
 
2241
+ 'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
2242
  $vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' );
2243
 
2244
  if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) {
2260
  return $vaulting_label;
2261
  },
2262
 
2263
+ 'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
2264
  $pay_later_label = '<span class="ppcp-pay-later-enabled-label">%s</span>';
2265
  $pay_later_label .= '<span class="ppcp-pay-later-disabled-label">';
2266
  $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' );
modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php CHANGED
@@ -12,13 +12,13 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
12
  use Psr\Log\LoggerInterface;
13
  use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
14
  use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
15
- use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
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\Processor\AuthorizedPaymentsProcessor;
23
  use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
24
  use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
@@ -160,6 +160,13 @@ class PayPalGateway extends \WC_Payment_Gateway {
160
  */
161
  private $logger;
162
 
 
 
 
 
 
 
 
163
  /**
164
  * PayPalGateway constructor.
165
  *
@@ -179,6 +186,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
179
  * @param LoggerInterface $logger The logger.
180
  * @param PaymentsEndpoint $payments_endpoint The payments endpoint.
181
  * @param OrderEndpoint $order_endpoint The order endpoint.
 
182
  */
183
  public function __construct(
184
  SettingsRenderer $settings_renderer,
@@ -196,7 +204,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
196
  PaymentTokenRepository $payment_token_repository,
197
  LoggerInterface $logger,
198
  PaymentsEndpoint $payments_endpoint,
199
- OrderEndpoint $order_endpoint
 
200
  ) {
201
 
202
  $this->id = self::ID;
@@ -277,6 +286,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
277
  $this->payments_endpoint = $payments_endpoint;
278
  $this->order_endpoint = $order_endpoint;
279
  $this->state = $state;
 
280
  }
281
 
282
  /**
@@ -342,6 +352,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
342
  if ( $this->is_paypal_tab() ) {
343
  return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
344
  }
 
 
 
 
345
  return __( 'PayPal', 'woocommerce-paypal-payments' );
346
  }
347
 
@@ -390,6 +404,19 @@ class PayPalGateway extends \WC_Payment_Gateway {
390
 
391
  }
392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  /**
394
  * Whether we are on the Webhooks Status tab.
395
  *
12
  use Psr\Log\LoggerInterface;
13
  use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
14
  use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
 
15
  use WooCommerce\PayPalCommerce\Onboarding\Environment;
16
  use WooCommerce\PayPalCommerce\Onboarding\State;
17
  use WooCommerce\PayPalCommerce\Session\SessionHandler;
18
  use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
19
  use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
20
  use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
21
+ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
22
  use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
23
  use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
24
  use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
160
  */
161
  private $logger;
162
 
163
+ /**
164
+ * The api shop country.
165
+ *
166
+ * @var string
167
+ */
168
+ protected $api_shop_country;
169
+
170
  /**
171
  * PayPalGateway constructor.
172
  *
186
  * @param LoggerInterface $logger The logger.
187
  * @param PaymentsEndpoint $payments_endpoint The payments endpoint.
188
  * @param OrderEndpoint $order_endpoint The order endpoint.
189
+ * @param string $api_shop_country The api shop country.
190
  */
191
  public function __construct(
192
  SettingsRenderer $settings_renderer,
204
  PaymentTokenRepository $payment_token_repository,
205
  LoggerInterface $logger,
206
  PaymentsEndpoint $payments_endpoint,
207
+ OrderEndpoint $order_endpoint,
208
+ string $api_shop_country
209
  ) {
210
 
211
  $this->id = self::ID;
286
  $this->payments_endpoint = $payments_endpoint;
287
  $this->order_endpoint = $order_endpoint;
288
  $this->state = $state;
289
+ $this->api_shop_country = $api_shop_country;
290
  }
291
 
292
  /**
352
  if ( $this->is_paypal_tab() ) {
353
  return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
354
  }
355
+ if ( $this->is_pui_tab() ) {
356
+ return __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' );
357
+ }
358
+
359
  return __( 'PayPal', 'woocommerce-paypal-payments' );
360
  }
361
 
404
 
405
  }
406
 
407
+ /**
408
+ * Whether we are on the PUI tab.
409
+ *
410
+ * @return bool
411
+ */
412
+ private function is_pui_tab():bool {
413
+ if ( 'DE' !== $this->api_shop_country ) {
414
+ return false;
415
+ }
416
+
417
+ return is_admin() && PayUponInvoiceGateway::ID === $this->page_id;
418
+ }
419
+
420
  /**
421
  * Whether we are on the Webhooks Status tab.
422
  *
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Fraudnet entity.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
12
+ /**
13
+ * Class FraudNet
14
+ */
15
+ class FraudNet {
16
+
17
+ /**
18
+ * The session ID.
19
+ *
20
+ * @var string
21
+ */
22
+ protected $session_id;
23
+
24
+ /**
25
+ * The source website ID.
26
+ *
27
+ * @var string
28
+ */
29
+ protected $source_website_id;
30
+
31
+ /**
32
+ * FraudNet constructor.
33
+ *
34
+ * @param string $session_id The session ID.
35
+ * @param string $source_website_id The source website ID.
36
+ */
37
+ public function __construct( string $session_id, string $source_website_id ) {
38
+ $this->session_id = $session_id;
39
+ $this->source_website_id = $source_website_id;
40
+ }
41
+
42
+ /**
43
+ * Returns the session ID.
44
+ *
45
+ * @return string
46
+ */
47
+ public function session_id(): string {
48
+ return $this->session_id;
49
+ }
50
+
51
+ /**
52
+ * Returns the source website id.
53
+ *
54
+ * @return string
55
+ */
56
+ public function source_website_id(): string {
57
+ return $this->source_website_id;
58
+ }
59
+ }
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Fraudnet session id.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
12
+ use Exception;
13
+
14
+ /**
15
+ * Class FraudNetSessionId.
16
+ */
17
+ class FraudNetSessionId {
18
+
19
+ /**
20
+ * Generates a session ID or use the existing one from WC session.
21
+ *
22
+ * @return array|string
23
+ * @throws Exception When there is a problem with the session ID.
24
+ */
25
+ public function __invoke() {
26
+ if ( WC()->session === null ) {
27
+ return '';
28
+ }
29
+
30
+ if ( WC()->session->get( 'ppcp_fraudnet_session_id' ) ) {
31
+ return WC()->session->get( 'ppcp_fraudnet_session_id' );
32
+ }
33
+
34
+ if ( isset( $_GET['pay_for_order'] ) && 'true' === $_GET['pay_for_order'] ) {
35
+ $pui_pay_for_order_session_id = filter_input( INPUT_POST, 'pui_pay_for_order_session_id', FILTER_SANITIZE_STRING );
36
+ if ( $pui_pay_for_order_session_id && '' !== $pui_pay_for_order_session_id ) {
37
+ return $pui_pay_for_order_session_id;
38
+ }
39
+ }
40
+
41
+ $session_id = bin2hex( random_bytes( 16 ) );
42
+ WC()->session->set( 'ppcp_fraudnet_session_id', $session_id );
43
+
44
+ return $session_id;
45
+ }
46
+ }
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Fraudnet source website ID.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
12
+ /**
13
+ * Class FraudNetSourceWebsiteId.
14
+ */
15
+ class FraudNetSourceWebsiteId {
16
+
17
+ /**
18
+ * The merchant id.
19
+ *
20
+ * @var string
21
+ */
22
+ protected $api_merchant_id;
23
+
24
+ /**
25
+ * FraudNetSourceWebsiteId constructor.
26
+ *
27
+ * @param string $api_merchant_id The merchant id.
28
+ */
29
+ public function __construct( string $api_merchant_id ) {
30
+ $this->api_merchant_id = $api_merchant_id;
31
+ }
32
+
33
+ /**
34
+ * Returns the source website ID.
35
+ *
36
+ * @return string
37
+ */
38
+ public function __invoke() {
39
+ return "{$this->api_merchant_id}_checkout-page";
40
+ }
41
+ }
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PUI integration.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
12
+ use Psr\Log\LoggerInterface;
13
+ use WC_Order;
14
+ use WC_Order_Item;
15
+ use WC_Order_Item_Product;
16
+ use WC_Product;
17
+ use WC_Product_Variable;
18
+ use WC_Product_Variation;
19
+ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
20
+ use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
21
+ use WooCommerce\PayPalCommerce\Onboarding\Environment;
22
+ use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
23
+ use WooCommerce\PayPalCommerce\Onboarding\State;
24
+ use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
25
+ use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
26
+ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
27
+ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
28
+ use WP_Error;
29
+
30
+ /**
31
+ * Class PayUponInvoice.
32
+ */
33
+ class PayUponInvoice {
34
+
35
+ use TransactionIdHandlingTrait;
36
+
37
+ /**
38
+ * The module URL.
39
+ *
40
+ * @var string
41
+ */
42
+ protected $module_url;
43
+
44
+ /**
45
+ * The FraudNet entity.
46
+ *
47
+ * @var FraudNet
48
+ */
49
+ protected $fraud_net;
50
+
51
+ /**
52
+ * The pui order endpoint.
53
+ *
54
+ * @var PayUponInvoiceOrderEndpoint
55
+ */
56
+ protected $pui_order_endpoint;
57
+
58
+ /**
59
+ * The logger.
60
+ *
61
+ * @var LoggerInterface
62
+ */
63
+ protected $logger;
64
+
65
+ /**
66
+ * The settings.
67
+ *
68
+ * @var Settings
69
+ */
70
+ protected $settings;
71
+
72
+ /**
73
+ * The environment.
74
+ *
75
+ * @var Environment
76
+ */
77
+ protected $environment;
78
+
79
+ /**
80
+ * The asset version.
81
+ *
82
+ * @var string
83
+ */
84
+ protected $asset_version;
85
+
86
+ /**
87
+ * The PUI helper.
88
+ *
89
+ * @var PayUponInvoiceHelper
90
+ */
91
+ protected $pui_helper;
92
+
93
+ /**
94
+ * The onboarding state.
95
+ *
96
+ * @var State
97
+ */
98
+ protected $state;
99
+
100
+ /**
101
+ * Whether the current page is the PPCP settings page.
102
+ *
103
+ * @var bool
104
+ */
105
+ protected $is_ppcp_settings_page;
106
+
107
+ /**
108
+ * Current PayPal settings page id.
109
+ *
110
+ * @var string
111
+ */
112
+ protected $current_ppcp_settings_page_id;
113
+
114
+ /**
115
+ * PUI seller product status.
116
+ *
117
+ * @var PayUponInvoiceProductStatus
118
+ */
119
+ protected $pui_product_status;
120
+
121
+ /**
122
+ * PayUponInvoice constructor.
123
+ *
124
+ * @param string $module_url The module URL.
125
+ * @param FraudNet $fraud_net The FraudNet entity.
126
+ * @param PayUponInvoiceOrderEndpoint $pui_order_endpoint The PUI order endpoint.
127
+ * @param LoggerInterface $logger The logger.
128
+ * @param Settings $settings The settings.
129
+ * @param Environment $environment The environment.
130
+ * @param string $asset_version The asset version.
131
+ * @param State $state The onboarding state.
132
+ * @param bool $is_ppcp_settings_page Whether page is PayPal settings poge.
133
+ * @param string $current_ppcp_settings_page_id Current PayPal settings page id.
134
+ * @param PayUponInvoiceProductStatus $pui_product_status The PUI product status.
135
+ * @param PayUponInvoiceHelper $pui_helper The PUI helper.
136
+ */
137
+ public function __construct(
138
+ string $module_url,
139
+ FraudNet $fraud_net,
140
+ PayUponInvoiceOrderEndpoint $pui_order_endpoint,
141
+ LoggerInterface $logger,
142
+ Settings $settings,
143
+ Environment $environment,
144
+ string $asset_version,
145
+ State $state,
146
+ bool $is_ppcp_settings_page,
147
+ string $current_ppcp_settings_page_id,
148
+ PayUponInvoiceProductStatus $pui_product_status,
149
+ PayUponInvoiceHelper $pui_helper
150
+ ) {
151
+ $this->module_url = $module_url;
152
+ $this->fraud_net = $fraud_net;
153
+ $this->pui_order_endpoint = $pui_order_endpoint;
154
+ $this->logger = $logger;
155
+ $this->settings = $settings;
156
+ $this->environment = $environment;
157
+ $this->asset_version = $asset_version;
158
+ $this->state = $state;
159
+ $this->is_ppcp_settings_page = $is_ppcp_settings_page;
160
+ $this->current_ppcp_settings_page_id = $current_ppcp_settings_page_id;
161
+ $this->pui_product_status = $pui_product_status;
162
+ $this->pui_helper = $pui_helper;
163
+ }
164
+
165
+ /**
166
+ * Initializes PUI integration.
167
+ *
168
+ * @throws NotFoundException When setting is not found.
169
+ */
170
+ public function init(): void {
171
+ add_filter(
172
+ 'ppcp_partner_referrals_data',
173
+ function ( array $data ): array {
174
+ if ( $this->settings->has( 'ppcp-onboarding-pui' ) && $this->settings->get( 'ppcp-onboarding-pui' ) !== '1' ) {
175
+ return $data;
176
+ }
177
+
178
+ $data['business_entity'] = array(
179
+ 'business_type' => array(
180
+ 'type' => 'PRIVATE_CORPORATION',
181
+ ),
182
+ 'addresses' => array(
183
+ array(
184
+ 'address_line_1' => WC()->countries->get_base_address(),
185
+ 'admin_area_1' => WC()->countries->get_base_city(),
186
+ 'postal_code' => WC()->countries->get_base_postcode(),
187
+ 'country_code' => WC()->countries->get_base_country(),
188
+ 'type' => 'WORK',
189
+ ),
190
+ ),
191
+ );
192
+
193
+ if ( in_array( 'PPCP', $data['products'], true ) ) {
194
+ $data['products'][] = 'PAYMENT_METHODS';
195
+ } elseif ( in_array( 'EXPRESS_CHECKOUT', $data['products'], true ) ) {
196
+ $data['products'][0] = 'PAYMENT_METHODS';
197
+ }
198
+ $data['capabilities'][] = 'PAY_UPON_INVOICE';
199
+
200
+ return $data;
201
+ }
202
+ );
203
+
204
+ add_action(
205
+ 'wp_enqueue_scripts',
206
+ array( $this, 'register_assets' )
207
+ );
208
+
209
+ add_action(
210
+ 'ppcp_payment_capture_completed_webhook_handler',
211
+ function ( WC_Order $wc_order, string $order_id ) {
212
+ try {
213
+ $payment_instructions = $this->pui_order_endpoint->order_payment_instructions( $order_id );
214
+ $wc_order->update_meta_data(
215
+ 'ppcp_ratepay_payment_instructions_payment_reference',
216
+ $payment_instructions
217
+ );
218
+ $wc_order->save_meta_data();
219
+ $this->logger->info( "Ratepay payment instructions added to order #{$wc_order->get_id()}." );
220
+
221
+ } catch ( RuntimeException $exception ) {
222
+ $this->logger->error( $exception->getMessage() );
223
+ }
224
+ },
225
+ 10,
226
+ 2
227
+ );
228
+
229
+ add_action(
230
+ 'woocommerce_email_before_order_table',
231
+ function( WC_Order $order, bool $sent_to_admin ) {
232
+ if ( ! $sent_to_admin && PayUponInvoiceGateway::ID === $order->get_payment_method() && $order->has_status( 'processing' ) ) {
233
+ $this->logger->info( "Adding Ratepay payment instructions to email for order #{$order->get_id()}." );
234
+
235
+ $instructions = $order->get_meta( 'ppcp_ratepay_payment_instructions_payment_reference' );
236
+
237
+ $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
238
+ $merchant_name = $gateway_settings['brand_name'] ?? '';
239
+
240
+ $order_date = $order->get_date_created();
241
+ if ( null === $order_date ) {
242
+ $this->logger->error( 'Could not get WC order date for Ratepay payment instructions.' );
243
+ return;
244
+ }
245
+
246
+ $order_purchase_date = $order_date->date( 'd-m-Y' );
247
+ $order_time = $order_date->date( 'H:i:s' );
248
+ $order_date = $order_date->date( 'd-m-Y H:i:s' );
249
+
250
+ $thirty_days_date = strtotime( $order_date . ' +30 days' );
251
+ if ( false === $thirty_days_date ) {
252
+ $this->logger->error( 'Could not create +30 days date from WC order date.' );
253
+ return;
254
+ }
255
+ $order_date_30d = gmdate( 'd-m-Y', $thirty_days_date );
256
+
257
+ $payment_reference = $instructions[0] ?? '';
258
+ $bic = $instructions[1]->bic ?? '';
259
+ $bank_name = $instructions[1]->bank_name ?? '';
260
+ $iban = $instructions[1]->iban ?? '';
261
+ $account_holder_name = $instructions[1]->account_holder_name ?? '';
262
+
263
+ echo wp_kses_post( "<p>Für Ihre Bestellung #{$order->get_id()} ({$order_purchase_date} $order_time) bei {$merchant_name} haben Sie die Zahlung mittels “Rechnungskauf mit Ratepay“ gewählt." );
264
+ echo '<br>Bitte benutzen Sie die folgenden Informationen für Ihre Überweisung:</br>';
265
+ echo wp_kses_post( "<p>Bitte überweisen Sie den Betrag in Höhe von {$order->get_currency()}{$order->get_total()} bis zum {$order_date_30d} auf das unten angegebene Konto. Wichtig: Bitte geben Sie unbedingt als Verwendungszweck {$payment_reference} an, sonst kann die Zahlung nicht zugeordnet werden.</p>" );
266
+
267
+ echo '<ul>';
268
+ echo wp_kses_post( "<li>Empfänger: {$account_holder_name}</li>" );
269
+ echo wp_kses_post( "<li>IBAN: {$iban}</li>" );
270
+ echo wp_kses_post( "<li>BIC: {$bic}</li>" );
271
+ echo wp_kses_post( "<li>Name der Bank: {$bank_name}</li>" );
272
+ echo wp_kses_post( "<li>Verwendungszweck: {$payment_reference}</li>" );
273
+ echo '</ul>';
274
+
275
+ echo wp_kses_post( "<p>{$merchant_name} hat die Forderung gegen Sie an die PayPal (Europe) S.à r.l. et Cie, S.C.A. abgetreten, die wiederum die Forderung an Ratepay GmbH abgetreten hat. Zahlungen mit schuldbefreiender Wirkung können nur an die Ratepay GmbH geleistet werden.</p>" );
276
+
277
+ echo '<p>Mit freundlichen Grüßen';
278
+ echo '<br>';
279
+ echo wp_kses_post( "{$merchant_name}</p>" );
280
+ }
281
+ },
282
+ 10,
283
+ 3
284
+ );
285
+
286
+ add_filter(
287
+ 'woocommerce_gateway_description',
288
+ function( string $description, string $id ): string {
289
+ if ( PayUponInvoiceGateway::ID === $id ) {
290
+ ob_start();
291
+
292
+ $site_country_code = explode( '-', get_bloginfo( 'language' ) )[0] ?? '';
293
+
294
+ echo '<div style="padding: 20px 0;">';
295
+
296
+ woocommerce_form_field(
297
+ 'billing_birth_date',
298
+ array(
299
+ 'type' => 'date',
300
+ 'label' => 'de' === $site_country_code ? 'Geburtsdatum' : 'Birth date',
301
+ 'class' => array( 'form-row-wide' ),
302
+ 'required' => true,
303
+ 'clear' => true,
304
+ )
305
+ );
306
+
307
+ echo '</div><div>';
308
+
309
+ // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
310
+ $button_text = apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) );
311
+
312
+ if ( 'de' === $site_country_code ) {
313
+ echo wp_kses_post(
314
+ 'Mit Klicken auf ' . $button_text . ' akzeptieren Sie die <a href="https://www.ratepay.com/legal-payment-terms" target="_blank">Ratepay Zahlungsbedingungen</a> und erklären sich mit der Durchführung einer <a href="https://www.ratepay.com/legal-payment-dataprivacy" target="_blank">Risikoprüfung durch Ratepay</a>, unseren Partner, einverstanden. Sie akzeptieren auch PayPals <a href="https://www.paypal.com/de/webapps/mpp/ua/privacy-full?locale.x=de_DE&_ga=1.228729434.718583817.1563460395" target="_blank">Datenschutzerklärung</a>. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.'
315
+ );
316
+ } else {
317
+ echo wp_kses_post(
318
+ 'By clicking on ' . $button_text . ', you agree to the <a href="https://www.ratepay.com/legal-payment-terms" target="_blank">terms of payment</a> and <a href="https://www.ratepay.com/legal-payment-dataprivacy">performance of a risk check</a> from the payment partner, Ratepay. You also agree to PayPal’s <a href="https://www.paypal.com/de/webapps/mpp/ua/privacy-full?locale.x=eng_DE&_ga=1.267010504.718583817.1563460395">privacy statement</a>. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.'
319
+ );
320
+ }
321
+ echo '</div>';
322
+
323
+ $description .= ob_get_clean() ?: '';
324
+ }
325
+
326
+ return $description;
327
+ },
328
+ 10,
329
+ 2
330
+ );
331
+
332
+ add_action(
333
+ 'woocommerce_after_checkout_validation',
334
+ function( array $fields, WP_Error $errors ) {
335
+ $payment_method = filter_input( INPUT_POST, 'payment_method', FILTER_SANITIZE_STRING );
336
+ if ( PayUponInvoiceGateway::ID !== $payment_method ) {
337
+ return;
338
+ }
339
+
340
+ if ( 'DE' !== $fields['billing_country'] ) {
341
+ $errors->add( 'validation', __( 'Billing country not available.', 'woocommerce-paypal-payments' ) );
342
+ }
343
+
344
+ $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING );
345
+ if ( ( $birth_date && ! $this->pui_helper->validate_birth_date( $birth_date ) ) || $birth_date === '' ) {
346
+ $errors->add( 'validation', __( 'Invalid birth date.', 'woocommerce-paypal-payments' ) );
347
+ }
348
+
349
+ $national_number = filter_input( INPUT_POST, 'billing_phone', FILTER_SANITIZE_STRING );
350
+ if ( $national_number ) {
351
+ $numeric_phone_number = preg_replace( '/[^0-9]/', '', $national_number );
352
+ if ( $numeric_phone_number && ! preg_match( '/^[0-9]{1,14}?$/', $numeric_phone_number ) ) {
353
+ $errors->add( 'validation', __( 'Phone number size must be between 1 and 14', 'woocommerce-paypal-payments' ) );
354
+ }
355
+ }
356
+ },
357
+ 10,
358
+ 2
359
+ );
360
+
361
+ add_filter(
362
+ 'woocommerce_available_payment_gateways',
363
+ function ( array $methods ): array {
364
+ if ( State::STATE_ONBOARDED !== $this->state->current_state() ) {
365
+ return $methods;
366
+ }
367
+
368
+ if (
369
+ ! $this->pui_product_status->pui_is_active()
370
+ || ! $this->pui_helper->is_checkout_ready_for_pui()
371
+ ) {
372
+ unset( $methods[ PayUponInvoiceGateway::ID ] );
373
+ }
374
+
375
+ return $methods;
376
+ }
377
+ );
378
+
379
+ add_action(
380
+ 'woocommerce_settings_checkout',
381
+ function () {
382
+ if (
383
+ PayUponInvoiceGateway::ID === $this->current_ppcp_settings_page_id
384
+ && ! $this->pui_product_status->pui_is_active()
385
+ ) {
386
+ $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
387
+ $gateway_enabled = $gateway_settings['enabled'] ?? '';
388
+ if ( 'yes' === $gateway_enabled ) {
389
+ $gateway_settings['enabled'] = 'no';
390
+ update_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings', $gateway_settings );
391
+ $redirect_url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-pay-upon-invoice-gateway' );
392
+ wp_safe_redirect( $redirect_url );
393
+ exit;
394
+ }
395
+
396
+ printf(
397
+ '<div class="notice notice-error"><p>%1$s</p></div>',
398
+ esc_html__( 'Could not enable gateway because the connected PayPal account is not activated for Pay upon Invoice. Reconnect your account while Onboard with Pay Upon Invoice is selected to try again.', 'woocommerce-paypal-payments' )
399
+ );
400
+ }
401
+ }
402
+ );
403
+
404
+ add_action(
405
+ 'woocommerce_update_options_checkout_ppcp-pay-upon-invoice-gateway',
406
+ function () {
407
+ $customer_service_instructions = filter_input( INPUT_POST, 'woocommerce_ppcp-pay-upon-invoice-gateway_customer_service_instructions', FILTER_SANITIZE_STRING );
408
+ if ( '' === $customer_service_instructions ) {
409
+ $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
410
+ $gateway_enabled = $gateway_settings['enabled'] ?? '';
411
+ if ( 'yes' === $gateway_enabled ) {
412
+ $gateway_settings['enabled'] = 'no';
413
+ update_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings', $gateway_settings );
414
+
415
+ $redirect_url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-pay-upon-invoice-gateway' );
416
+ wp_safe_redirect( $redirect_url );
417
+ exit;
418
+ }
419
+ }
420
+ }
421
+ );
422
+
423
+ add_action(
424
+ 'woocommerce_settings_checkout',
425
+ function() {
426
+ if (
427
+ PayUponInvoiceGateway::ID === $this->current_ppcp_settings_page_id
428
+ && $this->pui_product_status->pui_is_active()
429
+ ) {
430
+ $error_messages = array();
431
+ $pui_gateway = WC()->payment_gateways->payment_gateways()[ PayUponInvoiceGateway::ID ];
432
+ if ( $pui_gateway->get_option( 'logo_url' ) === '' ) {
433
+ $error_messages[] = esc_html__( 'Could not enable gateway because "Logo URL" field is empty.', 'woocommerce-paypal-payments' );
434
+ }
435
+ if ( $pui_gateway->get_option( 'customer_service_instructions' ) === '' ) {
436
+ $error_messages[] = esc_html__( 'Could not enable gateway because "Customer service instructions" field is empty.', 'woocommerce-paypal-payments' );
437
+ }
438
+ if ( count( $error_messages ) > 0 ) { ?>
439
+ <div class="notice notice-error">
440
+ <?php
441
+ array_map(
442
+ static function( $message ) {
443
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
444
+ echo '<p>' . $message . '</p>';
445
+ },
446
+ $error_messages
447
+ )
448
+ ?>
449
+ </div>
450
+ <?php
451
+ }
452
+ }
453
+ }
454
+ );
455
+
456
+ add_action(
457
+ 'add_meta_boxes',
458
+ function( string $post_type ) {
459
+ if ( $post_type === 'shop_order' ) {
460
+ $post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_STRING );
461
+ $order = wc_get_order( $post_id );
462
+ if ( is_a( $order, WC_Order::class ) && $order->get_payment_method() === 'ppcp-pay-upon-invoice-gateway' ) {
463
+ $instructions = $order->get_meta( 'ppcp_ratepay_payment_instructions_payment_reference' );
464
+ if ( $instructions ) {
465
+ add_meta_box(
466
+ 'ppcp_pui_ratepay_payment_instructions',
467
+ __( 'RatePay payment instructions', 'woocommerce-paypal-payments' ),
468
+ function() use ( $instructions ) {
469
+ $payment_reference = $instructions[0] ?? '';
470
+ $bic = $instructions[1]->bic ?? '';
471
+ $bank_name = $instructions[1]->bank_name ?? '';
472
+ $iban = $instructions[1]->iban ?? '';
473
+ $account_holder_name = $instructions[1]->account_holder_name ?? '';
474
+
475
+ echo '<ul>';
476
+ echo wp_kses_post( "<li>Empfänger: {$account_holder_name}</li>" );
477
+ echo wp_kses_post( "<li>IBAN: {$iban}</li>" );
478
+ echo wp_kses_post( "<li>BIC: {$bic}</li>" );
479
+ echo wp_kses_post( "<li>Name der Bank: {$bank_name}</li>" );
480
+ echo wp_kses_post( "<li>Verwendungszweck: {$payment_reference}</li>" );
481
+ echo '</ul>';
482
+ },
483
+ $post_type,
484
+ 'side',
485
+ 'high'
486
+ );
487
+ }
488
+ }
489
+ }
490
+ }
491
+ );
492
+ }
493
+
494
+ /**
495
+ * Registers PUI assets.
496
+ */
497
+ public function register_assets(): void {
498
+ wp_enqueue_script(
499
+ 'ppcp-pay-upon-invoice',
500
+ trailingslashit( $this->module_url ) . 'assets/js/pay-upon-invoice.js',
501
+ array(),
502
+ $this->asset_version
503
+ );
504
+
505
+ wp_localize_script(
506
+ 'ppcp-pay-upon-invoice',
507
+ 'FraudNetConfig',
508
+ array(
509
+ 'f' => $this->fraud_net->session_id(),
510
+ 's' => $this->fraud_net->source_website_id(),
511
+ 'sandbox' => $this->environment->current_environment_is( Environment::SANDBOX ),
512
+ )
513
+ );
514
+ }
515
+ }
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Pay upon invoice Gateway
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
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
+
26
+ /**
27
+ * Class PayUponInvoiceGateway.
28
+ */
29
+ class PayUponInvoiceGateway extends WC_Payment_Gateway {
30
+
31
+ use OrderMetaTrait;
32
+
33
+ const ID = 'ppcp-pay-upon-invoice-gateway';
34
+
35
+ /**
36
+ * The order endpoint.
37
+ *
38
+ * @var PayUponInvoiceOrderEndpoint
39
+ */
40
+ protected $order_endpoint;
41
+
42
+ /**
43
+ * The purchase unit factory.
44
+ *
45
+ * @var PurchaseUnitFactory
46
+ */
47
+ protected $purchase_unit_factory;
48
+
49
+ /**
50
+ * The payment source factory.
51
+ *
52
+ * @var PaymentSourceFactory
53
+ */
54
+ protected $payment_source_factory;
55
+
56
+ /**
57
+ * The environment.
58
+ *
59
+ * @var Environment
60
+ */
61
+ protected $environment;
62
+
63
+ /**
64
+ * The transaction url provider.
65
+ *
66
+ * @var TransactionUrlProvider
67
+ */
68
+ protected $transaction_url_provider;
69
+
70
+ /**
71
+ * The logger interface.
72
+ *
73
+ * @var LoggerInterface
74
+ */
75
+ protected $logger;
76
+
77
+ /**
78
+ * The PUI helper.
79
+ *
80
+ * @var PayUponInvoiceHelper
81
+ */
82
+ protected $pui_helper;
83
+
84
+ /**
85
+ * PayUponInvoiceGateway constructor.
86
+ *
87
+ * @param PayUponInvoiceOrderEndpoint $order_endpoint The order endpoint.
88
+ * @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
89
+ * @param PaymentSourceFactory $payment_source_factory The payment source factory.
90
+ * @param Environment $environment The environment.
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,
97
+ PurchaseUnitFactory $purchase_unit_factory,
98
+ PaymentSourceFactory $payment_source_factory,
99
+ Environment $environment,
100
+ TransactionUrlProvider $transaction_url_provider,
101
+ LoggerInterface $logger,
102
+ PayUponInvoiceHelper $pui_helper
103
+ ) {
104
+ $this->id = self::ID;
105
+
106
+ $this->method_title = __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' );
107
+ $this->method_description = __( 'Pay upon Invoice is an invoice payment method in Germany. It is a local buy now, pay later payment method that allows the buyer to place an order, receive the goods, try them, verify they are in good order, and then pay the invoice within 30 days.', 'woocommerce-paypal-payments' );
108
+
109
+ $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
110
+ $this->title = $gateway_settings['title'] ?? $this->method_title;
111
+ $this->description = $gateway_settings['description'] ?? __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' );
112
+
113
+ $this->init_form_fields();
114
+ $this->init_settings();
115
+
116
+ add_action(
117
+ 'woocommerce_update_options_payment_gateways_' . $this->id,
118
+ array(
119
+ $this,
120
+ 'process_admin_options',
121
+ )
122
+ );
123
+
124
+ $this->order_endpoint = $order_endpoint;
125
+ $this->purchase_unit_factory = $purchase_unit_factory;
126
+ $this->payment_source_factory = $payment_source_factory;
127
+ $this->logger = $logger;
128
+ $this->environment = $environment;
129
+ $this->transaction_url_provider = $transaction_url_provider;
130
+ $this->pui_helper = $pui_helper;
131
+ }
132
+
133
+ /**
134
+ * Initialize the form fields.
135
+ */
136
+ public function init_form_fields() {
137
+ $this->form_fields = array(
138
+ 'enabled' => array(
139
+ 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
140
+ 'type' => 'checkbox',
141
+ 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
142
+ 'default' => 'no',
143
+ 'desc_tip' => true,
144
+ 'description' => __( 'Enable/Disable Pay Upon Invoice payment gateway.', 'woocommerce-paypal-payments' ),
145
+ ),
146
+ 'title' => array(
147
+ 'title' => __( 'Title', 'woocommerce-paypal-payments' ),
148
+ 'type' => 'text',
149
+ 'default' => $this->title,
150
+ 'desc_tip' => true,
151
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
152
+ ),
153
+ 'description' => array(
154
+ 'title' => __( 'Description', 'woocommerce-paypal-payments' ),
155
+ 'type' => 'text',
156
+ 'default' => $this->description,
157
+ 'desc_tip' => true,
158
+ 'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
159
+ ),
160
+ 'experience_context' => array(
161
+ 'title' => __( 'Experience Context', 'woocommerce-paypal-payments' ),
162
+ 'type' => 'title',
163
+ 'description' => __( "Specify brand name, logo and customer service instructions to be presented on Ratepay's payment instructions.", 'woocommerce-paypal-payments' ),
164
+ ),
165
+ 'brand_name' => array(
166
+ 'title' => __( 'Brand name', 'woocommerce-paypal-payments' ),
167
+ 'type' => 'text',
168
+ 'default' => get_bloginfo( 'name' ) ?? '',
169
+ 'desc_tip' => true,
170
+ 'description' => __( 'Merchant name displayed in Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
171
+ ),
172
+ 'logo_url' => array(
173
+ 'title' => __( 'Logo URL', 'woocommerce-paypal-payments' ),
174
+ 'type' => 'url',
175
+ 'default' => '',
176
+ 'desc_tip' => true,
177
+ 'description' => __( 'Logo to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
178
+ ),
179
+ 'customer_service_instructions' => array(
180
+ 'title' => __( 'Customer service instructions', 'woocommerce-paypal-payments' ),
181
+ 'type' => 'text',
182
+ 'default' => '',
183
+ 'desc_tip' => true,
184
+ 'description' => __( 'Customer service instructions to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
185
+ ),
186
+ );
187
+ }
188
+
189
+ /**
190
+ * Processes the order.
191
+ *
192
+ * @param int $order_id The WC order ID.
193
+ * @return array
194
+ */
195
+ public function process_payment( $order_id ) {
196
+ $wc_order = wc_get_order( $order_id );
197
+ $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING ) ?? '';
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',
205
+ );
206
+ }
207
+ }
208
+
209
+ $wc_order->update_status( 'on-hold', __( 'Awaiting Pay Upon Invoice payment.', 'woocommerce-paypal-payments' ) );
210
+ $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
211
+ $payment_source = $this->payment_source_factory->from_wc_order( $wc_order, $birth_date );
212
+
213
+ try {
214
+ $order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source );
215
+ $this->add_paypal_meta( $wc_order, $order, $this->environment );
216
+
217
+ as_schedule_single_action(
218
+ time() + ( 5 * MINUTE_IN_SECONDS ),
219
+ 'woocommerce_paypal_payments_check_pui_payment_captured',
220
+ array(
221
+ 'wc_order_id' => $order_id,
222
+ 'order_id' => $order->id(),
223
+ )
224
+ );
225
+
226
+ WC()->cart->empty_cart();
227
+
228
+ return array(
229
+ 'result' => 'success',
230
+ 'redirect' => $this->get_return_url( $wc_order ),
231
+ );
232
+ } catch ( RuntimeException $exception ) {
233
+ $error = $exception->getMessage();
234
+
235
+ if ( is_a( $exception, PayPalApiException::class ) && is_array( $exception->details() ) ) {
236
+ $details = '';
237
+ foreach ( $exception->details() as $detail ) {
238
+ $issue = $detail->issue ?? '';
239
+ $field = $detail->field ?? '';
240
+ $description = $detail->description ?? '';
241
+ $details .= $issue . ' ' . $field . ' ' . $description . '<br>';
242
+ }
243
+
244
+ $error = $details;
245
+ }
246
+
247
+ $this->logger->error( $error );
248
+ wc_add_notice( $error, 'error' );
249
+
250
+ $wc_order->update_status(
251
+ 'failed',
252
+ $error
253
+ );
254
+
255
+ return array(
256
+ 'result' => 'failure',
257
+ 'redirect' => wc_get_checkout_url(),
258
+ );
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Return transaction url for this gateway and given order.
264
+ *
265
+ * @param WC_Order $order WC order to get transaction url by.
266
+ *
267
+ * @return string
268
+ */
269
+ public function get_transaction_url( $order ): string {
270
+ $this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
271
+
272
+ return parent::get_transaction_url( $order );
273
+ }
274
+ }
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PUI payment source.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
12
+ /**
13
+ * Class PaymentSource.
14
+ */
15
+ class PaymentSource {
16
+
17
+ /**
18
+ * The given name.
19
+ *
20
+ * @var string
21
+ */
22
+ protected $given_name;
23
+
24
+ /**
25
+ * The surname.
26
+ *
27
+ * @var string
28
+ */
29
+ protected $surname;
30
+
31
+ /**
32
+ * The email.
33
+ *
34
+ * @var string
35
+ */
36
+ protected $email;
37
+
38
+ /**
39
+ * The birth date.
40
+ *
41
+ * @var string
42
+ */
43
+ protected $birth_date;
44
+
45
+ /**
46
+ * The phone number.
47
+ *
48
+ * @var string
49
+ */
50
+ protected $national_number;
51
+
52
+ /**
53
+ * The phone country code.
54
+ *
55
+ * @var string
56
+ */
57
+ protected $phone_country_code;
58
+
59
+ /**
60
+ * The address line 1.
61
+ *
62
+ * @var string
63
+ */
64
+ protected $address_line_1;
65
+
66
+ /**
67
+ * The admin area 2.
68
+ *
69
+ * @var string
70
+ */
71
+ protected $admin_area_2;
72
+
73
+ /**
74
+ * The postal code.
75
+ *
76
+ * @var string
77
+ */
78
+ protected $postal_code;
79
+
80
+ /**
81
+ * The country code.
82
+ *
83
+ * @var string
84
+ */
85
+ protected $country_code;
86
+
87
+ /**
88
+ * The locale.
89
+ *
90
+ * @var string
91
+ */
92
+ protected $locale;
93
+
94
+ /**
95
+ * The brand name.
96
+ *
97
+ * @var string
98
+ */
99
+ protected $brand_name;
100
+
101
+ /**
102
+ * The logo URL.
103
+ *
104
+ * @var string
105
+ */
106
+ protected $logo_url;
107
+
108
+ /**
109
+ * The customer service instructions.
110
+ *
111
+ * @var array
112
+ */
113
+ protected $customer_service_instructions;
114
+
115
+ /**
116
+ * PaymentSource constructor.
117
+ *
118
+ * @param string $given_name The given name.
119
+ * @param string $surname The surname.
120
+ * @param string $email The email.
121
+ * @param string $birth_date The birth date.
122
+ * @param string $national_number The phone number.
123
+ * @param string $phone_country_code The phone country code.
124
+ * @param string $address_line_1 The address line 1.
125
+ * @param string $admin_area_2 The admin area 2.
126
+ * @param string $postal_code The postal code.
127
+ * @param string $country_code The country code.
128
+ * @param string $locale The locale.
129
+ * @param string $brand_name The brand name.
130
+ * @param string $logo_url The logo URL.
131
+ * @param array $customer_service_instructions The customer service instructions.
132
+ */
133
+ public function __construct(
134
+ string $given_name,
135
+ string $surname,
136
+ string $email,
137
+ string $birth_date,
138
+ string $national_number,
139
+ string $phone_country_code,
140
+ string $address_line_1,
141
+ string $admin_area_2,
142
+ string $postal_code,
143
+ string $country_code,
144
+ string $locale,
145
+ string $brand_name,
146
+ string $logo_url,
147
+ array $customer_service_instructions
148
+ ) {
149
+ $this->given_name = $given_name;
150
+ $this->surname = $surname;
151
+ $this->email = $email;
152
+ $this->birth_date = $birth_date;
153
+ $this->national_number = $national_number;
154
+ $this->phone_country_code = $phone_country_code;
155
+ $this->address_line_1 = $address_line_1;
156
+ $this->admin_area_2 = $admin_area_2;
157
+ $this->postal_code = $postal_code;
158
+ $this->country_code = $country_code;
159
+ $this->locale = $locale;
160
+ $this->brand_name = $brand_name;
161
+ $this->logo_url = $logo_url;
162
+ $this->customer_service_instructions = $customer_service_instructions;
163
+ }
164
+
165
+ /**
166
+ * Returns the given name.
167
+ *
168
+ * @return string
169
+ */
170
+ public function given_name(): string {
171
+ return $this->given_name;
172
+ }
173
+
174
+ /**
175
+ * Returns the surname.
176
+ *
177
+ * @return string
178
+ */
179
+ public function surname(): string {
180
+ return $this->surname;
181
+ }
182
+
183
+ /**
184
+ * Returns the email.
185
+ *
186
+ * @return string
187
+ */
188
+ public function email(): string {
189
+ return $this->email;
190
+ }
191
+
192
+ /**
193
+ * Returns the birth date.
194
+ *
195
+ * @return string
196
+ */
197
+ public function birth_date(): string {
198
+ return $this->birth_date;
199
+ }
200
+
201
+ /**
202
+ * Returns the national number.
203
+ *
204
+ * @return string
205
+ */
206
+ public function national_number(): string {
207
+ return $this->national_number;
208
+ }
209
+
210
+ /**
211
+ * Returns the phone country code.
212
+ *
213
+ * @return string
214
+ */
215
+ public function phone_country_code(): string {
216
+ return $this->phone_country_code;
217
+ }
218
+
219
+ /**
220
+ * Returns the address line 1.
221
+ *
222
+ * @return string
223
+ */
224
+ public function address_line_1(): string {
225
+ return $this->address_line_1;
226
+ }
227
+
228
+ /**
229
+ * Returns the admin area 2.
230
+ *
231
+ * @return string
232
+ */
233
+ public function admin_area_2(): string {
234
+ return $this->admin_area_2;
235
+ }
236
+
237
+ /**
238
+ * Returns the postal code.
239
+ *
240
+ * @return string
241
+ */
242
+ public function postal_code(): string {
243
+ return $this->postal_code;
244
+ }
245
+
246
+ /**
247
+ * Returns the country code.
248
+ *
249
+ * @return string
250
+ */
251
+ public function country_code(): string {
252
+ return $this->country_code;
253
+ }
254
+
255
+ /**
256
+ * Returns the locale.
257
+ *
258
+ * @return string
259
+ */
260
+ public function locale(): string {
261
+ return $this->locale;
262
+ }
263
+
264
+ /**
265
+ * Returns the brand name.
266
+ *
267
+ * @return string
268
+ */
269
+ public function brand_name(): string {
270
+ return $this->brand_name;
271
+ }
272
+
273
+ /**
274
+ * The logo URL.
275
+ *
276
+ * @return string
277
+ */
278
+ public function logo_url(): string {
279
+ return $this->logo_url;
280
+ }
281
+
282
+ /**
283
+ * Returns the customer service instructions.
284
+ *
285
+ * @return array
286
+ */
287
+ public function customer_service_instructions(): array {
288
+ return $this->customer_service_instructions;
289
+ }
290
+
291
+ /**
292
+ * Returns payment source as array.
293
+ *
294
+ * @return array
295
+ */
296
+ public function to_array(): array {
297
+ return array(
298
+ 'name' => array(
299
+ 'given_name' => $this->given_name(),
300
+ 'surname' => $this->surname(),
301
+ ),
302
+ 'email' => $this->email(),
303
+ 'birth_date' => $this->birth_date(),
304
+ 'phone' => array(
305
+ 'national_number' => $this->national_number(),
306
+ 'country_code' => $this->phone_country_code(),
307
+ ),
308
+ 'billing_address' => array(
309
+ 'address_line_1' => $this->address_line_1(),
310
+ 'admin_area_2' => $this->admin_area_2(),
311
+ 'postal_code' => $this->postal_code(),
312
+ 'country_code' => $this->country_code(),
313
+ ),
314
+ 'experience_context' => array(
315
+ 'locale' => $this->locale(),
316
+ 'brand_name' => $this->brand_name(),
317
+ 'logo_url' => $this->logo_url(),
318
+ 'customer_service_instructions' => $this->customer_service_instructions(),
319
+ ),
320
+ );
321
+ }
322
+ }
modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PUI payment source factory.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice
6
+ */
7
+
8
+ declare(strict_types=1);
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice;
11
+
12
+ use WC_Order;
13
+
14
+ /**
15
+ * Class PaymentSourceFactory.
16
+ */
17
+ class PaymentSourceFactory {
18
+
19
+ /**
20
+ * Create a PUI payment source from a WC order.
21
+ *
22
+ * @param WC_Order $order The WC order.
23
+ * @param string $birth_date The birth date.
24
+ * @return PaymentSource
25
+ */
26
+ public function from_wc_order( WC_Order $order, string $birth_date ) {
27
+ $address = $order->get_address();
28
+
29
+ $phone_country_code = WC()->countries->get_country_calling_code( $address['country'] );
30
+ $phone_country_code = is_array( $phone_country_code ) && ! empty( $phone_country_code ) ? $phone_country_code[0] : $phone_country_code;
31
+ if ( is_string( $phone_country_code ) && '' !== $phone_country_code ) {
32
+ $phone_country_code = substr( $phone_country_code, strlen( '+' ) ) ?: '';
33
+ } else {
34
+ $phone_country_code = '';
35
+ }
36
+
37
+ $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
38
+ $merchant_name = $gateway_settings['brand_name'] ?? '';
39
+ $logo_url = $gateway_settings['logo_url'] ?? '';
40
+ $customer_service_instructions = $gateway_settings['customer_service_instructions'] ?? '';
41
+
42
+ return new PaymentSource(
43
+ $address['first_name'] ?? '',
44
+ $address['last_name'] ?? '',
45
+ $address['email'] ?? '',
46
+ $birth_date,
47
+ preg_replace( '/[^0-9]/', '', $address['phone'] ) ?? '',
48
+ $phone_country_code,
49
+ $address['address_1'] ?? '',
50
+ $address['city'] ?? '',
51
+ $address['postcode'] ?? '',
52
+ $address['country'] ?? '',
53
+ 'en-DE',
54
+ $merchant_name,
55
+ $logo_url,
56
+ array( $customer_service_instructions )
57
+ );
58
+ }
59
+ }
modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Helper methods for PUI.
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
+ * 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
+ /**
74
+ * Checks whether checkout is ready for PUI.
75
+ *
76
+ * @return bool
77
+ */
78
+ public function is_checkout_ready_for_pui(): bool {
79
+ $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' );
80
+ if ( $gateway_settings && '' === $gateway_settings['customer_service_instructions'] ) {
81
+ return false;
82
+ }
83
+
84
+ $billing_country = filter_input( INPUT_POST, 'country', FILTER_SANITIZE_STRING ) ?? null;
85
+ if ( $billing_country && 'DE' !== $billing_country ) {
86
+ return false;
87
+ }
88
+
89
+ if ( 'EUR' !== get_woocommerce_currency() ) {
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;
139
+ }
140
+ }
modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Manage the Seller status.
4
+ *
5
+ * @package WooCommerce\PayPalCommerce\WcGateway\Helper
6
+ */
7
+
8
+ declare( strict_types=1 );
9
+
10
+ namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
11
+
12
+ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
13
+ use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
14
+ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
15
+ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
16
+ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
17
+
18
+ /**
19
+ * Class PayUponInvoiceProductStatus
20
+ */
21
+ class PayUponInvoiceProductStatus {
22
+
23
+ /**
24
+ * Caches the status for the current load.
25
+ *
26
+ * @var bool|null
27
+ */
28
+ private $current_status_cache;
29
+ /**
30
+ * The settings.
31
+ *
32
+ * @var Settings
33
+ */
34
+ private $settings;
35
+
36
+ /**
37
+ * The partners endpoint.
38
+ *
39
+ * @var PartnersEndpoint
40
+ */
41
+ private $partners_endpoint;
42
+
43
+ /**
44
+ * PayUponInvoiceProductStatus constructor.
45
+ *
46
+ * @param Settings $settings The Settings.
47
+ * @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
48
+ */
49
+ public function __construct(
50
+ Settings $settings,
51
+ PartnersEndpoint $partners_endpoint
52
+ ) {
53
+ $this->settings = $settings;
54
+ $this->partners_endpoint = $partners_endpoint;
55
+ }
56
+
57
+ /**
58
+ * Whether the active/subscribed products support PUI.
59
+ *
60
+ * @return bool
61
+ */
62
+ public function pui_is_active() : bool {
63
+ if ( is_bool( $this->current_status_cache ) ) {
64
+ return $this->current_status_cache;
65
+ }
66
+ if ( $this->settings->has( 'products_pui_enabled' ) && $this->settings->get( 'products_pui_enabled' ) ) {
67
+ $this->current_status_cache = true;
68
+ return true;
69
+ }
70
+
71
+ try {
72
+ $seller_status = $this->partners_endpoint->seller_status();
73
+ } catch ( RuntimeException $error ) {
74
+ $this->current_status_cache = false;
75
+ return false;
76
+ }
77
+
78
+ foreach ( $seller_status->products() as $product ) {
79
+ if ( $product->name() !== 'PAYMENT_METHODS' ) {
80
+ continue;
81
+ }
82
+
83
+ if ( ! in_array(
84
+ $product->vetting_status(),
85
+ array(
86
+ SellerStatusProduct::VETTING_STATUS_APPROVED,
87
+ SellerStatusProduct::VETTING_STATUS_SUBSCRIBED,
88
+ ),
89
+ true
90
+ )
91
+ ) {
92
+ continue;
93
+ }
94
+
95
+ if ( in_array( 'PAY_UPON_INVOICE', $product->capabilities(), true ) ) {
96
+ $this->settings->set( 'products_pui_enabled', true );
97
+ $this->settings->persist();
98
+ $this->current_status_cache = true;
99
+ return true;
100
+ }
101
+ }
102
+
103
+ $this->current_status_cache = false;
104
+ return false;
105
+ }
106
+ }
modules/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php CHANGED
@@ -131,6 +131,7 @@ class AuthorizedPaymentsProcessor {
131
  try {
132
  $order = $this->paypal_order_from_wc_order( $wc_order );
133
  } catch ( Exception $exception ) {
 
134
  if ( $exception->getCode() === 404 ) {
135
  return self::NOT_FOUND;
136
  }
131
  try {
132
  $order = $this->paypal_order_from_wc_order( $wc_order );
133
  } catch ( Exception $exception ) {
134
+ $this->logger->error( 'Could not get PayPal order from WC order: ' . $exception->getMessage() );
135
  if ( $exception->getCode() === 404 ) {
136
  return self::NOT_FOUND;
137
  }
modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php CHANGED
@@ -41,6 +41,8 @@ trait OrderMetaTrait {
41
  if ( $payment_source ) {
42
  $wc_order->update_meta_data( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY, $payment_source );
43
  }
 
 
44
  }
45
 
46
  /**
41
  if ( $payment_source ) {
42
  $wc_order->update_meta_data( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY, $payment_source );
43
  }
44
+
45
+ $wc_order->save();
46
  }
47
 
48
  /**
modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php CHANGED
@@ -14,6 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
14
  use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
15
  use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
16
  use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
 
17
  use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
18
  use WooCommerce\PayPalCommerce\Onboarding\Environment;
19
  use WooCommerce\PayPalCommerce\Session\SessionHandler;
@@ -106,6 +107,13 @@ class OrderProcessor {
106
  */
107
  private $subscription_helper;
108
 
 
 
 
 
 
 
 
109
  /**
110
  * OrderProcessor constructor.
111
  *
@@ -118,6 +126,7 @@ class OrderProcessor {
118
  * @param LoggerInterface $logger A logger service.
119
  * @param Environment $environment The environment.
120
  * @param SubscriptionHelper $subscription_helper The subscription helper.
 
121
  */
122
  public function __construct(
123
  SessionHandler $session_handler,
@@ -128,7 +137,8 @@ class OrderProcessor {
128
  Settings $settings,
129
  LoggerInterface $logger,
130
  Environment $environment,
131
- SubscriptionHelper $subscription_helper
 
132
  ) {
133
 
134
  $this->session_handler = $session_handler;
@@ -140,6 +150,7 @@ class OrderProcessor {
140
  $this->environment = $environment;
141
  $this->logger = $logger;
142
  $this->subscription_helper = $subscription_helper;
 
143
  }
144
 
145
  /**
@@ -160,9 +171,9 @@ class OrderProcessor {
160
  $this->add_paypal_meta( $wc_order, $order, $this->environment );
161
 
162
  $error_message = null;
163
- if ( ! $this->order_is_approved( $order ) ) {
164
  $error_message = __(
165
- 'The payment has not been approved yet.',
166
  'woocommerce-paypal-payments'
167
  );
168
  }
@@ -204,7 +215,7 @@ class OrderProcessor {
204
  __( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
205
  );
206
  $wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
207
- $wc_order->update_status( 'processing' );
208
  }
209
  $this->last_error = '';
210
  return true;
@@ -269,15 +280,15 @@ class OrderProcessor {
269
  }
270
 
271
  /**
272
- * Whether a given order is approved.
273
  *
274
  * @param Order $order The order.
275
  *
276
  * @return bool
277
  */
278
- private function order_is_approved( Order $order ): bool {
279
 
280
- if ( $order->status()->is( OrderStatus::APPROVED ) ) {
281
  return true;
282
  }
283
 
@@ -285,7 +296,7 @@ class OrderProcessor {
285
  return false;
286
  }
287
 
288
- $is_approved = in_array(
289
  $this->threed_secure->proceed_with_order( $order ),
290
  array(
291
  ThreeDSecure::NO_DECISION,
@@ -293,6 +304,5 @@ class OrderProcessor {
293
  ),
294
  true
295
  );
296
- return $is_approved;
297
  }
298
  }
14
  use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
15
  use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
16
  use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
17
+ use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
18
  use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
19
  use WooCommerce\PayPalCommerce\Onboarding\Environment;
20
  use WooCommerce\PayPalCommerce\Session\SessionHandler;
107
  */
108
  private $subscription_helper;
109
 
110
+ /**
111
+ * The order helper.
112
+ *
113
+ * @var OrderHelper
114
+ */
115
+ private $order_helper;
116
+
117
  /**
118
  * OrderProcessor constructor.
119
  *
126
  * @param LoggerInterface $logger A logger service.
127
  * @param Environment $environment The environment.
128
  * @param SubscriptionHelper $subscription_helper The subscription helper.
129
+ * @param OrderHelper $order_helper The order helper.
130
  */
131
  public function __construct(
132
  SessionHandler $session_handler,
137
  Settings $settings,
138
  LoggerInterface $logger,
139
  Environment $environment,
140
+ SubscriptionHelper $subscription_helper,
141
+ OrderHelper $order_helper
142
  ) {
143
 
144
  $this->session_handler = $session_handler;
150
  $this->environment = $environment;
151
  $this->logger = $logger;
152
  $this->subscription_helper = $subscription_helper;
153
+ $this->order_helper = $order_helper;
154
  }
155
 
156
  /**
171
  $this->add_paypal_meta( $wc_order, $order, $this->environment );
172
 
173
  $error_message = null;
174
+ if ( $this->order_helper->contains_physical_goods( $order ) && ! $this->order_is_ready_for_process( $order ) ) {
175
  $error_message = __(
176
+ 'The payment is not ready for processing yet.',
177
  'woocommerce-paypal-payments'
178
  );
179
  }
215
  __( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
216
  );
217
  $wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
218
+ $wc_order->update_status( 'completed' );
219
  }
220
  $this->last_error = '';
221
  return true;
280
  }
281
 
282
  /**
283
+ * Whether a given order is ready for processing.
284
  *
285
  * @param Order $order The order.
286
  *
287
  * @return bool
288
  */
289
+ private function order_is_ready_for_process( Order $order ): bool {
290
 
291
+ if ( $order->status()->is( OrderStatus::APPROVED ) || $order->status()->is( OrderStatus::CREATED ) ) {
292
  return true;
293
  }
294
 
296
  return false;
297
  }
298
 
299
+ return in_array(
300
  $this->threed_secure->proceed_with_order( $order ),
301
  array(
302
  ThreeDSecure::NO_DECISION,
304
  ),
305
  true
306
  );
 
307
  }
308
  }
modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php CHANGED
@@ -11,6 +11,7 @@ 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;
15
 
16
  /**
@@ -27,13 +28,22 @@ class SectionsRenderer {
27
  */
28
  protected $page_id;
29
 
 
 
 
 
 
 
 
30
  /**
31
  * SectionsRenderer constructor.
32
  *
33
  * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
 
34
  */
35
- public function __construct( string $page_id ) {
36
- $this->page_id = $page_id;
 
37
  }
38
 
39
  /**
@@ -54,17 +64,25 @@ class SectionsRenderer {
54
  }
55
 
56
  $sections = array(
57
- PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
58
- CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
59
- WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
 
60
  );
61
 
 
 
 
 
62
  echo '<ul class="subsubsub">';
63
 
64
  $array_keys = array_keys( $sections );
65
 
66
  foreach ( $sections as $id => $label ) {
67
  $url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway&' . self::KEY . '=' . $id );
 
 
 
68
  echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $this->page_id === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
69
  }
70
 
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
  /**
28
  */
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
  /**
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
  }
88
 
modules/ppcp-wc-gateway/src/Settings/SettingsListener.php CHANGED
@@ -81,6 +81,20 @@ class SettingsListener {
81
  */
82
  protected $page_id;
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  /**
85
  * SettingsListener constructor.
86
  *
@@ -91,6 +105,8 @@ class SettingsListener {
91
  * @param State $state The state.
92
  * @param Bearer $bearer The bearer.
93
  * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
 
 
94
  */
95
  public function __construct(
96
  Settings $settings,
@@ -99,7 +115,9 @@ class SettingsListener {
99
  Cache $cache,
100
  State $state,
101
  Bearer $bearer,
102
- string $page_id
 
 
103
  ) {
104
 
105
  $this->settings = $settings;
@@ -109,6 +127,8 @@ class SettingsListener {
109
  $this->state = $state;
110
  $this->bearer = $bearer;
111
  $this->page_id = $page_id;
 
 
112
  }
113
 
114
  /**
@@ -251,6 +271,7 @@ class SettingsListener {
251
  if ( $credentials_change_status ) {
252
  if ( self::CREDENTIALS_UNCHANGED !== $credentials_change_status ) {
253
  $this->settings->set( 'products_dcc_enabled', null );
 
254
  }
255
 
256
  if ( in_array(
@@ -259,6 +280,12 @@ class SettingsListener {
259
  true
260
  ) ) {
261
  $this->webhook_registrar->unregister();
 
 
 
 
 
 
262
  }
263
  }
264
 
81
  */
82
  protected $page_id;
83
 
84
+ /**
85
+ * The signup link cache.
86
+ *
87
+ * @var Cache
88
+ */
89
+ protected $signup_link_cache;
90
+
91
+ /**
92
+ * Signup link ids
93
+ *
94
+ * @var array
95
+ */
96
+ protected $signup_link_ids;
97
+
98
  /**
99
  * SettingsListener constructor.
100
  *
105
  * @param State $state The state.
106
  * @param Bearer $bearer The bearer.
107
  * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
108
+ * @param Cache $signup_link_cache The signup link cache.
109
+ * @param array $signup_link_ids Signup link ids.
110
  */
111
  public function __construct(
112
  Settings $settings,
115
  Cache $cache,
116
  State $state,
117
  Bearer $bearer,
118
+ string $page_id,
119
+ Cache $signup_link_cache,
120
+ array $signup_link_ids
121
  ) {
122
 
123
  $this->settings = $settings;
127
  $this->state = $state;
128
  $this->bearer = $bearer;
129
  $this->page_id = $page_id;
130
+ $this->signup_link_cache = $signup_link_cache;
131
+ $this->signup_link_ids = $signup_link_ids;
132
  }
133
 
134
  /**
271
  if ( $credentials_change_status ) {
272
  if ( self::CREDENTIALS_UNCHANGED !== $credentials_change_status ) {
273
  $this->settings->set( 'products_dcc_enabled', null );
274
+ $this->settings->set( 'products_pui_enabled', null );
275
  }
276
 
277
  if ( in_array(
280
  true
281
  ) ) {
282
  $this->webhook_registrar->unregister();
283
+
284
+ foreach ( $this->signup_link_ids as $key ) {
285
+ if ( $this->signup_link_cache->has( $key ) ) {
286
+ $this->signup_link_cache->delete( $key );
287
+ }
288
+ }
289
  }
290
  }
291
 
modules/ppcp-wc-gateway/src/WCGatewayModule.php CHANGED
@@ -14,6 +14,7 @@ use Dhii\Modular\Module\ModuleInterface;
14
  use WC_Order;
15
  use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
 
17
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
18
  use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
19
  use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
@@ -214,7 +215,7 @@ class WCGatewayModule implements ModuleInterface {
214
  assert( $settings instanceof Settings );
215
 
216
  try {
217
- if ( $settings->get( '3d_secure_contingency' ) === '3D_SECURE' ) {
218
  $settings->set( '3d_secure_contingency', 'SCA_ALWAYS' );
219
  $settings->persist();
220
  }
@@ -223,6 +224,42 @@ class WCGatewayModule implements ModuleInterface {
223
  }
224
  }
225
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  }
227
 
228
  /**
@@ -246,6 +283,11 @@ class WCGatewayModule implements ModuleInterface {
246
  if ( $dcc_applies->for_country_currency() ) {
247
  $methods[] = $container->get( 'wcgateway.credit-card-gateway' );
248
  }
 
 
 
 
 
249
  return (array) $methods;
250
  }
251
  );
14
  use WC_Order;
15
  use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository;
16
  use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
17
+ use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
18
  use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
19
  use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
20
  use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
215
  assert( $settings instanceof Settings );
216
 
217
  try {
218
+ if ( $settings->has( '3d_secure_contingency' ) && $settings->get( '3d_secure_contingency' ) === '3D_SECURE' ) {
219
  $settings->set( '3d_secure_contingency', 'SCA_ALWAYS' );
220
  $settings->persist();
221
  }
224
  }
225
  }
226
  );
227
+
228
+ add_action(
229
+ 'init',
230
+ function () use ( $c ) {
231
+ if ( 'DE' === $c->get( 'api.shop.country' ) && 'EUR' === get_woocommerce_currency() ) {
232
+ ( $c->get( 'wcgateway.pay-upon-invoice' ) )->init();
233
+ }
234
+ }
235
+ );
236
+
237
+ add_action(
238
+ 'woocommerce_paypal_payments_check_pui_payment_captured',
239
+ function ( int $wc_order_id, string $order_id ) use ( $c ) {
240
+ $order_endpoint = $c->get( 'api.endpoint.order' );
241
+ $logger = $c->get( 'woocommerce.logger.woocommerce' );
242
+ $order = $order_endpoint->order( $order_id );
243
+ $order_status = $order->status();
244
+ $logger->info( "Checking payment captured webhook for WC order #{$wc_order_id}, PayPal order status: " . $order_status->name() );
245
+
246
+ $wc_order = wc_get_order( $wc_order_id );
247
+ if ( ! is_a( $wc_order, WC_Order::class ) || $wc_order->get_status() !== 'on-hold' ) {
248
+ return;
249
+ }
250
+
251
+ if ( $order_status->name() !== OrderStatus::COMPLETED ) {
252
+ $message = __(
253
+ 'Could not process WC order because PAYMENT.CAPTURE.COMPLETED webhook not received.',
254
+ 'woocommerce-paypal-payments'
255
+ );
256
+ $logger->error( $message );
257
+ $wc_order->update_status( 'failed', $message );
258
+ }
259
+ },
260
+ 10,
261
+ 2
262
+ );
263
  }
264
 
265
  /**
283
  if ( $dcc_applies->for_country_currency() ) {
284
  $methods[] = $container->get( 'wcgateway.credit-card-gateway' );
285
  }
286
+
287
+ if ( 'DE' === $container->get( 'api.shop.country' ) ) {
288
+ $methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' );
289
+ }
290
+
291
  return (array) $methods;
292
  }
293
  );
modules/ppcp-wc-gateway/webpack.config.js CHANGED
@@ -7,6 +7,7 @@ module.exports = {
7
  target: 'web',
8
  entry: {
9
  'gateway-settings': path.resolve('./resources/js/gateway-settings.js'),
 
10
  },
11
  output: {
12
  path: path.resolve(__dirname, 'assets/'),
7
  target: 'web',
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/'),
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
 
16
  /**
17
  * Class CheckoutOrderApproved
@@ -188,6 +189,10 @@ class CheckoutOrderApproved implements RequestHandler {
188
  }
189
 
190
  foreach ( $wc_orders as $wc_order ) {
 
 
 
 
191
  if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
192
  continue;
193
  }
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
  /**
18
  * Class CheckoutOrderApproved
189
  }
190
 
191
  foreach ( $wc_orders as $wc_order ) {
192
+ if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() ) {
193
+ continue;
194
+ }
195
+
196
  if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
197
  continue;
198
  }
modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php CHANGED
@@ -10,6 +10,7 @@ declare(strict_types=1);
10
  namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
11
 
12
  use Psr\Log\LoggerInterface;
 
13
 
14
  /**
15
  * Class CheckoutOrderCompleted
@@ -131,6 +132,10 @@ class CheckoutOrderCompleted implements RequestHandler {
131
  }
132
 
133
  foreach ( $wc_orders as $wc_order ) {
 
 
 
 
134
  if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
135
  continue;
136
  }
10
  namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
11
 
12
  use Psr\Log\LoggerInterface;
13
+ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
14
 
15
  /**
16
  * Class CheckoutOrderCompleted
132
  }
133
 
134
  foreach ( $wc_orders as $wc_order ) {
135
+ if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() ) {
136
+ continue;
137
+ }
138
+
139
  if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
140
  continue;
141
  }
modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php CHANGED
@@ -112,6 +112,13 @@ class PaymentCaptureCompleted implements RequestHandler {
112
  return new WP_REST_Response( $response );
113
  }
114
 
 
 
 
 
 
 
 
115
  if ( $wc_order->get_status() !== 'on-hold' ) {
116
  $response['success'] = true;
117
  return new WP_REST_Response( $response );
@@ -139,8 +146,6 @@ class PaymentCaptureCompleted implements RequestHandler {
139
  )
140
  );
141
 
142
- $order_id = $resource['supplementary_data']['related_ids']['order_id'] ?? null;
143
-
144
  if ( $order_id ) {
145
  try {
146
  $order = $this->order_endpoint->order( (string) $order_id );
112
  return new WP_REST_Response( $response );
113
  }
114
 
115
+ $order_id = $resource['supplementary_data']['related_ids']['order_id'] ?? null;
116
+
117
+ /**
118
+ * Allow access to the webhook logic before updating the WC order.
119
+ */
120
+ do_action( 'ppcp_payment_capture_completed_webhook_handler', $wc_order, $order_id );
121
+
122
  if ( $wc_order->get_status() !== 'on-hold' ) {
123
  $response['success'] = true;
124
  return new WP_REST_Response( $response );
146
  )
147
  );
148
 
 
 
149
  if ( $order_id ) {
150
  try {
151
  $order = $this->order_endpoint->order( (string) $order_id );
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === WooCommerce PayPal Payments ===
2
- Contributors: woocommerce, automattic
3
  Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell, shop, shopping, cart, checkout
4
  Requires at least: 5.3
5
  Tested up to: 6.0
6
  Requires PHP: 7.1
7
- Stable tag: 1.8.1
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -81,6 +81,23 @@ Follow the steps below to connect the plugin to your PayPal account:
81
 
82
  == Changelog ==
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  = 1.8.1 =
85
  * Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
86
  * Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
1
  === WooCommerce PayPal Payments ===
2
+ Contributors: woocommerce, automattic, inpsyde
3
  Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell, shop, shopping, cart, checkout
4
  Requires at least: 5.3
5
  Tested up to: 6.0
6
  Requires PHP: 7.1
7
+ Stable tag: 1.9.0
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
81
 
82
  == Changelog ==
83
 
84
+ = 1.9.0 =
85
+ * Add - New Feature - Pay Upon Invoice (Germany only) #608
86
+ * Fix - Order not approved: payment via vaulted PayPal account fails #677
87
+ * Fix - Cant' refund : "ERROR Refund failed: No country given for address." #639
88
+ * Fix - Something went wrong error in Virtual products when using vaulted payment #673
89
+ * Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669
90
+ * Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
91
+ * Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
92
+ * Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
93
+ * Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
94
+ * Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523
95
+ * Fix - Order details are sometimes empty in PayPal dashboard #689
96
+ * Fix - Incorrect TAX details on PayPal order overview #541
97
+ * Fix - Fatal error: Uncaught Error: Call to a member function get_name() on bool #622
98
+ * Fix - DCC causes checkout continuation state after checkout validation error #695
99
+ * Enhancement - Improve checkout validation & order creation #513
100
+
101
  = 1.8.1 =
102
  * Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
103
  * Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitbb1f66c3033b9835db7b2fd5e2dee2d5::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
  'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
 
10
  'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
11
  'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
12
  'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
7
 
8
  return array(
9
  'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
10
+ 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
11
  'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
12
  'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
13
  'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff
6
  {
7
  private static $loader;
8
 
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff
22
  return self::$loader;
23
  }
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
- spl_autoload_unregister(array('ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff', '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\ComposerStaticInit5a08559ae58536f83fd0f0260535ccff::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
@@ -51,19 +51,19 @@ class ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff
51
  $loader->register(true);
52
 
53
  if ($useStaticLoader) {
54
- $includeFiles = Composer\Autoload\ComposerStaticInit5a08559ae58536f83fd0f0260535ccff::$files;
55
  } else {
56
  $includeFiles = require __DIR__ . '/autoload_files.php';
57
  }
58
  foreach ($includeFiles as $fileIdentifier => $file) {
59
- composerRequire5a08559ae58536f83fd0f0260535ccff($fileIdentifier, $file);
60
  }
61
 
62
  return $loader;
63
  }
64
  }
65
 
66
- function composerRequire5a08559ae58536f83fd0f0260535ccff($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 ComposerAutoloaderInitbb1f66c3033b9835db7b2fd5e2dee2d5
6
  {
7
  private static $loader;
8
 
22
  return self::$loader;
23
  }
24
 
25
+ spl_autoload_register(array('ComposerAutoloaderInitbb1f66c3033b9835db7b2fd5e2dee2d5', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
+ spl_autoload_unregister(array('ComposerAutoloaderInitbb1f66c3033b9835db7b2fd5e2dee2d5', '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\ComposerStaticInitbb1f66c3033b9835db7b2fd5e2dee2d5::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\ComposerStaticInitbb1f66c3033b9835db7b2fd5e2dee2d5::$files;
55
  } else {
56
  $includeFiles = require __DIR__ . '/autoload_files.php';
57
  }
58
  foreach ($includeFiles as $fileIdentifier => $file) {
59
+ composerRequirebb1f66c3033b9835db7b2fd5e2dee2d5($fileIdentifier, $file);
60
  }
61
 
62
  return $loader;
63
  }
64
  }
65
 
66
+ function composerRequirebb1f66c3033b9835db7b2fd5e2dee2d5($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 ComposerStaticInit5a08559ae58536f83fd0f0260535ccff
8
  {
9
  public static $files = array (
10
  'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
@@ -164,6 +164,7 @@ class ComposerStaticInit5a08559ae58536f83fd0f0260535ccff
164
 
165
  public static $classMap = array (
166
  'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
 
167
  'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
168
  'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
169
  'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
@@ -172,9 +173,9 @@ class ComposerStaticInit5a08559ae58536f83fd0f0260535ccff
172
  public static function getInitializer(ClassLoader $loader)
173
  {
174
  return \Closure::bind(function () use ($loader) {
175
- $loader->prefixLengthsPsr4 = ComposerStaticInit5a08559ae58536f83fd0f0260535ccff::$prefixLengthsPsr4;
176
- $loader->prefixDirsPsr4 = ComposerStaticInit5a08559ae58536f83fd0f0260535ccff::$prefixDirsPsr4;
177
- $loader->classMap = ComposerStaticInit5a08559ae58536f83fd0f0260535ccff::$classMap;
178
 
179
  }, null, ClassLoader::class);
180
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitbb1f66c3033b9835db7b2fd5e2dee2d5
8
  {
9
  public static $files = array (
10
  'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
164
 
165
  public static $classMap = array (
166
  'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
167
+ 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
168
  'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
169
  'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
170
  'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
173
  public static function getInitializer(ClassLoader $loader)
174
  {
175
  return \Closure::bind(function () use ($loader) {
176
+ $loader->prefixLengthsPsr4 = ComposerStaticInitbb1f66c3033b9835db7b2fd5e2dee2d5::$prefixLengthsPsr4;
177
+ $loader->prefixDirsPsr4 = ComposerStaticInitbb1f66c3033b9835db7b2fd5e2dee2d5::$prefixDirsPsr4;
178
+ $loader->classMap = ComposerStaticInitbb1f66c3033b9835db7b2fd5e2dee2d5::$classMap;
179
 
180
  }, null, ClassLoader::class);
181
  }
vendor/composer/installed.json CHANGED
@@ -530,27 +530,27 @@
530
  },
531
  {
532
  "name": "symfony/polyfill-php80",
533
- "version": "v1.24.0",
534
- "version_normalized": "1.24.0.0",
535
  "source": {
536
  "type": "git",
537
  "url": "https://github.com/symfony/polyfill-php80.git",
538
- "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9"
539
  },
540
  "dist": {
541
  "type": "zip",
542
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9",
543
- "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9",
544
  "shasum": ""
545
  },
546
  "require": {
547
  "php": ">=7.1"
548
  },
549
- "time": "2021-09-13T13:58:33+00:00",
550
  "type": "library",
551
  "extra": {
552
  "branch-alias": {
553
- "dev-main": "1.23-dev"
554
  },
555
  "thanks": {
556
  "name": "symfony/polyfill",
530
  },
531
  {
532
  "name": "symfony/polyfill-php80",
533
+ "version": "v1.26.0",
534
+ "version_normalized": "1.26.0.0",
535
  "source": {
536
  "type": "git",
537
  "url": "https://github.com/symfony/polyfill-php80.git",
538
+ "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
539
  },
540
  "dist": {
541
  "type": "zip",
542
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
543
+ "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
544
  "shasum": ""
545
  },
546
  "require": {
547
  "php": ">=7.1"
548
  },
549
+ "time": "2022-05-10T07:21:04+00:00",
550
  "type": "library",
551
  "extra": {
552
  "branch-alias": {
553
+ "dev-main": "1.26-dev"
554
  },
555
  "thanks": {
556
  "name": "symfony/polyfill",
vendor/symfony/polyfill-php80/Php80.php CHANGED
@@ -100,6 +100,16 @@ final class Php80
100
 
101
  public static function str_ends_with(string $haystack, string $needle): bool
102
  {
103
- return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle)));
 
 
 
 
 
 
 
 
 
 
104
  }
105
  }
100
 
101
  public static function str_ends_with(string $haystack, string $needle): bool
102
  {
103
+ if ('' === $needle || $needle === $haystack) {
104
+ return true;
105
+ }
106
+
107
+ if ('' === $haystack) {
108
+ return false;
109
+ }
110
+
111
+ $needleLength = \strlen($needle);
112
+
113
+ return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
114
  }
115
  }
vendor/symfony/polyfill-php80/PhpToken.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Polyfill\Php80;
13
+
14
+ /**
15
+ * @author Fedonyuk Anton <info@ensostudio.ru>
16
+ *
17
+ * @internal
18
+ */
19
+ class PhpToken implements \Stringable
20
+ {
21
+ /**
22
+ * @var int
23
+ */
24
+ public $id;
25
+
26
+ /**
27
+ * @var string
28
+ */
29
+ public $text;
30
+
31
+ /**
32
+ * @var int
33
+ */
34
+ public $line;
35
+
36
+ /**
37
+ * @var int
38
+ */
39
+ public $pos;
40
+
41
+ public function __construct(int $id, string $text, int $line = -1, int $position = -1)
42
+ {
43
+ $this->id = $id;
44
+ $this->text = $text;
45
+ $this->line = $line;
46
+ $this->pos = $position;
47
+ }
48
+
49
+ public function getTokenName(): ?string
50
+ {
51
+ if ('UNKNOWN' === $name = token_name($this->id)) {
52
+ $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
53
+ }
54
+
55
+ return $name;
56
+ }
57
+
58
+ /**
59
+ * @param int|string|array $kind
60
+ */
61
+ public function is($kind): bool
62
+ {
63
+ foreach ((array) $kind as $value) {
64
+ if (\in_array($value, [$this->id, $this->text], true)) {
65
+ return true;
66
+ }
67
+ }
68
+
69
+ return false;
70
+ }
71
+
72
+ public function isIgnorable(): bool
73
+ {
74
+ return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
75
+ }
76
+
77
+ public function __toString(): string
78
+ {
79
+ return (string) $this->text;
80
+ }
81
+
82
+ /**
83
+ * @return static[]
84
+ */
85
+ public static function tokenize(string $code, int $flags = 0): array
86
+ {
87
+ $line = 1;
88
+ $position = 0;
89
+ $tokens = token_get_all($code, $flags);
90
+ foreach ($tokens as $index => $token) {
91
+ if (\is_string($token)) {
92
+ $id = \ord($token);
93
+ $text = $token;
94
+ } else {
95
+ [$id, $text, $line] = $token;
96
+ }
97
+ $tokens[$index] = new static($id, $text, $line, $position);
98
+ $position += \strlen($text);
99
+ }
100
+
101
+ return $tokens;
102
+ }
103
+ }
vendor/symfony/polyfill-php80/README.md CHANGED
@@ -3,12 +3,13 @@ Symfony Polyfill / Php80
3
 
4
  This component provides features added to PHP 8.0 core:
5
 
6
- - `Stringable` interface
7
  - [`fdiv`](https://php.net/fdiv)
8
- - `ValueError` class
9
- - `UnhandledMatchError` class
10
  - `FILTER_VALIDATE_BOOL` constant
11
  - [`get_debug_type`](https://php.net/get_debug_type)
 
12
  - [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
13
  - [`str_contains`](https://php.net/str_contains)
14
  - [`str_starts_with`](https://php.net/str_starts_with)
3
 
4
  This component provides features added to PHP 8.0 core:
5
 
6
+ - [`Stringable`](https://php.net/stringable) interface
7
  - [`fdiv`](https://php.net/fdiv)
8
+ - [`ValueError`](https://php.net/valueerror) class
9
+ - [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
10
  - `FILTER_VALIDATE_BOOL` constant
11
  - [`get_debug_type`](https://php.net/get_debug_type)
12
+ - [`PhpToken`](https://php.net/phptoken) class
13
  - [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
14
  - [`str_contains`](https://php.net/str_contains)
15
  - [`str_starts_with`](https://php.net/str_starts_with)
vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (\PHP_VERSION_ID < 80000 && \extension_loaded('tokenizer')) {
4
+ class PhpToken extends Symfony\Polyfill\Php80\PhpToken
5
+ {
6
+ }
7
+ }
vendor/symfony/polyfill-php80/composer.json CHANGED
@@ -30,7 +30,7 @@
30
  "minimum-stability": "dev",
31
  "extra": {
32
  "branch-alias": {
33
- "dev-main": "1.23-dev"
34
  },
35
  "thanks": {
36
  "name": "symfony/polyfill",
30
  "minimum-stability": "dev",
31
  "extra": {
32
  "branch-alias": {
33
+ "dev-main": "1.26-dev"
34
  },
35
  "thanks": {
36
  "name": "symfony/polyfill",
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.8.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.5
13
  * Text Domain: woocommerce-paypal-payments
14
  *
15
  * @package WooCommerce\PayPalCommerce
@@ -33,7 +33,10 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
33
  ! defined( 'CONNECT_WOO_SANDBOX_URL' ) && define( 'CONNECT_WOO_SANDBOX_URL', 'https://connect.woocommerce.com/ppcsandbox' );
34
 
35
  ( function () {
36
- include __DIR__ . '/vendor/autoload.php';
 
 
 
37
 
38
  /**
39
  * Initialize the plugin and its modules.
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.0
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
33
  ! defined( 'CONNECT_WOO_SANDBOX_URL' ) && define( 'CONNECT_WOO_SANDBOX_URL', 'https://connect.woocommerce.com/ppcsandbox' );
34
 
35
  ( function () {
36
+ $autoload_filepath = __DIR__ . '/vendor/autoload.php';
37
+ if ( file_exists( $autoload_filepath ) && ! class_exists( '\WooCommerce\PayPalCommerce\PluginModule' ) ) {
38
+ require $autoload_filepath;
39
+ }
40
 
41
  /**
42
  * Initialize the plugin and its modules.