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 | WooCommerce PayPal Payments |
Version | 1.9.0 |
Comparing to | |
See all releases |
Code changes from version 1.8.1 to 1.9.0
- bootstrap.php +4 -2
- changelog.txt +19 -2
- modules/ppcp-api-client/services.php +4 -0
- modules/ppcp-api-client/src/Endpoint/PayUponInvoiceOrderEndpoint.php +260 -0
- modules/ppcp-api-client/src/Endpoint/RequestTrait.php +4 -2
- modules/ppcp-api-client/src/Entity/Item.php +26 -4
- modules/ppcp-api-client/src/Entity/OrderStatus.php +10 -10
- modules/ppcp-api-client/src/Entity/PurchaseUnit.php +11 -4
- modules/ppcp-api-client/src/Factory/AddressFactory.php +1 -6
- modules/ppcp-api-client/src/Factory/AmountFactory.php +9 -36
- modules/ppcp-api-client/src/Factory/ItemFactory.php +10 -22
- modules/ppcp-api-client/src/Factory/PayerFactory.php +10 -0
- modules/ppcp-api-client/src/Helper/Cache.php +3 -2
- modules/ppcp-api-client/src/Helper/OrderHelper.php +34 -0
- modules/ppcp-api-client/src/Repository/PartnerReferralsData.php +47 -40
- modules/ppcp-button/assets/js/button.js +1 -1
- modules/ppcp-button/resources/js/button.js +15 -0
- modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +5 -3
- modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +4 -0
- modules/ppcp-button/resources/js/modules/Renderer/MessageRenderer.js +9 -0
- modules/ppcp-button/services.php +26 -15
- modules/ppcp-button/src/Assets/SmartButton.php +109 -41
- modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php +13 -3
- modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +5 -6
- modules/ppcp-button/src/Endpoint/RequestData.php +3 -9
- modules/ppcp-onboarding/assets/js/onboarding.js +32 -0
- modules/ppcp-onboarding/services.php +27 -3
- modules/ppcp-onboarding/src/Assets/OnboardingAssets.php +2 -0
- modules/ppcp-onboarding/src/Endpoint/LoginSellerEndpoint.php +2 -0
- modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php +143 -0
- modules/ppcp-onboarding/src/OnboardingModule.php +8 -0
- modules/ppcp-onboarding/src/OnboardingRESTController.php +1 -0
- modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php +38 -5
- modules/ppcp-onboarding/src/Render/OnboardingRenderer.php +20 -1
- modules/ppcp-session/src/Cancellation/CancelController.php +8 -1
- modules/ppcp-wc-gateway/assets/js/pay-upon-invoice.js +1 -0
- modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +55 -0
- modules/ppcp-wc-gateway/services.php +133 -44
- modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +29 -2
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php +59 -0
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php +46 -0
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php +41 -0
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +515 -0
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +274 -0
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php +322 -0
- modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +59 -0
- modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php +140 -0
- modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php +106 -0
- modules/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php +1 -0
- modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php +2 -0
- modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php +19 -9
- modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +23 -5
- modules/ppcp-wc-gateway/src/Settings/SettingsListener.php +28 -1
- modules/ppcp-wc-gateway/src/WCGatewayModule.php +43 -1
- modules/ppcp-wc-gateway/webpack.config.js +1 -0
- modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +5 -0
- modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php +5 -0
- modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php +7 -2
- readme.txt +19 -2
- vendor/autoload.php +1 -1
- vendor/composer/autoload_classmap.php +1 -0
- vendor/composer/autoload_real.php +7 -7
- vendor/composer/autoload_static.php +5 -4
- vendor/composer/installed.json +7 -7
- vendor/symfony/polyfill-php80/Php80.php +11 -1
- vendor/symfony/polyfill-php80/PhpToken.php +103 -0
- vendor/symfony/polyfill-php80/README.md +4 -3
- vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php +7 -0
- vendor/symfony/polyfill-php80/composer.json +1 -1
- 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 |
-
|
24 |
-
|
|
|
|
|
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 (
|
|
|
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 |
-
|
|
|
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
|
21 |
-
const
|
22 |
-
const
|
23 |
-
const
|
24 |
-
const
|
25 |
-
const
|
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::
|
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
|
347 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
$
|
397 |
-
$
|
|
|
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 |
-
$
|
73 |
-
$
|
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()
|
84 |
$this->currency
|
85 |
);
|
86 |
|
87 |
$taxes = new Money(
|
88 |
-
$cart->
|
89 |
$this->currency
|
90 |
);
|
91 |
|
92 |
$discount = null;
|
93 |
if ( $cart->get_discount_total() ) {
|
94 |
$discount = new Money(
|
95 |
-
(float) $cart->get_discount_total()
|
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(
|
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)
|
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()
|
171 |
$currency
|
172 |
);
|
173 |
$taxes = new Money(
|
174 |
-
(float)
|
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
|
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( $
|
64 |
$quantity,
|
65 |
substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ) ?: '',
|
66 |
-
|
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 |
-
|
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( $
|
143 |
new Money( $price_without_tax_rounded, $currency ),
|
144 |
$quantity,
|
145 |
-
substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ) ?: '',
|
146 |
-
|
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 |
-
|
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 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
'
|
82 |
-
'
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
),
|
92 |
-
'
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
'granted' => true,
|
99 |
),
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
|
|
|
|
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§ion=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
|
|
|
|
|
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:
|
38 |
createaccount: createaccount
|
39 |
})
|
40 |
}).then(function (res) {
|
@@ -59,7 +61,7 @@ class CheckoutActionHandler {
|
|
59 |
}
|
60 |
}
|
61 |
|
62 |
-
|
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'
|
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'
|
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'
|
95 |
return plugins_url(
|
96 |
'/modules/ppcp-button/',
|
97 |
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
98 |
);
|
99 |
},
|
100 |
-
'button.request-data'
|
101 |
return new RequestData();
|
102 |
},
|
103 |
-
'button.endpoint.change-cart'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
183 |
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
184 |
return new ThreeDSecure( $logger );
|
185 |
},
|
186 |
-
'button.helper.messages-apply'
|
187 |
return new MessagesApply(
|
188 |
$container->get( 'api.shop.country' )
|
189 |
);
|
190 |
},
|
191 |
|
192 |
-
'button.is-logged-in'
|
193 |
return is_user_logged_in();
|
194 |
},
|
195 |
-
'button.registration-required'
|
196 |
return WC()->checkout()->is_registration_required();
|
197 |
},
|
198 |
-
'button.current-user-must-register'
|
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
|
200 |
-
$this->version
|
201 |
-
$this->session_handler
|
202 |
-
$this->settings
|
203 |
-
$this->payer_factory
|
204 |
-
$this->client_id
|
205 |
-
$this->request_data
|
206 |
-
$this->dcc_applies
|
207 |
-
$this->subscription_helper
|
208 |
-
$this->messages_apply
|
209 |
-
$this->environment
|
210 |
-
$this->payment_token_repository
|
211 |
-
$this->settings_status
|
212 |
-
$this->currency
|
213 |
-
$this->all_funding_sources
|
214 |
-
$this->
|
|
|
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 |
-
|
|
|
|
|
|
|
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'
|
765 |
-
'data_client_id'
|
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'
|
773 |
-
'context'
|
774 |
-
'ajax'
|
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'
|
793 |
-
'can_save_vault_token'
|
794 |
-
'is_free_trial_cart'
|
795 |
-
'vaulted_paypal_email'
|
796 |
-
'bn_codes'
|
797 |
-
'payer'
|
798 |
-
'button'
|
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'
|
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'
|
840 |
-
'labels'
|
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'
|
849 |
-
'single_product_buttons_enabled'
|
850 |
-
'mini_cart_buttons_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 =
|
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->
|
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' ) ) && $
|
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
|
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 |
-
|
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
|
453 |
* @throws \RuntimeException When field is not checked.
|
454 |
*/
|
455 |
-
private function validate_paynow_form(
|
456 |
-
$
|
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 |
-
|
86 |
-
|
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
|
34 |
-
* @param string
|
|
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
155 |
return new Settings();
|
156 |
},
|
157 |
-
'wcgateway.notice.connect'
|
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'
|
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'
|
174 |
-
return new SectionsRenderer(
|
|
|
|
|
|
|
175 |
},
|
176 |
-
'wcgateway.settings.status'
|
177 |
$settings = $container->get( 'wcgateway.settings' );
|
178 |
return new SettingsStatus( $settings );
|
179 |
},
|
180 |
-
'wcgateway.settings.render'
|
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'
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
},
|
210 |
-
'wcgateway.order-processor'
|
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'
|
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'
|
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'
|
256 |
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
257 |
return new RenderAuthorizeAction( $column );
|
258 |
},
|
259 |
-
'wcgateway.admin.order-payment-status'
|
260 |
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
261 |
return new PaymentStatusOrderDetail( $column );
|
262 |
},
|
263 |
-
'wcgateway.admin.orders-payment-status-column'
|
264 |
$settings = $container->get( 'wcgateway.settings' );
|
265 |
return new OrderTablePaymentStatusColumn( $settings );
|
266 |
},
|
267 |
-
'wcgateway.admin.fees-renderer'
|
268 |
return new FeesRenderer();
|
269 |
},
|
270 |
|
271 |
-
'wcgateway.settings.fields'
|
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'
|
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'
|
2066 |
|
2067 |
return new CheckoutPayPalAddressPreset(
|
2068 |
$container->get( 'session.handler' )
|
2069 |
);
|
2070 |
},
|
2071 |
-
'wcgateway.url'
|
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'
|
2078 |
return 'modules/ppcp-wc-gateway/';
|
2079 |
},
|
2080 |
-
'wcgateway.absolute-path'
|
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'
|
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'
|
2098 |
return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
2099 |
},
|
2100 |
|
2101 |
-
'wcgateway.transaction-url-live'
|
2102 |
return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
2103 |
},
|
2104 |
|
2105 |
-
'wcgateway.transaction-url-provider'
|
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'
|
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'
|
2120 |
return new MessagesDisclaimers(
|
2121 |
$container->get( 'api.shop.country' )
|
2122 |
);
|
2123 |
},
|
2124 |
|
2125 |
-
'wcgateway.funding-source.renderer'
|
2126 |
return new FundingSourceRenderer(
|
2127 |
$container->get( 'wcgateway.settings' )
|
2128 |
);
|
2129 |
},
|
2130 |
-
|
2131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2132 |
$settings = $container->get( 'wcgateway.settings' );
|
2133 |
|
2134 |
/**
|
@@ -2140,7 +2229,7 @@ return array(
|
|
2140 |
);
|
2141 |
},
|
2142 |
|
2143 |
-
'wcgateway.helper.vaulting-scope'
|
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'
|
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'
|
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§ion=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§ion=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->
|
164 |
$error_message = __(
|
165 |
-
'The payment
|
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( '
|
208 |
}
|
209 |
$this->last_error = '';
|
210 |
return true;
|
@@ -269,15 +280,15 @@ class OrderProcessor {
|
|
269 |
}
|
270 |
|
271 |
/**
|
272 |
-
* Whether a given order is
|
273 |
*
|
274 |
* @param Order $order The order.
|
275 |
*
|
276 |
* @return bool
|
277 |
*/
|
278 |
-
private function
|
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 |
-
|
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
|
|
|
37 |
}
|
38 |
|
39 |
/**
|
@@ -54,17 +64,25 @@ class SectionsRenderer {
|
|
54 |
}
|
55 |
|
56 |
$sections = array(
|
57 |
-
PayPalGateway::ID
|
58 |
-
CreditCardGateway::ID
|
59 |
-
|
|
|
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§ion=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§ion=ppcp-gateway&' . self::KEY . '=' . $id );
|
83 |
+
if ( PayUponInvoiceGateway::ID === $id ) {
|
84 |
+
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=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 |
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
|
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
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff
|
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
-
spl_autoload_register(array('
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
-
spl_autoload_unregister(array('
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
-
call_user_func(\Composer\Autoload\
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
@@ -51,19 +51,19 @@ class ComposerAutoloaderInit5a08559ae58536f83fd0f0260535ccff
|
|
51 |
$loader->register(true);
|
52 |
|
53 |
if ($useStaticLoader) {
|
54 |
-
$includeFiles = Composer\Autoload\
|
55 |
} else {
|
56 |
$includeFiles = require __DIR__ . '/autoload_files.php';
|
57 |
}
|
58 |
foreach ($includeFiles as $fileIdentifier => $file) {
|
59 |
-
|
60 |
}
|
61 |
|
62 |
return $loader;
|
63 |
}
|
64 |
}
|
65 |
|
66 |
-
function
|
67 |
{
|
68 |
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
69 |
require $file;
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class 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
|
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 =
|
176 |
-
$loader->prefixDirsPsr4 =
|
177 |
-
$loader->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.
|
534 |
-
"version_normalized": "1.
|
535 |
"source": {
|
536 |
"type": "git",
|
537 |
"url": "https://github.com/symfony/polyfill-php80.git",
|
538 |
-
"reference": "
|
539 |
},
|
540 |
"dist": {
|
541 |
"type": "zip",
|
542 |
-
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/
|
543 |
-
"reference": "
|
544 |
"shasum": ""
|
545 |
},
|
546 |
"require": {
|
547 |
"php": ">=7.1"
|
548 |
},
|
549 |
-
"time": "
|
550 |
"type": "library",
|
551 |
"extra": {
|
552 |
"branch-alias": {
|
553 |
-
"dev-main": "1.
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
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.
|
7 |
* Author: WooCommerce
|
8 |
* Author URI: https://woocommerce.com/
|
9 |
* License: GPL-2.0
|
10 |
* Requires PHP: 7.1
|
11 |
* WC requires at least: 3.9
|
12 |
-
* WC tested up to: 6.
|
13 |
* Text Domain: woocommerce-paypal-payments
|
14 |
*
|
15 |
* @package WooCommerce\PayPalCommerce
|
@@ -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 |
-
|
|
|
|
|
|
|
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.
|