From db4b667c576766f56abaef991df6b2063740494e Mon Sep 17 00:00:00 2001
From: Woo
Date: Tue, 23 Apr 2024 18:19:15 +0000
Subject: [PATCH] Updates to 2.1.0
---
assets/css/wc-pre-orders-admin.css | 1 +
assets/css/wc-pre-orders-admin.scss | 187 ++
assets/js/admin/wc-pre-orders-admin.js | 46 +
assets/js/admin/wc-pre-orders-admin.min.js | 1 +
.../jquery-ui-timepicker-addon.js | 1919 +++++++++++++++++
.../jquery-ui-timepicker-addon.min.js | 1 +
.../jquery.countdown/jquery.countdown-ar.js | 13 +
.../jquery.countdown-ar.min.js | 1 +
.../jquery.countdown/jquery.countdown-bg.js | 13 +
.../jquery.countdown-bg.min.js | 1 +
.../jquery.countdown/jquery.countdown-bn.js | 14 +
.../jquery.countdown-bn.min.js | 1 +
.../jquery.countdown/jquery.countdown-bs.js | 16 +
.../jquery.countdown-bs.min.js | 1 +
.../jquery.countdown/jquery.countdown-ca.js | 13 +
.../jquery.countdown-ca.min.js | 1 +
.../jquery.countdown/jquery.countdown-cs.js | 16 +
.../jquery.countdown-cs.min.js | 1 +
.../jquery.countdown/jquery.countdown-cy.js | 1 +
.../jquery.countdown-cy.min.js | 1 +
.../jquery.countdown/jquery.countdown-da.js | 13 +
.../jquery.countdown-da.min.js | 1 +
.../jquery.countdown/jquery.countdown-de.js | 13 +
.../jquery.countdown-de.min.js | 1 +
.../jquery.countdown/jquery.countdown-el.js | 13 +
.../jquery.countdown-el.min.js | 1 +
.../jquery.countdown/jquery.countdown-es.js | 13 +
.../jquery.countdown-es.min.js | 1 +
.../jquery.countdown/jquery.countdown-et.js | 13 +
.../jquery.countdown-et.min.js | 1 +
.../jquery.countdown/jquery.countdown-fa.js | 13 +
.../jquery.countdown-fa.min.js | 1 +
.../jquery.countdown/jquery.countdown-fi.js | 13 +
.../jquery.countdown-fi.min.js | 1 +
.../jquery.countdown/jquery.countdown-fr.js | 15 +
.../jquery.countdown-fr.min.js | 1 +
.../jquery.countdown/jquery.countdown-gl.js | 13 +
.../jquery.countdown-gl.min.js | 1 +
.../jquery.countdown/jquery.countdown-gu.js | 13 +
.../jquery.countdown-gu.min.js | 1 +
.../jquery.countdown/jquery.countdown-he.js | 13 +
.../jquery.countdown-he.min.js | 1 +
.../jquery.countdown/jquery.countdown-hr.js | 16 +
.../jquery.countdown-hr.min.js | 1 +
.../jquery.countdown/jquery.countdown-hu.js | 13 +
.../jquery.countdown-hu.min.js | 1 +
.../jquery.countdown/jquery.countdown-hy.js | 13 +
.../jquery.countdown-hy.min.js | 1 +
.../jquery.countdown/jquery.countdown-id.js | 13 +
.../jquery.countdown-id.min.js | 1 +
.../jquery.countdown/jquery.countdown-it.js | 13 +
.../jquery.countdown-it.min.js | 1 +
.../jquery.countdown/jquery.countdown-ja.js | 13 +
.../jquery.countdown-ja.min.js | 1 +
.../jquery.countdown/jquery.countdown-kn.js | 13 +
.../jquery.countdown-kn.min.js | 1 +
.../jquery.countdown/jquery.countdown-ko.js | 14 +
.../jquery.countdown-ko.min.js | 1 +
.../jquery.countdown/jquery.countdown-lt.js | 13 +
.../jquery.countdown-lt.min.js | 1 +
.../jquery.countdown/jquery.countdown-lv.js | 13 +
.../jquery.countdown-lv.min.js | 1 +
.../jquery.countdown/jquery.countdown-ms.js | 13 +
.../jquery.countdown-ms.min.js | 1 +
.../jquery.countdown/jquery.countdown-my.js | 13 +
.../jquery.countdown-my.min.js | 1 +
.../jquery.countdown/jquery.countdown-nb.js | 13 +
.../jquery.countdown-nb.min.js | 1 +
.../jquery.countdown/jquery.countdown-nl.js | 13 +
.../jquery.countdown-nl.min.js | 1 +
.../jquery.countdown/jquery.countdown-pl.js | 18 +
.../jquery.countdown-pl.min.js | 1 +
.../jquery.countdown-pt-BR.js | 14 +
.../jquery.countdown-pt-BR.min.js | 1 +
.../jquery.countdown/jquery.countdown-ro.js | 13 +
.../jquery.countdown-ro.min.js | 1 +
.../jquery.countdown/jquery.countdown-ru.js | 19 +
.../jquery.countdown-ru.min.js | 1 +
.../jquery.countdown/jquery.countdown-sk.js | 16 +
.../jquery.countdown-sk.min.js | 1 +
.../jquery.countdown/jquery.countdown-sl.js | 13 +
.../jquery.countdown-sl.min.js | 1 +
.../jquery.countdown/jquery.countdown-sq.js | 13 +
.../jquery.countdown-sq.min.js | 1 +
.../jquery.countdown-sr-SR.js | 16 +
.../jquery.countdown-sr-SR.min.js | 1 +
.../jquery.countdown/jquery.countdown-sr.js | 16 +
.../jquery.countdown-sr.min.js | 1 +
.../jquery.countdown/jquery.countdown-sv.js | 13 +
.../jquery.countdown-sv.min.js | 1 +
.../jquery.countdown/jquery.countdown-th.js | 13 +
.../jquery.countdown-th.min.js | 1 +
.../jquery.countdown/jquery.countdown-tr.js | 13 +
.../jquery.countdown-tr.min.js | 1 +
.../jquery.countdown/jquery.countdown-uk.js | 16 +
.../jquery.countdown-uk.min.js | 1 +
.../jquery.countdown/jquery.countdown-uz.js | 13 +
.../jquery.countdown-uz.min.js | 1 +
.../jquery.countdown/jquery.countdown-vi.js | 13 +
.../jquery.countdown-vi.min.js | 1 +
.../jquery.countdown-zh-CN.js | 13 +
.../jquery.countdown-zh-CN.min.js | 1 +
.../jquery.countdown-zh-TW.js | 13 +
.../jquery.countdown-zh-TW.min.js | 1 +
.../js/jquery.countdown/jquery.countdown.js | 800 +++++++
.../jquery.countdown/jquery.countdown.min.js | 1 +
.../admin/blocks/date-time-picker/block.json | 34 +
.../blocks/date-time-picker/index.asset.php | 1 +
build/admin/blocks/date-time-picker/index.js | 1 +
build/admin/blocks/message-control/block.json | 22 +
.../blocks/message-control/index.asset.php | 1 +
build/admin/blocks/message-control/index.js | 1 +
build/admin/blocks/select-control/block.json | 38 +
.../blocks/select-control/index.asset.php | 1 +
build/admin/blocks/select-control/index.js | 1 +
build/gateway/index.asset.php | 1 +
build/gateway/index.css | 1 +
build/gateway/index.js | 3 +
changelog.txt | 405 ++++
.../admin/class-wc-pre-orders-admin-ajax.php | 151 ++
.../class-wc-pre-orders-admin-orders.php | 277 +++
.../class-wc-pre-orders-admin-pre-orders.php | 833 +++++++
.../class-wc-pre-orders-admin-products.php | 182 ++
.../class-wc-pre-orders-admin-settings.php | 202 ++
includes/admin/class-wc-pre-orders-admin.php | 123 ++
...re-orders-product-editor-compatibility.php | 293 +++
includes/admin/filters.php | 56 +
.../admin/views/html-product-tab-options.php | 87 +
.../class-wc-pre-orders-blocks-gateway.php | 140 ++
...class-wc-pre-orders-blocks-integration.php | 119 +
.../class-wc-pre-orders-extend-store-api.php | 107 +
includes/class-wc-pre-orders-cart.php | 296 +++
includes/class-wc-pre-orders-checkout.php | 317 +++
includes/class-wc-pre-orders-cron.php | 78 +
includes/class-wc-pre-orders-list-table.php | 856 ++++++++
includes/class-wc-pre-orders-manager.php | 1002 +++++++++
.../class-wc-pre-orders-my-pre-orders.php | 189 ++
includes/class-wc-pre-orders-order.php | 474 ++++
includes/class-wc-pre-orders-privacy.php | 24 +
includes/class-wc-pre-orders-product.php | 589 +++++
includes/class-wc-pre-orders.php | 443 ++++
...orders-email-admin-pre-order-cancelled.php | 130 ++
...lass-wc-pre-orders-email-new-pre-order.php | 188 ++
...c-pre-orders-email-pre-order-available.php | 140 ++
...c-pre-orders-email-pre-order-cancelled.php | 138 ++
...re-orders-email-pre-order-date-changed.php | 157 ++
.../class-wc-pre-orders-email-pre-ordered.php | 141 ++
.../class-wc-pre-orders-gateway-pay-later.php | 175 ++
...lass-wc-pre-orders-shortcode-countdown.php | 229 ++
languages/woocommerce-pre-orders.pot | 1152 ++++++++++
src/admin/blocks/date-time-picker/block.json | 34 +
src/admin/blocks/date-time-picker/edit.tsx | 98 +
src/admin/blocks/date-time-picker/index.ts | 30 +
src/admin/blocks/message-control/block.json | 22 +
src/admin/blocks/message-control/edit.tsx | 27 +
src/admin/blocks/message-control/index.ts | 30 +
src/admin/blocks/select-control/block.json | 38 +
src/admin/blocks/select-control/edit.tsx | 47 +
src/admin/blocks/select-control/index.ts | 30 +
src/preorder-gateway/gateway.js | 45 +
src/preorder-gateway/index.js | 95 +
src/preorder-gateway/index.scss | 1 +
templates/emails/admin-new-pre-order.php | 35 +
.../emails/admin-pre-order-cancelled.php | 76 +
.../emails/customer-pre-order-available.php | 102 +
.../emails/customer-pre-order-cancelled.php | 47 +
.../customer-pre-order-date-changed.php | 55 +
templates/emails/customer-pre-ordered.php | 63 +
.../emails/plain/admin-new-pre-order.php | 57 +
.../plain/admin-pre-order-cancelled.php | 70 +
.../plain/customer-pre-order-available.php | 81 +
.../plain/customer-pre-order-cancelled.php | 63 +
.../plain/customer-pre-order-date-changed.php | 70 +
.../emails/plain/customer-pre-ordered.php | 71 +
templates/myaccount/my-pre-orders.php | 79 +
woocommerce-pre-orders.php | 96 +
176 files changed, 14927 insertions(+)
create mode 100644 assets/css/wc-pre-orders-admin.css
create mode 100644 assets/css/wc-pre-orders-admin.scss
create mode 100644 assets/js/admin/wc-pre-orders-admin.js
create mode 100644 assets/js/admin/wc-pre-orders-admin.min.js
create mode 100644 assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.js
create mode 100644 assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ar.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ar.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-bg.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-bg.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-bn.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-bn.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-bs.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-bs.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ca.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ca.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-cs.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-cs.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-cy.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-cy.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-da.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-da.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-de.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-de.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-el.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-el.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-es.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-es.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-et.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-et.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-fa.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-fa.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-fi.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-fi.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-fr.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-fr.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-gl.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-gl.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-gu.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-gu.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-he.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-he.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-hr.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-hr.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-hu.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-hu.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-hy.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-hy.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-id.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-id.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-it.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-it.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ja.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ja.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-kn.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-kn.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ko.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ko.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-lt.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-lt.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-lv.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-lv.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ms.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ms.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-my.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-my.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-nb.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-nb.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-nl.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-nl.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-pl.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-pl.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-pt-BR.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-pt-BR.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ro.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ro.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-ru.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-ru.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-sk.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-sk.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-sl.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-sl.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-sq.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-sq.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-sr-SR.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-sr-SR.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-sr.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-sr.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-sv.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-sv.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-th.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-th.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-tr.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-tr.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-uk.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-uk.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-uz.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-uz.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-vi.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-vi.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-zh-CN.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-zh-CN.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown-zh-TW.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown-zh-TW.min.js
create mode 100755 assets/js/jquery.countdown/jquery.countdown.js
create mode 100644 assets/js/jquery.countdown/jquery.countdown.min.js
create mode 100644 build/admin/blocks/date-time-picker/block.json
create mode 100644 build/admin/blocks/date-time-picker/index.asset.php
create mode 100644 build/admin/blocks/date-time-picker/index.js
create mode 100644 build/admin/blocks/message-control/block.json
create mode 100644 build/admin/blocks/message-control/index.asset.php
create mode 100644 build/admin/blocks/message-control/index.js
create mode 100644 build/admin/blocks/select-control/block.json
create mode 100644 build/admin/blocks/select-control/index.asset.php
create mode 100644 build/admin/blocks/select-control/index.js
create mode 100644 build/gateway/index.asset.php
create mode 100644 build/gateway/index.css
create mode 100644 build/gateway/index.js
create mode 100644 changelog.txt
create mode 100644 includes/admin/class-wc-pre-orders-admin-ajax.php
create mode 100644 includes/admin/class-wc-pre-orders-admin-orders.php
create mode 100644 includes/admin/class-wc-pre-orders-admin-pre-orders.php
create mode 100644 includes/admin/class-wc-pre-orders-admin-products.php
create mode 100644 includes/admin/class-wc-pre-orders-admin-settings.php
create mode 100644 includes/admin/class-wc-pre-orders-admin.php
create mode 100644 includes/admin/class-wc-pre-orders-product-editor-compatibility.php
create mode 100644 includes/admin/filters.php
create mode 100644 includes/admin/views/html-product-tab-options.php
create mode 100644 includes/blocks/class-wc-pre-orders-blocks-gateway.php
create mode 100644 includes/blocks/class-wc-pre-orders-blocks-integration.php
create mode 100644 includes/blocks/class-wc-pre-orders-extend-store-api.php
create mode 100644 includes/class-wc-pre-orders-cart.php
create mode 100644 includes/class-wc-pre-orders-checkout.php
create mode 100644 includes/class-wc-pre-orders-cron.php
create mode 100644 includes/class-wc-pre-orders-list-table.php
create mode 100644 includes/class-wc-pre-orders-manager.php
create mode 100644 includes/class-wc-pre-orders-my-pre-orders.php
create mode 100644 includes/class-wc-pre-orders-order.php
create mode 100644 includes/class-wc-pre-orders-privacy.php
create mode 100644 includes/class-wc-pre-orders-product.php
create mode 100644 includes/class-wc-pre-orders.php
create mode 100644 includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php
create mode 100644 includes/emails/class-wc-pre-orders-email-new-pre-order.php
create mode 100644 includes/emails/class-wc-pre-orders-email-pre-order-available.php
create mode 100644 includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php
create mode 100644 includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php
create mode 100644 includes/emails/class-wc-pre-orders-email-pre-ordered.php
create mode 100644 includes/gateways/class-wc-pre-orders-gateway-pay-later.php
create mode 100644 includes/shortcodes/class-wc-pre-orders-shortcode-countdown.php
create mode 100644 languages/woocommerce-pre-orders.pot
create mode 100644 src/admin/blocks/date-time-picker/block.json
create mode 100644 src/admin/blocks/date-time-picker/edit.tsx
create mode 100644 src/admin/blocks/date-time-picker/index.ts
create mode 100644 src/admin/blocks/message-control/block.json
create mode 100644 src/admin/blocks/message-control/edit.tsx
create mode 100644 src/admin/blocks/message-control/index.ts
create mode 100644 src/admin/blocks/select-control/block.json
create mode 100644 src/admin/blocks/select-control/edit.tsx
create mode 100644 src/admin/blocks/select-control/index.ts
create mode 100644 src/preorder-gateway/gateway.js
create mode 100644 src/preorder-gateway/index.js
create mode 100644 src/preorder-gateway/index.scss
create mode 100644 templates/emails/admin-new-pre-order.php
create mode 100644 templates/emails/admin-pre-order-cancelled.php
create mode 100644 templates/emails/customer-pre-order-available.php
create mode 100644 templates/emails/customer-pre-order-cancelled.php
create mode 100644 templates/emails/customer-pre-order-date-changed.php
create mode 100644 templates/emails/customer-pre-ordered.php
create mode 100644 templates/emails/plain/admin-new-pre-order.php
create mode 100644 templates/emails/plain/admin-pre-order-cancelled.php
create mode 100644 templates/emails/plain/customer-pre-order-available.php
create mode 100644 templates/emails/plain/customer-pre-order-cancelled.php
create mode 100644 templates/emails/plain/customer-pre-order-date-changed.php
create mode 100644 templates/emails/plain/customer-pre-ordered.php
create mode 100644 templates/myaccount/my-pre-orders.php
create mode 100644 woocommerce-pre-orders.php
diff --git a/assets/css/wc-pre-orders-admin.css b/assets/css/wc-pre-orders-admin.css
new file mode 100644
index 0000000..663b277
--- /dev/null
+++ b/assets/css/wc-pre-orders-admin.css
@@ -0,0 +1 @@
+.widefat .column-order_status mark.pre-ordered{display:block;text-indent:-9999px;position:relative;height:1em;width:1em;background:0 0;font-size:1.4em;margin:0 auto}.widefat .column-order_status mark.pre-ordered:after{font-family:WooCommerce;speak:none;font-weight:400;font-variant:normal;text-transform:none;line-height:1;margin:0;text-indent:0;position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;content:"";color:#7ad03a}.pre-orders .column-status{width:90px}#woocommerce-product-data ul.product_data_tabs li.wc_pre_orders_tab a:before{content:""}.ui-timepicker-div .ui-widget-header{margin-bottom:8px}.ui-timepicker-div dl{text-align:left}.ui-timepicker-div dl dt{height:25px;margin-bottom:-25px}.ui-timepicker-div dl dd{margin:0 10px 10px 65px}.ui-timepicker-div td{font-size:90%}.ui-tpicker-grid-label{background:0 0;border:none;margin:0;padding:0}.ui-timepicker-rtl{direction:rtl}.ui-timepicker-rtl dl{text-align:right}.ui-timepicker-rtl dl dd{margin:0 65px 10px 10px}.widefat.pre-orders td.column-status{padding:6px 7px}.widefat.pre-orders .column-status{text-align:left}.widefat.pre-orders .column-status mark.active,.widefat.pre-orders .column-status mark.cancelled,.widefat.pre-orders .column-status mark.completed{display:block;text-indent:-9999px;position:relative;height:1em;width:1em;background:0 0;font-size:1.4em;margin:0 auto}.widefat.pre-orders .column-status mark.active:after,.widefat.pre-orders .column-status mark.cancelled:after,.widefat.pre-orders .column-status mark.completed:after{font-family:WooCommerce;speak:none;font-weight:400;font-variant:normal;text-transform:none;line-height:1;margin:0;text-indent:0;position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;content:""}.widefat.pre-orders .column-status mark.active:after{content:"\e012";color:#7ad03a}.widefat.pre-orders .column-status mark.completed:after{content:"\e015";color:#2ea2cc}.widefat.pre-orders .column-status mark.cancelled:after{content:"\e013";color:#a00}.widefat.pre-orders .column-customer{width:15%}.widefat.pre-orders .column-product{width:30%}.widefat.pre-orders .column-order{width:15%}.widefat.pre-orders .column-order_date{width:100px}.widefat.pre-orders .column-availability-date{width:100px}.wp-list-table.pre-orders .column-status .row-actions{text-align:center}.wp-list-table.pre-orders .column-status .row-actions .cancel a{color:#a00}.wp-list-table.pre-orders .column-status .row-actions .cancel a:hover{color:#e44}
\ No newline at end of file
diff --git a/assets/css/wc-pre-orders-admin.scss b/assets/css/wc-pre-orders-admin.scss
new file mode 100644
index 0000000..20c3945
--- /dev/null
+++ b/assets/css/wc-pre-orders-admin.scss
@@ -0,0 +1,187 @@
+// WooCommerce Pre-Orders Admin.
+
+// Variables from woocommerce/assets/css/_variables.scss.
+$green: #7ad03a;
+$red: #a00;
+$blue: #2ea2cc;
+
+// Mixins from woocommerce/assets/css/_mixins.scss.
+@mixin ir() {
+ display: block;
+ text-indent: -9999px;
+ position: relative;
+ height: 1em;
+ width: 1em;
+}
+
+@mixin icon( $glyph: '\e001' ) {
+ font-family: 'WooCommerce';
+ speak: none;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ margin: 0;
+ text-indent: 0;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ content: $glyph;
+}
+
+// Order status icon
+.widefat .column-order_status {
+ mark.pre-ordered {
+ @include ir();
+ background: none;
+ font-size: 1.4em;
+ margin: 0 auto;
+
+ &:after {
+ @include icon( "\e012" );
+ color: $green;
+ }
+ }
+}
+.pre-orders {
+ .column-status {
+ width: 90px;
+ }
+}
+
+// Product tab
+#woocommerce-product-data {
+ ul.product_data_tabs {
+ li.wc_pre_orders_tab a {
+ &:before {
+ content: "";
+ }
+ }
+ }
+}
+
+// jQuery UI timepicker
+.ui-timepicker-div {
+
+ .ui-widget-header {
+ margin-bottom: 8px;
+ }
+
+ dl {
+ text-align: left;
+ dt {
+ height: 25px; margin-bottom: -25px;
+ }
+ dd {
+ margin: 0 10px 10px 65px;
+ }
+ }
+
+ td {
+ font-size: 90%;
+ }
+}
+
+.ui-tpicker-grid-label {
+ background: none;
+ border: none;
+ margin: 0;
+ padding: 0;
+}
+
+.ui-timepicker-rtl {
+ direction: rtl;
+ dl {
+ text-align: right;
+ dd {
+ margin: 0 65px 10px 10px;
+ }
+ }
+}
+
+// List Table
+.widefat.pre-orders {
+
+ td {
+ &.column-status {
+ padding: 6px 7px;
+ }
+
+ }
+
+ .column-status {
+ text-align: left;
+
+ mark.active, mark.completed, mark.cancelled {
+ @include ir();
+ background: none;
+ font-size: 1.4em;
+ margin: 0 auto;
+
+ &:after {
+ @include icon();
+ }
+ }
+
+ mark {
+ &.active {
+ &:after {
+ content: "\e012";
+ color: $green;
+ }
+ }
+ &.completed {
+ &:after {
+ content: "\e015";
+ color: $blue;
+ }
+ }
+ &.cancelled {
+ &:after {
+ content: "\e013";
+ color: $red;
+ }
+ }
+ }
+ }
+
+ .column-customer {
+ width: 15%;
+ }
+
+ .column-product {
+ width: 30%;
+ }
+
+ .column-order {
+ width: 15%;
+ }
+
+ .column-order_date {
+ width: 100px;
+ }
+
+ .column-availability-date {
+ width: 100px;
+ }
+}
+
+// List table row actions
+.wp-list-table.pre-orders .column-status .row-actions {
+ text-align: center;
+
+ .cancel {
+ a {
+ color: $red;
+
+ &:hover {
+ color: $red + #444;
+ }
+ }
+ }
+}
+
+
diff --git a/assets/js/admin/wc-pre-orders-admin.js b/assets/js/admin/wc-pre-orders-admin.js
new file mode 100644
index 0000000..bf0576e
--- /dev/null
+++ b/assets/js/admin/wc-pre-orders-admin.js
@@ -0,0 +1,46 @@
+jQuery( document ).ready( function( $ ) {
+ 'use strict';
+
+ var $actionEmailMessage = $( 'textarea[name="wc_pre_orders_action_email_message"]' ),
+ $dateTimeField = null;
+
+ // Get the proper datetime field (either on the edit product page or the pre-orders > actions tab
+ if ( $( 'input[name="_wc_pre_orders_availability_datetime"]' ).length ) {
+ $dateTimeField = $( 'input[name="_wc_pre_orders_availability_datetime"]' );
+ } else if ( $( 'input[name="wc_pre_orders_action_new_availability_date"]').length ) {
+ $dateTimeField = $( 'input[name="wc_pre_orders_action_new_availability_date"]' );
+ }
+
+ // Add Pre-Order DateTimePicker (see http://trentrichardson.com/examples/timepicker/)
+ if ( null !== $dateTimeField ) {
+ $dateTimeField.datetimepicker({
+ dateFormat: 'yy-mm-dd',
+ numberOfMonths: 1
+ });
+ }
+
+ // Hide email notification message textarea when "send email notification" is disabled
+ if ( $actionEmailMessage.length ) {
+ $( 'input[name="wc_pre_orders_action_enable_email_notification"]').on( 'change', function() {
+ if ( ! $( this ).is( ':checked' ) ) {
+ $actionEmailMessage.removeAttr( 'required' );
+ $actionEmailMessage.closest( 'tr' ).hide();
+ } else {
+ $actionEmailMessage.closest( 'tr' ).show();
+ $actionEmailMessage.attr( 'required', 'required' );
+ }
+ }).trigger( 'change' );
+ }
+
+ /**
+ * Hide pre-orders options when product type is changed to variable-subscription.
+ *
+ * Read explanation about this change in WC_Pre_Orders_Admin_Products::product_data_tab function
+ * @since 2.0.2
+ */
+ $( 'body' ).on( 'woocommerce-product-type-change', function ( e, select_val ) {
+ if ( 'variable-subscription' === select_val ) {
+ $( 'li.pre_orders_options' ).hide();
+ }
+ } );
+});
diff --git a/assets/js/admin/wc-pre-orders-admin.min.js b/assets/js/admin/wc-pre-orders-admin.min.js
new file mode 100644
index 0000000..ae8da20
--- /dev/null
+++ b/assets/js/admin/wc-pre-orders-admin.min.js
@@ -0,0 +1 @@
+jQuery(document).ready(function(i){"use strict";var e=i('textarea[name="wc_pre_orders_action_email_message"]'),t=null;i('input[name="_wc_pre_orders_availability_datetime"]').length?t=i('input[name="_wc_pre_orders_availability_datetime"]'):i('input[name="wc_pre_orders_action_new_availability_date"]').length&&(t=i('input[name="wc_pre_orders_action_new_availability_date"]')),null!==t&&t.datetimepicker({dateFormat:"yy-mm-dd",numberOfMonths:1}),e.length&&i('input[name="wc_pre_orders_action_enable_email_notification"]').on("change",function(){i(this).is(":checked")?(e.closest("tr").show(),e.attr("required","required")):(e.removeAttr("required"),e.closest("tr").hide())}).trigger("change"),i("body").on("woocommerce-product-type-change",function(e,t){"variable-subscription"===t&&i("li.pre_orders_options").hide()})});
diff --git a/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.js b/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.js
new file mode 100644
index 0000000..663195c
--- /dev/null
+++ b/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.js
@@ -0,0 +1,1919 @@
+/*
+ * jQuery timepicker addon
+ * By: Trent Richardson [http://trentrichardson.com]
+ * Version 1.2
+ * Last Modified: 02/02/2013
+ *
+ * Copyright 2013 Trent Richardson
+ * You may use this project under MIT or GPL licenses.
+ * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
+ * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
+ */
+
+/*jslint evil: true, white: false, undef: false, nomen: false */
+
+(function($) {
+
+ /*
+ * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
+ */
+ $.ui.timepicker = $.ui.timepicker || {};
+ if ($.ui.timepicker.version) {
+ return;
+ }
+
+ /*
+ * Extend jQueryUI, get it started with our version number
+ */
+ $.extend($.ui, {
+ timepicker: {
+ version: "1.2"
+ }
+ });
+
+ /*
+ * Timepicker manager.
+ * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+ * Settings for (groups of) time pickers are maintained in an instance object,
+ * allowing multiple different settings on the same page.
+ */
+ var Timepicker = function() {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ currentText: 'Now',
+ closeText: 'Done',
+ amNames: ['AM', 'A'],
+ pmNames: ['PM', 'P'],
+ timeFormat: 'HH:mm',
+ timeSuffix: '',
+ timeOnlyTitle: 'Choose Time',
+ timeText: 'Time',
+ hourText: 'Hour',
+ minuteText: 'Minute',
+ secondText: 'Second',
+ millisecText: 'Millisecond',
+ timezoneText: 'Time Zone',
+ isRTL: false
+ };
+ this._defaults = { // Global defaults for all the datetime picker instances
+ showButtonPanel: true,
+ timeOnly: false,
+ showHour: true,
+ showMinute: true,
+ showSecond: false,
+ showMillisec: false,
+ showTimezone: false,
+ showTime: true,
+ stepHour: 1,
+ stepMinute: 1,
+ stepSecond: 1,
+ stepMillisec: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ timezone: null,
+ useLocalTimezone: false,
+ defaultTimezone: "+0000",
+ hourMin: 0,
+ minuteMin: 0,
+ secondMin: 0,
+ millisecMin: 0,
+ hourMax: 23,
+ minuteMax: 59,
+ secondMax: 59,
+ millisecMax: 999,
+ minDateTime: null,
+ maxDateTime: null,
+ onSelect: null,
+ hourGrid: 0,
+ minuteGrid: 0,
+ secondGrid: 0,
+ millisecGrid: 0,
+ alwaysSetTime: true,
+ separator: ' ',
+ altFieldTimeOnly: true,
+ altTimeFormat: null,
+ altSeparator: null,
+ altTimeSuffix: null,
+ pickerTimeFormat: null,
+ pickerTimeSuffix: null,
+ showTimepicker: true,
+ timezoneIso8601: false,
+ timezoneList: null,
+ addSliderAccess: false,
+ sliderAccessArgs: null,
+ controlType: 'slider',
+ defaultValue: null,
+ parse: 'strict'
+ };
+ $.extend(this._defaults, this.regional['']);
+ };
+
+ $.extend(Timepicker.prototype, {
+ $input: null,
+ $altInput: null,
+ $timeObj: null,
+ inst: null,
+ hour_slider: null,
+ minute_slider: null,
+ second_slider: null,
+ millisec_slider: null,
+ timezone_select: null,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ timezone: null,
+ defaultTimezone: "+0000",
+ hourMinOriginal: null,
+ minuteMinOriginal: null,
+ secondMinOriginal: null,
+ millisecMinOriginal: null,
+ hourMaxOriginal: null,
+ minuteMaxOriginal: null,
+ secondMaxOriginal: null,
+ millisecMaxOriginal: null,
+ ampm: '',
+ formattedDate: '',
+ formattedTime: '',
+ formattedDateTime: '',
+ timezoneList: null,
+ units: ['hour','minute','second','millisec'],
+ control: null,
+
+ /*
+ * Override the default settings for all instances of the time picker.
+ * @param settings object - the new settings to use as defaults (anonymous object)
+ * @return the manager object
+ */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /*
+ * Create a new Timepicker instance
+ */
+ _newInst: function($input, o) {
+ var tp_inst = new Timepicker(),
+ inlineSettings = {},
+ fns = {},
+ overrides, i;
+
+ for (var attrName in this._defaults) {
+ if(this._defaults.hasOwnProperty(attrName)){
+ var attrValue = $input.attr('time:' + attrName);
+ if (attrValue) {
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ }
+ overrides = {
+ beforeShow: function (input, dp_inst) {
+ if (typeof tp_inst._defaults.evnts.beforeShow === 'function'){
+ return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
+ }
+ },
+ onChangeMonthYear: function (year, month, dp_inst) {
+ // Update the time as well : this prevents the time from disappearing from the $input field.
+ tp_inst._updateDateTime(dp_inst);
+ if (typeof tp_inst._defaults.evnts.onChangeMonthYear === 'function') {
+ tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
+ }
+ },
+ onClose: function (dateText, dp_inst) {
+ if (tp_inst.timeDefined === true && $input.val() !== '') {
+ tp_inst._updateDateTime(dp_inst);
+ }
+ if (typeof tp_inst._defaults.evnts.onClose === 'function') {
+ tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
+ }
+ }
+ };
+ for (i in overrides) {
+ if (overrides.hasOwnProperty(i)) {
+ fns[i] = o[i] || null;
+ }
+ }
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, {
+ evnts:fns,
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+ });
+ tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) {
+ return val.toUpperCase();
+ });
+ tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) {
+ return val.toUpperCase();
+ });
+
+ // controlType is string - key to our this._controls
+ if(typeof(tp_inst._defaults.controlType) === 'string'){
+ if($.fn[tp_inst._defaults.controlType] === undefined){
+ tp_inst._defaults.controlType = 'select';
+ }
+ tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
+ }
+ // controlType is an object and must implement create, options, value methods
+ else{
+ tp_inst.control = tp_inst._defaults.controlType;
+ }
+
+ if (tp_inst._defaults.timezoneList === null) {
+ var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000',
+ '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930',
+ '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400'];
+
+ if (tp_inst._defaults.timezoneIso8601) {
+ timezoneList = $.map(timezoneList, function(val) {
+ return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
+ });
+ }
+ tp_inst._defaults.timezoneList = timezoneList;
+ }
+
+ tp_inst.timezone = tp_inst._defaults.timezone;
+ tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin? tp_inst._defaults.hourMin :
+ tp_inst._defaults.hour > tp_inst._defaults.hourMax? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
+ tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin? tp_inst._defaults.minuteMin :
+ tp_inst._defaults.minute > tp_inst._defaults.minuteMax? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
+ tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin? tp_inst._defaults.secondMin :
+ tp_inst._defaults.second > tp_inst._defaults.secondMax? tp_inst._defaults.secondMax : tp_inst._defaults.second;
+ tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin? tp_inst._defaults.millisecMin :
+ tp_inst._defaults.millisec > tp_inst._defaults.millisecMax? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
+ tp_inst.ampm = '';
+ tp_inst.$input = $input;
+
+ if (o.altField) {
+ tp_inst.$altInput = $(o.altField).css({
+ cursor: 'pointer'
+ }).on( 'focus', function() {
+ $input.trigger("focus");
+ });
+ }
+
+ if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
+ tp_inst._defaults.minDate = new Date();
+ }
+ if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
+ tp_inst._defaults.maxDate = new Date();
+ }
+
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+ if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+ }
+ if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+ }
+ if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+ }
+ if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+ }
+ tp_inst.$input.on('focus', function() {
+ tp_inst._onFocus();
+ });
+
+ return tp_inst;
+ },
+
+ /*
+ * add our sliders to the calendar
+ */
+ _addTimePicker: function(dp_inst) {
+ var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
+
+ this.timeDefined = this._parseTime(currDT);
+ this._limitMinMaxDateTime(dp_inst, false);
+ this._injectTimePicker();
+ },
+
+ /*
+ * parse the time string from input value or _setTime
+ */
+ _parseTime: function(timeString, withDate) {
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ if (withDate || !this._defaults.timeOnly) {
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+ try {
+ var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
+ if (!parseRes.timeObj) {
+ return false;
+ }
+ $.extend(this, parseRes.timeObj);
+ } catch (err) {
+ $.timepicker.log("Error parsing the date/time string: " + err +
+ "\ndate/time string = " + timeString +
+ "\ntimeFormat = " + this._defaults.timeFormat +
+ "\ndateFormat = " + dp_dateFormat);
+ return false;
+ }
+ return true;
+ } else {
+ var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
+ if (!timeObj) {
+ return false;
+ }
+ $.extend(this, timeObj);
+ return true;
+ }
+ },
+
+ /*
+ * generate and inject html for timepicker into ui datepicker
+ */
+ _injectTimePicker: function() {
+ var $dp = this.inst.dpDiv,
+ o = this.inst.settings,
+ tp_inst = this,
+ litem = '',
+ uitem = '',
+ max = {},
+ gridSize = {},
+ size = null;
+
+ // Prevent displaying twice
+ if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
+ var noDisplay = ' style="display:none;"',
+ html = '' + '' + o.timeText + ' ' +
+ ' ';
+
+ // Create the markup
+ for(var i=0,l=this.units.length; i' + o[litem +'Text'] + '' +
+ '
';
+
+ if (o['show'+uitem] && o[litem+'Grid'] > 0) {
+ html += '';
+
+ if(litem == 'hour'){
+ for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) {
+ gridSize[litem]++;
+ var tmph = $.datepicker.formatTime(useAmpm(o.pickerTimeFormat || o.timeFormat)? 'hht':'HH', {hour:h}, o);
+ html += '' + tmph + ' ';
+ }
+ }
+ else{
+ for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) {
+ gridSize[litem]++;
+ html += '' + ((m < 10) ? '0' : '') + m + ' ';
+ }
+ }
+
+ html += '
';
+ }
+ html += ' ';
+ }
+
+ // Timezone
+ html += '' + o.timezoneText + ' ';
+ html += ' ';
+
+ // Create the elements from string
+ html += ' ';
+ var $tp = $(html);
+
+ // if we only want time picker...
+ if (o.timeOnly === true) {
+ $tp.prepend('');
+ $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
+ }
+
+ // add sliders, adjust grids, add events
+ for(var i=0,l=tp_inst.units.length; i 0) {
+ size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']);
+ $tp.find('.ui_tpicker_'+litem+' table').css({
+ width: size + "%",
+ marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"),
+ marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0',
+ borderCollapse: 'collapse'
+ }).find("td").on( 'click', function(e){
+ var $t = $(this),
+ h = $t.html(),
+ n = parseInt(h.replace(/[^0-9]/g),10),
+ ap = h.replace(/[^apm]/ig),
+ f = $t.data('for'); // loses scope, so we use data-for
+
+ if(f == 'hour'){
+ if(ap.indexOf('p') !== -1 && n < 12){
+ n += 12;
+ }
+ else{
+ if(ap.indexOf('a') !== -1 && n === 12){
+ n = 0;
+ }
+ }
+ }
+
+ tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n);
+
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ })
+ .css({
+ cursor: 'pointer',
+ width: (100 / gridSize[litem]) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ } // end if grid > 0
+ } // end for loop
+
+ // Add timezone options
+ this.timezone_select = $tp.find('.ui_tpicker_timezone').append(' ').find("select");
+ $.fn.append.apply(this.timezone_select,
+ $.map(o.timezoneList, function(val, idx) {
+ return $(" ").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val);
+ }));
+ if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") {
+ var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12);
+ var local_timezone = $.timepicker.timeZoneOffsetString(local_date);
+ if (local_timezone == this.timezone) {
+ selectLocalTimeZone(tp_inst);
+ } else {
+ this.timezone_select.val(this.timezone);
+ }
+ } else {
+ if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") {
+ this.timezone_select.val(o.defaultTimezone);
+ } else {
+ selectLocalTimeZone(tp_inst);
+ }
+ }
+ this.timezone_select.on( 'change', function() {
+ tp_inst._defaults.useLocalTimezone = false;
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+ // End timezone options
+
+ // inject timepicker into datepicker
+ var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
+ if ($buttonPanel.length) {
+ $buttonPanel.before($tp);
+ } else {
+ $dp.append($tp);
+ }
+
+ this.$timeObj = $tp.find('.ui_tpicker_time');
+
+ if (this.inst !== null) {
+ var timeDefined = this.timeDefined;
+ this._onTimeChange();
+ this.timeDefined = timeDefined;
+ }
+
+ // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
+ if (this._defaults.addSliderAccess) {
+ var sliderAccessArgs = this._defaults.sliderAccessArgs,
+ rtl = this._defaults.isRTL;
+ sliderAccessArgs.isRTL = rtl;
+
+ setTimeout(function() { // fix for inline mode
+ if ($tp.find('.ui-slider-access').length === 0) {
+ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
+
+ // fix any grids since sliders are shorter
+ var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
+ if (sliderAccessWidth) {
+ $tp.find('table:visible').each(function() {
+ var $g = $(this),
+ oldWidth = $g.outerWidth(),
+ oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''),
+ newWidth = oldWidth - sliderAccessWidth,
+ newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
+ css = { width: newWidth, marginRight: 0, marginLeft: 0 };
+ css[rtl? 'marginRight':'marginLeft'] = newMarginLeft;
+ $g.css(css);
+ });
+ }
+ }
+ }, 10);
+ }
+ // end slideAccess integration
+
+ }
+ },
+
+ /*
+ * This function tries to limit the ability to go outside the
+ * min/max date range
+ */
+ _limitMinMaxDateTime: function(dp_inst, adjustSliders) {
+ var o = this._defaults,
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
+
+ if (!this._defaults.showTimepicker) {
+ return;
+ } // No time so nothing to check here
+
+ if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
+ var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
+ minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) {
+ this.hourMinOriginal = o.hourMin;
+ this.minuteMinOriginal = o.minuteMin;
+ this.secondMinOriginal = o.secondMin;
+ this.millisecMinOriginal = o.millisecMin;
+ }
+
+ if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
+ this._defaults.hourMin = minDateTime.getHours();
+ if (this.hour <= this._defaults.hourMin) {
+ this.hour = this._defaults.hourMin;
+ this._defaults.minuteMin = minDateTime.getMinutes();
+ if (this.minute <= this._defaults.minuteMin) {
+ this.minute = this._defaults.minuteMin;
+ this._defaults.secondMin = minDateTime.getSeconds();
+ if (this.second <= this._defaults.secondMin) {
+ this.second = this._defaults.secondMin;
+ this._defaults.millisecMin = minDateTime.getMilliseconds();
+ } else {
+ if (this.millisec < this._defaults.millisecMin) {
+ this.millisec = this._defaults.millisecMin;
+ }
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ }
+ } else {
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ }
+ } else {
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ }
+ } else {
+ this._defaults.hourMin = this.hourMinOriginal;
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ }
+ }
+
+ if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
+ var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
+ maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) {
+ this.hourMaxOriginal = o.hourMax;
+ this.minuteMaxOriginal = o.minuteMax;
+ this.secondMaxOriginal = o.secondMax;
+ this.millisecMaxOriginal = o.millisecMax;
+ }
+
+ if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) {
+ this._defaults.hourMax = maxDateTime.getHours();
+ if (this.hour >= this._defaults.hourMax) {
+ this.hour = this._defaults.hourMax;
+ this._defaults.minuteMax = maxDateTime.getMinutes();
+ if (this.minute >= this._defaults.minuteMax) {
+ this.minute = this._defaults.minuteMax;
+ this._defaults.secondMax = maxDateTime.getSeconds();
+ if (this.second >= this._defaults.secondMax) {
+ this.second = this._defaults.secondMax;
+ this._defaults.millisecMax = maxDateTime.getMilliseconds();
+ } else {
+ if (this.millisec > this._defaults.millisecMax) {
+ this.millisec = this._defaults.millisecMax;
+ }
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ }
+ } else {
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ }
+ } else {
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ }
+ } else {
+ this._defaults.hourMax = this.hourMaxOriginal;
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ }
+ }
+
+ if (adjustSliders !== undefined && adjustSliders === true) {
+ var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
+ minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
+ secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
+ millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10);
+
+ if (this.hour_slider) {
+ this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax });
+ this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
+ }
+ if (this.minute_slider) {
+ this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax });
+ this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
+ }
+ if (this.second_slider) {
+ this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax });
+ this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
+ }
+ if (this.millisec_slider) {
+ this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax });
+ this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
+ }
+ }
+
+ },
+
+ /*
+ * when a slider moves, set the internal time...
+ * on time change is also called when the time is updated in the text field
+ */
+ _onTimeChange: function() {
+ var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
+ minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
+ second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
+ millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
+ timezone = (this.timezone_select) ? this.timezone_select.val() : false,
+ o = this._defaults,
+ pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
+ pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
+
+ if (typeof(hour) == 'object') {
+ hour = false;
+ }
+ if (typeof(minute) == 'object') {
+ minute = false;
+ }
+ if (typeof(second) == 'object') {
+ second = false;
+ }
+ if (typeof(millisec) == 'object') {
+ millisec = false;
+ }
+ if (typeof(timezone) == 'object') {
+ timezone = false;
+ }
+
+ if (hour !== false) {
+ hour = parseInt(hour, 10);
+ }
+ if (minute !== false) {
+ minute = parseInt(minute, 10);
+ }
+ if (second !== false) {
+ second = parseInt(second, 10);
+ }
+ if (millisec !== false) {
+ millisec = parseInt(millisec, 10);
+ }
+
+ var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
+
+ // If the update was done in the input field, the input field should not be updated.
+ // If the update was done using the sliders, update the input field.
+ var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec
+ || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
+ || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone)));
+
+ if (hasChanged) {
+
+ if (hour !== false) {
+ this.hour = hour;
+ }
+ if (minute !== false) {
+ this.minute = minute;
+ }
+ if (second !== false) {
+ this.second = second;
+ }
+ if (millisec !== false) {
+ this.millisec = millisec;
+ }
+ if (timezone !== false) {
+ this.timezone = timezone;
+ }
+
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ this._limitMinMaxDateTime(this.inst, true);
+ }
+ if (useAmpm(o.timeFormat)) {
+ this.ampm = ampm;
+ }
+
+ // Updates the time within the timepicker
+ this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
+ if (this.$timeObj) {
+ if(pickerTimeFormat === o.timeFormat){
+ this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
+ }
+ else{
+ this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
+ }
+ }
+
+ this.timeDefined = true;
+ if (hasChanged) {
+ this._updateDateTime();
+ }
+ },
+
+ /*
+ * call custom onSelect.
+ * bind to sliders slidestop, and grid click.
+ */
+ _onSelectHandler: function() {
+ var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
+ var inputEl = this.$input ? this.$input[0] : null;
+ if (onSelect && inputEl) {
+ onSelect.apply(inputEl, [this.formattedDateTime, this]);
+ }
+ },
+
+ /*
+ * update our input with the new date time..
+ */
+ _updateDateTime: function(dp_inst) {
+ dp_inst = this.inst || dp_inst;
+ var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+ formatCfg = $.datepicker._getFormatConfig(dp_inst),
+ timeAvailable = dt !== null && this.timeDefined;
+ this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
+ var formattedDateTime = this.formattedDate;
+
+ // if a slider was changed but datepicker doesn't have a value yet, set it
+ if(dp_inst.lastVal==""){
+ dp_inst.currentYear=dp_inst.selectedYear;
+ dp_inst.currentMonth=dp_inst.selectedMonth;
+ dp_inst.currentDay=dp_inst.selectedDay;
+ }
+
+ /*
+ * remove following lines to force every changes in date picker to change the input value
+ * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
+ * If the user manually empty the value in the input field, the date picker will never change selected value.
+ */
+ //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
+ // return;
+ //}
+
+ if (this._defaults.timeOnly === true) {
+ formattedDateTime = this.formattedTime;
+ } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
+ formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
+ }
+
+ this.formattedDateTime = formattedDateTime;
+
+ if (!this._defaults.showTimepicker) {
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
+ this.$altInput.val(this.formattedTime);
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput) {
+ this.$input.val(formattedDateTime);
+ var altFormattedDateTime = '',
+ altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator,
+ altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
+
+ if (this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
+ else altFormattedDateTime = this.formattedDate;
+ if (altFormattedDateTime) altFormattedDateTime += altSeparator;
+ if (this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
+ else altFormattedDateTime += this.formattedTime + altTimeSuffix;
+ this.$altInput.val(altFormattedDateTime);
+ } else {
+ this.$input.val(formattedDateTime);
+ }
+
+ this.$input.trigger("change");
+ },
+
+ _onFocus: function() {
+ if (!this.$input.val() && this._defaults.defaultValue) {
+ this.$input.val(this._defaults.defaultValue);
+ var inst = $.datepicker._getInst(this.$input.get(0)),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+ }
+ },
+
+ /*
+ * Small abstraction to control types
+ * We can add more, just be sure to follow the pattern: create, options, value
+ */
+ _controls: {
+ // slider methods
+ slider: {
+ create: function(tp_inst, obj, unit, val, min, max, step){
+ var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
+ return obj.prop('slide', null).slider({
+ orientation: "horizontal",
+ value: rtl? val*-1 : val,
+ min: rtl? max*-1 : min,
+ max: rtl? min*-1 : max,
+ step: step,
+ slide: function(event, ui) {
+ tp_inst.control.value(tp_inst, $(this), unit, rtl? ui.value*-1:ui.value);
+ tp_inst._onTimeChange();
+ },
+ stop: function(event, ui) {
+ tp_inst._onSelectHandler();
+ }
+ });
+ },
+ options: function(tp_inst, obj, unit, opts, val){
+ if(tp_inst._defaults.isRTL){
+ if(typeof(opts) == 'string'){
+ if(opts == 'min' || opts == 'max'){
+ if(val !== undefined)
+ return obj.slider(opts, val*-1);
+ return Math.abs(obj.slider(opts));
+ }
+ return obj.slider(opts);
+ }
+ var min = opts.min,
+ max = opts.max;
+ opts.min = opts.max = null;
+ if(min !== undefined)
+ opts.max = min * -1;
+ if(max !== undefined)
+ opts.min = max * -1;
+ return obj.slider(opts);
+ }
+ if(typeof(opts) == 'string' && val !== undefined)
+ return obj.slider(opts, val);
+ return obj.slider(opts);
+ },
+ value: function(tp_inst, obj, unit, val){
+ if(tp_inst._defaults.isRTL){
+ if(val !== undefined)
+ return obj.slider('value', val*-1);
+ return Math.abs(obj.slider('value'));
+ }
+ if(val !== undefined)
+ return obj.slider('value', val);
+ return obj.slider('value');
+ }
+ },
+ // select methods
+ select: {
+ create: function(tp_inst, obj, unit, val, min, max, step){
+ var sel = '',
+ ul = tp_inst._defaults.timeFormat.indexOf('t') !== -1? 'toLowerCase':'toUpperCase',
+ m = 0;
+
+ for(var i=min; i<=max; i+=step){
+ sel += '';
+ if(unit == 'hour' && useAmpm(tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat))
+ sel += $.datepicker.formatTime("hh TT", {hour:i}, tp_inst._defaults);
+ else if(unit == 'millisec' || i >= 10) sel += i;
+ else sel += '0'+ i.toString();
+ sel += ' ';
+ }
+ sel += ' ';
+
+ obj.children('select').remove();
+
+ $(sel).appendTo(obj).on( 'change', function(e){
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+
+ return obj;
+ },
+ options: function(tp_inst, obj, unit, opts, val){
+ var o = {},
+ $t = obj.children('select');
+ if(typeof(opts) == 'string'){
+ if(val === undefined)
+ return $t.data(opts);
+ o[opts] = val;
+ }
+ else o = opts;
+ return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
+ },
+ value: function(tp_inst, obj, unit, val){
+ var $t = obj.children('select');
+ if(val !== undefined)
+ return $t.val(val);
+ return $t.val();
+ }
+ }
+ } // end _controls
+
+ });
+
+ $.fn.extend({
+ /*
+ * shorthand just to use timepicker..
+ */
+ timepicker: function(o) {
+ o = o || {};
+ var tmp_args = Array.prototype.slice.call(arguments);
+
+ if (typeof o == 'object') {
+ tmp_args[0] = $.extend(o, {
+ timeOnly: true
+ });
+ }
+
+ return $(this).each(function() {
+ $.fn.datetimepicker.apply($(this), tmp_args);
+ });
+ },
+
+ /*
+ * extend timepicker to datepicker
+ */
+ datetimepicker: function(o) {
+ o = o || {};
+ var tmp_args = arguments;
+
+ if (typeof(o) == 'string') {
+ if (o == 'getDate') {
+ return $.fn.datepicker.apply($(this[0]), tmp_args);
+ } else {
+ return this.each(function() {
+ var $t = $(this);
+ $t.datepicker.apply($t, tmp_args);
+ });
+ }
+ } else {
+ return this.each(function() {
+ var $t = $(this);
+ $t.datepicker($.timepicker._newInst($t, o)._defaults);
+ });
+ }
+ }
+ });
+
+ /*
+ * Public Utility to parse date and time
+ */
+ $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
+ if (parseRes.timeObj) {
+ var t = parseRes.timeObj;
+ parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
+ }
+
+ return parseRes.date;
+ };
+
+ /*
+ * Public utility to parse time
+ */
+ $.datepicker.parseTime = function(timeFormat, timeString, options) {
+ var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {});
+
+ // Strict parse requires the timeString to match the timeFormat exactly
+ var strictParse = function(f, s, o){
+
+ // pattern for standard and localized AM/PM markers
+ var getPatternAmpm = function(amNames, pmNames) {
+ var markers = [];
+ if (amNames) {
+ $.merge(markers, amNames);
+ }
+ if (pmNames) {
+ $.merge(markers, pmNames);
+ }
+ markers = $.map(markers, function(val) {
+ return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
+ });
+ return '(' + markers.join('|') + ')?';
+ };
+
+ // figure out position of time elements.. cause js cant do named captures
+ var getFormatPositions = function(timeFormat) {
+ var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g),
+ orders = {
+ h: -1,
+ m: -1,
+ s: -1,
+ l: -1,
+ t: -1,
+ z: -1
+ };
+
+ if (finds) {
+ for (var i = 0; i < finds.length; i++) {
+ if (orders[finds[i].toString().charAt(0)] == -1) {
+ orders[finds[i].toString().charAt(0)] = i + 1;
+ }
+ }
+ }
+ return orders;
+ };
+
+ var regstr = '^' + f.toString()
+ .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) {
+ var ml = match.length;
+ switch (match.charAt(0).toLowerCase()) {
+ case 'h': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
+ case 'm': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
+ case 's': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
+ case 'l': return '(\\d?\\d?\\d)';
+ case 'z': return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
+ case 't': return getPatternAmpm(o.amNames, o.pmNames);
+ default: // literal escaped in quotes
+ return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
+ }
+ })
+ .replace(/\s/g, '\\s?') +
+ o.timeSuffix + '$',
+ order = getFormatPositions(f),
+ ampm = '',
+ treg;
+
+ treg = s.match(new RegExp(regstr, 'i'));
+
+ var resTime = {
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0
+ };
+
+ if (treg) {
+ if (order.t !== -1) {
+ if (treg[order.t] === undefined || treg[order.t].length === 0) {
+ ampm = '';
+ resTime.ampm = '';
+ } else {
+ ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
+ resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
+ }
+ }
+
+ if (order.h !== -1) {
+ if (ampm == 'AM' && treg[order.h] == '12') {
+ resTime.hour = 0; // 12am = 0 hour
+ } else {
+ if (ampm == 'PM' && treg[order.h] != '12') {
+ resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
+ } else {
+ resTime.hour = Number(treg[order.h]);
+ }
+ }
+ }
+
+ if (order.m !== -1) {
+ resTime.minute = Number(treg[order.m]);
+ }
+ if (order.s !== -1) {
+ resTime.second = Number(treg[order.s]);
+ }
+ if (order.l !== -1) {
+ resTime.millisec = Number(treg[order.l]);
+ }
+ if (order.z !== -1 && treg[order.z] !== undefined) {
+ var tz = treg[order.z].toUpperCase();
+ switch (tz.length) {
+ case 1:
+ // Z
+ tz = o.timezoneIso8601 ? 'Z' : '+0000';
+ break;
+ case 5:
+ // +hhmm
+ if (o.timezoneIso8601) {
+ tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3);
+ }
+ break;
+ case 6:
+ // +hh:mm
+ if (!o.timezoneIso8601) {
+ tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, '');
+ } else {
+ if (tz.substring(1) == '00:00') {
+ tz = 'Z';
+ }
+ }
+ break;
+ }
+ resTime.timezone = tz;
+ }
+
+
+ return resTime;
+ }
+ return false;
+ };// end strictParse
+
+ // First try JS Date, if that fails, use strictParse
+ var looseParse = function(f,s,o){
+ try{
+ var d = new Date('2012-01-01 '+ s);
+ if(isNaN(d.getTime())){
+ d = new Date('2012-01-01T'+ s);
+ if(isNaN(d.getTime())){
+ d = new Date('01/01/2012 '+ s);
+ if(isNaN(d.getTime())){
+ throw "Unable to parse time with native Date: "+ s;
+ }
+ }
+ }
+
+ return {
+ hour: d.getHours(),
+ minute: d.getMinutes(),
+ second: d.getSeconds(),
+ millisec: d.getMilliseconds(),
+ timezone: $.timepicker.timeZoneOffsetString(d)
+ };
+ }
+ catch(err){
+ try{
+ return strictParse(f,s,o);
+ }
+ catch(err2){
+ $.timepicker.log("Unable to parse \ntimeString: "+ s +"\ntimeFormat: "+ f);
+ }
+ }
+ return false;
+ }; // end looseParse
+
+ if(typeof o.parse === "function"){
+ return o.parse(timeFormat, timeString, o)
+ }
+ if(o.parse === 'loose'){
+ return looseParse(timeFormat, timeString, o);
+ }
+ return strictParse(timeFormat, timeString, o);
+ };
+
+ /*
+ * Public utility to format the time
+ * format = string format of the time
+ * time = a {}, not a Date() for timezones
+ * options = essentially the regional[].. amNames, pmNames, ampm
+ */
+ $.datepicker.formatTime = function(format, time, options) {
+ options = options || {};
+ options = $.extend({}, $.timepicker._defaults, options);
+ time = $.extend({
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ timezone: '+0000'
+ }, time);
+
+ var tmptime = format,
+ ampmName = options.amNames[0],
+ hour = parseInt(time.hour, 10);
+
+ if (hour > 11) {
+ ampmName = options.pmNames[0];
+ }
+
+ tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) {
+ switch (match) {
+ case 'HH':
+ return ('0' + hour).slice(-2);
+ case 'H':
+ return hour;
+ case 'hh':
+ return ('0' + convert24to12(hour)).slice(-2);
+ case 'h':
+ return convert24to12(hour);
+ case 'mm':
+ return ('0' + time.minute).slice(-2);
+ case 'm':
+ return time.minute;
+ case 'ss':
+ return ('0' + time.second).slice(-2);
+ case 's':
+ return time.second;
+ case 'l':
+ return ('00' + time.millisec).slice(-3);
+ case 'z':
+ return time.timezone === null? options.defaultTimezone : time.timezone;
+ case 'T':
+ return ampmName.charAt(0).toUpperCase();
+ case 'TT':
+ return ampmName.toUpperCase();
+ case 't':
+ return ampmName.charAt(0).toLowerCase();
+ case 'tt':
+ return ampmName.toLowerCase();
+ default:
+ return match.replace(/\'/g, "") || "'";
+ }
+ });
+
+ tmptime = 'string' === typeof tmptime ? tmptime.trim() : ''
+ return tmptime;
+ };
+
+ /*
+ * the bad hack :/ override datepicker so it doesnt close on select
+ // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
+ */
+ $.datepicker._base_selectDate = $.datepicker._selectDate;
+ $.datepicker._selectDate = function(id, dateStr) {
+ var inst = this._getInst($(id)[0]),
+ tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ tp_inst._limitMinMaxDateTime(inst, true);
+ inst.inline = inst.stay_open = true;
+ //This way the onSelect handler called from calendarpicker get the full dateTime
+ this._base_selectDate(id, dateStr);
+ inst.inline = inst.stay_open = false;
+ this._notifyChange(inst);
+ this._updateDatepicker(inst);
+ } else {
+ this._base_selectDate(id, dateStr);
+ }
+ };
+
+ /*
+ * second bad hack :/ override datepicker so it triggers an event when changing the input field
+ * and does not redraw the datepicker on every selectDate event
+ */
+ $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
+ $.datepicker._updateDatepicker = function(inst) {
+
+ // don't popup the datepicker if there is another instance already opened
+ var input = inst.input[0];
+ if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) {
+ return;
+ }
+
+ if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
+
+ this._base_updateDatepicker(inst);
+
+ // Reload the time control when changing something in the input text field.
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._addTimePicker(inst);
+
+// if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date.
+// var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12);
+// selectLocalTimeZone(tp_inst, date);
+// tp_inst._onTimeChange();
+// }
+ }
+ }
+ };
+
+ /*
+ * third bad hack :/ override datepicker so it allows spaces and colon in the input field
+ */
+ $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
+ $.datepicker._doKeyPress = function(event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if ($.datepicker._get(inst, 'constrainInput')) {
+ var ampm = useAmpm(tp_inst._defaults.timeFormat),
+ dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+ datetimeChars = tp_inst._defaults.timeFormat.toString()
+ .replace(/[hms]/g, '')
+ .replace(/TT/g, ampm ? 'APM' : '')
+ .replace(/Tt/g, ampm ? 'AaPpMm' : '')
+ .replace(/tT/g, ampm ? 'AaPpMm' : '')
+ .replace(/T/g, ampm ? 'AP' : '')
+ .replace(/tt/g, ampm ? 'apm' : '')
+ .replace(/t/g, ampm ? 'ap' : '') +
+ " " + tp_inst._defaults.separator +
+ tp_inst._defaults.timeSuffix +
+ (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
+ (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
+ dateChars,
+ chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
+ return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
+ }
+ }
+
+ return $.datepicker._base_doKeyPress(event);
+ };
+
+ /*
+ * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
+ */
+ $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
+ /* Update any alternate field to synchronise with the main field. */
+ $.datepicker._updateAlternate = function(inst) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if(tp_inst){
+ var altField = tp_inst._defaults.altField;
+ if (altField) { // update alternate field too
+ var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
+ date = this._getDate(inst),
+ formatCfg = $.datepicker._getFormatConfig(inst),
+ altFormattedDateTime = '',
+ altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
+ altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
+ altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
+
+ altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
+ if(!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null){
+ if(tp_inst._defaults.altFormat)
+ altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
+ else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
+ }
+ $(altField).val(altFormattedDateTime);
+ }
+ }
+ else{
+ $.datepicker._base_updateAlternate(inst);
+ }
+ };
+
+ /*
+ * Override key up event to sync manual input changes.
+ */
+ $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
+ $.datepicker._doKeyUp = function(event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+
+ return $.datepicker._base_doKeyUp(event);
+ };
+
+ /*
+ * override "Today" button to also grab the time.
+ */
+ $.datepicker._base_gotoToday = $.datepicker._gotoToday;
+ $.datepicker._gotoToday = function(id) {
+ var inst = this._getInst($(id)[0]),
+ $dp = inst.dpDiv;
+ this._base_gotoToday(id);
+ var tp_inst = this._get(inst, 'timepicker');
+ selectLocalTimeZone(tp_inst);
+ var now = new Date();
+ this._setTime(inst, now);
+ $('.ui-datepicker-today', $dp).trigger( 'click' );
+ };
+
+ /*
+ * Disable & enable the Time in the datetimepicker
+ */
+ $.datepicker._disableTimepickerDatepicker = function(target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ tp_inst._defaults.showTimepicker = false;
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ $.datepicker._enableTimepickerDatepicker = function(target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ tp_inst._defaults.showTimepicker = true;
+ tp_inst._addTimePicker(inst); // Could be disabled on page load
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create our own set time function
+ */
+ $.datepicker._setTime = function(inst, date) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var defaults = tp_inst._defaults;
+
+ // calling _setTime with no date sets time to defaults
+ tp_inst.hour = date ? date.getHours() : defaults.hour;
+ tp_inst.minute = date ? date.getMinutes() : defaults.minute;
+ tp_inst.second = date ? date.getSeconds() : defaults.second;
+ tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
+
+ //check if within min/max times..
+ tp_inst._limitMinMaxDateTime(inst, true);
+
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create new public method to set only time, callable as $().datepicker('setTime', date)
+ */
+ $.datepicker._setTimeDatepicker = function(target, date, withDate) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ this._setDateFromField(inst);
+ var tp_date;
+ if (date) {
+ if (typeof date == "string") {
+ tp_inst._parseTime(date, withDate);
+ tp_date = new Date();
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ } else {
+ tp_date = new Date(date.getTime());
+ }
+ if (tp_date.toString() == 'Invalid Date') {
+ tp_date = undefined;
+ }
+ this._setTime(inst, tp_date);
+ }
+ }
+
+ };
+
+ /*
+ * override setDate() to allow setting time too within Date object
+ */
+ $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
+ $.datepicker._setDateDatepicker = function(target, date) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
+
+ this._updateDatepicker(inst);
+ this._base_setDateDatepicker.apply(this, arguments);
+ this._setTimeDatepicker(target, tp_date, true);
+ };
+
+ /*
+ * override getDate() to allow getting time too within Date object
+ */
+ $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
+ $.datepicker._getDateDatepicker = function(target, noDefault) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ // if it hasn't yet been defined, grab from field
+ if(inst.lastVal === undefined){
+ this._setDateFromField(inst, noDefault);
+ }
+
+ var date = this._getDate(inst);
+ if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
+ date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ }
+ return date;
+ }
+ return this._base_getDateDatepicker(target, noDefault);
+ };
+
+ /*
+ * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
+ * An option in datapicker to ignore extra format characters would be nicer.
+ */
+ $.datepicker._base_parseDate = $.datepicker.parseDate;
+ $.datepicker.parseDate = function(format, value, settings) {
+ var date;
+ try {
+ date = this._base_parseDate(format, value, settings);
+ } catch (err) {
+ // Hack! The error message ends with a colon, a space, and
+ // the "extra" characters. We rely on that instead of
+ // attempting to perfectly reproduce the parsing algorithm.
+ date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
+ $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
+ }
+ return date;
+ };
+
+ /*
+ * override formatDate to set date with time to the input
+ */
+ $.datepicker._base_formatDate = $.datepicker._formatDate;
+ $.datepicker._formatDate = function(inst, day, month, year) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._updateDateTime(inst);
+ return tp_inst.$input.val();
+ }
+ return this._base_formatDate(inst);
+ };
+
+ /*
+ * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
+ */
+ $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
+ $.datepicker._optionDatepicker = function(target, name, value) {
+ var inst = this._getInst(target),
+ name_clone;
+ if (!inst) {
+ return null;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var min = null,
+ max = null,
+ onselect = null,
+ overrides = tp_inst._defaults.evnts,
+ fns = {},
+ prop;
+ if (typeof name == 'string') { // if min/max was set with the string
+ if (name === 'minDate' || name === 'minDateTime') {
+ min = value;
+ } else if (name === 'maxDate' || name === 'maxDateTime') {
+ max = value;
+ } else if (name === 'onSelect') {
+ onselect = value;
+ } else if (overrides.hasOwnProperty(name)) {
+ if (typeof (value) === 'undefined') {
+ return overrides[name];
+ }
+ fns[name] = value;
+ name_clone = {}; //empty results in exiting function after overrides updated
+ }
+ } else if (typeof name == 'object') { //if min/max was set with the JSON
+ if (name.minDate) {
+ min = name.minDate;
+ } else if (name.minDateTime) {
+ min = name.minDateTime;
+ } else if (name.maxDate) {
+ max = name.maxDate;
+ } else if (name.maxDateTime) {
+ max = name.maxDateTime;
+ }
+ for (prop in overrides) {
+ if (overrides.hasOwnProperty(prop) && name[prop]) {
+ fns[prop] = name[prop];
+ }
+ }
+ }
+ for (prop in fns) {
+ if (fns.hasOwnProperty(prop)) {
+ overrides[prop] = fns[prop];
+ if (!name_clone) { name_clone = $.extend({}, name);}
+ delete name_clone[prop];
+ }
+ }
+ if (name_clone && isEmptyObject(name_clone)) { return; }
+ if (min) { //if min was set
+ if (min === 0) {
+ min = new Date();
+ } else {
+ min = new Date(min);
+ }
+ tp_inst._defaults.minDate = min;
+ tp_inst._defaults.minDateTime = min;
+ } else if (max) { //if max was set
+ if (max === 0) {
+ max = new Date();
+ } else {
+ max = new Date(max);
+ }
+ tp_inst._defaults.maxDate = max;
+ tp_inst._defaults.maxDateTime = max;
+ } else if (onselect) {
+ tp_inst._defaults.onSelect = onselect;
+ }
+ }
+ if (value === undefined) {
+ return this._base_optionDatepicker.call($.datepicker, target, name);
+ }
+ return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ };
+ /*
+ * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
+ * it will return false for all objects
+ */
+ var isEmptyObject = function(obj) {
+ var prop;
+ for (prop in obj) {
+ if (obj.hasOwnProperty(obj)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /*
+ * jQuery extend now ignores nulls!
+ */
+ var extendRemove = function(target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] === null || props[name] === undefined) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+ };
+
+ /*
+ * Determine by the time format if should use ampm
+ * Returns true if should use ampm, false if not
+ */
+ var useAmpm = function(timeFormat){
+ return (timeFormat.indexOf('t') !== -1 && timeFormat.indexOf('h') !== -1);
+ };
+
+ /*
+ * Converts 24 hour format into 12 hour
+ * Returns 12 hour without leading 0
+ */
+ var convert24to12 = function(hour) {
+ if (hour > 12) {
+ hour = hour - 12;
+ }
+
+ if (hour == 0) {
+ hour = 12;
+ }
+
+ return String(hour);
+ };
+
+ /*
+ * Splits datetime string into date ans time substrings.
+ * Throws exception when date can't be parsed
+ * Returns [dateString, timeString]
+ */
+ var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) {
+ try {
+ // The idea is to get the number separator occurances in datetime and the time format requested (since time has
+ // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
+ var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator,
+ format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat,
+ timeParts = format.split(separator), // how many occurances of separator may be in our format?
+ timePartsLen = timeParts.length,
+ allParts = dateTimeString.split(separator),
+ allPartsLen = allParts.length;
+
+ if (allPartsLen > 1) {
+ return [
+ allParts.splice(0,allPartsLen-timePartsLen).join(separator),
+ allParts.splice(0,timePartsLen).join(separator)
+ ];
+ }
+
+ } catch (err) {
+ $.timepicker.log('Could not split the date from the time. Please check the following datetimepicker options' +
+ "\nthrown error: " + err +
+ "\ndateTimeString" + dateTimeString +
+ "\ndateFormat = " + dateFormat +
+ "\nseparator = " + timeSettings.separator +
+ "\ntimeFormat = " + timeSettings.timeFormat);
+
+ if (err.indexOf(":") >= 0) {
+ // Hack! The error message ends with a colon, a space, and
+ // the "extra" characters. We rely on that instead of
+ // attempting to perfectly reproduce the parsing algorithm.
+ var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2),
+ timeString = dateTimeString.substring(dateStringLength);
+
+ return [dateTimeString.substring(0, dateStringLength).trim(), dateTimeString.substring(dateStringLength).trim()];
+
+ } else {
+ throw err;
+ }
+ }
+ return [dateTimeString, ''];
+ };
+
+ /*
+ * Internal function to parse datetime interval
+ * Returns: {date: Date, timeObj: Object}, where
+ * date - parsed date without time (type Date)
+ * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional
+ */
+ var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var date;
+ var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings);
+ date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings);
+ if (splitRes[1] !== '') {
+ var timeString = splitRes[1],
+ parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings);
+
+ if (parsedTime === null) {
+ throw 'Wrong time format';
+ }
+ return {
+ date: date,
+ timeObj: parsedTime
+ };
+ } else {
+ return {
+ date: date
+ };
+ }
+ };
+
+ /*
+ * Internal function to set timezone_select to the local timezone
+ */
+ var selectLocalTimeZone = function(tp_inst, date) {
+ if (tp_inst && tp_inst.timezone_select) {
+ tp_inst._defaults.useLocalTimezone = true;
+ var now = typeof date !== 'undefined' ? date : new Date();
+ var tzoffset = $.timepicker.timeZoneOffsetString(now);
+ if (tp_inst._defaults.timezoneIso8601) {
+ tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
+ }
+ tp_inst.timezone_select.val(tzoffset);
+ }
+ };
+
+ /*
+ * Create a Singleton Insance
+ */
+ $.timepicker = new Timepicker();
+
+ /**
+ * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
+ * @param date
+ * @return string
+ */
+ $.timepicker.timeZoneOffsetString = function(date) {
+ var off = date.getTimezoneOffset() * -1,
+ minutes = off % 60,
+ hours = (off - minutes) / 60;
+ return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).slice(-2) + ('0' + (minutes * 101).toString()).slice(-2);
+ };
+
+ /**
+ * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * n.b. The input value must be correctly formatted (reformatting is not supported)
+ * @param Element startTime
+ * @param Element endTime
+ * @param obj options Options for the timepicker() call
+ * @return jQuery
+ */
+ $.timepicker.timeRange = function(startTime, endTime, options) {
+ return $.timepicker.handleRange('timepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param Element startTime
+ * @param Element endTime
+ * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @param string method Can be used to specify the type of picker to be added
+ * @return jQuery
+ */
+ $.timepicker.dateTimeRange = function(startTime, endTime, options) {
+ $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker');
+ };
+
+ /**
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param Element startTime
+ * @param Element endTime
+ * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @param string method Can be used to specify the type of picker to be added
+ * @return jQuery
+ */
+ $.timepicker.dateRange = function(startTime, endTime, options, method) {
+ method = method || 'datepicker';
+ $.timepicker.handleRange(method, startTime, endTime, options);
+ };
+
+ /**
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param string method Can be used to specify the type of picker to be added
+ * @param Element startTime
+ * @param Element endTime
+ * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return jQuery
+ */
+ $.timepicker.handleRange = function(method, startTime, endTime, options) {
+ $.fn[method].call(startTime, $.extend({
+ onClose: function(dateText, inst) {
+ checkDates(this, endTime, dateText);
+ },
+ onSelect: function(selectedDateTime) {
+ selected(this, endTime, 'minDate');
+ }
+ }, options, options.start));
+ $.fn[method].call(endTime, $.extend({
+ onClose: function(dateText, inst) {
+ checkDates(this, startTime, dateText);
+ },
+ onSelect: function(selectedDateTime) {
+ selected(this, startTime, 'maxDate');
+ }
+ }, options, options.end));
+ // timepicker doesn't provide access to its 'timeFormat' option,
+ // nor could I get datepicker.formatTime() to behave with times, so I
+ // have disabled reformatting for timepicker
+ if (method != 'timepicker' && options.reformat) {
+ $([startTime, endTime]).each(function() {
+ var format = $(this)[method].call($(this), 'option', 'dateFormat'),
+ date = new Date($(this).val());
+ if ($(this).val() && date) {
+ $(this).val($.datepicker.formatDate(format, date));
+ }
+ });
+ }
+ checkDates(startTime, endTime, startTime.val());
+
+ function checkDates(changed, other, dateText) {
+ if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) {
+ other.val(dateText);
+ }
+ }
+ selected(startTime, endTime, 'minDate');
+ selected(endTime, startTime, 'maxDate');
+
+ function selected(changed, other, option) {
+ if (!$(changed).val()) {
+ return;
+ }
+ var date = $(changed)[method].call($(changed), 'getDate');
+ // timepicker doesn't implement 'getDate' and returns a jQuery
+ if (date.getTime) {
+ $(other)[method].call($(other), 'option', option, date);
+ }
+ }
+ return $([startTime.get(0), endTime.get(0)]);
+ };
+
+ /**
+ * Log error or data to the console during error or debugging
+ * @param Object err pass any type object to log to the console during error or debugging
+ * @return void
+ */
+ $.timepicker.log = function(err){
+ if(window.console)
+ console.log(err);
+ };
+
+ /*
+ * Keep up with the version
+ */
+ $.timepicker.version = "1.2";
+
+})(jQuery);
diff --git a/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.min.js b/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.min.js
new file mode 100644
index 0000000..d62a234
--- /dev/null
+++ b/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.min.js
@@ -0,0 +1 @@
+!function($){var Timepicker,isEmptyObject,extendRemove,useAmpm,convert24to12,splitDateTime,parseDateTimeInternal,selectLocalTimeZone;$.ui.timepicker=$.ui.timepicker||{},$.ui.timepicker.version||($.extend($.ui,{timepicker:{version:"1.2"}}),Timepicker=function(){this.regional=[],this.regional[""]={currentText:"Now",closeText:"Done",amNames:["AM","A"],pmNames:["PM","P"],timeFormat:"HH:mm",timeSuffix:"",timeOnlyTitle:"Choose Time",timeText:"Time",hourText:"Hour",minuteText:"Minute",secondText:"Second",millisecText:"Millisecond",timezoneText:"Time Zone",isRTL:!1},this._defaults={showButtonPanel:!0,timeOnly:!1,showHour:!0,showMinute:!0,showSecond:!1,showMillisec:!1,showTimezone:!1,showTime:!0,stepHour:1,stepMinute:1,stepSecond:1,stepMillisec:1,hour:0,minute:0,second:0,millisec:0,timezone:null,useLocalTimezone:!1,defaultTimezone:"+0000",hourMin:0,minuteMin:0,secondMin:0,millisecMin:0,hourMax:23,minuteMax:59,secondMax:59,millisecMax:999,minDateTime:null,maxDateTime:null,onSelect:null,hourGrid:0,minuteGrid:0,secondGrid:0,millisecGrid:0,alwaysSetTime:!0,separator:" ",altFieldTimeOnly:!0,altTimeFormat:null,altSeparator:null,altTimeSuffix:null,pickerTimeFormat:null,pickerTimeSuffix:null,showTimepicker:!0,timezoneIso8601:!1,timezoneList:null,addSliderAccess:!1,sliderAccessArgs:null,controlType:"slider",defaultValue:null,parse:"strict"},$.extend(this._defaults,this.regional[""])},$.extend(Timepicker.prototype,{$input:null,$altInput:null,$timeObj:null,inst:null,hour_slider:null,minute_slider:null,second_slider:null,millisec_slider:null,timezone_select:null,hour:0,minute:0,second:0,millisec:0,timezone:null,defaultTimezone:"+0000",hourMinOriginal:null,minuteMinOriginal:null,secondMinOriginal:null,millisecMinOriginal:null,hourMaxOriginal:null,minuteMaxOriginal:null,secondMaxOriginal:null,millisecMaxOriginal:null,ampm:"",formattedDate:"",formattedTime:"",formattedDateTime:"",timezoneList:null,units:["hour","minute","second","millisec"],control:null,setDefaults:function(e){return extendRemove(this._defaults,e||{}),this},_newInst:function($input,o){var tp_inst=new Timepicker,inlineSettings={},fns={},overrides,i,attrName,timezoneList;for(attrName in this._defaults)if(this._defaults.hasOwnProperty(attrName)){var attrValue=$input.attr("time:"+attrName);if(attrValue)try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}for(i in overrides={beforeShow:function(e,t){if("function"==typeof tp_inst._defaults.evnts.beforeShow)return tp_inst._defaults.evnts.beforeShow.call($input[0],e,t,tp_inst)},onChangeMonthYear:function(e,t,i){tp_inst._updateDateTime(i),"function"==typeof tp_inst._defaults.evnts.onChangeMonthYear&&tp_inst._defaults.evnts.onChangeMonthYear.call($input[0],e,t,i,tp_inst)},onClose:function(e,t){!0===tp_inst.timeDefined&&""!==$input.val()&&tp_inst._updateDateTime(t),"function"==typeof tp_inst._defaults.evnts.onClose&&tp_inst._defaults.evnts.onClose.call($input[0],e,t,tp_inst)}},overrides)overrides.hasOwnProperty(i)&&(fns[i]=o[i]||null);return tp_inst._defaults=$.extend({},this._defaults,inlineSettings,o,overrides,{evnts:fns,timepicker:tp_inst}),tp_inst.amNames=$.map(tp_inst._defaults.amNames,function(e){return e.toUpperCase()}),tp_inst.pmNames=$.map(tp_inst._defaults.pmNames,function(e){return e.toUpperCase()}),"string"==typeof tp_inst._defaults.controlType?(void 0===$.fn[tp_inst._defaults.controlType]&&(tp_inst._defaults.controlType="select"),tp_inst.control=tp_inst._controls[tp_inst._defaults.controlType]):tp_inst.control=tp_inst._defaults.controlType,null===tp_inst._defaults.timezoneList&&(timezoneList=["-1200","-1100","-1000","-0930","-0900","-0800","-0700","-0600","-0500","-0430","-0400","-0330","-0300","-0200","-0100","+0000","+0100","+0200","+0300","+0330","+0400","+0430","+0500","+0530","+0545","+0600","+0630","+0700","+0800","+0845","+0900","+0930","+1000","+1030","+1100","+1130","+1200","+1245","+1300","+1400"],tp_inst._defaults.timezoneIso8601&&(timezoneList=$.map(timezoneList,function(e){return"+0000"==e?"Z":e.substring(0,3)+":"+e.substring(3)})),tp_inst._defaults.timezoneList=timezoneList),tp_inst.timezone=tp_inst._defaults.timezone,tp_inst.hour=tp_inst._defaults.hourtp_inst._defaults.hourMax?tp_inst._defaults.hourMax:tp_inst._defaults.hour,tp_inst.minute=tp_inst._defaults.minutetp_inst._defaults.minuteMax?tp_inst._defaults.minuteMax:tp_inst._defaults.minute,tp_inst.second=tp_inst._defaults.secondtp_inst._defaults.secondMax?tp_inst._defaults.secondMax:tp_inst._defaults.second,tp_inst.millisec=tp_inst._defaults.millisectp_inst._defaults.millisecMax?tp_inst._defaults.millisecMax:tp_inst._defaults.millisec,tp_inst.ampm="",tp_inst.$input=$input,o.altField&&(tp_inst.$altInput=$(o.altField).css({cursor:"pointer"}).on("focus",function(){$input.trigger("focus")})),0!==tp_inst._defaults.minDate&&0!==tp_inst._defaults.minDateTime||(tp_inst._defaults.minDate=new Date),0!==tp_inst._defaults.maxDate&&0!==tp_inst._defaults.maxDateTime||(tp_inst._defaults.maxDate=new Date),void 0!==tp_inst._defaults.minDate&&tp_inst._defaults.minDate instanceof Date&&(tp_inst._defaults.minDateTime=new Date(tp_inst._defaults.minDate.getTime())),void 0!==tp_inst._defaults.minDateTime&&tp_inst._defaults.minDateTime instanceof Date&&(tp_inst._defaults.minDate=new Date(tp_inst._defaults.minDateTime.getTime())),void 0!==tp_inst._defaults.maxDate&&tp_inst._defaults.maxDate instanceof Date&&(tp_inst._defaults.maxDateTime=new Date(tp_inst._defaults.maxDate.getTime())),void 0!==tp_inst._defaults.maxDateTime&&tp_inst._defaults.maxDateTime instanceof Date&&(tp_inst._defaults.maxDate=new Date(tp_inst._defaults.maxDateTime.getTime())),tp_inst.$input.on("focus",function(){tp_inst._onFocus()}),tp_inst},_addTimePicker:function(e){var t=this.$altInput&&this._defaults.altFieldTimeOnly?this.$input.val()+" "+this.$altInput.val():this.$input.val();this.timeDefined=this._parseTime(t),this._limitMinMaxDateTime(e,!1),this._injectTimePicker()},_parseTime:function(t,i){if(this.inst||(this.inst=$.datepicker._getInst(this.$input[0])),!i&&this._defaults.timeOnly)return!!(i=$.datepicker.parseTime(this._defaults.timeFormat,t,this._defaults))&&($.extend(this,i),!0);i=$.datepicker._get(this.inst,"dateFormat");try{var e=parseDateTimeInternal(i,this._defaults.timeFormat,t,$.datepicker._getFormatConfig(this.inst),this._defaults);if(!e.timeObj)return!1;$.extend(this,e.timeObj)}catch(e){return $.timepicker.log("Error parsing the date/time string: "+e+"\ndate/time string = "+t+"\ntimeFormat = "+this._defaults.timeFormat+"\ndateFormat = "+i),!1}return!0},_injectTimePicker:function(){var e,t=this.inst.dpDiv,i=this.inst.settings,a=this,n="",s="",r={},l={};if(0===t.find("div.ui-timepicker-div").length&&i.showTimepicker){for(var o=' style="display:none;"',u='"+i.timeText+' ",d=0,m=this.units.length;d"+i[n+"Text"]+'
",i["show"+s]&&0',"hour"==n)for(var c=i[n+"Min"];c<=r[n];c+=parseInt(i[n+"Grid"],10)){l[n]++;var p=$.datepicker.formatTime(useAmpm(i.pickerTimeFormat||i.timeFormat)?"hht":"HH",{hour:c},i);u+=''+p+" "}else for(var h=i[n+"Min"];h<=r[n];h+=parseInt(i[n+"Grid"],10))l[n]++,u+=''+(h<10?"0":"")+h+" ";u+="
"}u+=""}var u=(u+='"+i.timezoneText+" ")+(' "),_=$(u+="");!0===i.timeOnly&&(_.prepend('"),t.find(".ui-datepicker-header, .ui-datepicker-calendar").hide());for(d=0,m=a.units.length;d").find("select"),$.fn.append.apply(this.timezone_select,$.map(i.timezoneList,function(e,t){return $(" ").val("object"==typeof e?e.value:e).text("object"==typeof e?e.label:e)})),void 0!==this.timezone&&null!==this.timezone&&""!==this.timezone?(k=new Date(this.inst.selectedYear,this.inst.selectedMonth,this.inst.selectedDay,12),$.timepicker.timeZoneOffsetString(k)==this.timezone?selectLocalTimeZone(a):this.timezone_select.val(this.timezone)):void 0!==this.hour&&null!==this.hour&&""!==this.hour?this.timezone_select.val(i.defaultTimezone):selectLocalTimeZone(a),this.timezone_select.on("change",function(){a._defaults.useLocalTimezone=!1,a._onTimeChange(),a._onSelectHandler()});var f,g,k=t.find(".ui-datepicker-buttonpane");k.length?k.before(_):t.append(_),this.$timeObj=_.find(".ui_tpicker_time"),null!==this.inst&&(k=this.timeDefined,this._onTimeChange(),this.timeDefined=k),this._defaults.addSliderAccess&&(f=this._defaults.sliderAccessArgs,g=this._defaults.isRTL,f.isRTL=g,setTimeout(function(){var n;0===_.find(".ui-slider-access").length&&(_.find(".ui-slider:visible").sliderAccess(f),n=_.find(".ui-slider-access:eq(0)").outerWidth(!0))&&_.find("table:visible").each(function(){var e=$(this),t=e.outerWidth(),i=e.css(g?"marginRight":"marginLeft").toString().replace("%",""),s=t-n,a={width:s,marginRight:0,marginLeft:0};a[g?"marginRight":"marginLeft"]=i*s/t+"%",e.css(a)})},10))}},_limitMinMaxDateTime:function(e,t){var i,s,a=this._defaults,n=new Date(e.selectedYear,e.selectedMonth,e.selectedDay);this._defaults.showTimepicker&&(null!==$.datepicker._get(e,"minDateTime")&&void 0!==$.datepicker._get(e,"minDateTime")&&n&&(s=$.datepicker._get(e,"minDateTime"),i=new Date(s.getFullYear(),s.getMonth(),s.getDate(),0,0,0,0),null!==this.hourMinOriginal&&null!==this.minuteMinOriginal&&null!==this.secondMinOriginal&&null!==this.millisecMinOriginal||(this.hourMinOriginal=a.hourMin,this.minuteMinOriginal=a.minuteMin,this.secondMinOriginal=a.secondMin,this.millisecMinOriginal=a.millisecMin),e.settings.timeOnly||i.getTime()==n.getTime()?(this._defaults.hourMin=s.getHours(),this.hour<=this._defaults.hourMin?(this.hour=this._defaults.hourMin,this._defaults.minuteMin=s.getMinutes(),this.minute<=this._defaults.minuteMin?(this.minute=this._defaults.minuteMin,this._defaults.secondMin=s.getSeconds(),this.second<=this._defaults.secondMin?(this.second=this._defaults.secondMin,this._defaults.millisecMin=s.getMilliseconds()):(this.millisec=this._defaults.hourMax?(this.hour=this._defaults.hourMax,this._defaults.minuteMax=i.getMinutes(),this.minute>=this._defaults.minuteMax?(this.minute=this._defaults.minuteMax,this._defaults.secondMax=i.getSeconds(),this.second>=this._defaults.secondMax?(this.second=this._defaults.secondMax,this._defaults.millisecMax=i.getMilliseconds()):(this.millisec>this._defaults.millisecMax&&(this.millisec=this._defaults.millisecMax),this._defaults.millisecMax=this.millisecMaxOriginal)):(this._defaults.secondMax=this.secondMaxOriginal,this._defaults.millisecMax=this.millisecMaxOriginal)):(this._defaults.minuteMax=this.minuteMaxOriginal,this._defaults.secondMax=this.secondMaxOriginal,this._defaults.millisecMax=this.millisecMaxOriginal)):(this._defaults.hourMax=this.hourMaxOriginal,this._defaults.minuteMax=this.minuteMaxOriginal,this._defaults.secondMax=this.secondMaxOriginal,this._defaults.millisecMax=this.millisecMaxOriginal)),void 0!==t)&&!0===t&&(a=parseInt(this._defaults.hourMax-(this._defaults.hourMax-this._defaults.hourMin)%this._defaults.stepHour,10),e=parseInt(this._defaults.minuteMax-(this._defaults.minuteMax-this._defaults.minuteMin)%this._defaults.stepMinute,10),s=parseInt(this._defaults.secondMax-(this._defaults.secondMax-this._defaults.secondMin)%this._defaults.stepSecond,10),n=parseInt(this._defaults.millisecMax-(this._defaults.millisecMax-this._defaults.millisecMin)%this._defaults.stepMillisec,10),this.hour_slider&&(this.control.options(this,this.hour_slider,"hour",{min:this._defaults.hourMin,max:a}),this.control.value(this,this.hour_slider,"hour",this.hour-this.hour%this._defaults.stepHour)),this.minute_slider&&(this.control.options(this,this.minute_slider,"minute",{min:this._defaults.minuteMin,max:e}),this.control.value(this,this.minute_slider,"minute",this.minute-this.minute%this._defaults.stepMinute)),this.second_slider&&(this.control.options(this,this.second_slider,"second",{min:this._defaults.secondMin,max:s}),this.control.value(this,this.second_slider,"second",this.second-this.second%this._defaults.stepSecond)),this.millisec_slider)&&(this.control.options(this,this.millisec_slider,"millisec",{min:this._defaults.millisecMin,max:n}),this.control.value(this,this.millisec_slider,"millisec",this.millisec-this.millisec%this._defaults.stepMillisec))},_onTimeChange:function(){var e=!!this.hour_slider&&this.control.value(this,this.hour_slider,"hour"),t=!!this.minute_slider&&this.control.value(this,this.minute_slider,"minute"),i=!!this.second_slider&&this.control.value(this,this.second_slider,"second"),s=!!this.millisec_slider&&this.control.value(this,this.millisec_slider,"millisec"),a=!!this.timezone_select&&this.timezone_select.val(),n=this._defaults,r=n.pickerTimeFormat||n.timeFormat,l=n.pickerTimeSuffix||n.timeSuffix,o=("object"==typeof t&&(t=!1),"object"==typeof i&&(i=!1),"object"==typeof s&&(s=!1),"object"==typeof a&&(a=!1),!1!==(e="object"==typeof e?!1:e)&&(e=parseInt(e,10)),!1!==t&&(t=parseInt(t,10)),!1!==i&&(i=parseInt(i,10)),!1!==s&&(s=parseInt(s,10)),n[e<12?"amNames":"pmNames"][0]),u=e!=this.hour||t!=this.minute||i!=this.second||s!=this.millisec||0',o=(t._defaults.timeFormat.indexOf("t"),a);o<=n;o+=r)l+='","hour"==i&&useAmpm(t._defaults.pickerTimeFormat||t._defaults.timeFormat)?l+=$.datepicker.formatTime("hh TT",{hour:o},t._defaults):l+="millisec"==i||10<=o?o:"0"+o.toString(),l+=" ";return l+="",e.children("select").remove(),$(l).appendTo(e).on("change",function(e){t._onTimeChange(),t._onSelectHandler()}),e},options:function(e,t,i,s,a){var n={},r=t.children("select");if("string"==typeof s){if(void 0===a)return r.data(s);n[s]=a}else n=s;return e.control.create(e,t,r.data("unit"),r.val(),n.min||r.data("min"),n.max||r.data("max"),n.step||r.data("step"))},value:function(e,t,i,s){t=t.children("select");return void 0!==s?t.val(s):t.val()}}}}),$.fn.extend({timepicker:function(e){e=e||{};var t=Array.prototype.slice.call(arguments);return"object"==typeof e&&(t[0]=$.extend(e,{timeOnly:!0})),$(this).each(function(){$.fn.datetimepicker.apply($(this),t)})},datetimepicker:function(t){t=t||{};var i=arguments;return"string"==typeof t?"getDate"==t?$.fn.datepicker.apply($(this[0]),i):this.each(function(){var e=$(this);e.datepicker.apply(e,i)}):this.each(function(){var e=$(this);e.datepicker($.timepicker._newInst(e,t)._defaults)})}}),$.datepicker.parseDateTime=function(e,t,i,s,a){e=parseDateTimeInternal(e,t,i,s,a);return e.timeObj&&(t=e.timeObj,e.date.setHours(t.hour,t.minute,t.second,t.millisec)),e.date},$.datepicker.parseTime=function(t,i,s){function a(e,t,n){var i="^"+e.toString().replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g,function(e){var t,i,s,a=e.length;switch(e.charAt(0).toLowerCase()){case"h":case"m":case"s":return 1===a?"(\\d?\\d)":"(\\d{"+a+"})";case"l":return"(\\d?\\d?\\d)";case"z":return"(z|[-+]\\d\\d:?\\d\\d|\\S+)?";case"t":return t=n.amNames,i=n.pmNames,s=[],t&&$.merge(s,t),i&&$.merge(s,i),"("+(s=$.map(s,function(e){return e.replace(/[.*+?|()\[\]{}\\]/g,"\\$&")})).join("|")+")?";default:return"("+e.replace(/\'/g,"").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g,function(e){return"\\"+e})+")?"}}).replace(/\s/g,"\\s?")+n.timeSuffix+"$",e=function(e){var t=e.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g),i={h:-1,m:-1,s:-1,l:-1,t:-1,z:-1};if(t)for(var s=0;snew Date(n.val())&&t.val(i)}function t(e,t,i){$(e).val()&&(e=$(e)[s].call($(e),"getDate")).getTime&&$(t)[s].call($(t),"option",i,e)}return $.fn[s].call(a,$.extend({onClose:function(e,t){i(0,n,e)},onSelect:function(e){t(this,n,"minDate")}},e,e.start)),$.fn[s].call(n,$.extend({onClose:function(e,t){i(0,a,e)},onSelect:function(e){t(this,a,"maxDate")}},e,e.end)),"timepicker"!=s&&e.reformat&&$([a,n]).each(function(){var e=$(this)[s].call($(this),"option","dateFormat"),t=new Date($(this).val());$(this).val()&&t&&$(this).val($.datepicker.formatDate(e,t))}),i(0,n,a.val()),t(a,n,"minDate"),t(n,a,"maxDate"),$([a.get(0),n.get(0)])},$.timepicker.log=function(e){window.console&&console.log(e)},$.timepicker.version="1.2")}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ar.js b/assets/js/jquery.countdown/jquery.countdown-ar.js
new file mode 100755
index 0000000..a8f9ff8
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ar.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Arabic (عربي) initialisation for the jQuery countdown extension
+ Translated by Talal Al Asmari (talal@psdgroups.com), April 2009. */
+(function($) {
+ $.countdown.regional['ar'] = {
+ labels: ['سنوات','أشهر','أسابيع','أيام','ساعات','دقائق','ثواني'],
+ labels1: ['سنة','شهر','أسبوع','يوم','ساعة','دقيقة','ثانية'],
+ compactLabels: ['س', 'ش', 'أ', 'ي'],
+ whichLabels: null,
+ digits: ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'],
+ timeSeparator: ':', isRTL: true};
+ $.countdown.setDefaults($.countdown.regional['ar']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ar.min.js b/assets/js/jquery.countdown/jquery.countdown-ar.min.js
new file mode 100644
index 0000000..741b2c8
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ar.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.ar={labels:["سنوات","أشهر","أسابيع","أيام","ساعات","دقائق","ثواني"],labels1:["سنة","شهر","أسبوع","يوم","ساعة","دقيقة","ثانية"],compactLabels:["س","ش","أ","ي"],whichLabels:null,digits:["٠","١","٢","٣","٤","٥","٦","٧","٨","٩"],timeSeparator:":",isRTL:!0},a.countdown.setDefaults(a.countdown.regional.ar)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-bg.js b/assets/js/jquery.countdown/jquery.countdown-bg.js
new file mode 100755
index 0000000..c194813
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-bg.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Bulgarian initialisation for the jQuery countdown extension
+ * Written by Manol Trendafilov manol@rastermania.com (2010) */
+(function($) {
+ $.countdown.regional['bg'] = {
+ labels: ['Години', 'Месеца', 'Седмица', 'Дни', 'Часа', 'Минути', 'Секунди'],
+ labels1: ['Година', 'Месец', 'Седмица', 'Ден', 'Час', 'Минута', 'Секунда'],
+ compactLabels: ['l', 'm', 'n', 'd'], compactLabels1: ['g', 'm', 'n', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['bg']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-bg.min.js b/assets/js/jquery.countdown/jquery.countdown-bg.min.js
new file mode 100644
index 0000000..c05f871
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-bg.min.js
@@ -0,0 +1 @@
+!function(l){l.countdown.regional.bg={labels:["Години","Месеца","Седмица","Дни","Часа","Минути","Секунди"],labels1:["Година","Месец","Седмица","Ден","Час","Минута","Секунда"],compactLabels:["l","m","n","d"],compactLabels1:["g","m","n","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},l.countdown.setDefaults(l.countdown.regional.bg)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-bn.js b/assets/js/jquery.countdown/jquery.countdown-bn.js
new file mode 100755
index 0000000..b5d5018
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-bn.js
@@ -0,0 +1,14 @@
+/* http://keith-wood.name/countdown.html
+ * Bengali/Bangla initialisation for the jQuery countdown extension
+ * Written by Mohammed Tajuddin (tajuddin@chittagong-it.com) Jan 2011. */
+(function($) {
+ $.countdown.regional['bn'] = {
+ labels: ['বছর', 'মাস', 'সপ্তাহ', 'দিন', 'ঘন্টা', 'মিনিট', 'সেকেন্ড'],
+ labels1: ['বছর', 'মাস', 'সপ্তাহ', 'দিন', 'ঘন্টা', 'মিনিট', 'সেকেন্ড'],
+ compactLabels: ['ব', 'মা', 'স', 'দি'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false
+ };
+ $.countdown.setDefaults($.countdown.regional['bn']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-bn.min.js b/assets/js/jquery.countdown/jquery.countdown-bn.min.js
new file mode 100644
index 0000000..f2570e1
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-bn.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.bn={labels:["বছর","মাস","সপ্তাহ","দিন","ঘন্টা","মিনিট","সেকেন্ড"],labels1:["বছর","মাস","সপ্তাহ","দিন","ঘন্টা","মিনিট","সেকেন্ড"],compactLabels:["ব","মা","স","দি"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.bn)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-bs.js b/assets/js/jquery.countdown/jquery.countdown-bs.js
new file mode 100755
index 0000000..f3eded4
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-bs.js
@@ -0,0 +1,16 @@
+/* http://keith-wood.name/countdown.html
+ * Bosnian Latin initialisation for the jQuery countdown extension
+ * Written by Miralem Mehic miralem@mehic.info (2011) */
+(function($) {
+ $.countdown.regional['bs'] = {
+ labels: ['Godina', 'Mjeseci', 'Sedmica', 'Dana', 'Sati', 'Minuta', 'Sekundi'],
+ labels1: ['Godina', 'Mjesec', 'Sedmica', 'Dan', 'Sat', 'Minuta', 'Sekunda'],
+ labels2: ['Godine', 'Mjeseca', 'Sedmica', 'Dana', 'Sata', 'Minute', 'Sekunde'],
+ compactLabels: ['g', 'm', 't', 'd'],
+ whichLabels: function(amount) {
+ return (amount == 1 ? 1 : (amount >= 2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['bs']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-bs.min.js b/assets/js/jquery.countdown/jquery.countdown-bs.min.js
new file mode 100644
index 0000000..ba23c6e
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-bs.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.bs={labels:["Godina","Mjeseci","Sedmica","Dana","Sati","Minuta","Sekundi"],labels1:["Godina","Mjesec","Sedmica","Dan","Sat","Minuta","Sekunda"],labels2:["Godine","Mjeseca","Sedmica","Dana","Sata","Minute","Sekunde"],compactLabels:["g","m","t","d"],whichLabels:function(a){return 1==a?1:2<=a&&a<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.bs)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ca.js b/assets/js/jquery.countdown/jquery.countdown-ca.js
new file mode 100755
index 0000000..2d6e2c5
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ca.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Catalan initialisation for the jQuery countdown extension
+ Written by Amanida Media www.amanidamedia.com (2010) */
+(function($) {
+ $.countdown.regional['ca'] = {
+ labels: ['Anys', 'Mesos', 'Setmanes', 'Dies', 'Hores', 'Minuts', 'Segons'],
+ labels1: ['Anys', 'Mesos', 'Setmanes', 'Dies', 'Hores', 'Minuts', 'Segons'],
+ compactLabels: ['a', 'm', 's', 'g'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['ca']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ca.min.js b/assets/js/jquery.countdown/jquery.countdown-ca.min.js
new file mode 100644
index 0000000..03e5036
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ca.min.js
@@ -0,0 +1 @@
+!function(s){s.countdown.regional.ca={labels:["Anys","Mesos","Setmanes","Dies","Hores","Minuts","Segons"],labels1:["Anys","Mesos","Setmanes","Dies","Hores","Minuts","Segons"],compactLabels:["a","m","s","g"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},s.countdown.setDefaults(s.countdown.regional.ca)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-cs.js b/assets/js/jquery.countdown/jquery.countdown-cs.js
new file mode 100755
index 0000000..5c3813c
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-cs.js
@@ -0,0 +1,16 @@
+/* http://keith-wood.name/countdown.html
+ * Czech initialisation for the jQuery countdown extension
+ * Written by Roman Chlebec (creamd@c64.sk) (2008) */
+(function($) {
+ $.countdown.regional['cs'] = {
+ labels: ['Roků', 'Měsíců', 'Týdnů', 'Dní', 'Hodin', 'Minut', 'Sekund'],
+ labels1: ['Rok', 'Měsíc', 'Týden', 'Den', 'Hodina', 'Minuta', 'Sekunda'],
+ labels2: ['Roky', 'Měsíce', 'Týdny', 'Dny', 'Hodiny', 'Minuty', 'Sekundy'],
+ compactLabels: ['r', 'm', 't', 'd'],
+ whichLabels: function(amount) {
+ return (amount == 1 ? 1 : (amount >= 2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['cs']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-cs.min.js b/assets/js/jquery.countdown/jquery.countdown-cs.min.js
new file mode 100644
index 0000000..b198401
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-cs.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.cs={labels:["Roků","Měsíců","Týdnů","Dní","Hodin","Minut","Sekund"],labels1:["Rok","Měsíc","Týden","Den","Hodina","Minuta","Sekunda"],labels2:["Roky","Měsíce","Týdny","Dny","Hodiny","Minuty","Sekundy"],compactLabels:["r","m","t","d"],whichLabels:function(n){return 1==n?1:2<=n&&n<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.cs)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-cy.js b/assets/js/jquery.countdown/jquery.countdown-cy.js
new file mode 100755
index 0000000..caf2d64
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-cy.js
@@ -0,0 +1 @@
+/* http://keith-wood.name/countdown.html
Welsh initialisation for the jQuery countdown extension
Written by Gareth Jones | http://garethvjones.com | October 2011. */
(function($) {
$.countdown.regional['cy'] = {
labels: ['Blynyddoedd', 'Mis', 'Wythnosau', 'Diwrnodau', 'Oriau', 'Munudau', 'Eiliadau'],
labels1: ['Blwyddyn', 'Mis', 'Wythnos', 'Diwrnod', 'Awr', 'Munud', 'Eiliad'],
compactLabels: ['b', 'm', 'w', 'd'],
whichLabels: null,
digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
timeSeparator: ':', isRTL: false};
$.countdown.setDefaults($.countdown.regional['cy']);
})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-cy.min.js b/assets/js/jquery.countdown/jquery.countdown-cy.min.js
new file mode 100644
index 0000000..bfb1fee
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-cy.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.cy={labels:["Blynyddoedd","Mis","Wythnosau","Diwrnodau","Oriau","Munudau","Eiliadau"],labels1:["Blwyddyn","Mis","Wythnos","Diwrnod","Awr","Munud","Eiliad"],compactLabels:["b","m","w","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.cy)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-da.js b/assets/js/jquery.countdown/jquery.countdown-da.js
new file mode 100755
index 0000000..2dee304
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-da.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Danish initialisation for the jQuery countdown extension
+ Written by Buch (admin@buch90.dk). */
+(function($) {
+ $.countdown.regional['da'] = {
+ labels: ['År', 'Måneder', 'Uger', 'Dage', 'Timer', 'Minutter', 'Sekunder'],
+ labels1: ['År', 'Månad', 'Uge', 'Dag', 'Time', 'Minut', 'Sekund'],
+ compactLabels: ['Å', 'M', 'U', 'D'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['da']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-da.min.js b/assets/js/jquery.countdown/jquery.countdown-da.min.js
new file mode 100644
index 0000000..b337715
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-da.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.da={labels:["År","Måneder","Uger","Dage","Timer","Minutter","Sekunder"],labels1:["År","Månad","Uge","Dag","Time","Minut","Sekund"],compactLabels:["Å","M","U","D"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.da)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-de.js b/assets/js/jquery.countdown/jquery.countdown-de.js
new file mode 100755
index 0000000..a5a51b4
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-de.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ German initialisation for the jQuery countdown extension
+ Written by Samuel Wulf. */
+(function($) {
+ $.countdown.regional['de'] = {
+ labels: ['Jahre', 'Monate', 'Wochen', 'Tage', 'Stunden', 'Minuten', 'Sekunden'],
+ labels1: ['Jahr', 'Monat', 'Woche', 'Tag', 'Stunde', 'Minute', 'Sekunde'],
+ compactLabels: ['J', 'M', 'W', 'T'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['de']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-de.min.js b/assets/js/jquery.countdown/jquery.countdown-de.min.js
new file mode 100644
index 0000000..f6f39ef
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-de.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.de={labels:["Jahre","Monate","Wochen","Tage","Stunden","Minuten","Sekunden"],labels1:["Jahr","Monat","Woche","Tag","Stunde","Minute","Sekunde"],compactLabels:["J","M","W","T"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.de)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-el.js b/assets/js/jquery.countdown/jquery.countdown-el.js
new file mode 100755
index 0000000..886ea3c
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-el.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Greek initialisation for the jQuery countdown extension
+ Written by Philip. */
+(function($) {
+ $.countdown.regional['el'] = {
+ labels: ['Χρόνια', 'Μήνες', 'Εβδομάδες', 'Μέρες', 'Ώρες', 'Λεπτά', 'Δευτερόλεπτα'],
+ labels1: ['Χρόνος', 'Μήνας', 'Εβδομάδα', 'Ημέρα', 'Ώρα', 'Λεπτό', 'Δευτερόλεπτο'],
+ compactLabels: ['Χρ.', 'Μην.', 'Εβδ.', 'Ημ.'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['el']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-el.min.js b/assets/js/jquery.countdown/jquery.countdown-el.min.js
new file mode 100644
index 0000000..7be653d
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-el.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.el={labels:["Χρόνια","Μήνες","Εβδομάδες","Μέρες","Ώρες","Λεπτά","Δευτερόλεπτα"],labels1:["Χρόνος","Μήνας","Εβδομάδα","Ημέρα","Ώρα","Λεπτό","Δευτερόλεπτο"],compactLabels:["Χρ.","Μην.","Εβδ.","Ημ."],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.el)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-es.js b/assets/js/jquery.countdown/jquery.countdown-es.js
new file mode 100755
index 0000000..2802058
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-es.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Spanish initialisation for the jQuery countdown extension
+ * Written by Sergio Carracedo Martinez webmaster@neodisenoweb.com (2008) */
+(function($) {
+ $.countdown.regional['es'] = {
+ labels: ['Años', 'Meses', 'Semanas', 'Días', 'Horas', 'Minutos', 'Segundos'],
+ labels1: ['Año', 'Mes', 'Semana', 'Día', 'Hora', 'Minuto', 'Segundo'],
+ compactLabels: ['a', 'm', 's', 'g'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['es']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-es.min.js b/assets/js/jquery.countdown/jquery.countdown-es.min.js
new file mode 100644
index 0000000..c613e14
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-es.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.es={labels:["Años","Meses","Semanas","Días","Horas","Minutos","Segundos"],labels1:["Año","Mes","Semana","Día","Hora","Minuto","Segundo"],compactLabels:["a","m","s","g"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.es)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-et.js b/assets/js/jquery.countdown/jquery.countdown-et.js
new file mode 100755
index 0000000..7c46cb3
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-et.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Estonian initialisation for the jQuery countdown extension
+ Written by Helmer */
+(function($) {
+ $.countdown.regional['et'] = {
+ labels: ['Aastat', 'Kuud', 'Nädalat', 'Päeva', 'Tundi', 'Minutit', 'Sekundit'],
+ labels1: ['Aasta', 'Kuu', 'Nädal', 'Päev', 'Tund', 'Minut', 'Sekund'],
+ compactLabels: ['a', 'k', 'n', 'p'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['et']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-et.min.js b/assets/js/jquery.countdown/jquery.countdown-et.min.js
new file mode 100644
index 0000000..d2df241
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-et.min.js
@@ -0,0 +1 @@
+!function(t){t.countdown.regional.et={labels:["Aastat","Kuud","Nädalat","Päeva","Tundi","Minutit","Sekundit"],labels1:["Aasta","Kuu","Nädal","Päev","Tund","Minut","Sekund"],compactLabels:["a","k","n","p"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},t.countdown.setDefaults(t.countdown.regional.et)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-fa.js b/assets/js/jquery.countdown/jquery.countdown-fa.js
new file mode 100755
index 0000000..4abb7ca
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-fa.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Persian (فارسی) initialisation for the jQuery countdown extension
+ Written by Alireza Ziaie (ziai@magfa.com) Oct 2008. */
+(function($) {
+ $.countdown.regional['fa'] = {
+ labels: ['سال', 'ماه', 'هفته', 'روز', 'ساعت', 'دقیقه', 'ثانیه'],
+ labels1: ['سال', 'ماه', 'هفته', 'روز', 'ساعت', 'دقیقه', 'ثانیه'],
+ compactLabels: ['س', 'م', 'ه', 'ر'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: true};
+ $.countdown.setDefaults($.countdown.regional['fa']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-fa.min.js b/assets/js/jquery.countdown/jquery.countdown-fa.min.js
new file mode 100644
index 0000000..f4421df
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-fa.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.fa={labels:["سال","ماه","هفته","روز","ساعت","دقیقه","ثانیه"],labels1:["سال","ماه","هفته","روز","ساعت","دقیقه","ثانیه"],compactLabels:["س","م","ه","ر"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!0},a.countdown.setDefaults(a.countdown.regional.fa)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-fi.js b/assets/js/jquery.countdown/jquery.countdown-fi.js
new file mode 100755
index 0000000..3fb113d
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-fi.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Finnish initialisation for the jQuery countdown extension
+ Written by Kalle Vänskä and Juha Suni (juhis.suni@gmail.com). Corrected by Olli. */
+(function($) {
+ $.countdown.regional['fi'] = {
+ labels: ['vuotta', 'kuukautta', 'viikkoa', 'päivää', 'tuntia', 'minuuttia', 'sekuntia'],
+ labels1: ['vuosi', 'kuukausi', 'viikko', 'päivä', 'tunti', 'minuutti', 'sekunti'],
+ compactLabels: ['v', 'kk', 'vk', 'pv'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['fi']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-fi.min.js b/assets/js/jquery.countdown/jquery.countdown-fi.min.js
new file mode 100644
index 0000000..6f2d27b
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-fi.min.js
@@ -0,0 +1 @@
+!function(i){i.countdown.regional.fi={labels:["vuotta","kuukautta","viikkoa","päivää","tuntia","minuuttia","sekuntia"],labels1:["vuosi","kuukausi","viikko","päivä","tunti","minuutti","sekunti"],compactLabels:["v","kk","vk","pv"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},i.countdown.setDefaults(i.countdown.regional.fi)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-fr.js b/assets/js/jquery.countdown/jquery.countdown-fr.js
new file mode 100755
index 0000000..646a50c
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-fr.js
@@ -0,0 +1,15 @@
+/* http://keith-wood.name/countdown.html
+ French initialisation for the jQuery countdown extension
+ Written by Keith Wood (kbwood{at}iinet.com.au) Jan 2008. */
+(function($) {
+ $.countdown.regional['fr'] = {
+ labels: ['Années', 'Mois', 'Semaines', 'Jours', 'Heures', 'Minutes', 'Secondes'],
+ labels1: ['Année', 'Mois', 'Semaine', 'Jour', 'Heure', 'Minute', 'Seconde'],
+ compactLabels: ['a', 'm', 's', 'j'],
+ whichLabels: function(amount) {
+ return (amount > 1 ? 0 : 1);
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['fr']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-fr.min.js b/assets/js/jquery.countdown/jquery.countdown-fr.min.js
new file mode 100644
index 0000000..1523c0b
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-fr.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.fr={labels:["Années","Mois","Semaines","Jours","Heures","Minutes","Secondes"],labels1:["Année","Mois","Semaine","Jour","Heure","Minute","Seconde"],compactLabels:["a","m","s","j"],whichLabels:function(e){return 1= 2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['hr']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-hr.min.js b/assets/js/jquery.countdown/jquery.countdown-hr.min.js
new file mode 100644
index 0000000..9fc9ce6
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-hr.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.hr={labels:["Godina","Mjeseci","Tjedana","Dana","Sati","Minuta","Sekundi"],labels1:["Godina","Mjesec","Tjedan","Dan","Sat","Minuta","Sekunda"],labels2:["Godine","Mjeseca","Tjedna","Dana","Sata","Minute","Sekunde"],compactLabels:["g","m","t","d"],whichLabels:function(a){return 1==a?1:2<=a&&a<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.hr)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-hu.js b/assets/js/jquery.countdown/jquery.countdown-hu.js
new file mode 100755
index 0000000..e23823f
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-hu.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Hungarian initialisation for the jQuery countdown extension
+ * Written by Edmond L. (webmond@gmail.com). */
+(function($) {
+ $.countdown.regional['hu'] = {
+ labels: ['Év', 'Hónap', 'Hét', 'Nap', 'Óra', 'Perc', 'Másodperc'],
+ labels1: ['Év', 'Hónap', 'Hét', 'Nap', 'Óra', 'Perc', 'Másodperc'],
+ compactLabels: ['É', 'H', 'Hé', 'N'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['hu']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-hu.min.js b/assets/js/jquery.countdown/jquery.countdown-hu.min.js
new file mode 100644
index 0000000..1e0c137
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-hu.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.hu={labels:["Év","Hónap","Hét","Nap","Óra","Perc","Másodperc"],labels1:["Év","Hónap","Hét","Nap","Óra","Perc","Másodperc"],compactLabels:["É","H","Hé","N"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.hu)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-hy.js b/assets/js/jquery.countdown/jquery.countdown-hy.js
new file mode 100755
index 0000000..ebc74b7
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-hy.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Armenian initialisation for the jQuery countdown extension
+ * Written by Artur Martirosyan. (artur{at}zoom.am) October 2011. */
+(function($) {
+ $.countdown.regional['hy'] = {
+ labels: ['Տարի', 'Ամիս', 'Շաբաթ', 'Օր', 'Ժամ', 'Րոպե', 'Վարկյան'],
+ labels1: ['Տարի', 'Ամիս', 'Շաբաթ', 'Օր', 'Ժամ', 'Րոպե', 'Վարկյան'],
+ compactLabels: ['տ', 'ա', 'շ', 'օ'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['hy']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-hy.min.js b/assets/js/jquery.countdown/jquery.countdown-hy.min.js
new file mode 100644
index 0000000..911fd49
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-hy.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.hy={labels:["Տարի","Ամիս","Շաբաթ","Օր","Ժամ","Րոպե","Վարկյան"],labels1:["Տարի","Ամիս","Շաբաթ","Օր","Ժամ","Րոպե","Վարկյան"],compactLabels:["տ","ա","շ","օ"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.hy)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-id.js b/assets/js/jquery.countdown/jquery.countdown-id.js
new file mode 100755
index 0000000..380193b
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-id.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Indonesian initialisation for the jQuery countdown extension
+ Written by Erwin Yonathan Jan 2009. */
+(function($) {
+ $.countdown.regional['id'] = {
+ labels: ['tahun', 'bulan', 'minggu', 'hari', 'jam', 'menit', 'detik'],
+ labels1: ['tahun', 'bulan', 'minggu', 'hari', 'jam', 'menit', 'detik'],
+ compactLabels: ['t', 'b', 'm', 'h'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['id']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-id.min.js b/assets/js/jquery.countdown/jquery.countdown-id.min.js
new file mode 100644
index 0000000..c7f1228
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-id.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.id={labels:["tahun","bulan","minggu","hari","jam","menit","detik"],labels1:["tahun","bulan","minggu","hari","jam","menit","detik"],compactLabels:["t","b","m","h"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.id)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-it.js b/assets/js/jquery.countdown/jquery.countdown-it.js
new file mode 100755
index 0000000..bf872f1
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-it.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Italian initialisation for the jQuery countdown extension
+ * Written by Davide Bellettini (davide.bellettini@gmail.com) and Roberto Chiaveri Feb 2008. */
+(function($) {
+ $.countdown.regional['it'] = {
+ labels: ['Anni', 'Mesi', 'Settimane', 'Giorni', 'Ore', 'Minuti', 'Secondi'],
+ labels1: ['Anno', 'Mese', 'Settimana', 'Giorno', 'Ora', 'Minuto', 'Secondo'],
+ compactLabels: ['a', 'm', 's', 'g'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['it']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-it.min.js b/assets/js/jquery.countdown/jquery.countdown-it.min.js
new file mode 100644
index 0000000..cd097b9
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-it.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.it={labels:["Anni","Mesi","Settimane","Giorni","Ore","Minuti","Secondi"],labels1:["Anno","Mese","Settimana","Giorno","Ora","Minuto","Secondo"],compactLabels:["a","m","s","g"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.it)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ja.js b/assets/js/jquery.countdown/jquery.countdown-ja.js
new file mode 100755
index 0000000..73b75f0
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ja.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Japanese initialisation for the jQuery countdown extension
+ Written by Ken Ishimoto (ken@ksroom.com) Aug 2009. */
+(function($) {
+ $.countdown.regional['ja'] = {
+ labels: ['年', '月', '週', '日', '時', '分', '秒'],
+ labels1: ['年', '月', '週', '日', '時', '分', '秒'],
+ compactLabels: ['年', '月', '週', '日'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['ja']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ja.min.js b/assets/js/jquery.countdown/jquery.countdown-ja.min.js
new file mode 100644
index 0000000..e78672a
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ja.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.ja={labels:["年","月","週","日","時","分","秒"],labels1:["年","月","週","日","時","分","秒"],compactLabels:["年","月","週","日"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.ja)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-kn.js b/assets/js/jquery.countdown/jquery.countdown-kn.js
new file mode 100755
index 0000000..d663045
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-kn.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Kannada initialization for the jQuery countdown extension
+ * Written by Guru Chaturvedi guru@gangarasa.com (2011) */
+(function($) {
+ $.countdown.regional['kn'] = {
+ labels: ['ವರ್ಷಗಳು', 'ತಿಂಗಳು', 'ವಾರಗಳು', 'ದಿನಗಳು', 'ಘಂಟೆಗಳು', 'ನಿಮಿಷಗಳು', 'ಕ್ಷಣಗಳು'],
+ labels1: ['ವರ್ಷ', 'ತಿಂಗಳು', 'ವಾರ', 'ದಿನ', 'ಘಂಟೆ', 'ನಿಮಿಷ', 'ಕ್ಷಣ'],
+ compactLabels: ['ವ', 'ತಿ', 'ವಾ', 'ದಿ'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['kn']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-kn.min.js b/assets/js/jquery.countdown/jquery.countdown-kn.min.js
new file mode 100644
index 0000000..f296b60
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-kn.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.kn={labels:["ವರ್ಷಗಳು","ತಿಂಗಳು","ವಾರಗಳು","ದಿನಗಳು","ಘಂಟೆಗಳು","ನಿಮಿಷಗಳು","ಕ್ಷಣಗಳು"],labels1:["ವರ್ಷ","ತಿಂಗಳು","ವಾರ","ದಿನ","ಘಂಟೆ","ನಿಮಿಷ","ಕ್ಷಣ"],compactLabels:["ವ","ತಿ","ವಾ","ದಿ"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.kn)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ko.js b/assets/js/jquery.countdown/jquery.countdown-ko.js
new file mode 100755
index 0000000..ebf04d6
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ko.js
@@ -0,0 +1,14 @@
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+/* http://keith-wood.name/countdown.html
+ Korean initialisation for the jQuery countdown extension
+ Written by Ryan Yu (ryanyu79@gmail.com). */
+(function($) {
+ $.countdown.regional['ko'] = {
+ labels: ['년', '월', '주', '일', '시', '분', '초'],
+ labels1: ['년', '월', '주', '일', '시', '분', '초'],
+ compactLabels: ['년', '월', '주', '일'],
+ compactLabels1: ['년', '월', '주', '일'],
+ whichLabels: null,
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['ko']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ko.min.js b/assets/js/jquery.countdown/jquery.countdown-ko.min.js
new file mode 100644
index 0000000..9274fab
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ko.min.js
@@ -0,0 +1 @@
+(function(o){o.countdown.regional.ko={labels:["년","월","주","일","시","분","초"],labels1:["년","월","주","일","시","분","초"],compactLabels:["년","월","주","일"],compactLabels1:["년","월","주","일"],whichLabels:null,timeSeparator:":",isRTL:!1},o.countdown.setDefaults(o.countdown.regional.ko)})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-lt.js b/assets/js/jquery.countdown/jquery.countdown-lt.js
new file mode 100755
index 0000000..8076f16
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-lt.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Lithuanian localisation for the jQuery countdown extension
+ * Written by Moacir P. de Sá Pereira (moacir{at}gmail.com) (2009) */
+(function($) {
+ $.countdown.regional['lt'] = {
+ labels: ['Metų', 'Mėnesių', 'Savaičių', 'Dienų', 'Valandų', 'Minučių', 'Sekundžių'],
+ labels1: ['Metai', 'Mėnuo', 'Savaitė', 'Diena', 'Valanda', 'Minutė', 'Sekundė'],
+ compactLabels: ['m', 'm', 's', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['lt']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-lt.min.js b/assets/js/jquery.countdown/jquery.countdown-lt.min.js
new file mode 100644
index 0000000..7947c48
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-lt.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.lt={labels:["Metų","Mėnesių","Savaičių","Dienų","Valandų","Minučių","Sekundžių"],labels1:["Metai","Mėnuo","Savaitė","Diena","Valanda","Minutė","Sekundė"],compactLabels:["m","m","s","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.lt)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-lv.js b/assets/js/jquery.countdown/jquery.countdown-lv.js
new file mode 100755
index 0000000..30f4dfd
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-lv.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Latvian initialisation for the jQuery countdown extension
+ * Written by Jānis Peisenieks janis.peisenieks@gmail.com (2010) */
+(function($) {
+ $.countdown.regional['lv'] = {
+ labels: ['Gadi', 'Mēneši', 'Nedēļas', 'Dienas', 'Stundas', 'Minūtes', 'Sekundes'],
+ labels1: ['Gads', 'Mēnesis', 'Nedēļa', 'Diena', 'Stunda', 'Minūte', 'Sekunde'],
+ compactLabels: ['l', 'm', 'n', 'd'], compactLabels1: ['g', 'm', 'n', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['lv']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-lv.min.js b/assets/js/jquery.countdown/jquery.countdown-lv.min.js
new file mode 100644
index 0000000..f2de488
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-lv.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.lv={labels:["Gadi","Mēneši","Nedēļas","Dienas","Stundas","Minūtes","Sekundes"],labels1:["Gads","Mēnesis","Nedēļa","Diena","Stunda","Minūte","Sekunde"],compactLabels:["l","m","n","d"],compactLabels1:["g","m","n","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.lv)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ms.js b/assets/js/jquery.countdown/jquery.countdown-ms.js
new file mode 100755
index 0000000..9c235db
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ms.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Malay initialisation for the jQuery countdown extension
+ Written by Jason Ong (jason{at}portalgroove.com) May 2010. */
+(function($) {
+ $.countdown.regional['ms'] = {
+ labels: ['Tahun', 'Bulan', 'Minggu', 'Hari', 'Jam', 'Minit', 'Saat'],
+ labels1: ['Tahun', 'Bulan', 'Minggu', 'Hari', 'Jam', 'Minit', 'Saat'],
+ compactLabels: ['t', 'b', 'm', 'h'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['ms']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ms.min.js b/assets/js/jquery.countdown/jquery.countdown-ms.min.js
new file mode 100644
index 0000000..6548acc
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ms.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.ms={labels:["Tahun","Bulan","Minggu","Hari","Jam","Minit","Saat"],labels1:["Tahun","Bulan","Minggu","Hari","Jam","Minit","Saat"],compactLabels:["t","b","m","h"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.ms)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-my.js b/assets/js/jquery.countdown/jquery.countdown-my.js
new file mode 100755
index 0000000..7160ce8
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-my.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Burmese initialisation for the jQuery countdown extension
+ Written by Win Lwin Moe (winnlwinmoe@gmail.com) Dec 2009. */
+(function($) {
+ $.countdown.regional['my'] = {
+ labels: ['နွစ္', 'လ', 'ရက္သတဿတပတ္', 'ရက္', 'နာရီ', 'မိနစ္', 'စကဿကန့္'],
+ labels1: ['နွစ္', 'လ', 'ရက္သတဿတပတ္', 'ရက္', 'နာရီ', 'မိနစ္', 'စကဿကန့္'],
+ compactLabels: ['နွစ္', 'လ', 'ရက္သတဿတပတ္', 'ရက္'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['my']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-my.min.js b/assets/js/jquery.countdown/jquery.countdown-my.min.js
new file mode 100644
index 0000000..6e11ad2
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-my.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.my={labels:["နွစ္","လ","ရက္သတဿတပတ္","ရက္","နာရီ","မိနစ္","စကဿကန့္"],labels1:["နွစ္","လ","ရက္သတဿတပတ္","ရက္","နာရီ","မိနစ္","စကဿကန့္"],compactLabels:["နွစ္","လ","ရက္သတဿတပတ္","ရက္"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.my)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-nb.js b/assets/js/jquery.countdown/jquery.countdown-nb.js
new file mode 100755
index 0000000..cd43589
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-nb.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Norwegian Bokmål translation
+ Written by Kristian Ravnevand */
+(function($) {
+ $.countdown.regional['nb'] = {
+ labels: ['År', 'Måneder', 'Uker', 'Dager', 'Timer', 'Minutter', 'Sekunder'],
+ labels1: ['År', 'Måned', 'Uke', 'Dag', 'Time', 'Minutt', 'Sekund'],
+ compactLabels: ['Å', 'M', 'U', 'D'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['nb']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-nb.min.js b/assets/js/jquery.countdown/jquery.countdown-nb.min.js
new file mode 100644
index 0000000..d56e8c5
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-nb.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.nb={labels:["År","Måneder","Uker","Dager","Timer","Minutter","Sekunder"],labels1:["År","Måned","Uke","Dag","Time","Minutt","Sekund"],compactLabels:["Å","M","U","D"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.nb)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-nl.js b/assets/js/jquery.countdown/jquery.countdown-nl.js
new file mode 100755
index 0000000..990906e
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-nl.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Dutch initialisation for the jQuery countdown extension
+ Written by Mathias Bynens Mar 2008. */
+(function($) {
+ $.countdown.regional['nl'] = {
+ labels: ['Jaren', 'Maanden', 'Weken', 'Dagen', 'Uren', 'Minuten', 'Seconden'],
+ labels1: ['Jaar', 'Maand', 'Week', 'Dag', 'Uur', 'Minuut', 'Seconde'],
+ compactLabels: ['j', 'm', 'w', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['nl']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-nl.min.js b/assets/js/jquery.countdown/jquery.countdown-nl.min.js
new file mode 100644
index 0000000..0e962cd
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-nl.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.nl={labels:["Jaren","Maanden","Weken","Dagen","Uren","Minuten","Seconden"],labels1:["Jaar","Maand","Week","Dag","Uur","Minuut","Seconde"],compactLabels:["j","m","w","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.nl)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-pl.js b/assets/js/jquery.countdown/jquery.countdown-pl.js
new file mode 100755
index 0000000..b94665c
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-pl.js
@@ -0,0 +1,18 @@
+/* http://keith-wood.name/countdown.html
+ * Polish initialisation for the jQuery countdown extension
+ * Written by Pawel Lewtak lewtak@gmail.com (2008) */
+(function($) {
+ $.countdown.regional['pl'] = {
+ labels: ['lat', 'miesięcy', 'tygodni', 'dni', 'godzin', 'minut', 'sekund'],
+ labels1: ['rok', 'miesiąc', 'tydzień', 'dzień', 'godzina', 'minuta', 'sekunda'],
+ labels2: ['lata', 'miesiące', 'tygodnie', 'dni', 'godziny', 'minuty', 'sekundy'],
+ compactLabels: ['l', 'm', 't', 'd'], compactLabels1: ['r', 'm', 't', 'd'],
+ whichLabels: function(amount) {
+ var units = amount % 10;
+ var tens = Math.floor((amount % 100) / 10);
+ return (amount == 1 ? 1 : (units >= 2 && units <= 4 && tens != 1 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['pl']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-pl.min.js b/assets/js/jquery.countdown/jquery.countdown-pl.min.js
new file mode 100644
index 0000000..d53e4ee
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-pl.min.js
@@ -0,0 +1 @@
+!function(i){i.countdown.regional.pl={labels:["lat","miesięcy","tygodni","dni","godzin","minut","sekund"],labels1:["rok","miesiąc","tydzień","dzień","godzina","minuta","sekunda"],labels2:["lata","miesiące","tygodnie","dni","godziny","minuty","sekundy"],compactLabels:["l","m","t","d"],compactLabels1:["r","m","t","d"],whichLabels:function(i){var n=i%10,e=Math.floor(i%100/10);return 1==i?1:2<=n&&n<=4&&1!=e?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},i.countdown.setDefaults(i.countdown.regional.pl)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-pt-BR.js b/assets/js/jquery.countdown/jquery.countdown-pt-BR.js
new file mode 100755
index 0000000..1613103
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-pt-BR.js
@@ -0,0 +1,14 @@
+/* http://keith-wood.name/countdown.html
+ Brazilian initialisation for the jQuery countdown extension
+ Translated by Marcelo Pellicano de Oliveira (pellicano@gmail.com) Feb 2008.
+ and Juan Roldan (juan.roldan[at]relayweb.com.br) Mar 2012. */
+(function($) {
+ $.countdown.regional['pt-BR'] = {
+ labels: ['Anos', 'Meses', 'Semanas', 'Dias', 'Horas', 'Minutos', 'Segundos'],
+ labels1: ['Ano', 'Ms', 'Semana', 'Dia', 'Hora', 'Minuto', 'Segundo'],
+ compactLabels: ['a', 'm', 's', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['pt-BR']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-pt-BR.min.js b/assets/js/jquery.countdown/jquery.countdown-pt-BR.min.js
new file mode 100644
index 0000000..7abbe2d
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-pt-BR.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional["pt-BR"]={labels:["Anos","Meses","Semanas","Dias","Horas","Minutos","Segundos"],labels1:["Ano","M�s","Semana","Dia","Hora","Minuto","Segundo"],compactLabels:["a","m","s","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional["pt-BR"])}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ro.js b/assets/js/jquery.countdown/jquery.countdown-ro.js
new file mode 100755
index 0000000..98e1bb6
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ro.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Romanian initialisation for the jQuery countdown extension
+ * Written by Edmond L. (webmond@gmail.com). */
+(function($) {
+ $.countdown.regional['ro'] = {
+ labels: ['Ani', 'Luni', 'Saptamani', 'Zile', 'Ore', 'Minute', 'Secunde'],
+ labels1: ['An', 'Luna', 'Saptamana', 'Ziua', 'Ora', 'Minutul', 'Secunda'],
+ compactLabels: ['A', 'L', 'S', 'Z'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['ro']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ro.min.js b/assets/js/jquery.countdown/jquery.countdown-ro.min.js
new file mode 100644
index 0000000..190e709
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ro.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.ro={labels:["Ani","Luni","Saptamani","Zile","Ore","Minute","Secunde"],labels1:["An","Luna","Saptamana","Ziua","Ora","Minutul","Secunda"],compactLabels:["A","L","S","Z"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.ro)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-ru.js b/assets/js/jquery.countdown/jquery.countdown-ru.js
new file mode 100755
index 0000000..67035d7
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ru.js
@@ -0,0 +1,19 @@
+/* http://keith-wood.name/countdown.html
+ * Russian initialisation for the jQuery countdown extension
+ * Written by Sergey K. (xslade{at}gmail.com) June 2010. */
+(function($) {
+ $.countdown.regional['ru'] = {
+ labels: ['Лет', 'Месяцев', 'Недель', 'Дней', 'Часов', 'Минут', 'Секунд'],
+ labels1: ['Год', 'Месяц', 'Неделя', 'День', 'Час', 'Минута', 'Секунда'],
+ labels2: ['Года', 'Месяца', 'Недели', 'Дня', 'Часа', 'Минуты', 'Секунды'],
+ compactLabels: ['л', 'м', 'н', 'д'], compactLabels1: ['г', 'м', 'н', 'д'],
+ whichLabels: function(amount) {
+ var units = amount % 10;
+ var tens = Math.floor((amount % 100) / 10);
+ return (amount == 1 ? 1 : (units >= 2 && units <= 4 && tens != 1 ? 2 :
+ (units == 1 && tens != 1 ? 1 : 0)));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['ru']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-ru.min.js b/assets/js/jquery.countdown/jquery.countdown-ru.min.js
new file mode 100644
index 0000000..b105bc0
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-ru.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.ru={labels:["Лет","Месяцев","Недель","Дней","Часов","Минут","Секунд"],labels1:["Год","Месяц","Неделя","День","Час","Минута","Секунда"],labels2:["Года","Месяца","Недели","Дня","Часа","Минуты","Секунды"],compactLabels:["л","м","н","д"],compactLabels1:["г","м","н","д"],whichLabels:function(a){var o=a%10,e=Math.floor(a%100/10);return 1==a?1:2<=o&&o<=4&&1!=e?2:1==o&&1!=e?1:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.ru)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sk.js b/assets/js/jquery.countdown/jquery.countdown-sk.js
new file mode 100755
index 0000000..acd1953
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sk.js
@@ -0,0 +1,16 @@
+/* http://keith-wood.name/countdown.html
+ * Slovak initialisation for the jQuery countdown extension
+ * Written by Roman Chlebec (creamd@c64.sk) (2008) */
+(function($) {
+ $.countdown.regional['sk'] = {
+ labels: ['Rokov', 'Mesiacov', 'Týždňov', 'Dní', 'Hodín', 'Minút', 'Sekúnd'],
+ labels1: ['Rok', 'Mesiac', 'Týždeň', 'Deň', 'Hodina', 'Minúta', 'Sekunda'],
+ labels2: ['Roky', 'Mesiace', 'Týždne', 'Dni', 'Hodiny', 'Minúty', 'Sekundy'],
+ compactLabels: ['r', 'm', 't', 'd'],
+ whichLabels: function(amount) {
+ return (amount == 1 ? 1 : (amount >= 2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['sk']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sk.min.js b/assets/js/jquery.countdown/jquery.countdown-sk.min.js
new file mode 100644
index 0000000..7dc70b3
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sk.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.sk={labels:["Rokov","Mesiacov","Týždňov","Dní","Hodín","Minút","Sekúnd"],labels1:["Rok","Mesiac","Týždeň","Deň","Hodina","Minúta","Sekunda"],labels2:["Roky","Mesiace","Týždne","Dni","Hodiny","Minúty","Sekundy"],compactLabels:["r","m","t","d"],whichLabels:function(n){return 1==n?1:2<=n&&n<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.sk)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sl.js b/assets/js/jquery.countdown/jquery.countdown-sl.js
new file mode 100755
index 0000000..8d59fd5
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sl.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Slovenian localisation for the jQuery countdown extension
+ * Written by Borut Tomažin (debijan{at}gmail.com) (2011) */
+(function($) {
+ $.countdown.regional['sl'] = {
+ labels: ['Let', 'Mesecev', 'Tednov', 'Dni', 'Ur', 'Minut', 'Sekund'],
+ labels1: ['Leto', 'Mesec', 'Teden', 'Dan', 'Ura', 'Minuta', 'Sekunda'],
+ compactLabels: ['l', 'm', 't', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['sl']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sl.min.js b/assets/js/jquery.countdown/jquery.countdown-sl.min.js
new file mode 100644
index 0000000..0fd49c2
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sl.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.sl={labels:["Let","Mesecev","Tednov","Dni","Ur","Minut","Sekund"],labels1:["Leto","Mesec","Teden","Dan","Ura","Minuta","Sekunda"],compactLabels:["l","m","t","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.sl)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sq.js b/assets/js/jquery.countdown/jquery.countdown-sq.js
new file mode 100755
index 0000000..4e4d120
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sq.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Albanian initialisation for the jQuery countdown extension
+ Written by Erzen Komoni. */
+(function($) {
+ $.countdown.regional['sq'] = {
+ labels: ['Vite', 'Muaj', 'Javë', 'Ditë', 'Orë', 'Minuta', 'Sekonda'],
+ labels1: ['Vit', 'Muaj', 'Javë', 'Dit', 'Orë', 'Minutë', 'Sekond'],
+ compactLabels: ['V', 'M', 'J', 'D'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['sq']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-sq.min.js b/assets/js/jquery.countdown/jquery.countdown-sq.min.js
new file mode 100644
index 0000000..a6290a6
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sq.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.sq={labels:["Vite","Muaj","Javë","Ditë","Orë","Minuta","Sekonda"],labels1:["Vit","Muaj","Javë","Dit","Orë","Minutë","Sekond"],compactLabels:["V","M","J","D"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.sq)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sr-SR.js b/assets/js/jquery.countdown/jquery.countdown-sr-SR.js
new file mode 100755
index 0000000..bc5bbed
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sr-SR.js
@@ -0,0 +1,16 @@
+/* http://keith-wood.name/countdown.html
+ * Serbian Latin initialisation for the jQuery countdown extension
+ * Written by Predrag Leka lp@lemurcake.com (2010) */
+(function($) {
+ $.countdown.regional['sr-SR'] = {
+ labels: ['Godina', 'Meseci', 'Nedelja', 'Dana', 'Časova', 'Minuta', 'Sekundi'],
+ labels1: ['Godina', 'Mesec', 'Nedelja', 'Dan', 'Čas', 'Minut', 'Sekunda'],
+ labels2: ['Godine', 'Meseca', 'Nedelje', 'Dana', 'Časa', 'Minuta', 'Sekunde'],
+ compactLabels: ['g', 'm', 'n', 'd'],
+ whichLabels: function(amount) {
+ return (amount == 1 ? 1 : (amount >= 2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['sr-SR']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sr-SR.min.js b/assets/js/jquery.countdown/jquery.countdown-sr-SR.min.js
new file mode 100644
index 0000000..277ad41
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sr-SR.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional["sr-SR"]={labels:["Godina","Meseci","Nedelja","Dana","Časova","Minuta","Sekundi"],labels1:["Godina","Mesec","Nedelja","Dan","Čas","Minut","Sekunda"],labels2:["Godine","Meseca","Nedelje","Dana","Časa","Minuta","Sekunde"],compactLabels:["g","m","n","d"],whichLabels:function(e){return 1==e?1:2<=e&&e<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional["sr-SR"])}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sr.js b/assets/js/jquery.countdown/jquery.countdown-sr.js
new file mode 100755
index 0000000..302c3b0
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sr.js
@@ -0,0 +1,16 @@
+/* http://keith-wood.name/countdown.html
+ * Serbian Cyrillic initialisation for the jQuery countdown extension
+ * Written by Predrag Leka lp@lemurcake.com (2010) */
+(function($) {
+ $.countdown.regional['sr'] = {
+ labels: ['Година', 'Месеци', 'Недеља', 'Дана', 'Часова', 'Минута', 'Секунди'],
+ labels1: ['Година', 'месец', 'Недеља', 'Дан', 'Час', 'Минут', 'Секунда'],
+ labels2: ['Године', 'Месеца', 'Недеље', 'Дана', 'Часа', 'Минута', 'Секунде'],
+ compactLabels: ['г', 'м', 'н', 'д'],
+ whichLabels: function(amount) {
+ return (amount == 1 ? 1 : (amount >= 2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['sr']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sr.min.js b/assets/js/jquery.countdown/jquery.countdown-sr.min.js
new file mode 100644
index 0000000..c578601
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sr.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.sr={labels:["Година","Месеци","Недеља","Дана","Часова","Минута","Секунди"],labels1:["Година","месец","Недеља","Дан","Час","Минут","Секунда"],labels2:["Године","Месеца","Недеље","Дана","Часа","Минута","Секунде"],compactLabels:["г","м","н","д"],whichLabels:function(e){return 1==e?1:2<=e&&e<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.sr)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sv.js b/assets/js/jquery.countdown/jquery.countdown-sv.js
new file mode 100755
index 0000000..461f3ed
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sv.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Swedish initialisation for the jQuery countdown extension
+ Written by Carl (carl@nordenfelt.com). */
+(function($) {
+ $.countdown.regional['sv'] = {
+ labels: ['År', 'Månader', 'Veckor', 'Dagar', 'Timmar', 'Minuter', 'Sekunder'],
+ labels1: ['År', 'Månad', 'Vecka', 'Dag', 'Timme', 'Minut', 'Sekund'],
+ compactLabels: ['Å', 'M', 'V', 'D'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['sv']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-sv.min.js b/assets/js/jquery.countdown/jquery.countdown-sv.min.js
new file mode 100644
index 0000000..502225d
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-sv.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.sv={labels:["År","Månader","Veckor","Dagar","Timmar","Minuter","Sekunder"],labels1:["År","Månad","Vecka","Dag","Timme","Minut","Sekund"],compactLabels:["Å","M","V","D"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.sv)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-th.js b/assets/js/jquery.countdown/jquery.countdown-th.js
new file mode 100755
index 0000000..778f9d2
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-th.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Thai initialisation for the jQuery countdown extension
+ Written by Pornchai Sakulsrimontri (li_sin_th@yahoo.com). */
+(function($) {
+ $.countdown.regional['th'] = {
+ labels: ['ปี', 'เดือน', 'สัปดาห์', 'วัน', 'ชั่วโมง', 'นาที', 'วินาที'],
+ labels1: ['ปี', 'เดือน', 'สัปดาห์', 'วัน', 'ชั่วโมง', 'นาที', 'วินาที'],
+ compactLabels: ['ปี', 'เดือน', 'สัปดาห์', 'วัน'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['th']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-th.min.js b/assets/js/jquery.countdown/jquery.countdown-th.min.js
new file mode 100644
index 0000000..c3132ad
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-th.min.js
@@ -0,0 +1 @@
+!function(t){t.countdown.regional.th={labels:["ปี","เดือน","สัปดาห์","วัน","ชั่วโมง","นาที","วินาที"],labels1:["ปี","เดือน","สัปดาห์","วัน","ชั่วโมง","นาที","วินาที"],compactLabels:["ปี","เดือน","สัปดาห์","วัน"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},t.countdown.setDefaults(t.countdown.regional.th)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-tr.js b/assets/js/jquery.countdown/jquery.countdown-tr.js
new file mode 100755
index 0000000..92195d4
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-tr.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+* Turkish initialisation for the jQuery countdown extension
+* Written by Bekir Ahmetoğlu (bekir@cerek.com) Aug 2008. */
+(function($) {
+ $.countdown.regional['tr'] = {
+ labels: ['Yıl', 'Ay', 'Hafta', 'Gün', 'Saat', 'Dakika', 'Saniye'],
+ labels1: ['Yıl', 'Ay', 'Hafta', 'Gün', 'Saat', 'Dakika', 'Saniye'],
+ compactLabels: ['y', 'a', 'h', 'g'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['tr']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-tr.min.js b/assets/js/jquery.countdown/jquery.countdown-tr.min.js
new file mode 100644
index 0000000..f81dbd7
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-tr.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.tr={labels:["Yıl","Ay","Hafta","Gün","Saat","Dakika","Saniye"],labels1:["Yıl","Ay","Hafta","Gün","Saat","Dakika","Saniye"],compactLabels:["y","a","h","g"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.tr)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-uk.js b/assets/js/jquery.countdown/jquery.countdown-uk.js
new file mode 100755
index 0000000..ef48cf3
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-uk.js
@@ -0,0 +1,16 @@
+/* http://keith-wood.name/countdown.html
+ * Ukrainian initialisation for the jQuery countdown extension
+ * Written by Goloborodko M misha.gm@gmail.com (2009), corrections by Iгор Kоновал */
+(function($) {
+ $.countdown.regional['uk'] = {
+ labels: ['Років', 'Місяців', 'Тижнів', 'Днів', 'Годин', 'Хвилин', 'Секунд'],
+ labels1: ['Рік', 'Місяць', 'Тиждень', 'День', 'Година', 'Хвилина', 'Секунда'],
+ labels2: ['Роки', 'Місяці', 'Тижні', 'Дні', 'Години', 'Хвилини', 'Секунди'],
+ compactLabels: ['r', 'm', 't', 'd'],
+ whichLabels: function(amount) {
+ return (amount == 1 ? 1 : (amount >=2 && amount <= 4 ? 2 : 0));
+ },
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['uk']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-uk.min.js b/assets/js/jquery.countdown/jquery.countdown-uk.min.js
new file mode 100644
index 0000000..ca1f712
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-uk.min.js
@@ -0,0 +1 @@
+!function(e){e.countdown.regional.uk={labels:["Років","Місяців","Тижнів","Днів","Годин","Хвилин","Секунд"],labels1:["Рік","Місяць","Тиждень","День","Година","Хвилина","Секунда"],labels2:["Роки","Місяці","Тижні","Дні","Години","Хвилини","Секунди"],compactLabels:["r","m","t","d"],whichLabels:function(e){return 1==e?1:2<=e&&e<=4?2:0},digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},e.countdown.setDefaults(e.countdown.regional.uk)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-uz.js b/assets/js/jquery.countdown/jquery.countdown-uz.js
new file mode 100755
index 0000000..7e6fa7c
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-uz.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Uzbek initialisation for the jQuery countdown extension
+ * Written by Alisher U. (ulugbekov{at}gmail.com) August 2012. */
+(function($) {
+ $.countdown.regional['uz'] = {
+ labels: ['Yil', 'Oy', 'Hafta', 'Kun', 'Soat', 'Daqiqa', 'Soniya'],
+ labels1: ['Yil', 'Oy', 'Hafta', 'Kun', 'Soat', 'Daqiqa', 'Soniya'],
+ compactLabels: ['y', 'o', 'h', 'k'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['uz']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-uz.min.js b/assets/js/jquery.countdown/jquery.countdown-uz.min.js
new file mode 100644
index 0000000..fbac432
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-uz.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional.uz={labels:["Yil","Oy","Hafta","Kun","Soat","Daqiqa","Soniya"],labels1:["Yil","Oy","Hafta","Kun","Soat","Daqiqa","Soniya"],compactLabels:["y","o","h","k"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional.uz)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-vi.js b/assets/js/jquery.countdown/jquery.countdown-vi.js
new file mode 100755
index 0000000..918fd36
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-vi.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ * Vietnamese initialisation for the jQuery countdown extension
+ * Written by Pham Tien Hung phamtienhung@gmail.com (2010) */
+(function($) {
+ $.countdown.regional['vi'] = {
+ labels: ['Năm', 'Tháng', 'Tuần', 'Ngày', 'Giờ', 'Phút', 'Giây'],
+ labels1: ['Năm', 'Tháng', 'Tuần', 'Ngày', 'Giờ', 'Phút', 'Giây'],
+ compactLabels: ['năm', 'th', 'tu', 'ng'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['vi']);
+})(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery.countdown/jquery.countdown-vi.min.js b/assets/js/jquery.countdown/jquery.countdown-vi.min.js
new file mode 100644
index 0000000..9c33403
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-vi.min.js
@@ -0,0 +1 @@
+!function(n){n.countdown.regional.vi={labels:["Năm","Tháng","Tuần","Ngày","Giờ","Phút","Giây"],labels1:["Năm","Tháng","Tuần","Ngày","Giờ","Phút","Giây"],compactLabels:["năm","th","tu","ng"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},n.countdown.setDefaults(n.countdown.regional.vi)}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-zh-CN.js b/assets/js/jquery.countdown/jquery.countdown-zh-CN.js
new file mode 100755
index 0000000..bc442cb
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-zh-CN.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Simplified Chinese initialisation for the jQuery countdown extension
+ Written by Cloudream (cloudream@gmail.com). */
+(function($) {
+ $.countdown.regional['zh-CN'] = {
+ labels: ['年', '月', '周', '天', '时', '分', '秒'],
+ labels1: ['年', '月', '周', '天', '时', '分', '秒'],
+ compactLabels: ['年', '月', '周', '天'], compactLabels1: ['年', '月', '周', '天'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['zh-CN']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-zh-CN.min.js b/assets/js/jquery.countdown/jquery.countdown-zh-CN.min.js
new file mode 100644
index 0000000..a999dcd
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-zh-CN.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional["zh-CN"]={labels:["年","月","周","天","时","分","秒"],labels1:["年","月","周","天","时","分","秒"],compactLabels:["年","月","周","天"],compactLabels1:["年","月","周","天"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional["zh-CN"])}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-zh-TW.js b/assets/js/jquery.countdown/jquery.countdown-zh-TW.js
new file mode 100755
index 0000000..24d50bd
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-zh-TW.js
@@ -0,0 +1,13 @@
+/* http://keith-wood.name/countdown.html
+ Traditional Chinese initialisation for the jQuery countdown extension
+ Written by Cloudream (cloudream@gmail.com). */
+(function($) {
+ $.countdown.regional['zh-TW'] = {
+ labels: ['年', '月', '周', '天', '時', '分', '秒'],
+ labels1: ['年', '月', '周', '天', '時', '分', '秒'],
+ compactLabels: ['年', '月', '周', '天'], compactLabels1: ['年', '月', '周', '天'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':', isRTL: false};
+ $.countdown.setDefaults($.countdown.regional['zh-TW']);
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown-zh-TW.min.js b/assets/js/jquery.countdown/jquery.countdown-zh-TW.min.js
new file mode 100644
index 0000000..a54a767
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown-zh-TW.min.js
@@ -0,0 +1 @@
+!function(a){a.countdown.regional["zh-TW"]={labels:["年","月","周","天","時","分","秒"],labels1:["年","月","周","天","時","分","秒"],compactLabels:["年","月","周","天"],compactLabels1:["年","月","周","天"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},a.countdown.setDefaults(a.countdown.regional["zh-TW"])}(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown.js b/assets/js/jquery.countdown/jquery.countdown.js
new file mode 100755
index 0000000..acd729c
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown.js
@@ -0,0 +1,800 @@
+/* http://keith-wood.name/countdown.html
+ Countdown for jQuery v1.6.1.
+ Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
+ Available under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license.
+ Please attribute the author if you use it. */
+
+/* Display a countdown timer.
+ Attach it with options like:
+ $('div selector').countdown(
+ {until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */
+
+(function($) { // Hide scope, no $ conflict
+
+/* Countdown manager. */
+function Countdown() {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ // The display texts for the counters
+ labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
+ // The display texts for the counters if only one
+ labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
+ compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters
+ whichLabels: null, // Function to determine which labels to use
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], // The digits to display
+ timeSeparator: ':', // Separator for time periods
+ isRTL: false // True for right-to-left languages, false for left-to-right
+ };
+ this._defaults = {
+ until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to
+ // or numeric for seconds offset, or string for unit offset(s):
+ // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
+ since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from
+ // or numeric for seconds offset, or string for unit offset(s):
+ // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
+ timezone: null, // The timezone (hours or minutes from GMT) for the target times,
+ // or null for client local
+ serverSync: null, // A function to retrieve the current server time for synchronisation
+ format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero,
+ // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
+ layout: '', // Build your own layout for the countdown
+ compact: false, // True to display in a compact format, false for an expanded one
+ significant: 0, // The number of periods with values to show, zero for all
+ description: '', // The description displayed for the countdown
+ expiryUrl: '', // A URL to load upon expiry, replacing the current page
+ expiryText: '', // Text to display upon expiry, replacing the countdown
+ alwaysExpire: false, // True to trigger onExpiry even if never counted down
+ onExpiry: null, // Callback when the countdown expires -
+ // receives no parameters and 'this' is the containing division
+ onTick: null, // Callback when the countdown is updated -
+ // receives int[7] being the breakdown by period (based on format)
+ // and 'this' is the containing division
+ tickInterval: 1 // Interval (seconds) between onTick callbacks
+ };
+ $.extend(this._defaults, this.regional['']);
+ this._serverSyncs = [];
+ // Shared timer for all countdowns
+ function timerCallBack(timestamp) {
+ var drawStart = (timestamp < 1e12 ? // New HTML5 high resolution timer
+ (drawStart = performance.now ?
+ (performance.now() + performance.timing.navigationStart) : Date.now()) :
+ // Integer milliseconds since unix epoch
+ timestamp || new Date().getTime());
+ if (drawStart - animationStartTime >= 1000) {
+ plugin._updateTargets();
+ animationStartTime = drawStart;
+ }
+ requestAnimationFrame(timerCallBack);
+ }
+ var requestAnimationFrame = window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame || window.msRequestAnimationFrame || null;
+ // This is when we expect a fall-back to setInterval as it's much more fluid
+ var animationStartTime = 0;
+ if (!requestAnimationFrame || $.noRequestAnimationFrame) {
+ $.noRequestAnimationFrame = null;
+ setInterval(function() { plugin._updateTargets(); }, 980); // Fall back to good old setInterval
+ }
+ else {
+ animationStartTime = window.animationStartTime ||
+ window.webkitAnimationStartTime || window.mozAnimationStartTime ||
+ window.oAnimationStartTime || window.msAnimationStartTime || new Date().getTime();
+ requestAnimationFrame(timerCallBack);
+ }
+}
+
+var Y = 0; // Years
+var O = 1; // Months
+var W = 2; // Weeks
+var D = 3; // Days
+var H = 4; // Hours
+var M = 5; // Minutes
+var S = 6; // Seconds
+
+$.extend(Countdown.prototype, {
+ /* Class name added to elements to indicate already configured with countdown. */
+ markerClassName: 'hasCountdown',
+ /* Name of the data property for instance settings. */
+ propertyName: 'countdown',
+
+ /* Class name for the right-to-left marker. */
+ _rtlClass: 'countdown_rtl',
+ /* Class name for the countdown section marker. */
+ _sectionClass: 'countdown_section',
+ /* Class name for the period amount marker. */
+ _amountClass: 'countdown_amount',
+ /* Class name for the countdown row marker. */
+ _rowClass: 'countdown_row',
+ /* Class name for the holding countdown marker. */
+ _holdingClass: 'countdown_holding',
+ /* Class name for the showing countdown marker. */
+ _showClass: 'countdown_show',
+ /* Class name for the description marker. */
+ _descrClass: 'countdown_descr',
+
+ /* List of currently active countdown targets. */
+ _timerTargets: [],
+
+ /* Override the default settings for all instances of the countdown widget.
+ @param options (object) the new settings to use as defaults */
+ setDefaults: function(options) {
+ this._resetExtraLabels(this._defaults, options);
+ $.extend(this._defaults, options || {});
+ },
+
+ /* Convert a date/time to UTC.
+ @param tz (number) the hour or minute offset from GMT, e.g. +9, -360
+ @param year (Date) the date/time in that timezone or
+ (number) the year in that timezone
+ @param month (number, optional) the month (0 - 11) (omit if year is a Date)
+ @param day (number, optional) the day (omit if year is a Date)
+ @param hours (number, optional) the hour (omit if year is a Date)
+ @param mins (number, optional) the minute (omit if year is a Date)
+ @param secs (number, optional) the second (omit if year is a Date)
+ @param ms (number, optional) the millisecond (omit if year is a Date)
+ @return (Date) the equivalent UTC date/time */
+ UTCDate: function(tz, year, month, day, hours, mins, secs, ms) {
+ if (typeof year == 'object' && year.constructor == Date) {
+ ms = year.getMilliseconds();
+ secs = year.getSeconds();
+ mins = year.getMinutes();
+ hours = year.getHours();
+ day = year.getDate();
+ month = year.getMonth();
+ year = year.getFullYear();
+ }
+ var d = new Date();
+ d.setUTCFullYear(year);
+ d.setUTCDate(1);
+ d.setUTCMonth(month || 0);
+ d.setUTCDate(day || 1);
+ d.setUTCHours(hours || 0);
+ d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz));
+ d.setUTCSeconds(secs || 0);
+ d.setUTCMilliseconds(ms || 0);
+ return d;
+ },
+
+ /* Convert a set of periods into seconds.
+ Averaged for months and years.
+ @param periods (number[7]) the periods per year/month/week/day/hour/minute/second
+ @return (number) the corresponding number of seconds */
+ periodsToSeconds: function(periods) {
+ return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
+ periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
+ },
+
+ /* Attach the countdown widget to a div.
+ @param target (element) the containing division
+ @param options (object) the initial settings for the countdown */
+ _attachPlugin: function(target, options) {
+ target = $(target);
+ if (target.hasClass(this.markerClassName)) {
+ return;
+ }
+ var inst = {options: $.extend({}, this._defaults), _periods: [0, 0, 0, 0, 0, 0, 0]};
+ target.addClass(this.markerClassName).data(this.propertyName, inst);
+ this._optionPlugin(target, options);
+ },
+
+ /* Add a target to the list of active ones.
+ @param target (element) the countdown target */
+ _addTarget: function(target) {
+ if (!this._hasTarget(target)) {
+ this._timerTargets.push(target);
+ }
+ },
+
+ /* See if a target is in the list of active ones.
+ @param target (element) the countdown target
+ @return (boolean) true if present, false if not */
+ _hasTarget: function(target) {
+ return ($.inArray(target, this._timerTargets) > -1);
+ },
+
+ /* Remove a target from the list of active ones.
+ @param target (element) the countdown target */
+ _removeTarget: function(target) {
+ this._timerTargets = $.map(this._timerTargets,
+ function(value) { return (value == target ? null : value); }); // delete entry
+ },
+
+ /* Update each active timer target. */
+ _updateTargets: function() {
+ for (var i = this._timerTargets.length - 1; i >= 0; i--) {
+ this._updateCountdown(this._timerTargets[i]);
+ }
+ },
+
+ /* Reconfigure the settings for a countdown div.
+ @param target (element) the control to affect
+ @param options (object) the new options for this instance or
+ (string) an individual property name
+ @param value (any) the individual property value (omit if options
+ is an object or to retrieve the value of a setting)
+ @return (any) if retrieving a value */
+ _optionPlugin: function(target, options, value) {
+ target = $(target);
+ var inst = target.data(this.propertyName);
+ if (!options || (typeof options == 'string' && value == null)) { // Get option
+ var name = options;
+ options = (inst || {}).options;
+ return (options && name ? options[name] : options);
+ }
+
+ if (!target.hasClass(this.markerClassName)) {
+ return;
+ }
+ options = options || {};
+ if (typeof options == 'string') {
+ var name = options;
+ options = {};
+ options[name] = value;
+ }
+ this._resetExtraLabels(inst.options, options);
+ $.extend(inst.options, options);
+ this._adjustSettings(target, inst);
+ var now = new Date();
+ if ((inst._since && inst._since < now) || (inst._until && inst._until > now)) {
+ this._addTarget(target[0]);
+ }
+ this._updateCountdown(target, inst);
+ },
+
+ /* Redisplay the countdown with an updated display.
+ @param target (jQuery) the containing division
+ @param inst (object) the current settings for this instance */
+ _updateCountdown: function(target, inst) {
+ var $target = $(target);
+ inst = inst || $target.data(this.propertyName);
+ if (!inst) {
+ return;
+ }
+ $target.html(this._generateHTML(inst)).toggleClass(this._rtlClass, inst.options.isRTL);
+ if (typeof inst.options.onTick === 'function') {
+ var periods = inst._hold != 'lap' ? inst._periods :
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date());
+ if (inst.options.tickInterval == 1 ||
+ this.periodsToSeconds(periods) % inst.options.tickInterval == 0) {
+ inst.options.onTick.apply(target, [periods]);
+ }
+ }
+ var expired = inst._hold != 'pause' &&
+ (inst._since ? inst._now.getTime() < inst._since.getTime() :
+ inst._now.getTime() >= inst._until.getTime());
+ if (expired && !inst._expiring) {
+ inst._expiring = true;
+ if (this._hasTarget(target) || inst.options.alwaysExpire) {
+ this._removeTarget(target);
+ if (typeof inst.options.onExpiry === 'function') {
+ inst.options.onExpiry.apply(target, []);
+ }
+ if (inst.options.expiryText) {
+ var layout = inst.options.layout;
+ inst.options.layout = inst.options.expiryText;
+ this._updateCountdown(target, inst);
+ inst.options.layout = layout;
+ }
+ if (inst.options.expiryUrl) {
+ window.location = inst.options.expiryUrl;
+ }
+ }
+ inst._expiring = false;
+ }
+ else if (inst._hold == 'pause') {
+ this._removeTarget(target);
+ }
+ $target.data(this.propertyName, inst);
+ },
+
+ /* Reset any extra labelsn and compactLabelsn entries if changing labels.
+ @param base (object) the options to be updated
+ @param options (object) the new option values */
+ _resetExtraLabels: function(base, options) {
+ var changingLabels = false;
+ for (var n in options) {
+ if (n != 'whichLabels' && n.match(/[Ll]abels/)) {
+ changingLabels = true;
+ break;
+ }
+ }
+ if (changingLabels) {
+ for (var n in base) { // Remove custom numbered labels
+ if (n.match(/[Ll]abels[02-9]/)) {
+ base[n] = null;
+ }
+ }
+ }
+ },
+
+ /* Calculate interal settings for an instance.
+ @param target (element) the containing division
+ @param inst (object) the current settings for this instance */
+ _adjustSettings: function(target, inst) {
+ var now;
+ var serverOffset = 0;
+ var serverEntry = null;
+ for (var i = 0; i < this._serverSyncs.length; i++) {
+ if (this._serverSyncs[i][0] == inst.options.serverSync) {
+ serverEntry = this._serverSyncs[i][1];
+ break;
+ }
+ }
+ if (serverEntry != null) {
+ serverOffset = (inst.options.serverSync ? serverEntry : 0);
+ now = new Date();
+ }
+ else {
+ var serverResult = (typeof inst.options.serverSync === 'function' ?
+ inst.options.serverSync.apply(target, []) : null);
+ now = new Date();
+ serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
+ this._serverSyncs.push([inst.options.serverSync, serverOffset]);
+ }
+ var timezone = inst.options.timezone;
+ timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
+ inst._since = inst.options.since;
+ if (inst._since != null) {
+ inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null));
+ if (inst._since && serverOffset) {
+ inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset);
+ }
+ }
+ inst._until = this.UTCDate(timezone, this._determineTime(inst.options.until, now));
+ if (serverOffset) {
+ inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
+ }
+ inst._show = this._determineShow(inst);
+ },
+
+ /* Remove the countdown widget from a div.
+ @param target (element) the containing division */
+ _destroyPlugin: function(target) {
+ target = $(target);
+ if (!target.hasClass(this.markerClassName)) {
+ return;
+ }
+ this._removeTarget(target[0]);
+ target.removeClass(this.markerClassName).empty().removeData(this.propertyName);
+ },
+
+ /* Pause a countdown widget at the current time.
+ Stop it running but remember and display the current time.
+ @param target (element) the containing division */
+ _pausePlugin: function(target) {
+ this._hold(target, 'pause');
+ },
+
+ /* Pause a countdown widget at the current time.
+ Stop the display but keep the countdown running.
+ @param target (element) the containing division */
+ _lapPlugin: function(target) {
+ this._hold(target, 'lap');
+ },
+
+ /* Resume a paused countdown widget.
+ @param target (element) the containing division */
+ _resumePlugin: function(target) {
+ this._hold(target, null);
+ },
+
+ /* Pause or resume a countdown widget.
+ @param target (element) the containing division
+ @param hold (string) the new hold setting */
+ _hold: function(target, hold) {
+ var inst = $.data(target, this.propertyName);
+ if (inst) {
+ if (inst._hold == 'pause' && !hold) {
+ inst._periods = inst._savePeriods;
+ var sign = (inst._since ? '-' : '+');
+ inst[inst._since ? '_since' : '_until'] =
+ this._determineTime(sign + inst._periods[0] + 'y' +
+ sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' +
+ sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' +
+ sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's');
+ this._addTarget(target);
+ }
+ inst._hold = hold;
+ inst._savePeriods = (hold == 'pause' ? inst._periods : null);
+ $.data(target, this.propertyName, inst);
+ this._updateCountdown(target, inst);
+ }
+ },
+
+ /* Return the current time periods.
+ @param target (element) the containing division
+ @return (number[7]) the current periods for the countdown */
+ _getTimesPlugin: function(target) {
+ var inst = $.data(target, this.propertyName);
+ return (!inst ? null : (!inst._hold ? inst._periods :
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date())));
+ },
+
+ /* A time may be specified as an exact value or a relative one.
+ @param setting (string or number or Date) - the date/time value
+ as a relative or absolute value
+ @param defaultTime (Date) the date/time to use if no other is supplied
+ @return (Date) the corresponding date/time */
+ _determineTime: function(setting, defaultTime) {
+ var offsetNumeric = function(offset) { // e.g. +300, -2
+ var time = new Date();
+ time.setTime(time.getTime() + offset * 1000);
+ return time;
+ };
+ var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m'
+ offset = offset.toLowerCase();
+ var time = new Date();
+ var year = time.getFullYear();
+ var month = time.getMonth();
+ var day = time.getDate();
+ var hour = time.getHours();
+ var minute = time.getMinutes();
+ var second = time.getSeconds();
+ var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g;
+ var matches = pattern.exec(offset);
+ while (matches) {
+ switch (matches[2] || 's') {
+ case 's': second += parseInt(matches[1], 10); break;
+ case 'm': minute += parseInt(matches[1], 10); break;
+ case 'h': hour += parseInt(matches[1], 10); break;
+ case 'd': day += parseInt(matches[1], 10); break;
+ case 'w': day += parseInt(matches[1], 10) * 7; break;
+ case 'o':
+ month += parseInt(matches[1], 10);
+ day = Math.min(day, plugin._getDaysInMonth(year, month));
+ break;
+ case 'y':
+ year += parseInt(matches[1], 10);
+ day = Math.min(day, plugin._getDaysInMonth(year, month));
+ break;
+ }
+ matches = pattern.exec(offset);
+ }
+ return new Date(year, month, day, hour, minute, second, 0);
+ };
+ var time = (setting == null ? defaultTime :
+ (typeof setting == 'string' ? offsetString(setting) :
+ (typeof setting == 'number' ? offsetNumeric(setting) : setting)));
+ if (time) time.setMilliseconds(0);
+ return time;
+ },
+
+ /* Determine the number of days in a month.
+ @param year (number) the year
+ @param month (number) the month
+ @return (number) the days in that month */
+ _getDaysInMonth: function(year, month) {
+ return 32 - new Date(year, month, 32).getDate();
+ },
+
+ /* Determine which set of labels should be used for an amount.
+ @param num (number) the amount to be displayed
+ @return (number) the set of labels to be used for this amount */
+ _normalLabels: function(num) {
+ return num;
+ },
+
+ /* Generate the HTML to display the countdown widget.
+ @param inst (object) the current settings for this instance
+ @return (string) the new HTML for the countdown display */
+ _generateHTML: function(inst) {
+ var self = this;
+ // Determine what to show
+ inst._periods = (inst._hold ? inst._periods :
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()));
+ // Show all 'asNeeded' after first non-zero value
+ var shownNonZero = false;
+ var showCount = 0;
+ var sigCount = inst.options.significant;
+ var show = $.extend({}, inst._show);
+ for (var period = Y; period <= S; period++) {
+ shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0);
+ show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]);
+ showCount += (show[period] ? 1 : 0);
+ sigCount -= (inst._periods[period] > 0 ? 1 : 0);
+ }
+ var showSignificant = [false, false, false, false, false, false, false];
+ for (var period = S; period >= Y; period--) { // Determine significant periods
+ if (inst._show[period]) {
+ if (inst._periods[period]) {
+ showSignificant[period] = true;
+ }
+ else {
+ showSignificant[period] = sigCount > 0;
+ sigCount--;
+ }
+ }
+ }
+ var labels = (inst.options.compact ? inst.options.compactLabels : inst.options.labels);
+ var whichLabels = inst.options.whichLabels || this._normalLabels;
+ var showCompact = function(period) {
+ var labelsNum = inst.options['compactLabels' + whichLabels(inst._periods[period])];
+ return (show[period] ? self._translateDigits(inst, inst._periods[period]) +
+ (labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
+ };
+ var showFull = function(period) {
+ var labelsNum = inst.options['labels' + whichLabels(inst._periods[period])];
+ return ((!inst.options.significant && show[period]) ||
+ (inst.options.significant && showSignificant[period]) ?
+ '' +
+ '' +
+ self._translateDigits(inst, inst._periods[period]) + ' ' +
+ (labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
+ };
+ return (inst.options.layout ? this._buildLayout(inst, show, inst.options.layout,
+ inst.options.compact, inst.options.significant, showSignificant) :
+ ((inst.options.compact ? // Compact version
+ '' +
+ showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
+ (show[H] ? this._minDigits(inst, inst._periods[H], 2) : '') +
+ (show[M] ? (show[H] ? inst.options.timeSeparator : '') +
+ this._minDigits(inst, inst._periods[M], 2) : '') +
+ (show[S] ? (show[H] || show[M] ? inst.options.timeSeparator : '') +
+ this._minDigits(inst, inst._periods[S], 2) : '') :
+ // Full version
+ '' +
+ showFull(Y) + showFull(O) + showFull(W) + showFull(D) +
+ showFull(H) + showFull(M) + showFull(S)) + ' ' +
+ (inst.options.description ? '' +
+ inst.options.description + ' ' : '')));
+ },
+
+ /* Construct a custom layout.
+ @param inst (object) the current settings for this instance
+ @param show (string[7]) flags indicating which periods are requested
+ @param layout (string) the customised layout
+ @param compact (boolean) true if using compact labels
+ @param significant (number) the number of periods with values to show, zero for all
+ @param showSignificant (boolean[7]) other periods to show for significance
+ @return (string) the custom HTML */
+ _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
+ var labels = inst.options[compact ? 'compactLabels' : 'labels'];
+ var whichLabels = inst.options.whichLabels || this._normalLabels;
+ var labelFor = function(index) {
+ return (inst.options[(compact ? 'compactLabels' : 'labels') +
+ whichLabels(inst._periods[index])] || labels)[index];
+ };
+ var digit = function(value, position) {
+ return inst.options.digits[Math.floor(value / position) % 10];
+ };
+ var subs = {desc: inst.options.description, sep: inst.options.timeSeparator,
+ yl: labelFor(Y), yn: this._minDigits(inst, inst._periods[Y], 1),
+ ynn: this._minDigits(inst, inst._periods[Y], 2),
+ ynnn: this._minDigits(inst, inst._periods[Y], 3), y1: digit(inst._periods[Y], 1),
+ y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100),
+ y1000: digit(inst._periods[Y], 1000),
+ ol: labelFor(O), on: this._minDigits(inst, inst._periods[O], 1),
+ onn: this._minDigits(inst, inst._periods[O], 2),
+ onnn: this._minDigits(inst, inst._periods[O], 3), o1: digit(inst._periods[O], 1),
+ o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100),
+ o1000: digit(inst._periods[O], 1000),
+ wl: labelFor(W), wn: this._minDigits(inst, inst._periods[W], 1),
+ wnn: this._minDigits(inst, inst._periods[W], 2),
+ wnnn: this._minDigits(inst, inst._periods[W], 3), w1: digit(inst._periods[W], 1),
+ w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100),
+ w1000: digit(inst._periods[W], 1000),
+ dl: labelFor(D), dn: this._minDigits(inst, inst._periods[D], 1),
+ dnn: this._minDigits(inst, inst._periods[D], 2),
+ dnnn: this._minDigits(inst, inst._periods[D], 3), d1: digit(inst._periods[D], 1),
+ d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100),
+ d1000: digit(inst._periods[D], 1000),
+ hl: labelFor(H), hn: this._minDigits(inst, inst._periods[H], 1),
+ hnn: this._minDigits(inst, inst._periods[H], 2),
+ hnnn: this._minDigits(inst, inst._periods[H], 3), h1: digit(inst._periods[H], 1),
+ h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100),
+ h1000: digit(inst._periods[H], 1000),
+ ml: labelFor(M), mn: this._minDigits(inst, inst._periods[M], 1),
+ mnn: this._minDigits(inst, inst._periods[M], 2),
+ mnnn: this._minDigits(inst, inst._periods[M], 3), m1: digit(inst._periods[M], 1),
+ m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100),
+ m1000: digit(inst._periods[M], 1000),
+ sl: labelFor(S), sn: this._minDigits(inst, inst._periods[S], 1),
+ snn: this._minDigits(inst, inst._periods[S], 2),
+ snnn: this._minDigits(inst, inst._periods[S], 3), s1: digit(inst._periods[S], 1),
+ s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100),
+ s1000: digit(inst._periods[S], 1000)};
+ var html = layout;
+ // Replace period containers: {p<}...{p>}
+ for (var i = Y; i <= S; i++) {
+ var period = 'yowdhms'.charAt(i);
+ var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g');
+ html = html.replace(re, ((!significant && show[i]) ||
+ (significant && showSignificant[i]) ? '$1' : ''));
+ }
+ // Replace period values: {pn}
+ $.each(subs, function(n, v) {
+ var re = new RegExp('\\{' + n + '\\}', 'g');
+ html = html.replace(re, v);
+ });
+ return html;
+ },
+
+ /* Ensure a numeric value has at least n digits for display.
+ @param inst (object) the current settings for this instance
+ @param value (number) the value to display
+ @param len (number) the minimum length
+ @return (string) the display text */
+ _minDigits: function(inst, value, len) {
+ value = '' + value;
+ if (value.length >= len) {
+ return this._translateDigits(inst, value);
+ }
+ value = '0000000000' + value;
+ return this._translateDigits(inst, value.substr(value.length - len));
+ },
+
+ /* Translate digits into other representations.
+ @param inst (object) the current settings for this instance
+ @param value (string) the text to translate
+ @return (string) the translated text */
+ _translateDigits: function(inst, value) {
+ return ('' + value).replace(/[0-9]/g, function(digit) {
+ return inst.options.digits[digit];
+ });
+ },
+
+ /* Translate the format into flags for each period.
+ @param inst (object) the current settings for this instance
+ @return (string[7]) flags indicating which periods are requested (?) or
+ required (!) by year, month, week, day, hour, minute, second */
+ _determineShow: function(inst) {
+ var format = inst.options.format;
+ var show = [];
+ show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null));
+ show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null));
+ show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null));
+ show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null));
+ show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null));
+ show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null));
+ show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null));
+ return show;
+ },
+
+ /* Calculate the requested periods between now and the target time.
+ @param inst (object) the current settings for this instance
+ @param show (string[7]) flags indicating which periods are requested/required
+ @param significant (number) the number of periods with values to show, zero for all
+ @param now (Date) the current date and time
+ @return (number[7]) the current time periods (always positive)
+ by year, month, week, day, hour, minute, second */
+ _calculatePeriods: function(inst, show, significant, now) {
+ // Find endpoints
+ inst._now = now;
+ inst._now.setMilliseconds(0);
+ var until = new Date(inst._now.getTime());
+ if (inst._since) {
+ if (now.getTime() < inst._since.getTime()) {
+ inst._now = now = until;
+ }
+ else {
+ now = inst._since;
+ }
+ }
+ else {
+ until.setTime(inst._until.getTime());
+ if (now.getTime() > inst._until.getTime()) {
+ inst._now = now = until;
+ }
+ }
+ // Calculate differences by period
+ var periods = [0, 0, 0, 0, 0, 0, 0];
+ if (show[Y] || show[O]) {
+ // Treat end of months as the same
+ var lastNow = plugin._getDaysInMonth(now.getFullYear(), now.getMonth());
+ var lastUntil = plugin._getDaysInMonth(until.getFullYear(), until.getMonth());
+ var sameDay = (until.getDate() == now.getDate() ||
+ (until.getDate() >= Math.min(lastNow, lastUntil) &&
+ now.getDate() >= Math.min(lastNow, lastUntil)));
+ var getSecs = function(date) {
+ return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds();
+ };
+ var months = Math.max(0,
+ (until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() +
+ ((until.getDate() < now.getDate() && !sameDay) ||
+ (sameDay && getSecs(until) < getSecs(now)) ? -1 : 0));
+ periods[Y] = (show[Y] ? Math.floor(months / 12) : 0);
+ periods[O] = (show[O] ? months - periods[Y] * 12 : 0);
+ // Adjust for months difference and end of month if necessary
+ now = new Date(now.getTime());
+ var wasLastDay = (now.getDate() == lastNow);
+ var lastDay = plugin._getDaysInMonth(now.getFullYear() + periods[Y],
+ now.getMonth() + periods[O]);
+ if (now.getDate() > lastDay) {
+ now.setDate(lastDay);
+ }
+ now.setFullYear(now.getFullYear() + periods[Y]);
+ now.setMonth(now.getMonth() + periods[O]);
+ if (wasLastDay) {
+ now.setDate(lastDay);
+ }
+ }
+ var diff = Math.floor((until.getTime() - now.getTime()) / 1000);
+ var extractPeriod = function(period, numSecs) {
+ periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0);
+ diff -= periods[period] * numSecs;
+ };
+ extractPeriod(W, 604800);
+ extractPeriod(D, 86400);
+ extractPeriod(H, 3600);
+ extractPeriod(M, 60);
+ extractPeriod(S, 1);
+ if (diff > 0 && !inst._since) { // Round up if left overs
+ var multiplier = [1, 12, 4.3482, 7, 24, 60, 60];
+ var lastShown = S;
+ var max = 1;
+ for (var period = S; period >= Y; period--) {
+ if (show[period]) {
+ if (periods[lastShown] >= max) {
+ periods[lastShown] = 0;
+ diff = 1;
+ }
+ if (diff > 0) {
+ periods[period]++;
+ diff = 0;
+ lastShown = period;
+ max = 1;
+ }
+ }
+ max *= multiplier[period];
+ }
+ }
+ if (significant) { // Zero out insignificant periods
+ for (var period = Y; period <= S; period++) {
+ if (significant && periods[period]) {
+ significant--;
+ }
+ else if (!significant) {
+ periods[period] = 0;
+ }
+ }
+ }
+ return periods;
+ }
+});
+
+// The list of commands that return values and don't permit chaining
+var getters = ['getTimes'];
+
+/* Determine whether a command is a getter and doesn't permit chaining.
+ @param command (string, optional) the command to run
+ @param otherArgs ([], optional) any other arguments for the command
+ @return true if the command is a getter, false if not */
+function isNotChained(command, otherArgs) {
+ if (command == 'option' && (otherArgs.length == 0 ||
+ (otherArgs.length == 1 && typeof otherArgs[0] == 'string'))) {
+ return true;
+ }
+ return $.inArray(command, getters) > -1;
+}
+
+/* Process the countdown functionality for a jQuery selection.
+ @param options (object) the new settings to use for these instances (optional) or
+ (string) the command to run (optional)
+ @return (jQuery) for chaining further calls or
+ (any) getter value */
+$.fn.countdown = function(options) {
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if (isNotChained(options, otherArgs)) {
+ return plugin['_' + options + 'Plugin'].
+ apply(plugin, [this[0]].concat(otherArgs));
+ }
+ return this.each(function() {
+ if (typeof options == 'string') {
+ if (!plugin['_' + options + 'Plugin']) {
+ throw 'Unknown command: ' + options;
+ }
+ plugin['_' + options + 'Plugin'].
+ apply(plugin, [this].concat(otherArgs));
+ }
+ else {
+ plugin._attachPlugin(this, options || {});
+ }
+ });
+};
+
+/* Initialise the countdown functionality. */
+var plugin = $.countdown = new Countdown(); // Singleton instance
+
+})(jQuery);
diff --git a/assets/js/jquery.countdown/jquery.countdown.min.js b/assets/js/jquery.countdown/jquery.countdown.min.js
new file mode 100644
index 0000000..bf1acce
--- /dev/null
+++ b/assets/js/jquery.countdown/jquery.countdown.min.js
@@ -0,0 +1 @@
+!function(c){function t(){this.regional=[],this.regional[""]={labels:["Years","Months","Weeks","Days","Hours","Minutes","Seconds"],labels1:["Year","Month","Week","Day","Hour","Minute","Second"],compactLabels:["y","m","w","d"],whichLabels:null,digits:["0","1","2","3","4","5","6","7","8","9"],timeSeparator:":",isRTL:!1},this._defaults={until:null,since:null,timezone:null,serverSync:null,format:"dHMS",layout:"",compact:!1,significant:0,description:"",expiryUrl:"",expiryText:"",alwaysExpire:!1,onExpiry:null,onTick:null,tickInterval:1},c.extend(this._defaults,this.regional[""]),this._serverSyncs=[];var i=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||null,s=0;!i||c.noRequestAnimationFrame?(c.noRequestAnimationFrame=null,setInterval(function(){m._updateTargets()},980)):(s=window.animationStartTime||window.webkitAnimationStartTime||window.mozAnimationStartTime||window.oAnimationStartTime||window.msAnimationStartTime||(new Date).getTime(),i(function t(e){e=e<1e12?performance.now?performance.now()+performance.timing.navigationStart:Date.now():e||(new Date).getTime();1e3<=e-s&&(m._updateTargets(),s=e),i(t)}))}c.extend(t.prototype,{markerClassName:"hasCountdown",propertyName:"countdown",_rtlClass:"countdown_rtl",_sectionClass:"countdown_section",_amountClass:"countdown_amount",_rowClass:"countdown_row",_holdingClass:"countdown_holding",_showClass:"countdown_show",_descrClass:"countdown_descr",_timerTargets:[],setDefaults:function(t){this._resetExtraLabels(this._defaults,t),c.extend(this._defaults,t||{})},UTCDate:function(t,e,i,s,n,o,a,r){"object"==typeof e&&e.constructor==Date&&(r=e.getMilliseconds(),a=e.getSeconds(),o=e.getMinutes(),n=e.getHours(),s=e.getDate(),i=e.getMonth(),e=e.getFullYear());var l=new Date;return l.setUTCFullYear(e),l.setUTCDate(1),l.setUTCMonth(i||0),l.setUTCDate(s||1),l.setUTCHours(n||0),l.setUTCMinutes((o||0)-(Math.abs(t)<30?60*t:t)),l.setUTCSeconds(a||0),l.setUTCMilliseconds(r||0),l},periodsToSeconds:function(t){return 31557600*t[0]+2629800*t[1]+604800*t[2]+86400*t[3]+3600*t[4]+60*t[5]+t[6]},_attachPlugin:function(t,e){var i;(t=c(t)).hasClass(this.markerClassName)||(i={options:c.extend({},this._defaults),_periods:[0,0,0,0,0,0,0]},t.addClass(this.markerClassName).data(this.propertyName,i),this._optionPlugin(t,e))},_addTarget:function(t){this._hasTarget(t)||this._timerTargets.push(t)},_hasTarget:function(t){return-1s)&&this._addTarget(t[0]),this._updateCountdown(t,n))},_updateCountdown:function(t,e){var i,s=c(t);(e=e||s.data(this.propertyName))&&(s.html(this._generateHTML(e)).toggleClass(this._rtlClass,e.options.isRTL),"function"==typeof e.options.onTick&&(i="lap"!=e._hold?e._periods:this._calculatePeriods(e,e._show,e.options.significant,new Date),1!=e.options.tickInterval&&this.periodsToSeconds(i)%e.options.tickInterval!=0||e.options.onTick.apply(t,[i])),"pause"!=e._hold&&(e._since?e._now.getTime()=e._until.getTime())&&!e._expiring?(e._expiring=!0,(this._hasTarget(t)||e.options.alwaysExpire)&&(this._removeTarget(t),"function"==typeof e.options.onExpiry&&e.options.onExpiry.apply(t,[]),e.options.expiryText&&(i=e.options.layout,e.options.layout=e.options.expiryText,this._updateCountdown(t,e),e.options.layout=i),e.options.expiryUrl)&&(window.location=e.options.expiryUrl),e._expiring=!1):"pause"==e._hold&&this._removeTarget(t),s.data(this.propertyName,e))},_resetExtraLabels:function(t,e){var i=!1;for(s in e)if("whichLabels"!=s&&s.match(/[Ll]abels/)){i=!0;break}if(i)for(var s in t)s.match(/[Ll]abels[02-9]/)&&(t[s]=null)},_adjustSettings:function(t,e){for(var i,s=0,n=null,o=0;o'+s._translateDigits(i,i._periods[t])+" "+(e||p)[t]+" ":""}var p=i.options.compact?i.options.compactLabels:i.options.labels,h=i.options.whichLabels||this._normalLabels;return i.options.layout?this._buildLayout(i,o,i.options.layout,i.options.compact,i.options.significant,r):(i.options.compact?''+l(0)+l(1)+l(2)+l(3)+(o[4]?this._minDigits(i,i._periods[4],2):"")+(o[5]?(o[4]?i.options.timeSeparator:"")+this._minDigits(i,i._periods[5],2):"")+(o[6]?(o[4]||o[5]?i.options.timeSeparator:"")+this._minDigits(i,i._periods[6],2):""):''+_(0)+_(1)+_(2)+_(3)+_(4)+_(5)+_(6))+" "+(i.options.description?''+i.options.description+" ":"")},_buildLayout:function(i,t,e,s,n,o){function a(t){return(i.options[(s?"compactLabels":"labels")+_(i._periods[t])]||l)[t]}function r(t,e){return i.options.digits[Math.floor(t/e)%10]}for(var l=i.options[s?"compactLabels":"labels"],_=i.options.whichLabels||this._normalLabels,p={desc:i.options.description,sep:i.options.timeSeparator,yl:a(0),yn:this._minDigits(i,i._periods[0],1),ynn:this._minDigits(i,i._periods[0],2),ynnn:this._minDigits(i,i._periods[0],3),y1:r(i._periods[0],1),y10:r(i._periods[0],10),y100:r(i._periods[0],100),y1000:r(i._periods[0],1e3),ol:a(1),on:this._minDigits(i,i._periods[1],1),onn:this._minDigits(i,i._periods[1],2),onnn:this._minDigits(i,i._periods[1],3),o1:r(i._periods[1],1),o10:r(i._periods[1],10),o100:r(i._periods[1],100),o1000:r(i._periods[1],1e3),wl:a(2),wn:this._minDigits(i,i._periods[2],1),wnn:this._minDigits(i,i._periods[2],2),wnnn:this._minDigits(i,i._periods[2],3),w1:r(i._periods[2],1),w10:r(i._periods[2],10),w100:r(i._periods[2],100),w1000:r(i._periods[2],1e3),dl:a(3),dn:this._minDigits(i,i._periods[3],1),dnn:this._minDigits(i,i._periods[3],2),dnnn:this._minDigits(i,i._periods[3],3),d1:r(i._periods[3],1),d10:r(i._periods[3],10),d100:r(i._periods[3],100),d1000:r(i._periods[3],1e3),hl:a(4),hn:this._minDigits(i,i._periods[4],1),hnn:this._minDigits(i,i._periods[4],2),hnnn:this._minDigits(i,i._periods[4],3),h1:r(i._periods[4],1),h10:r(i._periods[4],10),h100:r(i._periods[4],100),h1000:r(i._periods[4],1e3),ml:a(5),mn:this._minDigits(i,i._periods[5],1),mnn:this._minDigits(i,i._periods[5],2),mnnn:this._minDigits(i,i._periods[5],3),m1:r(i._periods[5],1),m10:r(i._periods[5],10),m100:r(i._periods[5],100),m1000:r(i._periods[5],1e3),sl:a(6),sn:this._minDigits(i,i._periods[6],1),snn:this._minDigits(i,i._periods[6],2),snnn:this._minDigits(i,i._periods[6],3),s1:r(i._periods[6],1),s10:r(i._periods[6],10),s100:r(i._periods[6],100),s1000:r(i._periods[6],1e3)},h=e,d=0;d<=6;d++)var u="yowdhms".charAt(d),u=new RegExp("\\{"+u+"<\\}(.*)\\{"+u+">\\}","g"),h=h.replace(u,!n&&t[d]||n&&o[d]?"$1":"");return c.each(p,function(t,e){t=new RegExp("\\{"+t+"\\}","g");h=h.replace(t,e)}),h},_minDigits:function(t,e,i){return(e=""+e).length>=i?this._translateDigits(t,e):this._translateDigits(t,(e="0000000000"+e).substr(e.length-i))},_translateDigits:function(e,t){return(""+t).replace(/[0-9]/g,function(t){return e.options.digits[t]})},_determineShow:function(t){var t=t.options.format,e=[];return e[0]=t.match("y")?"?":t.match("Y")?"!":null,e[1]=t.match("o")?"?":t.match("O")?"!":null,e[2]=t.match("w")?"?":t.match("W")?"!":null,e[3]=t.match("d")?"?":t.match("D")?"!":null,e[4]=t.match("h")?"?":t.match("H")?"!":null,e[5]=t.match("m")?"?":t.match("M")?"!":null,e[6]=t.match("s")?"?":t.match("S")?"!":null,e},_calculatePeriods:function(t,i,e,s){t._now=s,t._now.setMilliseconds(0);function n(t,e){_[t]=i[t]?Math.floor(p/e):0,p-=_[t]*e}var o,a,r,l=new Date(t._now.getTime()),_=(t._since?s.getTime()t._until.getTime()&&(t._now=s=l)),[0,0,0,0,0,0,0]),p=((i[0]||i[1])&&(o=m._getDaysInMonth(s.getFullYear(),s.getMonth()),r=m._getDaysInMonth(l.getFullYear(),l.getMonth()),r=l.getDate()==s.getDate()||l.getDate()>=Math.min(o,r)&&s.getDate()>=Math.min(o,r),a=function(t){return 60*(60*t.getHours()+t.getMinutes())+t.getSeconds()},r=Math.max(0,12*(l.getFullYear()-s.getFullYear())+l.getMonth()-s.getMonth()+(l.getDate()r&&s.setDate(r),s.setFullYear(s.getFullYear()+_[0]),s.setMonth(s.getMonth()+_[1]),a)&&s.setDate(r),Math.floor((l.getTime()-s.getTime())/1e3));if(n(2,604800),n(3,86400),n(4,3600),n(5,60),n(6,1),0 array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '69774a8ff160b789e777bfed59e24478');
\ No newline at end of file
diff --git a/build/admin/blocks/date-time-picker/index.js b/build/admin/blocks/date-time-picker/index.js
new file mode 100644
index 0000000..65b9ecf
--- /dev/null
+++ b/build/admin/blocks/date-time-picker/index.js
@@ -0,0 +1 @@
+(function(){var __webpack_modules__={9861:function(e,t,u){"use strict";const n=u(8202),r={findRule(e,t){for(let u=0;u1&&e.delimiter&&a(e.delimiter)))},semantic_and:o,semantic_not:o,rule_ref(t){const u=r.findRule(e,t.name);return u?a(u):void 0},literal(e){return""!==e.value},class:u,any:u});return a(t)}};e.exports=r},9203:function(module,__unused_webpack_exports,__webpack_require__){"use strict";const generateBytecode=__webpack_require__(2886),generateJS=__webpack_require__(5843),inferenceMatchResult=__webpack_require__(5412),removeProxyRules=__webpack_require__(2929),reportDuplicateLabels=__webpack_require__(6734),reportDuplicateRules=__webpack_require__(1117),reportInfiniteRecursion=__webpack_require__(730),reportInfiniteRepetition=__webpack_require__(9505),reportUndefinedRules=__webpack_require__(1442),reportIncorrectPlucking=__webpack_require__(6237),Session=__webpack_require__(425),visitor=__webpack_require__(8202),{base64:base64}=__webpack_require__(6443);function processOptions(e,t){const u={};return Object.keys(e).forEach((t=>{u[t]=e[t]})),Object.keys(t).forEach((e=>{Object.prototype.hasOwnProperty.call(u,e)||(u[e]=t[e])})),u}function isSourceMapCapable(e){return"string"==typeof e?e.length>0:e&&"function"==typeof e.offset}const compiler={visitor:visitor,passes:{check:[reportUndefinedRules,reportDuplicateRules,reportDuplicateLabels,reportInfiniteRecursion,reportInfiniteRepetition,reportIncorrectPlucking],transform:[removeProxyRules,inferenceMatchResult],generate:[generateBytecode,generateJS]},compile(ast,passes,options){if(options=void 0!==options?options:{},options=processOptions(options,{allowedStartRules:[ast.rules[0].name],cache:!1,dependencies:{},exportVar:null,format:"bare",output:"parser",trace:!1}),!Array.isArray(options.allowedStartRules))throw new Error("allowedStartRules must be an array");if(0===options.allowedStartRules.length)throw new Error("Must have at least one start rule");const allRules=ast.rules.map((e=>e.name));if(options.allowedStartRules.some((e=>"*"===e)))options.allowedStartRules=allRules;else for(const e of options.allowedStartRules)if(-1===allRules.indexOf(e))throw new Error(`Unknown start rule "${e}"`);if(("source-and-map"===options.output||"source-with-inline-map"===options.output)&&!isSourceMapCapable(options.grammarSource))throw new Error("Must provide grammarSource (as a string or GrammarLocation) in order to generate source maps");const session=new Session(options);switch(Object.keys(passes).forEach((e=>{session.stage=e,session.info(`Process stage ${e}`),passes[e].forEach((t=>{session.info(`Process pass ${e}.${t.name}`),t(ast,options,session)})),session.checkErrors()})),options.output){case"parser":return eval(ast.code.toString());case"source":return ast.code.toString();case"source-and-map":return ast.code;case"source-with-inline-map":{if("undefined"==typeof TextEncoder)throw new Error("TextEncoder is not supported by this platform");const e=ast.code.toStringWithSourceMap(),t=new TextEncoder,u=base64(t.encode(JSON.stringify(e.map.toJSON())));return e.code+`//# sourceMappingURL=data:application/json;charset=utf-8;base64,${u}\n`}case"ast":return ast;default:throw new Error("Invalid output format: "+options.output+".")}}};module.exports=compiler},6164:function(e){"use strict";e.exports={PUSH:0,PUSH_EMPTY_STRING:35,PUSH_UNDEFINED:1,PUSH_NULL:2,PUSH_FAILED:3,PUSH_EMPTY_ARRAY:4,PUSH_CURR_POS:5,POP:6,POP_CURR_POS:7,POP_N:8,NIP:9,APPEND:10,WRAP:11,TEXT:12,PLUCK:36,IF:13,IF_ERROR:14,IF_NOT_ERROR:15,IF_LT:30,IF_GE:31,IF_LT_DYNAMIC:32,IF_GE_DYNAMIC:33,WHILE_NOT_ERROR:16,MATCH_ANY:17,MATCH_STRING:18,MATCH_STRING_IC:19,MATCH_CHAR_CLASS:20,MATCH_REGEXP:20,ACCEPT_N:21,ACCEPT_STRING:22,FAIL:23,LOAD_SAVED_POS:24,UPDATE_SAVED_POS:25,CALL:26,RULE:27,SILENT_FAILS_ON:28,SILENT_FAILS_OFF:29,SOURCE_MAP_PUSH:37,SOURCE_MAP_POP:38,SOURCE_MAP_LABEL_PUSH:39,SOURCE_MAP_LABEL_POP:40}},2886:function(e,t,u){"use strict";const n=u(9861),r=u(6164),o=u(8202),{ALWAYS_MATCH:a,SOMETIMES_MATCH:i,NEVER_MATCH:s}=u(5412);e.exports=function(e,t){const u=[],c=[],l=[],p=[],A=[];function h(e){const t=u.indexOf(e);return-1===t?u.push(e)-1:t}function d(e){const t=JSON.stringify(e),u=l.findIndex((e=>JSON.stringify(e)===t));return-1===u?l.push(e)-1:u}function E(e,t,u){const n={predicate:e,params:t,body:u.code,location:u.codeLocation},r=JSON.stringify(n),o=p.findIndex((e=>JSON.stringify(e)===r));return-1===o?p.push(n)-1:o}function f(e){return A.push(e)-1}function C(e){const t={};return Object.keys(e).forEach((u=>{t[u]=e[u]})),t}function g(e,...t){return e.concat(...t)}function m(e,t,u,n){return e===a?u:e===s?n:t.concat([u.length,n.length],u,n)}function F(e,t,u,n){const o=Object.keys(u).map((e=>n-u[e]));return[r.CALL,e,t,o.length].concat(o)}function _(e,t,u){const n=0|e.match;return g([r.PUSH_CURR_POS],[r.SILENT_FAILS_ON],y(e,{sp:u.sp+1,env:C(u.env),action:null}),[r.SILENT_FAILS_OFF],m(t?-n:n,[t?r.IF_ERROR:r.IF_NOT_ERROR],g([r.POP],[t?r.POP:r.POP_CURR_POS],[r.PUSH_UNDEFINED]),g([r.POP],[t?r.POP_CURR_POS:r.POP],[r.PUSH_FAILED])))}function D(e,t,u){const n=E(!0,Object.keys(u.env),e);return g([r.UPDATE_SAVED_POS],F(n,0,u.env,u.sp),m(0|e.match,[r.IF],g([r.POP],t?[r.PUSH_FAILED]:[r.PUSH_UNDEFINED]),g([r.POP],t?[r.PUSH_UNDEFINED]:[r.PUSH_FAILED])))}function B(e){return t=[r.WHILE_NOT_ERROR],u=g([r.APPEND],e),t.concat([u.length],u);var t,u}function x(e,t,u,n){switch(e.type){case"constant":return{pre:[],post:[],sp:u};case"variable":return e.sp=n+u-t[e.value],{pre:[],post:[],sp:u};case"function":return e.sp=n,{pre:F(E(!0,Object.keys(t),{code:e.value,codeLocation:e.codeLocation}),0,t,u),post:[r.NIP],sp:u+1};default:throw new Error(`Unknown boundary type "${e.type}" for the "repeated" node`)}}function v(e,t){if(null!==t.value){const u="constant"===t.type?[r.IF_GE,t.value]:[r.IF_GE_DYNAMIC,t.sp];return m(i,u,[r.PUSH_FAILED],e)}return e}const y=(S={grammar(e){e.rules.forEach(y),e.literals=u,e.classes=c,e.expectations=l,e.functions=p,e.locations=A},rule(e){e.bytecode=y(e.expression,{sp:-1,env:{},pluck:[],action:null})},named(e,t){const u=0|e.match,n=u===s?null:d({type:"rule",value:e.name});return g([r.SILENT_FAILS_ON],y(e.expression,t),[r.SILENT_FAILS_OFF],m(u,[r.IF_ERROR],[r.FAIL,n],[]))},choice(e,t){return function e(t,u){const n=0|t[0].match,o=y(t[0],{sp:u.sp,env:C(u.env),action:null});return n===a?o:g(o,t.length>1?m(i,[r.IF_ERROR],g([r.POP],e(t.slice(1),u)),[]):[])}(e.alternatives,t)},action(e,t){const u=C(t.env),n="sequence"!==e.expression.type||0===e.expression.elements.length,o=y(e.expression,{sp:t.sp+(n?1:0),env:u,action:e}),a=0|e.expression.match,i=n&&a!==s?E(!1,Object.keys(u),e):null;return n?g([r.PUSH_CURR_POS],o,m(a,[r.IF_NOT_ERROR],g([r.LOAD_SAVED_POS,1],F(i,1,u,t.sp+2)),[]),[r.NIP]):o},sequence(e,t){return g([r.PUSH_CURR_POS],function t(u,n){if(u.length>0){const o=e.elements.length-u.length+1;return g(y(u[0],{sp:n.sp,env:n.env,pluck:n.pluck,action:null}),m(0|u[0].match,[r.IF_NOT_ERROR],t(u.slice(1),{sp:n.sp+1,env:n.env,pluck:n.pluck,action:n.action}),g(o>1?[r.POP_N,o]:[r.POP],[r.POP_CURR_POS],[r.PUSH_FAILED])))}if(n.pluck.length>0)return g([r.PLUCK,e.elements.length+1,n.pluck.length],n.pluck.map((e=>n.sp-e)));if(n.action){const t=E(!1,Object.keys(n.env),n.action);return g([r.LOAD_SAVED_POS,e.elements.length],F(t,e.elements.length+1,n.env,n.sp))}return g([r.WRAP,e.elements.length],[r.NIP])}(e.elements,{sp:t.sp+1,env:t.env,pluck:[],action:t.action}))},labeled(e,u){let n=u.env;const o=e.label,a=u.sp+1;o&&(n=C(u.env),u.env[e.label]=a),e.pick&&u.pluck.push(a);const i=y(e.expression,{sp:u.sp,env:n,action:null});return o&&e.labelLocation&&t&&"source-and-map"===t.output?g([r.SOURCE_MAP_LABEL_PUSH,a,h(o),f(e.labelLocation)],i,[r.SOURCE_MAP_LABEL_POP,a]):i},text(e,t){return g([r.PUSH_CURR_POS],y(e.expression,{sp:t.sp+1,env:C(t.env),action:null}),m(0|e.match,[r.IF_NOT_ERROR],g([r.POP],[r.TEXT]),[r.NIP]))},simple_and(e,t){return _(e.expression,!1,t)},simple_not(e,t){return _(e.expression,!0,t)},optional(e,t){return g(y(e.expression,{sp:t.sp,env:C(t.env),action:null}),m(-(0|e.expression.match),[r.IF_ERROR],g([r.POP],[r.PUSH_NULL]),[]))},zero_or_more(e,t){const u=y(e.expression,{sp:t.sp+1,env:C(t.env),action:null});return g([r.PUSH_EMPTY_ARRAY],u,B(u),[r.POP])},one_or_more(e,t){const u=y(e.expression,{sp:t.sp+1,env:C(t.env),action:null});return g([r.PUSH_EMPTY_ARRAY],u,m(0|e.expression.match,[r.IF_NOT_ERROR],g(B(u),[r.POP]),g([r.POP],[r.POP],[r.PUSH_FAILED])))},repeated(e,t){const u=e.min?e.min:e.max,n="constant"!==u.type||u.value>0,o="constant"!==e.max.type&&null!==e.max.value,a=n?2:1,s=e.min?x(e.min,t.env,t.sp,2+("function"===e.max.type?1:0)):{pre:[],post:[],sp:t.sp},c=x(e.max,t.env,s.sp,a),l=y(e.expression,{sp:c.sp+a,env:C(t.env),action:null}),p=null!==e.delimiter?y(e.expression,{sp:c.sp+a+1,env:C(t.env),action:null}):l,A=function(e,t,u,n,o){return e?g([r.PUSH_CURR_POS],y(e,{sp:n.sp+o+1,env:C(n.env),action:null}),m(0|e.match,[r.IF_NOT_ERROR],g([r.POP],u,m(-t,[r.IF_ERROR],[r.POP,r.POP_CURR_POS,r.PUSH_FAILED],[r.NIP])),[r.NIP])):u}(e.delimiter,0|e.expression.match,p,t,a),h=v(A,e.max),d=o?v(l,e.max):l,E=g(n?[r.PUSH_CURR_POS]:[],[r.PUSH_EMPTY_ARRAY],d,B(h),[r.POP]);return g(s.pre,c.pre,n?function(e,t){const u="constant"===t.type?[r.IF_LT,t.value]:[r.IF_LT_DYNAMIC,t.sp];return g(e,m(i,u,[r.POP,r.POP_CURR_POS,r.PUSH_FAILED],[r.NIP]))}(E,u):E,c.post,s.post)},group(e,t){return y(e.expression,{sp:t.sp,env:C(t.env),action:null})},semantic_and(e,t){return D(e,!1,t)},semantic_not(e,t){return D(e,!0,t)},rule_ref(t){return[r.RULE,n.indexOfRule(e,t.name)]},literal(e){if(e.value.length>0){const t=0|e.match,u=t===i||t===a&&!e.ignoreCase?h(e.ignoreCase?e.value.toLowerCase():e.value):null,n=t!==a?d({type:"literal",value:e.value,ignoreCase:e.ignoreCase}):null;return m(t,e.ignoreCase?[r.MATCH_STRING_IC,u]:[r.MATCH_STRING,u],e.ignoreCase?[r.ACCEPT_N,e.value.length]:[r.ACCEPT_STRING,u],[r.FAIL,n])}return[r.PUSH_EMPTY_STRING]},class(e){const t=0|e.match,u=t===i?function(e){const t={value:e.parts,inverted:e.inverted,ignoreCase:e.ignoreCase},u=JSON.stringify(t),n=c.findIndex((e=>JSON.stringify(e)===u));return-1===n?c.push(t)-1:n}(e):null,n=t!==a?d({type:"class",value:e.parts,inverted:e.inverted,ignoreCase:e.ignoreCase}):null;return m(t,[r.MATCH_CHAR_CLASS,u],[r.ACCEPT_N,1],[r.FAIL,n])},any(e){const t=0|e.match,u=t!==a?d({type:"any"}):null;return m(t,[r.MATCH_ANY],[r.ACCEPT_N,1],[r.FAIL,u])}},t&&"source-and-map"===t.output&&Object.entries(S).forEach((([e,t])=>{S[e]=function(e,...u){const n=t(e,...u);return void 0!==n&&e.location?g([r.SOURCE_MAP_PUSH,f(e.location)],n,[r.SOURCE_MAP_POP]):n}})),o.build(S));var S;y(e)}},5843:function(e,t,u){"use strict";const n=u(9861),r=u(6164),o=u(8013),a=u(244),{stringEscape:i,regexpClassEscape:s}=u(6443),{SourceNode:c}=u(4738),l=u(2190);function p(e,t,u){const n=l.offsetStart(t),r=n.line,o=n.column-1,a=e.split("\n");return 1===a.length?new c(r,o,String(t.source),e,u):new c(null,null,String(t.source),a.map(((e,n)=>new c(r+n,0===n?o:0,String(t.source),n===a.length-1?e:[e,"\n"],u))))}function A(e,t,u,n,r){if(u){const o=l.offsetEnd(u);return new c(null,null,String(u.source),[e,p(t,u,r),new c(o.line,o.column-1,String(u.source),n)])}return new c(null,null,null,[e,t,n])}e.exports=function(e,t){function u(e){let t=!0,u=0;return function e(n){return Array.isArray(n)?n.map(e):n instanceof c?(u++,n.children=e(n.children),u--,n):(n=t?n.replace(/^(.+)$/gm," $1"):n.replace(/\n(\s*\S)/g,"\n $1"),t=!u||n.endsWith("\n"),n)}(e)}function l(e){return"peg$c"+e}function h(e){return"peg$r"+e}function d(e){return"peg$e"+e}function E(e){return"peg$f"+e}function f(e){return"peg$parse"+e}function C(e){return e.codeLocation?p(e.code,e.codeLocation,"$"+e.type):e.code}e.code=function(e){function n(){return[`// Generated by Peggy ${a}.`,"//","// https://peggyjs.org/"]}function r(){return t.trace?["{"," SyntaxError: peg$SyntaxError,"," DefaultTracer: peg$DefaultTracer,"," parse: peg$parse","}"].join("\n"):["{"," SyntaxError: peg$SyntaxError,"," parse: peg$parse","}"].join("\n")}const o={bare(){return[...n(),"(function() {",' "use strict";',"",e,"",u("return "+r()+";"),"})()"]},commonjs(){const u=Object.keys(t.dependencies),o=n();return o.push("",'"use strict";',""),u.length>0&&(u.forEach((e=>{o.push("var "+e+' = require("'+i(t.dependencies[e])+'");')})),o.push("")),o.push(e,"","module.exports = "+r()+";"),o},es(){const u=Object.keys(t.dependencies),r=n();return r.push(""),u.length>0&&(u.forEach((e=>{r.push("import "+e+' from "'+i(t.dependencies[e])+'";')})),r.push("")),r.push(e,"","export {"," peg$SyntaxError as SyntaxError,",t.trace?" peg$DefaultTracer as DefaultTracer,":""," peg$parse as parse","};"),r},amd(){const o=Object.keys(t.dependencies),a="["+o.map((e=>t.dependencies[e])).map((e=>'"'+i(e)+'"')).join(", ")+"]",s=o.join(", ");return[...n(),"define("+a+", function("+s+") {",' "use strict";',"",e,"",u("return "+r()+";"),"});"]},globals(){return[...n(),"(function(root) {",' "use strict";',"",e,"",u("root."+t.exportVar+" = "+r()+";"),"})(this);"]},umd(){const o=Object.keys(t.dependencies),a=o.map((e=>t.dependencies[e])),s="["+a.map((e=>'"'+i(e)+'"')).join(", ")+"]",c=a.map((e=>'require("'+i(e)+'")')).join(", "),l=o.join(", "),p=n();return p.push("(function(root, factory) {",' if (typeof define === "function" && define.amd) {'," define("+s+", factory);",' } else if (typeof module === "object" && module.exports) {'," module.exports = factory("+c+");"),null!==t.exportVar&&p.push(" } else {"," root."+t.exportVar+" = factory();"),p.push(" }","})(this, function("+l+") {",' "use strict";',"",e,"",u("return "+r()+";"),"});"),p}}[t.format]();return new c(null,null,t.grammarSource,o.map((e=>e instanceof c?e:e+"\n")))}(function(){const a=[];e.topLevelInitializer&&(a.push(C(e.topLevelInitializer)),a.push("")),a.push("function peg$subclass(child, parent) {"," function C() { this.constructor = child; }"," C.prototype = parent.prototype;"," child.prototype = new C();","}","","function peg$SyntaxError(message, expected, found, location) {"," var self = Error.call(this, message);"," // istanbul ignore next Check is a necessary evil to support older environments"," if (Object.setPrototypeOf) {"," Object.setPrototypeOf(self, peg$SyntaxError.prototype);"," }"," self.expected = expected;"," self.found = found;"," self.location = location;",' self.name = "SyntaxError";'," return self;","}","","peg$subclass(peg$SyntaxError, Error);","","function peg$padEnd(str, targetLength, padString) {",' padString = padString || " ";'," if (str.length > targetLength) { return str; }"," targetLength -= str.length;"," padString += padString.repeat(targetLength);"," return str + padString.slice(0, targetLength);","}","","peg$SyntaxError.prototype.format = function(sources) {",' var str = "Error: " + this.message;'," if (this.location) {"," var src = null;"," var k;"," for (k = 0; k < sources.length; k++) {"," if (sources[k].source === this.location.source) {"," src = sources[k].text.split(/\\r\\n|\\n|\\r/g);"," break;"," }"," }"," var s = this.location.start;",' var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))'," ? this.location.source.offset(s)"," : s;",' var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;'," if (src) {"," var e = this.location.end;"," var filler = peg$padEnd(\"\", offset_s.line.toString().length, ' ');"," var line = src[s.line - 1];"," var last = s.line === e.line ? e.column : line.length + 1;"," var hatLen = (last - s.column) || 1;",' str += "\\n --\x3e " + loc + "\\n"',' + filler + " |\\n"',' + offset_s.line + " | " + line + "\\n"',' + filler + " | " + peg$padEnd("", s.column - 1, \' \')',' + peg$padEnd("", hatLen, "^");'," } else {",' str += "\\n at " + loc;'," }"," }"," return str;","};","","peg$SyntaxError.buildMessage = function(expected, found) {"," var DESCRIBE_EXPECTATION_FNS = {"," literal: function(expectation) {",' return "\\"" + literalEscape(expectation.text) + "\\"";'," },",""," class: function(expectation) {"," var escapedParts = expectation.parts.map(function(part) {"," return Array.isArray(part)",' ? classEscape(part[0]) + "-" + classEscape(part[1])'," : classEscape(part);"," });","",' return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";'," },",""," any: function() {",' return "any character";'," },",""," end: function() {",' return "end of input";'," },",""," other: function(expectation) {"," return expectation.description;"," }"," };",""," function hex(ch) {"," return ch.charCodeAt(0).toString(16).toUpperCase();"," }",""," function literalEscape(s) {"," return s",' .replace(/\\\\/g, "\\\\\\\\")',' .replace(/"/g, "\\\\\\"")',' .replace(/\\0/g, "\\\\0")',' .replace(/\\t/g, "\\\\t")',' .replace(/\\n/g, "\\\\n")',' .replace(/\\r/g, "\\\\r")',' .replace(/[\\x00-\\x0F]/g, function(ch) { return "\\\\x0" + hex(ch); })',' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return "\\\\x" + hex(ch); });'," }",""," function classEscape(s) {"," return s",' .replace(/\\\\/g, "\\\\\\\\")',' .replace(/\\]/g, "\\\\]")',' .replace(/\\^/g, "\\\\^")',' .replace(/-/g, "\\\\-")',' .replace(/\\0/g, "\\\\0")',' .replace(/\\t/g, "\\\\t")',' .replace(/\\n/g, "\\\\n")',' .replace(/\\r/g, "\\\\r")',' .replace(/[\\x00-\\x0F]/g, function(ch) { return "\\\\x0" + hex(ch); })',' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return "\\\\x" + hex(ch); });'," }",""," function describeExpectation(expectation) {"," return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);"," }",""," function describeExpected(expected) {"," var descriptions = expected.map(describeExpectation);"," var i, j;",""," descriptions.sort();",""," if (descriptions.length > 0) {"," for (i = 1, j = 1; i < descriptions.length; i++) {"," if (descriptions[i - 1] !== descriptions[i]) {"," descriptions[j] = descriptions[i];"," j++;"," }"," }"," descriptions.length = j;"," }",""," switch (descriptions.length) {"," case 1:"," return descriptions[0];",""," case 2:",' return descriptions[0] + " or " + descriptions[1];',""," default:",' return descriptions.slice(0, -1).join(", ")',' + ", or "'," + descriptions[descriptions.length - 1];"," }"," }",""," function describeFound(found) {",' return found ? "\\"" + literalEscape(found) + "\\"" : "end of input";'," }","",' return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";',"};",""),t.trace&&a.push("function peg$DefaultTracer() {"," this.indentLevel = 0;","}","","peg$DefaultTracer.prototype.trace = function(event) {"," var that = this;",""," function log(event) {"," function repeat(string, n) {",' var result = "", i;',""," for (i = 0; i < n; i++) {"," result += string;"," }",""," return result;"," }",""," function pad(string, length) {",' return string + repeat(" ", length - string.length);'," }","",' if (typeof console === "object") {'," console.log(",' event.location.start.line + ":" + event.location.start.column + "-"',' + event.location.end.line + ":" + event.location.end.column + " "',' + pad(event.type, 10) + " "',' + repeat(" ", that.indentLevel) + event.rule'," );"," }"," }",""," switch (event.type) {",' case "rule.enter":'," log(event);"," this.indentLevel++;"," break;","",' case "rule.match":'," this.indentLevel--;"," log(event);"," break;","",' case "rule.fail":'," this.indentLevel--;"," log(event);"," break;",""," default:",' throw new Error("Invalid event type: " + event.type + ".");'," }","};","");const p="{ "+t.allowedStartRules.map((e=>e+": "+f(e))).join(", ")+" }",g=f(t.allowedStartRules[0]);return a.push("function peg$parse(input, options) {"," options = options !== undefined ? options : {};",""," var peg$FAILED = {};"," var peg$source = options.grammarSource;",""," var peg$startRuleFunctions = "+p+";"," var peg$startRuleFunction = "+g+";","",new c(null,null,t.grammarSource,[e.literals.map(((e,t)=>" var "+l(t)+' = "'+i(e)+'";')).concat("",e.classes.map(((e,t)=>{return" var "+h(t)+" = /^["+((u=e).inverted?"^":"")+u.value.map((e=>Array.isArray(e)?s(e[0])+"-"+s(e[1]):s(e))).join("")+"]/"+(u.ignoreCase?"i":"")+";";var u}))).concat("",e.expectations.map(((e,t)=>" var "+d(t)+" = "+function(e){switch(e.type){case"rule":return'peg$otherExpectation("'+i(e.value)+'")';case"literal":return'peg$literalExpectation("'+i(e.value)+'", '+e.ignoreCase+")";case"class":return"peg$classExpectation(["+e.value.map((e=>Array.isArray(e)?'["'+i(e[0])+'", "'+i(e[1])+'"]':'"'+i(e)+'"')).join(", ")+"], "+e.inverted+", "+e.ignoreCase+")";case"any":return"peg$anyExpectation()";default:throw new Error("Unknown expectation type ("+JSON.stringify(e)+")")}}(e)+";"))).concat("").join("\n"),e.functions.map((function(e,t){return A(`\n var ${E(t)} = function(${e.params.join(", ")}) {`,e.body,e.location,"};")}))]),""," var peg$currPos = 0;"," var peg$savedPos = 0;"," var peg$posDetailsCache = [{ line: 1, column: 1 }];"," var peg$maxFailPos = 0;"," var peg$maxFailExpected = [];"," var peg$silentFails = 0;",""),t.cache&&a.push(" var peg$resultsCache = {};",""),t.trace&&a.push(' var peg$tracer = "tracer" in options ? options.tracer : new peg$DefaultTracer();',""),a.push(" var peg$result;","",' if ("startRule" in options) {'," if (!(options.startRule in peg$startRuleFunctions)) {",' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");'," }",""," peg$startRuleFunction = peg$startRuleFunctions[options.startRule];"," }",""," function text() {"," return input.substring(peg$savedPos, peg$currPos);"," }",""," function offset() {"," return peg$savedPos;"," }",""," function range() {"," return {"," source: peg$source,"," start: peg$savedPos,"," end: peg$currPos"," };"," }",""," function location() {"," return peg$computeLocation(peg$savedPos, peg$currPos);"," }",""," function expected(description, location) {"," location = location !== undefined"," ? location"," : peg$computeLocation(peg$savedPos, peg$currPos);",""," throw peg$buildStructuredError("," [peg$otherExpectation(description)],"," input.substring(peg$savedPos, peg$currPos),"," location"," );"," }",""," function error(message, location) {"," location = location !== undefined"," ? location"," : peg$computeLocation(peg$savedPos, peg$currPos);",""," throw peg$buildSimpleError(message, location);"," }",""," function peg$literalExpectation(text, ignoreCase) {",' return { type: "literal", text: text, ignoreCase: ignoreCase };'," }",""," function peg$classExpectation(parts, inverted, ignoreCase) {",' return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };'," }",""," function peg$anyExpectation() {",' return { type: "any" };'," }",""," function peg$endExpectation() {",' return { type: "end" };'," }",""," function peg$otherExpectation(description) {",' return { type: "other", description: description };'," }",""," function peg$computePosDetails(pos) {"," var details = peg$posDetailsCache[pos];"," var p;",""," if (details) {"," return details;"," } else {"," p = pos - 1;"," while (!peg$posDetailsCache[p]) {"," p--;"," }",""," details = peg$posDetailsCache[p];"," details = {"," line: details.line,"," column: details.column"," };",""," while (p < pos) {"," if (input.charCodeAt(p) === 10) {"," details.line++;"," details.column = 1;"," } else {"," details.column++;"," }",""," p++;"," }",""," peg$posDetailsCache[pos] = details;",""," return details;"," }"," }",""," function peg$computeLocation(startPos, endPos, offset) {"," var startPosDetails = peg$computePosDetails(startPos);"," var endPosDetails = peg$computePosDetails(endPos);",""," var res = {"," source: peg$source,"," start: {"," offset: startPos,"," line: startPosDetails.line,"," column: startPosDetails.column"," },"," end: {"," offset: endPos,"," line: endPosDetails.line,"," column: endPosDetails.column"," }"," };",' if (offset && peg$source && (typeof peg$source.offset === "function")) {'," res.start = peg$source.offset(res.start);"," res.end = peg$source.offset(res.end);"," }"," return res;"," }",""," function peg$fail(expected) {"," if (peg$currPos < peg$maxFailPos) { return; }",""," if (peg$currPos > peg$maxFailPos) {"," peg$maxFailPos = peg$currPos;"," peg$maxFailExpected = [];"," }",""," peg$maxFailExpected.push(expected);"," }",""," function peg$buildSimpleError(message, location) {"," return new peg$SyntaxError(message, null, null, location);"," }",""," function peg$buildStructuredError(expected, found, location) {"," return new peg$SyntaxError("," peg$SyntaxError.buildMessage(expected, found),"," expected,"," found,"," location"," );"," }",""),e.rules.forEach((s=>{a.push(...u(function(a){const s=[],c=new o(a.name,"s","var",a.bytecode),p=function t(n){let o=0;const i=n.length,s=[];let p;function A(e,r){const a=r+3,i=n[o+a-2],l=n[o+a-1];let p,A;c.checkedIf(o,(()=>{o+=a,p=t(n.slice(o,o+i)),o+=i}),l>0?()=>{A=t(n.slice(o,o+l)),o+=l}:null),s.push("if ("+e+") {"),s.push(...u(p)),l>0&&(s.push("} else {"),s.push(...u(A))),s.push("}")}function C(e){const r=n[o+2-1];let a;c.checkedLoop(o,(()=>{o+=2,a=t(n.slice(o,o+r)),o+=r})),s.push("while ("+e+") {"),s.push(...u(a)),s.push("}")}function g(e){const t=n[o+e-1];return E(n[o+1])+"("+n.slice(o+e,o+e+t).map((e=>c.index(e))).join(", ")+")"}for(;oc.index(e))).join(", ")} ]`,c.pop(n[o+1]),s.push(c.push(p)),o+=u;break}case r.IF:A(c.top(),0);break;case r.IF_ERROR:A(c.top()+" === peg$FAILED",0);break;case r.IF_NOT_ERROR:A(c.top()+" !== peg$FAILED",0);break;case r.IF_LT:A(c.top()+".length < "+n[o+1],1);break;case r.IF_GE:A(c.top()+".length >= "+n[o+1],1);break;case r.IF_LT_DYNAMIC:A(c.top()+".length < ("+c.index(n[o+1])+"|0)",1);break;case r.IF_GE_DYNAMIC:A(c.top()+".length >= ("+c.index(n[o+1])+"|0)",1);break;case r.WHILE_NOT_ERROR:C(c.top()+" !== peg$FAILED");break;case r.MATCH_ANY:A("input.length > peg$currPos",0);break;case r.MATCH_STRING:A(e.literals[n[o+1]].length>1?"input.substr(peg$currPos, "+e.literals[n[o+1]].length+") === "+l(n[o+1]):"input.charCodeAt(peg$currPos) === "+e.literals[n[o+1]].charCodeAt(0),1);break;case r.MATCH_STRING_IC:A("input.substr(peg$currPos, "+e.literals[n[o+1]].length+").toLowerCase() === "+l(n[o+1]),1);break;case r.MATCH_CHAR_CLASS:A(h(n[o+1])+".test(input.charAt(peg$currPos))",1);break;case r.ACCEPT_N:s.push(c.push(n[o+1]>1?"input.substr(peg$currPos, "+n[o+1]+")":"input.charAt(peg$currPos)")),s.push(n[o+1]>1?"peg$currPos += "+n[o+1]+";":"peg$currPos++;"),o+=2;break;case r.ACCEPT_STRING:s.push(c.push(l(n[o+1]))),s.push(e.literals[n[o+1]].length>1?"peg$currPos += "+e.literals[n[o+1]].length+";":"peg$currPos++;"),o+=2;break;case r.FAIL:s.push(c.push("peg$FAILED")),s.push("if (peg$silentFails === 0) { peg$fail("+d(n[o+1])+"); }"),o+=2;break;case r.LOAD_SAVED_POS:s.push("peg$savedPos = "+c.index(n[o+1])+";"),o+=2;break;case r.UPDATE_SAVED_POS:s.push("peg$savedPos = peg$currPos;"),o++;break;case r.CALL:p=g(4),c.pop(n[o+2]),s.push(c.push(p)),o+=4+n[o+3];break;case r.RULE:s.push(c.push(f(e.rules[n[o+1]].name)+"()")),o+=2;break;case r.SILENT_FAILS_ON:s.push("peg$silentFails++;"),o++;break;case r.SILENT_FAILS_OFF:s.push("peg$silentFails--;"),o++;break;case r.SOURCE_MAP_PUSH:c.sourceMapPush(s,e.locations[n[o+1]]),o+=2;break;case r.SOURCE_MAP_POP:c.sourceMapPop(),o++;break;case r.SOURCE_MAP_LABEL_PUSH:c.labels[n[o+1]]={label:e.literals[n[o+2]],location:e.locations[n[o+3]]},o+=4;break;case r.SOURCE_MAP_LABEL_POP:delete c.labels[n[o+1]],o+=2;break;default:throw new Error("Invalid opcode: "+n[o]+".",{rule:a.name,bytecode:n})}return s}(a.bytecode);return s.push(A("function ",f(a.name),a.nameLocation,"() {\n",a.name)),t.trace&&s.push(" var startPos = peg$currPos;"),s.push(u(c.defines())),s.push(...u(function(u,n){const r=[];return r.push(""),t.trace&&r.push("peg$tracer.trace({",' type: "rule.enter",'," rule: "+u+","," location: peg$computeLocation(startPos, startPos, true)","});",""),t.cache&&(r.push("var key = peg$currPos * "+e.rules.length+" + "+n+";","var cached = peg$resultsCache[key];","","if (cached) {"," peg$currPos = cached.nextPos;",""),t.trace&&r.push("if (cached.result !== peg$FAILED) {"," peg$tracer.trace({",' type: "rule.match",'," rule: "+u+","," result: cached.result,"," location: peg$computeLocation(startPos, peg$currPos, true)"," });","} else {"," peg$tracer.trace({",' type: "rule.fail",'," rule: "+u+","," location: peg$computeLocation(startPos, startPos, true)"," });","}",""),r.push(" return cached.result;","}","")),r}('"'+i(a.name)+'"',n.indexOfRule(e,a.name)))),s.push(...u(p)),s.push(...u(function(e,u){const n=[];return t.cache&&n.push("","peg$resultsCache[key] = { nextPos: peg$currPos, result: "+u+" };"),t.trace&&n.push("","if ("+u+" !== peg$FAILED) {"," peg$tracer.trace({",' type: "rule.match",'," rule: "+e+","," result: "+u+","," location: peg$computeLocation(startPos, peg$currPos, true)"," });","} else {"," peg$tracer.trace({",' type: "rule.fail",'," rule: "+e+","," location: peg$computeLocation(startPos, startPos, true)"," });","}"),n.push("","return "+u+";"),n}('"'+i(a.name)+'"',c.result()))),s.push("}"),s}(s))),a.push("")})),e.initializer&&(a.push(C(e.initializer)),a.push("")),a.push(" peg$result = peg$startRuleFunction();",""," if (peg$result !== peg$FAILED && peg$currPos === input.length) {"," return peg$result;"," } else {"," if (peg$result !== peg$FAILED && peg$currPos < input.length) {"," peg$fail(peg$endExpectation());"," }",""," throw peg$buildStructuredError("," peg$maxFailExpected,"," peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,"," peg$maxFailPos < input.length"," ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)"," : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)"," );"," }","}"),new c(null,null,t.grammarSource,a.map((e=>e instanceof c?e:e+"\n")))}())}},5412:function(e,t,u){"use strict";const n=u(8202),r=u(9861),o=u(4297),a=-1;function i(e){function t(e){return e.match=0}function u(e){return c(e.expression),e.match=1}function i(e){return e.match=c(e.expression)}function s(e,t){const u=e.length;let n=0,r=0;for(let t=0;t0?a:0}const c=n.build({rule(e){let t,u=0;if(void 0===e.match){e.match=0;do{if(t=e.match,e.match=c(e.expression),++u>6)throw new o("Infinity cycle detected when trying to evaluate node match result",e.location)}while(t!==e.match)}return e.match},named:i,choice(e){return e.match=s(e.alternatives,!0)},action:i,sequence(e){return e.match=s(e.elements,!1)},labeled:i,text:i,simple_and:i,simple_not(e){return e.match=-c(e.expression)},optional:u,zero_or_more:u,one_or_more:i,repeated(e){const t=c(e.expression),u=e.delimiter?c(e.delimiter):a,n=e.min?e.min:e.max;return"constant"!==n.type||"constant"!==e.max.type?e.match=0:0===e.max.value||null!==e.max.value&&n.value>e.max.value?e.match=a:t===a?e.match=0===n.value?1:a:1===t?e.delimiter&&n.value>=2?e.match=u:e.match=1:e.delimiter&&n.value>=2?e.match=u===a?a:0:e.match=0===n.value?1:0},group:i,semantic_and:t,semantic_not:t,rule_ref(t){const u=r.findRule(e,t.name);return t.match=c(u)},literal(e){const t=0===e.value.length?1:0;return e.match=t},class(e){const t=0===e.parts.length?a:0;return e.match=t},any:t});c(e)}i.ALWAYS_MATCH=1,i.SOMETIMES_MATCH=0,i.NEVER_MATCH=a,e.exports=i},2929:function(e,t,u){"use strict";const n=u(9861),r=u(8202);e.exports=function(e,t,u){const o=[];e.rules.forEach(((a,i)=>{var s;"rule"===(s=a).type&&"rule_ref"===s.expression.type&&(function(e,t,o){r.build({rule_ref(r){r.name===t&&(r.name=o,u.info(`Proxy rule "${t}" replaced by the rule "${o}"`,r.location,[{message:"This rule will be used",location:n.findRule(e,o).nameLocation}]))}})(e)}(e,a.name,a.expression.name),-1===t.allowedStartRules.indexOf(a.name)&&o.push(i))})),o.reverse(),o.forEach((t=>{e.rules.splice(t,1)}))}},6734:function(e,t,u){"use strict";const n=u(8202);e.exports=function(e,t,u){function r(e){const t={};return Object.keys(e).forEach((u=>{t[u]=e[u]})),t}function o(e,t){a(e.expression,r(t))}const a=n.build({rule(e){a(e.expression,{})},choice(e,t){e.alternatives.forEach((e=>{a(e,r(t))}))},action:o,labeled(e,t){const n=e.label;n&&Object.prototype.hasOwnProperty.call(t,n)&&u.error(`Label "${e.label}" is already defined`,e.labelLocation,[{message:"Original label location",location:t[n]}]),a(e.expression,t),t[e.label]=e.labelLocation},text:o,simple_and:o,simple_not:o,optional:o,zero_or_more:o,one_or_more:o,repeated(e,t){e.delimiter&&a(e.delimiter,r(t)),a(e.expression,r(t))},group:o});a(e)}},1117:function(e,t,u){"use strict";const n=u(8202);e.exports=function(e,t,u){const r={};n.build({rule(e){Object.prototype.hasOwnProperty.call(r,e.name)?u.error(`Rule "${e.name}" is already defined`,e.nameLocation,[{message:"Original rule location",location:r[e.name]}]):r[e.name]=e.nameLocation}})(e)}},6237:function(e,t,u){"use strict";const n=u(8202);e.exports=function(e,t,u){const r=n.build({action(e){r(e.expression,e)},labeled(e,t){e.pick&&t&&u.error('"@" cannot be used with an action block',e.labelLocation,[{message:"Action block location",location:t.codeLocation}]),r(e.expression)}});r(e)}},730:function(e,t,u){"use strict";const n=u(9861),r=u(8202);e.exports=function(e,t,u){const o=[],a=[],i=r.build({rule(e){o.push(e.name),i(e.expression),o.pop()},sequence(t){t.elements.every((t=>(i(t),!n.alwaysConsumesOnSuccess(e,t))))},repeated(t){i(t.expression),t.delimiter&&!n.alwaysConsumesOnSuccess(e,t.expression)&&i(t.delimiter)},rule_ref(t){a.push(t);const r=n.findRule(e,t.name);if(-1!==o.indexOf(t.name))return o.push(t.name),void u.error("Possible infinite loop when parsing (left recursion: "+o.join(" -> ")+")",r.nameLocation,a.map(((e,t,u)=>({message:t+1!==u.length?`Step ${t+1}: call of the rule "${e.name}" without input consumption`:`Step ${t+1}: call itself without input consumption - left recursion`,location:e.location}))));r&&i(r),a.pop()}});i(e)}},9505:function(e,t,u){"use strict";const n=u(9861),r=u(8202);e.exports=function(e,t,u){const o=r.build({zero_or_more(t){n.alwaysConsumesOnSuccess(e,t.expression)||u.error("Possible infinite loop when parsing (repetition used with an expression that may not consume any input)",t.location)},one_or_more(t){n.alwaysConsumesOnSuccess(e,t.expression)||u.error("Possible infinite loop when parsing (repetition used with an expression that may not consume any input)",t.location)},repeated(t){if(t.delimiter&&o(t.delimiter),!(n.alwaysConsumesOnSuccess(e,t.expression)||t.delimiter&&n.alwaysConsumesOnSuccess(e,t.delimiter)))if(null===t.max.value)u.error("Possible infinite loop when parsing (unbounded range repetition used with an expression that may not consume any input)",t.location);else{const e=t.min?t.min:t.max;u.warning("constant"===e.type&&"constant"===t.max.type?`An expression may not consume any input and may always match ${t.max.value} times`:"An expression may not consume any input and may always match with a maximum repetition count",t.location)}}});o(e)}},1442:function(e,t,u){"use strict";const n=u(9861),r=u(8202);e.exports=function(e,t,u){r.build({rule_ref(t){n.findRule(e,t.name)||u.error(`Rule "${t.name}" is not defined`,t.location)}})(e)}},425:function(e,t,u){"use strict";const n=u(4297);class r{constructor(e){"function"==typeof(e=void 0!==e?e:{}).error&&(this.error=e.error),"function"==typeof e.warning&&(this.warning=e.warning),"function"==typeof e.info&&(this.info=e.info)}error(){}warning(){}info(){}}e.exports=class{constructor(e){this._callbacks=new r(e),this._firstError=null,this.errors=0,this.problems=[],this.stage=null}error(...e){++this.errors,null===this._firstError&&(this._firstError=new n(...e),this._firstError.stage=this.stage,this._firstError.problems=this.problems),this.problems.push(["error",...e]),this._callbacks.error(this.stage,...e)}warning(...e){this.problems.push(["warning",...e]),this._callbacks.warning(this.stage,...e)}info(...e){this.problems.push(["info",...e]),this._callbacks.info(this.stage,...e)}checkErrors(){if(0!==this.errors)throw this._firstError}}},8013:function(e,t,u){"use strict";const{SourceNode:n}=u(4738),r=u(2190);class o{constructor(e,t,u,n){this.sp=-1,this.maxSp=-1,this.varName=t,this.ruleName=e,this.type=u,this.bytecode=n,this.labels={},this.sourceMapStack=[]}name(e){if(e<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack underflow: attempt to use a variable '${this.varName}' at an index ${e}.\nBytecode: ${this.bytecode}`);return this.varName+e}static sourceNode(e,t,u){const o=r.offsetStart(e);return new n(o.line,o.column?o.column-1:null,String(e.source),t,u)}push(e){++this.sp>this.maxSp&&(this.maxSp=this.sp);const t=this.labels[this.sp],u=[this.name(this.sp)," = ",e,";"];if(t){if(this.sourceMapStack.length){const e=o.sourceNode(t.location,u.splice(0,2),t.label),{parts:r,location:a}=this.sourceMapPopInternal(),i=a.start.offsetthis.name(this.sp+1+t)))):this.name(this.sp--)}top(){return this.name(this.sp)}index(e){if(e<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack overflow: attempt to get a variable at a negative index ${e}.\nBytecode: ${this.bytecode}`);return this.name(this.sp-e)}result(){if(this.maxSp<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack is empty, can't get the result.\nBytecode: ${this.bytecode}`);return this.name(0)}defines(){return this.maxSp<0?"":this.type+" "+Array.from({length:this.maxSp+1},((e,t)=>this.name(t))).join(", ")+";"}checkedIf(e,t,u){const n=this.sp;if(t(),u){const t=this.sp;if(this.sp=n,u(),t!==this.sp)throw new Error("Rule '"+this.ruleName+"', position "+e+": Branches of a condition can't move the stack pointer differently (before: "+n+", after then: "+t+", after else: "+this.sp+"). Bytecode: "+this.bytecode)}}checkedLoop(e,t){const u=this.sp;if(t(),u!==this.sp)throw new Error("Rule '"+this.ruleName+"', position "+e+": Body of a loop can't move the stack pointer (before: "+u+", after: "+this.sp+"). Bytecode: "+this.bytecode)}sourceMapPush(e,t){if(this.sourceMapStack.length){const e=this.sourceMapStack[this.sourceMapStack.length-1];e[2].start.offset===t.start.offset&&e[2].end.offset>t.end.offset&&(e[2]={start:t.end,end:e[2].end,source:e[2].source})}this.sourceMapStack.push([e,e.length,t])}sourceMapPopInternal(){const[e,t,u]=this.sourceMapStack.pop(),o=e.splice(t).map((e=>e instanceof n?e:e+"\n"));if(o.length){const t=r.offsetStart(u);e.push(new n(t.line,t.column-1,String(u.source),o))}return{parts:e,location:u}}sourceMapPop(e){const{location:t}=this.sourceMapPopInternal();if(this.sourceMapStack.length&&t.end.offset"\\x0"+u(e))).replace(/[\x10-\x1F\x7F-\xFF]/g,(e=>"\\x"+u(e))).replace(/[\u0100-\u0FFF]/g,(e=>"\\u0"+u(e))).replace(/[\u1000-\uFFFF]/g,(e=>"\\u"+u(e)))},t.regexpClassEscape=function(e){return e.replace(/\\/g,"\\\\").replace(/\//g,"\\/").replace(/]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\v/g,"\\v").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,(e=>"\\x0"+u(e))).replace(/[\x10-\x1F\x7F-\xFF]/g,(e=>"\\x"+u(e))).replace(/[\u0100-\u0FFF]/g,(e=>"\\u0"+u(e))).replace(/[\u1000-\uFFFF]/g,(e=>"\\u"+u(e)))},t.base64=function(e){const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",u=e.length%3,n=e.length-u;let r="";for(let u=0;u>2],r+=t[(3&e[u])<<4|e[u+1]>>4],r+=t[(15&e[u+1])<<2|e[u+2]>>6],r+=t[63&e[u+2]];return 1===u?(r+=t[e[n]>>2],r+=t[(3&e[n])<<4],r+="=="):2===u&&(r+=t[e[n]>>2],r+=t[(3&e[n])<<4|e[n+1]>>4],r+=t[(15&e[n+1])<<2],r+="="),r}},8202:function(e){"use strict";const t={build(e){function t(t,...u){return e[t.type](t,...u)}function u(){}function n(e,...u){return t(e.expression,...u)}function r(e){return function(u,...n){u[e].forEach((e=>t(e,...n)))}}const o={grammar(e,...u){e.topLevelInitializer&&t(e.topLevelInitializer,...u),e.initializer&&t(e.initializer,...u),e.rules.forEach((e=>t(e,...u)))},top_level_initializer:u,initializer:u,rule:n,named:n,choice:r("alternatives"),action:n,sequence:r("elements"),labeled:n,text:n,simple_and:n,simple_not:n,optional:n,zero_or_more:n,one_or_more:n,repeated(e,...u){return e.delimiter&&t(e.delimiter,...u),t(e.expression,...u)},group:n,semantic_and:u,semantic_not:u,rule_ref:u,literal:u,class:u,any:u};return Object.keys(o).forEach((t=>{Object.prototype.hasOwnProperty.call(e,t)||(e[t]=o[t])})),t}};e.exports=t},4297:function(e,t,u){"use strict";const n=u(2190),r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(const u in t)Object.prototype.hasOwnProperty.call(t,u)&&(e[u]=t[u])};class o extends Error{constructor(e,t,u){super(e),r(this,o.prototype),this.name="GrammarError",this.location=t,void 0===u&&(u=[]),this.diagnostics=u,this.stage=null,this.problems=[["error",e,t,u]]}toString(){let e=super.toString();this.location&&(e+="\n at ",void 0!==this.location.source&&null!==this.location.source&&(e+=`${this.location.source}:`),e+=`${this.location.start.line}:${this.location.start.column}`);for(const t of this.diagnostics)e+="\n from ",void 0!==t.location.source&&null!==t.location.source&&(e+=`${t.location.source}:`),e+=`${t.location.start.line}:${t.location.start.column}: ${t.message}`;return e}format(e){const t=e.map((({source:e,text:t})=>({source:e,text:null!=t?String(t).split(/\r\n|\n|\r/g):[]})));function u(e,u,r=""){let o="";const a=t.find((({source:t})=>t===e.source)),i=e.start,s=n.offsetStart(e);if(a){const t=e.end,n=a.text[i.line-1],c=(i.line===t.line?t.column:n.length+1)-i.column||1;r&&(o+=`\nnote: ${r}`),o+=`\n --\x3e ${e.source}:${s.line}:${s.column}\n${"".padEnd(u)} |\n${s.line.toString().padStart(u)} | ${n}\n${"".padEnd(u)} | ${"".padEnd(i.column-1)}${"".padEnd(c,"^")}`}else o+=`\n at ${e.source}:${s.line}:${s.column}`,r&&(o+=`: ${r}`);return o}return this.problems.filter((e=>"info"!==e[0])).map((e=>function(e,t,r,o=[]){let a=-1/0;a=r?o.reduce(((e,{location:t})=>Math.max(e,n.offsetStart(t).line)),r.start.line):Math.max.apply(null,o.map((e=>e.location.start.line))),a=a.toString().length;let i=`${e}: ${t}`;r&&(i+=u(r,a));for(const e of o)i+=u(e.location,a,e.message);return i}(...e))).join("\n\n")}}e.exports=o},2190:function(e){"use strict";e.exports=class{constructor(e,t){this.source=e,this.start=t}toString(){return String(this.source)}offset(e){return{line:e.line+this.start.line-1,column:1===e.line?e.column+this.start.column-1:e.column,offset:e.offset+this.start.offset}}static offsetStart(e){return e.source&&"function"==typeof e.source.offset?e.source.offset(e.start):e.start}static offsetEnd(e){return e.source&&"function"==typeof e.source.offset?e.source.offset(e.end):e.end}}},170:function(e){"use strict";const t={$:"text","&":"simple_and","!":"simple_not"},u={"?":"optional","*":"zero_or_more","+":"one_or_more"},n={"&":"semantic_and","!":"semantic_not"};function r(e,t,u,n){var o=Error.call(this,e);return Object.setPrototypeOf&&Object.setPrototypeOf(o,r.prototype),o.expected=t,o.found=u,o.location=n,o.name="SyntaxError",o}function o(e,t,u){return u=u||" ",e.length>t?e:(t-=e.length,e+(u+=u.repeat(t)).slice(0,t))}!function(e,t){function u(){this.constructor=e}u.prototype=t.prototype,e.prototype=new u}(r,Error),r.prototype.format=function(e){var t="Error: "+this.message;if(this.location){var u,n=null;for(u=0;u0){for(t=1,u=1;t0?{type:"choice",alternatives:[e].concat(t),location:ju()}:e},Kt=function(e,t){return null!==t?{type:"action",expression:e,code:t[0],codeLocation:t[1],location:ju()}:e},eu=function(e,t){return t.length>0||"labeled"===e.type&&e.pick?{type:"sequence",elements:[e].concat(t),location:ju()}:e},tu=function(e,t,u){return u.type.startsWith("semantic_")&&Hu('"@" cannot be used on a semantic predicate',e),{type:"labeled",label:null!==t?t[0]:null,labelLocation:null!==t?t[1]:e,pick:!0,expression:u,location:ju()}},uu=function(e,t){return{type:"labeled",label:e[0],labelLocation:e[1],expression:t,location:ju()}},nu=function(){return ju()},ru=function(e){return $n.indexOf(e[0])>=0&&Hu(`Label can't be a reserved word "${e[0]}"`,e[1]),e},ou=function(e,u){return{type:t[e],expression:u,location:ju()}},au=function(e,t){return{type:u[t],expression:e,location:ju()}},iu=function(e,t,u){let n=t[0],r=t[1];return"constant"===r.type&&0===r.value&&Hu("The maximum count of repetitions of the rule must be > 0",r.location),{type:"repeated",min:n,max:r,expression:e,delimiter:u,location:ju()}},su=function(e,t){return[null!==e?e:{type:"constant",value:0},null!==t?t:{type:"constant",value:null}]},cu=function(e){return[null,e]},lu=function(e){return{type:"constant",value:e,location:ju()}},pu=function(e){return{type:"variable",value:e[0],location:ju()}},Au=function(e){return{type:"function",value:e[0],codeLocation:e[1],location:ju()}},hu=function(e){return"labeled"===e.type||"sequence"===e.type?{type:"group",expression:e,location:ju()}:e},du=function(e){return{type:"rule_ref",name:e[0],location:ju()}},Eu=function(e,t){return{type:n[e],code:t[0],codeLocation:t[1],location:ju()}},fu=function(e,t){return[e+t.join(""),ju()]},Cu=function(e,t){return{type:"literal",value:e,ignoreCase:null!==t,location:ju()}},gu=function(e){return e.join("")},mu=function(e){return e.join("")},Fu=function(e,t,u){return{type:"class",parts:t.filter((e=>""!==e)),inverted:null!==e,ignoreCase:null!==u,location:ju()}},_u=function(t,u){return t.charCodeAt(0)>u.charCodeAt(0)&&Hu("Invalid character range: "+e.substring(Iu,ku)+"."),[t,u]},Du=function(){return""},Bu=function(){return"\0"},xu=function(){return"\b"},vu=function(){return"\f"},yu=function(){return"\n"},Su=function(){return"\r"},bu=function(){return"\t"},Pu=function(){return"\v"},Ou=function(e){return String.fromCharCode(parseInt(e,16))},wu=function(e){return String.fromCharCode(parseInt(e,16))},$u=function(){return{type:"any",location:ju()}},Ru=function(e){return[e,ju()]},Lu=function(e){return parseInt(e,10)},ku=0,Iu=0,Nu=[{line:1,column:1}],Tu=0,Mu=[],Uu=0;if("startRule"in o){if(!(o.startRule in c))throw new Error("Can't start parsing from rule \""+o.startRule+'".');l=c[o.startRule]}function ju(){return Wu(Iu,ku)}function Hu(e,t){throw function(e,t){return new r(e,null,null,t)}(e,t=void 0!==t?t:Wu(Iu,ku))}function qu(e,t){return{type:"literal",text:e,ignoreCase:t}}function Gu(e,t,u){return{type:"class",parts:e,inverted:t,ignoreCase:u}}function zu(e){return{type:"other",description:e}}function Yu(t){var u,n=Nu[t];if(n)return n;for(u=t-1;!Nu[u];)u--;for(n={line:(n=Nu[u]).line,column:n.column};uTu&&(Tu=ku,Mu=[]),Mu.push(e))}function Ju(){var t,u,n,r,o,a;if(t=ku,On(),u=ku,n=function(){var t,u,n,r;return t=ku,123===e.charCodeAt(ku)?(u=p,ku++):(u=i,0===Uu&&Vu(ve)),u!==i&&(n=bn())!==i?(125===e.charCodeAt(ku)?(r=A,ku++):(r=i,0===Uu&&Vu(ye)),r!==i&&wn()!==i?(Iu=t,t=Jt(n)):(ku=t,t=i)):(ku=t,t=i),t}(),n!==i?(r=On(),u=n):(ku=u,u=i),u===i&&(u=null),n=ku,r=function(){var e,t;return e=ku,(t=bn())!==i&&wn()!==i?(Iu=e,e=Xt(t)):(ku=e,e=i),e}(),r!==i?(o=On(),n=r):(ku=n,n=i),n===i&&(n=null),r=[],o=ku,(a=Xu())!==i?(On(),o=a):(ku=o,o=i),o!==i)for(;o!==i;)r.push(o),o=ku,(a=Xu())!==i?(On(),o=a):(ku=o,o=i);else r=i;return r!==i?(Iu=t,t=Vt(u,n,r)):(ku=t,t=i),t}function Xu(){var t,u,n,r,o;return t=ku,(u=hn())!==i?(On(),n=ku,(r=fn())!==i?(On(),n=r):(ku=n,n=i),n===i&&(n=null),61===e.charCodeAt(ku)?(r=h,ku++):(r=i,0===Uu&&Vu(Se)),r!==i?(On(),(o=Zu())!==i&&wn()!==i?(Iu=t,t=Zt(u,n,o)):(ku=t,t=i)):(ku=t,t=i)):(ku=t,t=i),t}function Zu(){var t,u,n,r,o,a;if(t=ku,(u=Qu())!==i){for(n=[],r=ku,On(),47===e.charCodeAt(ku)?(o=d,ku++):(o=i,0===Uu&&Vu(be)),o!==i?(On(),(a=Qu())!==i?r=a:(ku=r,r=i)):(ku=r,r=i);r!==i;)n.push(r),r=ku,On(),47===e.charCodeAt(ku)?(o=d,ku++):(o=i,0===Uu&&Vu(be)),o!==i?(On(),(a=Qu())!==i?r=a:(ku=r,r=i)):(ku=r,r=i);Iu=t,t=Qt(u,n)}else ku=t,t=i;return t}function Qu(){var e,t,u,n;return e=ku,t=function(){var e,t,u,n,r;if(e=ku,(t=Ku())!==i){for(u=[],n=ku,On(),(r=Ku())!==i?n=r:(ku=n,n=i);n!==i;)u.push(n),n=ku,On(),(r=Ku())!==i?n=r:(ku=n,n=i);Iu=e,e=eu(t,u)}else ku=e,e=i;return e}(),t!==i?(u=ku,On(),(n=bn())!==i?u=n:(ku=u,u=i),u===i&&(u=null),Iu=e,e=Kt(t,u)):(ku=e,e=i),e}function Ku(){var t,u,n,r;return t=ku,u=function(){var t,u;return t=ku,64===e.charCodeAt(ku)?(u=E,ku++):(u=i,0===Uu&&Vu(Pe)),u!==i&&(Iu=t,u=nu()),t=u}(),u!==i?((n=en())===i&&(n=null),(r=tn())!==i?(Iu=t,t=tu(u,n,r)):(ku=t,t=i)):(ku=t,t=i),t===i&&(t=ku,(u=en())!==i?(n=On(),(r=tn())!==i?(Iu=t,t=uu(u,r)):(ku=t,t=i)):(ku=t,t=i),t===i&&(t=tn())),t}function en(){var t,u,n;return t=ku,(u=hn())!==i?(On(),58===e.charCodeAt(ku)?(n=f,ku++):(n=i,0===Uu&&Vu(Oe)),n!==i?(Iu=t,t=ru(u)):(ku=t,t=i)):(ku=t,t=i),t}function tn(){var t,u,n;return t=ku,u=function(){var t;return 36===e.charCodeAt(ku)?(t=C,ku++):(t=i,0===Uu&&Vu(we)),t===i&&(38===e.charCodeAt(ku)?(t=g,ku++):(t=i,0===Uu&&Vu($e)),t===i&&(33===e.charCodeAt(ku)?(t=m,ku++):(t=i,0===Uu&&Vu(Re)))),t}(),u!==i?(On(),(n=un())!==i?(Iu=t,t=ou(u,n)):(ku=t,t=i)):(ku=t,t=i),t===i&&(t=un()),t}function un(){var t,u,n;return t=ku,(u=rn())!==i?(On(),n=function(){var t;return 63===e.charCodeAt(ku)?(t=F,ku++):(t=i,0===Uu&&Vu(Le)),t===i&&(42===e.charCodeAt(ku)?(t=_,ku++):(t=i,0===Uu&&Vu(ke)),t===i&&(43===e.charCodeAt(ku)?(t=D,ku++):(t=i,0===Uu&&Vu(Ie)))),t}(),n!==i?(Iu=t,t=au(u,n)):(ku=t,t=i)):(ku=t,t=i),t===i&&(t=function(){var t,u,n,r,o,a,s;return t=ku,(u=rn())!==i?(On(),124===e.charCodeAt(ku)?(n=B,ku++):(n=i,0===Uu&&Vu(Ne)),n!==i?(On(),r=function(){var t,u,n,r;return t=ku,(u=nn())===i&&(u=null),On(),e.substr(ku,2)===v?(n=v,ku+=2):(n=i,0===Uu&&Vu(Me)),n!==i?(On(),(r=nn())===i&&(r=null),Iu=t,t=su(u,r)):(ku=t,t=i),t===i&&(t=ku,(u=nn())!==i&&(Iu=t,u=cu(u)),t=u),t}(),r!==i?(On(),o=ku,44===e.charCodeAt(ku)?(a=x,ku++):(a=i,0===Uu&&Vu(Te)),a!==i?(On(),(s=Zu())!==i?(On(),o=s):(ku=o,o=i)):(ku=o,o=i),o===i&&(o=null),124===e.charCodeAt(ku)?(a=B,ku++):(a=i,0===Uu&&Vu(Ne)),a!==i?(Iu=t,t=iu(u,r,o)):(ku=t,t=i)):(ku=t,t=i)):(ku=t,t=i)):(ku=t,t=i),t}(),t===i&&(t=rn())),t}function nn(){var t,u;return t=ku,u=function(){var t,u,n,r;if(t=ku,u=ku,n=[],(r=yn())!==i)for(;r!==i;)n.push(r),r=yn();else n=i;return(u=n!==i?e.substring(u,ku):n)!==i&&(Iu=t,u=Lu(u)),t=u}(),u!==i&&(Iu=t,u=lu(u)),(t=u)===i&&(t=ku,(u=hn())!==i&&(Iu=t,u=pu(u)),(t=u)===i&&(t=ku,(u=bn())!==i&&(Iu=t,u=Au(u)),t=u)),t}function rn(){var t,u,n,r;return t=function(){var t,u,n;return Uu++,t=ku,(u=fn())!==i?(105===e.charCodeAt(ku)?(n=Y,ku++):(n=i,0===Uu&&Vu(ht)),n===i&&(n=null),Iu=t,t=Cu(u,n)):(ku=t,t=i),Uu--,t===i&&(u=i,0===Uu&&Vu(At)),t}(),t===i&&(t=function(){var t,u,n,r,o,a;if(Uu++,t=ku,91===e.charCodeAt(ku)?(u=J,ku++):(u=i,0===Uu&&Vu(gt)),u!==i){for(94===e.charCodeAt(ku)?(n=X,ku++):(n=i,0===Uu&&Vu(mt)),n===i&&(n=null),r=[],(o=mn())===i&&(o=Fn());o!==i;)r.push(o),(o=mn())===i&&(o=Fn());93===e.charCodeAt(ku)?(o=Z,ku++):(o=i,0===Uu&&Vu(Ft)),o!==i?(105===e.charCodeAt(ku)?(a=Y,ku++):(a=i,0===Uu&&Vu(ht)),a===i&&(a=null),Iu=t,t=Fu(n,r,a)):(ku=t,t=i)}else ku=t,t=i;return Uu--,t===i&&(u=i,0===Uu&&Vu(Ct)),t}(),t===i&&(t=function(){var t,u;return t=ku,46===e.charCodeAt(ku)?(u=se,ku++):(u=i,0===Uu&&Vu(Rt)),u!==i&&(Iu=t,u=$u()),t=u}(),t===i&&(t=function(){var t,u,n,r,o,a,s;return t=ku,(u=hn())!==i?(n=ku,Uu++,r=ku,o=On(),a=ku,(s=fn())!==i?a=s=[s,On()]:(ku=a,a=i),a===i&&(a=null),61===e.charCodeAt(ku)?(s=h,ku++):(s=i,0===Uu&&Vu(Se)),s!==i?r=o=[o,a,s]:(ku=r,r=i),Uu--,r===i?n=void 0:(ku=n,n=i),n!==i?(Iu=t,t=du(u)):(ku=t,t=i)):(ku=t,t=i),t}(),t===i&&(t=function(){var t,u,n;return t=ku,u=function(){var t;return 38===e.charCodeAt(ku)?(t=g,ku++):(t=i,0===Uu&&Vu($e)),t===i&&(33===e.charCodeAt(ku)?(t=m,ku++):(t=i,0===Uu&&Vu(Re))),t}(),u!==i?(On(),(n=bn())!==i?(Iu=t,t=Eu(u,n)):(ku=t,t=i)):(ku=t,t=i),t}(),t===i&&(t=ku,40===e.charCodeAt(ku)?(u=y,ku++):(u=i,0===Uu&&Vu(Ue)),u!==i?(On(),(n=Zu())!==i?(On(),41===e.charCodeAt(ku)?(r=S,ku++):(r=i,0===Uu&&Vu(je)),r!==i?(Iu=t,t=hu(n)):(ku=t,t=i)):(ku=t,t=i)):(ku=t,t=i)))))),t}function on(){var t;return e.length>ku?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(He)),t}function an(){var t;return Uu++,9===e.charCodeAt(ku)?(t=b,ku++):(t=i,0===Uu&&Vu(Ge)),t===i&&(11===e.charCodeAt(ku)?(t=P,ku++):(t=i,0===Uu&&Vu(ze)),t===i&&(12===e.charCodeAt(ku)?(t=O,ku++):(t=i,0===Uu&&Vu(Ye)),t===i&&(32===e.charCodeAt(ku)?(t=w,ku++):(t=i,0===Uu&&Vu(We)),t===i&&(160===e.charCodeAt(ku)?(t=$,ku++):(t=i,0===Uu&&Vu(Ve)),t===i&&(65279===e.charCodeAt(ku)?(t=R,ku++):(t=i,0===Uu&&Vu(Je)),t===i&&(t=function(){var t;return xe.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Yt)),t}())))))),Uu--,t===i&&0===Uu&&Vu(qe),t}function sn(){var t;return le.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Xe)),t}function cn(){var t;return Uu++,10===e.charCodeAt(ku)?(t=L,ku++):(t=i,0===Uu&&Vu(Qe)),t===i&&(e.substr(ku,2)===k?(t=k,ku+=2):(t=i,0===Uu&&Vu(Ke)),t===i&&(13===e.charCodeAt(ku)?(t=I,ku++):(t=i,0===Uu&&Vu(et)),t===i&&(8232===e.charCodeAt(ku)?(t=N,ku++):(t=i,0===Uu&&Vu(tt)),t===i&&(8233===e.charCodeAt(ku)?(t=T,ku++):(t=i,0===Uu&&Vu(ut)))))),Uu--,t===i&&0===Uu&&Vu(Ze),t}function ln(){var t;return Uu++,(t=function(){var t,u,n,r,o,a;if(t=ku,e.substr(ku,2)===M?(u=M,ku+=2):(u=i,0===Uu&&Vu(rt)),u!==i){for(n=[],r=ku,o=ku,Uu++,e.substr(ku,2)===U?(a=U,ku+=2):(a=i,0===Uu&&Vu(ot)),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);r!==i;)n.push(r),r=ku,o=ku,Uu++,e.substr(ku,2)===U?(a=U,ku+=2):(a=i,0===Uu&&Vu(ot)),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);e.substr(ku,2)===U?(r=U,ku+=2):(r=i,0===Uu&&Vu(ot)),r!==i?t=u=[u,n,r]:(ku=t,t=i)}else ku=t,t=i;return t}())===i&&(t=An()),Uu--,t===i&&0===Uu&&Vu(nt),t}function pn(){var t,u,n,r,o,a;if(t=ku,e.substr(ku,2)===M?(u=M,ku+=2):(u=i,0===Uu&&Vu(rt)),u!==i){for(n=[],r=ku,o=ku,Uu++,e.substr(ku,2)===U?(a=U,ku+=2):(a=i,0===Uu&&Vu(ot)),a===i&&(a=sn()),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);r!==i;)n.push(r),r=ku,o=ku,Uu++,e.substr(ku,2)===U?(a=U,ku+=2):(a=i,0===Uu&&Vu(ot)),a===i&&(a=sn()),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);e.substr(ku,2)===U?(r=U,ku+=2):(r=i,0===Uu&&Vu(ot)),r!==i?t=u=[u,n,r]:(ku=t,t=i)}else ku=t,t=i;return t}function An(){var t,u,n,r,o,a;if(t=ku,e.substr(ku,2)===j?(u=j,ku+=2):(u=i,0===Uu&&Vu(at)),u!==i){for(n=[],r=ku,o=ku,Uu++,a=sn(),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);r!==i;)n.push(r),r=ku,o=ku,Uu++,a=sn(),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);t=u=[u,n]}else ku=t,t=i;return t}function hn(){var e,t,u,n;if(Uu++,e=ku,(t=dn())!==i){for(u=[],n=En();n!==i;)u.push(n),n=En();Iu=e,e=fu(t,u)}else ku=e,e=i;return Uu--,e===i&&(t=i,0===Uu&&Vu(it)),e}function dn(){var t,u,n;return(t=function(){var t;return(t=function(){var t;return ge.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Ut)),t}())===i&&(t=function(){var t;return de.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(It)),t}())===i&&(t=function(){var t;return Ce.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Mt)),t}())===i&&(t=function(){var t;return Ee.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Nt)),t}())===i&&(t=function(){var t;return fe.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Tt)),t}())===i&&(t=function(){var t;return De.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Gt)),t}()),t}())===i&&(95===e.charCodeAt(ku)?(t=H,ku++):(t=i,0===Uu&&Vu(st)),t===i&&(t=ku,92===e.charCodeAt(ku)?(u=q,ku++):(u=i,0===Uu&&Vu(ct)),u!==i&&(n=vn())!==i?t=n:(ku=t,t=i))),t}function En(){var t;return(t=dn())===i&&(36===e.charCodeAt(ku)?(t=C,ku++):(t=i,0===Uu&&Vu(we)),t===i&&(t=function(){var t;return(t=function(){var t;return Fe.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(Ht)),t}())===i&&(t=function(){var t;return me.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(jt)),t}()),t}())===i&&(t=function(){var t;return _e.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(qt)),t}())===i&&(t=function(){var t;return Be.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(zt)),t}())===i&&(8204===e.charCodeAt(ku)?(t=G,ku++):(t=i,0===Uu&&Vu(lt)),t===i&&(8205===e.charCodeAt(ku)?(t=z,ku++):(t=i,0===Uu&&Vu(pt))))),t}function fn(){var t,u,n,r;if(Uu++,t=ku,34===e.charCodeAt(ku)?(u=W,ku++):(u=i,0===Uu&&Vu(Et)),u!==i){for(n=[],r=Cn();r!==i;)n.push(r),r=Cn();34===e.charCodeAt(ku)?(r=W,ku++):(r=i,0===Uu&&Vu(Et)),r!==i?(Iu=t,t=gu(n)):(ku=t,t=i)}else ku=t,t=i;if(t===i)if(t=ku,39===e.charCodeAt(ku)?(u=V,ku++):(u=i,0===Uu&&Vu(ft)),u!==i){for(n=[],r=gn();r!==i;)n.push(r),r=gn();39===e.charCodeAt(ku)?(r=V,ku++):(r=i,0===Uu&&Vu(ft)),r!==i?(Iu=t,t=mu(n)):(ku=t,t=i)}else ku=t,t=i;return Uu--,t===i&&(u=i,0===Uu&&Vu(dt)),t}function Cn(){var t,u,n,r;return t=ku,u=ku,n=ku,Uu++,34===e.charCodeAt(ku)?(r=W,ku++):(r=i,0===Uu&&Vu(Et)),r===i&&(92===e.charCodeAt(ku)?(r=q,ku++):(r=i,0===Uu&&Vu(ct)),r===i&&(r=sn())),Uu--,r===i?n=void 0:(ku=n,n=i),n!==i&&(r=on())!==i?u=n=[n,r]:(ku=u,u=i),(t=u!==i?e.substring(t,ku):u)===i&&(t=ku,92===e.charCodeAt(ku)?(u=q,ku++):(u=i,0===Uu&&Vu(ct)),u!==i&&(n=Bn())!==i?t=n:(ku=t,t=i),t===i&&(t=Dn())),t}function gn(){var t,u,n,r;return t=ku,u=ku,n=ku,Uu++,39===e.charCodeAt(ku)?(r=V,ku++):(r=i,0===Uu&&Vu(ft)),r===i&&(92===e.charCodeAt(ku)?(r=q,ku++):(r=i,0===Uu&&Vu(ct)),r===i&&(r=sn())),Uu--,r===i?n=void 0:(ku=n,n=i),n!==i&&(r=on())!==i?u=n=[n,r]:(ku=u,u=i),(t=u!==i?e.substring(t,ku):u)===i&&(t=ku,92===e.charCodeAt(ku)?(u=q,ku++):(u=i,0===Uu&&Vu(ct)),u!==i&&(n=Bn())!==i?t=n:(ku=t,t=i),t===i&&(t=Dn())),t}function mn(){var t,u,n,r;return t=ku,(u=Fn())!==i?(45===e.charCodeAt(ku)?(n=Q,ku++):(n=i,0===Uu&&Vu(_t)),n!==i&&(r=Fn())!==i?(Iu=t,t=_u(u,r)):(ku=t,t=i)):(ku=t,t=i),t}function Fn(){var t,u,n,r;return t=ku,u=ku,n=ku,Uu++,93===e.charCodeAt(ku)?(r=Z,ku++):(r=i,0===Uu&&Vu(Ft)),r===i&&(92===e.charCodeAt(ku)?(r=q,ku++):(r=i,0===Uu&&Vu(ct)),r===i&&(r=sn())),Uu--,r===i?n=void 0:(ku=n,n=i),n!==i&&(r=on())!==i?u=n=[n,r]:(ku=u,u=i),(t=u!==i?e.substring(t,ku):u)===i&&(t=ku,92===e.charCodeAt(ku)?(u=q,ku++):(u=i,0===Uu&&Vu(ct)),u!==i&&(n=Bn())!==i?t=n:(ku=t,t=i),t===i&&(t=Dn())),t}function Dn(){var t,u;return t=ku,92===e.charCodeAt(ku)?(u=q,ku++):(u=i,0===Uu&&Vu(ct)),u!==i&&cn()!==i?(Iu=t,t=Du()):(ku=t,t=i),t}function Bn(){var t,u,n,r;return t=function(){var t;return(t=xn())===i&&(t=function(){var t,u,n,r;return t=ku,u=ku,n=ku,Uu++,r=function(){var t;return(t=xn())===i&&(t=yn())===i&&(120===e.charCodeAt(ku)?(t=ae,ku++):(t=i,0===Uu&&Vu(Pt)),t===i&&(117===e.charCodeAt(ku)?(t=ie,ku++):(t=i,0===Uu&&Vu(Ot)))),t}(),r===i&&(r=sn()),Uu--,r===i?n=void 0:(ku=n,n=i),n!==i&&(r=on())!==i?u=n=[n,r]:(ku=u,u=i),t=u!==i?e.substring(t,ku):u}()),t}(),t===i&&(t=ku,48===e.charCodeAt(ku)?(u=K,ku++):(u=i,0===Uu&&Vu(Dt)),u!==i?(n=ku,Uu++,r=yn(),Uu--,r===i?n=void 0:(ku=n,n=i),n!==i?(Iu=t,t=Bu()):(ku=t,t=i)):(ku=t,t=i),t===i&&(t=function(){var t,u,n,r,o,a;return t=ku,120===e.charCodeAt(ku)?(u=ae,ku++):(u=i,0===Uu&&Vu(Pt)),u!==i?(n=ku,r=ku,(o=Sn())!==i&&(a=Sn())!==i?r=o=[o,a]:(ku=r,r=i),(n=r!==i?e.substring(n,ku):r)!==i?(Iu=t,t=Ou(n)):(ku=t,t=i)):(ku=t,t=i),t}(),t===i&&(t=vn()))),t}function xn(){var t,u;return 39===e.charCodeAt(ku)?(t=V,ku++):(t=i,0===Uu&&Vu(ft)),t===i&&(34===e.charCodeAt(ku)?(t=W,ku++):(t=i,0===Uu&&Vu(Et)),t===i&&(92===e.charCodeAt(ku)?(t=q,ku++):(t=i,0===Uu&&Vu(ct)),t===i&&(t=ku,98===e.charCodeAt(ku)?(u=ee,ku++):(u=i,0===Uu&&Vu(Bt)),u!==i&&(Iu=t,u=xu()),(t=u)===i&&(t=ku,102===e.charCodeAt(ku)?(u=te,ku++):(u=i,0===Uu&&Vu(xt)),u!==i&&(Iu=t,u=vu()),(t=u)===i&&(t=ku,110===e.charCodeAt(ku)?(u=ue,ku++):(u=i,0===Uu&&Vu(vt)),u!==i&&(Iu=t,u=yu()),(t=u)===i&&(t=ku,114===e.charCodeAt(ku)?(u=ne,ku++):(u=i,0===Uu&&Vu(yt)),u!==i&&(Iu=t,u=Su()),(t=u)===i&&(t=ku,116===e.charCodeAt(ku)?(u=re,ku++):(u=i,0===Uu&&Vu(St)),u!==i&&(Iu=t,u=bu()),(t=u)===i&&(t=ku,118===e.charCodeAt(ku)?(u=oe,ku++):(u=i,0===Uu&&Vu(bt)),u!==i&&(Iu=t,u=Pu()),t=u)))))))),t}function vn(){var t,u,n,r,o,a,s,c;return t=ku,117===e.charCodeAt(ku)?(u=ie,ku++):(u=i,0===Uu&&Vu(Ot)),u!==i?(n=ku,r=ku,(o=Sn())!==i&&(a=Sn())!==i&&(s=Sn())!==i&&(c=Sn())!==i?r=o=[o,a,s,c]:(ku=r,r=i),(n=r!==i?e.substring(n,ku):r)!==i?(Iu=t,t=wu(n)):(ku=t,t=i)):(ku=t,t=i),t}function yn(){var t;return pe.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu(wt)),t}function Sn(){var t;return Ae.test(e.charAt(ku))?(t=e.charAt(ku),ku++):(t=i,0===Uu&&Vu($t)),t}function bn(){var t,u,n,r;return Uu++,t=ku,123===e.charCodeAt(ku)?(u=p,ku++):(u=i,0===Uu&&Vu(ve)),u!==i?(n=function(){var e,t;return e=ku,t=Pn(),Iu=e,e=t=Ru(t)}(),125===e.charCodeAt(ku)?(r=A,ku++):(r=i,0===Uu&&Vu(ye)),r!==i?t=n:(ku=t,t=i)):(ku=t,t=i),Uu--,t===i&&(u=i,0===Uu&&Vu(Lt)),t}function Pn(){var t,u,n,r,o,a;if(t=ku,u=[],n=[],r=ku,o=ku,Uu++,he.test(e.charAt(ku))?(a=e.charAt(ku),ku++):(a=i,0===Uu&&Vu(kt)),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i),r!==i)for(;r!==i;)n.push(r),r=ku,o=ku,Uu++,he.test(e.charAt(ku))?(a=e.charAt(ku),ku++):(a=i,0===Uu&&Vu(kt)),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);else n=i;for(n===i&&(n=ku,123===e.charCodeAt(ku)?(r=p,ku++):(r=i,0===Uu&&Vu(ve)),r!==i?(o=Pn(),125===e.charCodeAt(ku)?(a=A,ku++):(a=i,0===Uu&&Vu(ye)),a!==i?n=r=[r,o,a]:(ku=n,n=i)):(ku=n,n=i));n!==i;){if(u.push(n),n=[],r=ku,o=ku,Uu++,he.test(e.charAt(ku))?(a=e.charAt(ku),ku++):(a=i,0===Uu&&Vu(kt)),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i),r!==i)for(;r!==i;)n.push(r),r=ku,o=ku,Uu++,he.test(e.charAt(ku))?(a=e.charAt(ku),ku++):(a=i,0===Uu&&Vu(kt)),Uu--,a===i?o=void 0:(ku=o,o=i),o!==i&&(a=on())!==i?r=o=[o,a]:(ku=r,r=i);else n=i;n===i&&(n=ku,123===e.charCodeAt(ku)?(r=p,ku++):(r=i,0===Uu&&Vu(ve)),r!==i?(o=Pn(),125===e.charCodeAt(ku)?(a=A,ku++):(a=i,0===Uu&&Vu(ye)),a!==i?n=r=[r,o,a]:(ku=n,n=i)):(ku=n,n=i))}return e.substring(t,ku)}function On(){var e,t;for(e=[],(t=an())===i&&(t=cn())===i&&(t=ln());t!==i;)e.push(t),(t=an())===i&&(t=cn())===i&&(t=ln());return e}function wn(){var t,u,n,r;if(t=[],u=ku,n=On(),59===e.charCodeAt(ku)?(r=ce,ku++):(r=i,0===Uu&&Vu(Wt)),r!==i?u=n=[n,r]:(ku=u,u=i),u!==i)for(;u!==i;)t.push(u),u=ku,n=On(),59===e.charCodeAt(ku)?(r=ce,ku++):(r=i,0===Uu&&Vu(Wt)),r!==i?u=n=[n,r]:(ku=u,u=i);else t=i;return t===i&&(t=ku,u=function(){var e,t;for(e=[],(t=an())===i&&(t=pn());t!==i;)e.push(t),(t=an())===i&&(t=pn());return e}(),(n=An())===i&&(n=null),(r=cn())!==i?t=u=[u,n,r]:(ku=t,t=i),t===i&&(t=ku,u=On(),n=function(){var t,u;return t=ku,Uu++,e.length>ku?(u=e.charAt(ku),ku++):(u=i,0===Uu&&Vu(He)),Uu--,u===i?t=void 0:(ku=t,t=i),t}(),n!==i?t=u=[u,n]:(ku=t,t=i))),t}const $n=o.reservedWords||[];if((a=l())!==i&&ku===e.length)return a;throw a!==i&&ku{t[u]=e[u].slice()})),t}(i.compiler.passes),reservedWords:i.RESERVED_WORDS.slice()};return u.forEach((e=>{e.use(n,t)})),i.compiler.compile(n.parser.parse(e,{grammarSource:t.grammarSource,reservedWords:n.reservedWords}),n.passes,t)}};e.exports=i},244:function(e){"use strict";e.exports="3.0.2"},8276:function(e,t){class u{constructor(){this._array=[],this._set=new Map}static fromArray(e,t){const n=new u;for(let u=0,r=e.length;u=0)return t;throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e>>=5,r>0&&(t|=32),u+=n.encode(t)}while(r>0);return u}},6728:function(e,t){const u="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");t.encode=function(e){if(0<=e&&eu||r==u&&a>=o||n.compareByGeneratedPositionsInflated(e,t)<=0}(this._last,e)?(this._sorted=!1,this._array.push(e)):(this._last=e,this._array.push(e))}toArray(){return this._sorted||(this._array.sort(n.compareByGeneratedPositionsInflated),this._sorted=!0),this._array}}},1027:function(e,t,u){const n=u(2020),r=u(858),o=u(8276).I,a=u(2265).H;class i{constructor(e){e||(e={}),this._file=r.getArg(e,"file",null),this._sourceRoot=r.getArg(e,"sourceRoot",null),this._skipValidation=r.getArg(e,"skipValidation",!1),this._sources=new o,this._names=new o,this._mappings=new a,this._sourcesContents=null}static fromSourceMap(e){const t=e.sourceRoot,u=new i({file:e.file,sourceRoot:t});return e.eachMapping((function(e){const n={generated:{line:e.generatedLine,column:e.generatedColumn}};null!=e.source&&(n.source=e.source,null!=t&&(n.source=r.relative(t,n.source)),n.original={line:e.originalLine,column:e.originalColumn},null!=e.name&&(n.name=e.name)),u.addMapping(n)})),e.sources.forEach((function(n){let o=n;null!=t&&(o=r.relative(t,n)),u._sources.has(o)||u._sources.add(o);const a=e.sourceContentFor(n);null!=a&&u.setSourceContent(n,a)})),u}addMapping(e){const t=r.getArg(e,"generated"),u=r.getArg(e,"original",null);let n=r.getArg(e,"source",null),o=r.getArg(e,"name",null);this._skipValidation||this._validateMapping(t,u,n,o),null!=n&&(n=String(n),this._sources.has(n)||this._sources.add(n)),null!=o&&(o=String(o),this._names.has(o)||this._names.add(o)),this._mappings.add({generatedLine:t.line,generatedColumn:t.column,originalLine:u&&u.line,originalColumn:u&&u.column,source:n,name:o})}setSourceContent(e,t){let u=e;null!=this._sourceRoot&&(u=r.relative(this._sourceRoot,u)),null!=t?(this._sourcesContents||(this._sourcesContents=Object.create(null)),this._sourcesContents[r.toSetString(u)]=t):this._sourcesContents&&(delete this._sourcesContents[r.toSetString(u)],0===Object.keys(this._sourcesContents).length&&(this._sourcesContents=null))}applySourceMap(e,t,u){let n=t;if(null==t){if(null==e.file)throw new Error('SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, or the source map\'s "file" property. Both were omitted.');n=e.file}const a=this._sourceRoot;null!=a&&(n=r.relative(a,n));const i=this._mappings.toArray().length>0?new o:this._sources,s=new o;this._mappings.unsortedForEach((function(t){if(t.source===n&&null!=t.originalLine){const n=e.originalPositionFor({line:t.originalLine,column:t.originalColumn});null!=n.source&&(t.source=n.source,null!=u&&(t.source=r.join(u,t.source)),null!=a&&(t.source=r.relative(a,t.source)),t.originalLine=n.line,t.originalColumn=n.column,null!=n.name&&(t.name=n.name))}const o=t.source;null==o||i.has(o)||i.add(o);const c=t.name;null==c||s.has(c)||s.add(c)}),this),this._sources=i,this._names=s,e.sources.forEach((function(t){const n=e.sourceContentFor(t);null!=n&&(null!=u&&(t=r.join(u,t)),null!=a&&(t=r.relative(a,t)),this.setSourceContent(t,n))}),this)}_validateMapping(e,t,u,n){if(t&&"number"!=typeof t.line&&"number"!=typeof t.column)throw new Error("original.line and original.column are not numbers -- you probably meant to omit the original mapping entirely and only map the generated position. If so, pass null for the original mapping instead of an object with empty or null values.");if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!t&&!u&&!n);else if(!(e&&"line"in e&&"column"in e&&t&&"line"in t&&"column"in t&&e.line>0&&e.column>=0&&t.line>0&&t.column>=0&&u))throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:u,original:t,name:n}))}_serializeMappings(){let e,t,u,o,a=0,i=1,s=0,c=0,l=0,p=0,A="";const h=this._mappings.toArray();for(let d=0,E=h.length;d0){if(!r.compareByGeneratedPositionsInflated(t,h[d-1]))continue;e+=","}e+=n.encode(t.generatedColumn-a),a=t.generatedColumn,null!=t.source&&(o=this._sources.indexOf(t.source),e+=n.encode(o-p),p=o,e+=n.encode(t.originalLine-1-c),c=t.originalLine-1,e+=n.encode(t.originalColumn-s),s=t.originalColumn,null!=t.name&&(u=this._names.indexOf(t.name),e+=n.encode(u-l),l=u)),A+=e}return A}_generateSourcesContent(e,t){return e.map((function(e){if(!this._sourcesContents)return null;null!=t&&(e=r.relative(t,e));const u=r.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,u)?this._sourcesContents[u]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};return null!=this._file&&(e.file=this._file),null!=this._sourceRoot&&(e.sourceRoot=this._sourceRoot),this._sourcesContents&&(e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)),e}toString(){return JSON.stringify(this.toJSON())}}i.prototype._version=3,t.SourceMapGenerator=i},1018:function(e,t,u){const n=u(1027).SourceMapGenerator,r=u(858),o=/(\r?\n)/,a="$$$isSourceNode$$$";class i{constructor(e,t,u,n,r){this.children=[],this.sourceContents={},this.line=null==e?null:e,this.column=null==t?null:t,this.source=null==u?null:u,this.name=null==r?null:r,this[a]=!0,null!=n&&this.add(n)}static fromStringWithSourceMap(e,t,u){const n=new i,a=e.split(o);let s=0;const c=function(){return e()+(e()||"");function e(){return s=0;t--)this.prepend(e[t]);else{if(!e[a]&&"string"!=typeof e)throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e);this.children.unshift(e)}return this}walk(e){let t;for(let u=0,n=this.children.length;u0){for(t=[],u=0;u=0;u--)if(36!==e.charCodeAt(u))return!1;return!0}function o(e,t){return e===t?0:null===e?1:null===t?-1:e>t?1:-1}t.toSetString=u?n:function(e){return r(e)?"$"+e:e},t.fromSetString=u?n:function(e){return r(e)?e.slice(1):e},t.compareByGeneratedPositionsInflated=function(e,t){let u=e.generatedLine-t.generatedLine;return 0!==u?u:(u=e.generatedColumn-t.generatedColumn,0!==u?u:(u=o(e.source,t.source),0!==u?u:(u=e.originalLine-t.originalLine,0!==u?u:(u=e.originalColumn-t.originalColumn,0!==u?u:o(e.name,t.name)))))};const a="http://host";function i(e){return t=>{const u=p(t),n=c(t),r=new URL(t,n);e(r);const o=r.toString();return"absolute"===u?o:"scheme-relative"===u?o.slice(5):"path-absolute"===u?o.slice(a.length):A(n,o)}}function s(e,t){return new URL(e,t).toString()}function c(e){const t=e.split("..").length-1,u=function(e,t){let u=0;for(;;){const e="p"+u++;if(-1===t.indexOf(e))return e}}(0,e);let n=`${a}/`;for(let e=0;e0&&!n[n.length-1]&&n.pop();u.length>0&&n.length>0&&u[0]===n[0];)u.shift(),n.shift();return n.map((()=>"..")).concat(u).join("/")+t.search+t.hash}const h=i((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")})),d=i((e=>{}));t.normalize=d,t.join=function(e,t){const u=p(t),n=p(e);if(e=h(e),"absolute"===u)return s(t,void 0);if("absolute"===n)return s(t,e);if("scheme-relative"===u)return d(t);if("scheme-relative"===n)return s(t,s(e,a)).slice(5);if("path-absolute"===u)return d(t);if("path-absolute"===n)return s(t,s(e,a)).slice(a.length);const r=c(t+e);return A(r,s(t,s(e,r)))},t.relative=function(e,t){const u=function(e,t){if(p(e)!==p(t))return null;const u=c(e+t),n=new URL(e,u),r=new URL(t,u);try{new URL("",r.toString())}catch(e){return null}return r.protocol!==n.protocol||r.user!==n.user||r.password!==n.password||r.hostname!==n.hostname||r.port!==n.port?null:A(n,r)}(e,t);return"string"==typeof u?u:d(t)}},4738:function(e,t,u){t.SourceMapGenerator=u(1027).SourceMapGenerator,t.SourceNode=u(1018).SourceNode}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var u=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](u,u.exports,__webpack_require__),u.exports}var __webpack_exports__={};!function(){"use strict";var e=window.wp.blocks,t=window.wp.element;const u=__webpack_require__(4193).generate('\n{{\n\tfunction evaluateUnaryExpression( operator, operand ) {\n\t\tswitch ( operator ) {\n\t\t\tcase \'!\':\n\t\t\t\treturn !operand;\n\t\t\t\tbreak;\n\t\t\tcase \'-\':\n\t\t\t\treturn -operand;\n\t\t\t\tbreak;\n\t\t\tcase \'+\':\n\t\t\t\treturn +operand;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tfunction evaluateBinaryExpression( head, tail ) {\n\t\treturn tail.reduce( ( leftOperand, tailElement ) => {\n\t\t\tconst operator = tailElement[ 1 ];\n\t\t\tconst rightOperand = tailElement[ 3 ];\n\n\t\t\tswitch ( operator ) {\n\t\t\t\tcase \'&&\':\n\t\t\t\t\treturn leftOperand && rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'||\':\n\t\t\t\t\treturn leftOperand || rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'===\':\n\t\t\t\t\treturn leftOperand === rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'!==\':\n\t\t\t\t\treturn leftOperand !== rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'==\':\n\t\t\t\t\treturn leftOperand == rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'!=\':\n\t\t\t\t\treturn leftOperand != rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'<=\':\n\t\t\t\t\treturn leftOperand <= rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'<\':\n\t\t\t\t\treturn leftOperand < rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'>=\':\n\t\t\t\t\treturn leftOperand >= rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'>\':\n\t\t\t\t\treturn leftOperand > rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'+\':\n\t\t\t\t\treturn leftOperand + rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'-\':\n\t\t\t\t\treturn leftOperand - rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'*\':\n\t\t\t\t\treturn leftOperand * rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'/\':\n\t\t\t\t\treturn leftOperand / rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'%\':\n\t\t\t\t\treturn leftOperand % rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn undefined;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}, head );\n\t}\n\n\tfunction getPropertyValue( obj, propertyName ) {\n\t\tif ( Object.hasOwn( obj, propertyName ) ) {\n\t\t\treturn obj[ propertyName ];\n\t\t} else if (\n\t\t\tArray.isArray( obj ) &&\n\t\t\tobj.length > 0 &&\n\t\t\tObject.hasOwn( obj[ 0 ], \'key\' ) &&\n\t\t\tObject.hasOwn( obj[ 0 ], \'value\' )\n\t\t) {\n\t\t\t// We likely dealing with an array of objects with key/value pairs (like post meta data)\n\t\t\tconst item = obj.find( ( item ) => item.key === propertyName );\n\t\t\treturn item?.value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}}\n\nStart\n\t= Expression\n\nSourceCharacter\n\t= .\n\nWhiteSpace\n\t= " "\n\t/ "\\t"\n\nLineTerminator\n\t= "\\n"\n\t/ "\\r"\n\t/ "\\u2028"\n\t/ "\\u2029"\n\nLineTerminatorSequence\n\t= "\\n"\n\t/ "\\r\\n"\n\t/ "\\r"\n\t/ "\\u2028"\n\t/ "\\u2029"\n\nComment "comment"\n\t= MultiLineComment\n\nMultiLineComment\n\t= "/*" (!"*/" SourceCharacter)* "*/"\n\n__ "skipped"\n\t= (WhiteSpace / LineTerminatorSequence / Comment)*\n\nIdentifierPath\n\t= variable:Identifier accessor:(__ "." __ Identifier)* {\n\t\tconst path = variable.split( \'.\' );\n\t\tlet result = path.reduce( getPropertyValue, options.context );\n\n\t\tfor ( let i = 0; i < accessor.length; i++ ) {\n\t\t\tresult = getPropertyValue( result, accessor[ i ][ 3 ] );\n\t\t}\n\n\t\treturn result;\n\t}\n\nIdentifier\n\t= !ReservedWord name:IdentifierName {\n\t\treturn name;\n\t}\n\nIdentifierName\n\t= first:IdentifierStart rest:IdentifierPart* {\n\t\treturn text();\n\t}\n\nIdentifierStart\n\t= [a-zA-Z]\n\t/ "_"\n\t/ "$"\n\nIdentifierPart\n\t= IdentifierStart\n\nReservedWord\n\t= NullLiteral\n\t/ BooleanLiteral\n\n// Literals\n\nLiteral\n\t= NullLiteral\n\t/ BooleanLiteral\n\t/ NumericLiteral\n\t/ StringLiteral\n\nNullLiteral\n\t= NullToken { return null; }\n\nBooleanLiteral\n\t= "true" { return true; }\n\t/ "false" { return false; }\n\nNumericLiteral\n\t= literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) {\n\t\treturn literal;\n\t}\n\t/ literal:DecimalLiteral !(IdentifierStart / DecimalDigit) {\n\t\treturn literal;\n\t}\n\nHexIntegerLiteral\n\t= "0x"i digits:$HexDigit+ {\n\t\treturn parseInt( digits, 16 );\n\t}\n\nHexDigit\n\t= [0-9a-f]i\n\nDecimalLiteral\n\t= DecimalIntegerLiteral "." DecimalDigit* ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\t/ "." DecimalDigit+ ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\t/ DecimalIntegerLiteral ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\nDecimalIntegerLiteral\n\t= "0"\n\t/ NonZeroDigit DecimalDigit*\n\nDecimalDigit\n\t= [0-9]\n\nNonZeroDigit\n\t= [1-9]\n\nExponentPart\n\t= ExponentIndicator SignedInteger\n\nExponentIndicator\n\t= "e"i\n\nSignedInteger\n\t= [+-]? DecimalDigit+\n\nStringLiteral\n\t= \'"\' chars:DoubleQuotedStringCharacter* \'"\' {\n\t\treturn chars.join( \'\' );\n\t}\n\t/ "\'" chars:SingleQuotedStringCharacter* "\'" {\n\t\treturn chars.join( \'\' );\n\t}\n\nDoubleQuotedStringCharacter\n\t= !(\'"\' / "\\\\" / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\t/ "\\\\" escapeSequence:EscapeSequence {\n\t\treturn escapeSequence;\n\t}\n\t/ LineContinuation\n\nSingleQuotedStringCharacter\n\t= !("\'" / "\\\\" / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\t/ "\\\\" escapeSequence:EscapeSequence {\n\t\treturn escapeSequence;\n\t}\n\t/ LineContinuation\n\nLineContinuation\n\t= "\\\\" LineTerminatorSequence {\n\t\treturn \'\';\n\t}\n\nEscapeSequence\n\t= CharacterEscapeSequence\n\t/ "0" !DecimalDigit {\n\t\treturn "\\0";\n\t}\n\t/ HexEscapeSequence\n\t/ UnicodeEscapeSequence\n\nCharacterEscapeSequence\n\t= SingleEscapeCharacter\n\t/ NonEscapeCharacter\n\nSingleEscapeCharacter\n\t= "\'"\n\t/ \'"\'\n\t/ "\\\\"\n\t/ "b" {\n\t\treturn "\\b";\n\t}\n\t/ "f" {\n\t\treturn "\\f";\n\t}\n\t/ "n" {\n\t\treturn "\\n";\n\t}\n\t/ "r" {\n\t\treturn "\\r";\n\t}\n\t/ "t" {\n\t\treturn "\\t";\n\t}\n\t/ "v" {\n\t\treturn "\\v";\n\t}\n\nNonEscapeCharacter\n\t= (!EscapeCharacter / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\nEscapeCharacter\n\t= SingleEscapeCharacter\n\t/ DecimalDigit\n\t/ "x"\n\t/ "u"\n\nHexEscapeSequence\n\t= "x" digits:$(HexDigit HexDigit) {\n\t\treturn String.fromCharCode( parseInt( digits, 16 ) );\n\t}\n\nUnicodeEscapeSequence\n\t= "u" digits:$(HexDigit HexDigit HexDigit HexDigit) {\n\t\treturn String.fromCharCode( parseInt( digits, 16 ) );\n\t}\n\n// Tokens\n\nNullToken\n\t= "null" !IdentifierPart\n\nTrueToken\n\t= "true" !IdentifierPart\n\nFalseToken\n\t= "false" !IdentifierPart\n\n// Expressions\n\nPrimaryExpression\n\t= IdentifierPath\n\t/ Literal\n\t/ "(" __ expression:Expression __ ")" {\n\t\treturn expression;\n\t}\n\nUnaryExpression\n\t= PrimaryExpression\n\t/ operator:UnaryOperator __ operand:UnaryExpression {\n\t\treturn evaluateUnaryExpression( operator, operand );\n\t}\n\nUnaryOperator\n\t= "!"\n\t/ "-"\n\t/ "+"\n\nMultiplicativeExpression\n\t= head:UnaryExpression tail:(__ MultiplicativeOperator __ UnaryExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nMultiplicativeOperator\n\t= "*"\n\t/ "/"\n\t/ "%"\n\nAdditiveExpression\n\t= head:MultiplicativeExpression tail:(__ AdditiveOperator __ MultiplicativeExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nAdditiveOperator\n\t= "+"\n\t/ "-"\n\nRelationalExpression\n\t= head:AdditiveExpression tail:(__ RelationalOperator __ AdditiveExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nRelationalOperator\n\t= "<="\n\t/ "<"\n\t/ ">="\n\t/ ">"\n\nEqualityExpression\n\t= head:RelationalExpression tail:(__ EqualityOperator __ RelationalExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nEqualityOperator\n\t= "==="\n\t/ "!=="\n\t/ "=="\n\t/ "!="\n\nLogicalAndExpression\n\t= head:EqualityExpression tail:(__ LogicalAndOperator __ EqualityExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nLogicalAndOperator\n\t= "&&"\n\nLogicalOrExpression\n\t= head:LogicalAndExpression tail:(__ LogicalOrOperator __ LogicalAndExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nLogicalOrOperator\n\t= "||"\n\nConditionalExpression\n\t= condition:LogicalOrExpression __ ConditionalTrueOperator __ expressionIfTrue:ConditionalExpression __ ConditionalFalseOperator __ expressionIfFalse:ConditionalExpression {\n\t\treturn condition ? expressionIfTrue : expressionIfFalse;\n\t}\n\t/ LogicalOrExpression\n\nConditionalTrueOperator\n\t= "?"\n\nConditionalFalseOperator\n\t= ":"\n\nExpression\n\t= __ expression:ConditionalExpression __ {\n\t\treturn expression;\n\t}\n');function n(e,t={}){return u.parse(e,{context:t})}var r=window.wp.data;function o(e){return{getEvaluationContext:()=>e}}function a(e,u){return o=>{const{context:a}=o,{_templateBlockHideConditions:i,_templateBlockDisableConditions:s}=o.attributes,{getEvaluationContext:c}=u(a),{shouldHide:l,shouldDisable:p}=(0,r.useSelect)((e=>{const t=c(e);return{shouldHide:i&&Array.isArray(i)&&i.some((e=>n(e.expression,t))),shouldDisable:s&&Array.isArray(s)&&s.some((e=>n(e.expression,t)))}}),[c,i,s]);return!e||l?null:(0,t.createElement)(e,{...o,attributes:{...o.attributes,disabled:o.attributes.disabled||p}})}}var i=window.wp.coreData;function s(e){const{postType:t}=e,u=(0,i.useEntityId)("postType",t);return{getEvaluationContext:n=>{const r=n("core").getEditedEntityRecord("postType",t,u);return{...e,editedProduct:r}}}}var c=window.React,l=window.wp.blockEditor,p=window.wp.components,A=window.wp.i18n,h=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"woocommerce-pre-orders/date-time-picker","version":"0.1.0","title":"Date-time picker","category":"widgets","icon":"flag","description":"A block to select the date-time","attributes":{"property":{"type":"string","default":""},"title":{"type":"string","default":""},"help":{"type":"string","default":""},"date":{"type":"object","default":null}},"supports":{"html":false,"inserter":false},"textdomain":"woocommerce-pre-orders","editorScript":"file:./index.js"}');const{name:d,...E}=h;!function(t){const{metadata:u,settings:n,name:r}=t;var i;!function(t,u){if(!t)return;const{metadata:n,settings:r,name:i}=t,{edit:s}=r;if(!s)return;const c={...n,attributes:(l=n.attributes,{...l,_templateBlockId:{type:"string",__experimentalRole:"content"},_templateBlockOrder:{type:"integer",__experimentalRole:"content"},_templateBlockHideConditions:{type:"array",__experimentalRole:"content"},_templateBlockDisableConditions:{type:"array",__experimentalRole:"content"},disabled:l.disabled||{type:"boolean",__experimentalRole:"content"}})};var l;(0,e.registerBlockType)({name:i,...c},{...r,edit:a(s,null!=u?u:o)})}({name:r,metadata:{...u,usesContext:(i=u.usesContext,[...i||[],"postType"])},settings:n},s)}({name:d,metadata:E,settings:{example:{},edit:function({attributes:e,context:{postType:u}}){const n=((e,t={})=>{const u={"data-template-block-id":e._templateBlockId,"data-template-block-order":e._templateBlockOrder,tabIndex:-1,...t};return(0,l.useBlockProps)(u)})(e),{title:r,property:o,help:a,date:s,disabled:h}=e,[d,E]=function(e,t){var u;const n=e.startsWith("meta_data."),r=e.replace("meta_data.",""),[o,a]=(0,i.useEntityProp)("postType",(null==t?void 0:t.postType)||"product",e),[s,c]=(0,i.useEntityProp)("postType",(null==t?void 0:t.postType)||"product","meta_data");return[n?(null===(u=s.find((e=>e.key===r)))||void 0===u?void 0:u.value)||(null==t?void 0:t.fallbackValue):o,n?e=>{const t=s.find((e=>e.key===r)),u=t?{...t,value:e}:{key:r,value:e};c([...s.filter((e=>e.key!==r)),u])}:a]}(o,{postType:u}),[f,C]=(0,t.useState)(!1);function g(e){const t=new Date(e);return isNaN(t)?"":`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}return(0,c.createElement)("div",{...n},(0,c.createElement)(p.BaseControl,{label:r,help:a},(0,c.createElement)(p.Flex,null,(0,c.createElement)(p.FlexItem,{isBlock:!0},(0,c.createElement)(p.TextControl,{onFocus:()=>C(!0),autoComplete:"off",placeholder:"YYYY-MM-DD HH:MM",value:g(d)||"",disabled:h})),(0,c.createElement)(p.FlexItem,null,(0,c.createElement)(p.Button,{variant:"link",disabled:h,onClick:()=>E("")},(0,A.__)("Clear","woocommerce-pre-orders"))))),f&&(0,c.createElement)(p.Popover,{onFocusOutside:()=>C(!1)},(0,c.createElement)(p.Card,null,(0,c.createElement)(p.CardBody,null,(0,c.createElement)(p.DateTimePicker,{currentDate:d?new Date(d).toISOString():"",onChange:e=>{E(g(e))}})))))}}})}()})();
\ No newline at end of file
diff --git a/build/admin/blocks/message-control/block.json b/build/admin/blocks/message-control/block.json
new file mode 100644
index 0000000..6b37971
--- /dev/null
+++ b/build/admin/blocks/message-control/block.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "woocommerce-pre-orders/message-control-block",
+ "version": "0.1.0",
+ "title": "Message Block",
+ "category": "widgets",
+ "icon": "flag",
+ "description": "A block to display messages in plain-text or HTML.",
+ "attributes": {
+ "content": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ "supports": {
+ "html": true,
+ "inserter": false
+ },
+ "textdomain": "woocommerce-pre-orders",
+ "editorScript": "file:./index.js"
+}
\ No newline at end of file
diff --git a/build/admin/blocks/message-control/index.asset.php b/build/admin/blocks/message-control/index.asset.php
new file mode 100644
index 0000000..4698531
--- /dev/null
+++ b/build/admin/blocks/message-control/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-core-data', 'wp-data', 'wp-element'), 'version' => '09de37f4709db0e17ea7678752904a87');
\ No newline at end of file
diff --git a/build/admin/blocks/message-control/index.js b/build/admin/blocks/message-control/index.js
new file mode 100644
index 0000000..ad6a360
--- /dev/null
+++ b/build/admin/blocks/message-control/index.js
@@ -0,0 +1 @@
+(function(){var __webpack_modules__={9960:function(e,t){"use strict";var n;Object.defineProperty(t,"__esModule",{value:!0}),t.Doctype=t.CDATA=t.Tag=t.Style=t.Script=t.Comment=t.Directive=t.Text=t.Root=t.isTag=t.ElementType=void 0,function(e){e.Root="root",e.Text="text",e.Directive="directive",e.Comment="comment",e.Script="script",e.Style="style",e.Tag="tag",e.CDATA="cdata",e.Doctype="doctype"}(n=t.ElementType||(t.ElementType={})),t.isTag=function(e){return e.type===n.Tag||e.type===n.Script||e.type===n.Style},t.Root=n.Root,t.Text=n.Text,t.Directive=n.Directive,t.Comment=n.Comment,t.Script=n.Script,t.Style=n.Style,t.Tag=n.Tag,t.CDATA=n.CDATA,t.Doctype=n.Doctype},885:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CASE_SENSITIVE_TAG_NAMES_MAP=t.CASE_SENSITIVE_TAG_NAMES=void 0,t.CASE_SENSITIVE_TAG_NAMES=["animateMotion","animateTransform","clipPath","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","foreignObject","linearGradient","radialGradient","textPath"],t.CASE_SENSITIVE_TAG_NAMES_MAP=t.CASE_SENSITIVE_TAG_NAMES.reduce((function(e,t){return e[t.toLowerCase()]=t,e}),{})},2260:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="html",r="head",u="body",o=/<([a-zA-Z]+[0-9]?)/,i=//i,a=//i,s=function(e,t){throw new Error("This browser does not support `document.implementation.createHTMLDocument`")},c=function(e,t){throw new Error("This browser does not support `DOMParser.prototype.parseFromString`")},l="object"==typeof window&&window.DOMParser;if("function"==typeof l){var p=new l;s=c=function(e,t){return t&&(e="<".concat(t,">").concat(e,"").concat(t,">")),p.parseFromString(e,"text/html")}}if("object"==typeof document&&document.implementation){var d=document.implementation.createHTMLDocument();s=function(e,t){if(t){var n=d.documentElement.querySelector(t);return n&&(n.innerHTML=e),d}return d.documentElement.innerHTML=e,d}}var h,f="object"==typeof document&&document.createElement("template");f&&f.content&&(h=function(e){return f.innerHTML=e,f.content.childNodes}),t.default=function(e){var t,l,p=e.match(o),d=p&&p[1]?p[1].toLowerCase():"";switch(d){case n:var f=c(e);return i.test(e)||null===(t=null==(m=f.querySelector(r))?void 0:m.parentNode)||void 0===t||t.removeChild(m),a.test(e)||null===(l=null==(m=f.querySelector(u))?void 0:m.parentNode)||void 0===l||l.removeChild(m),f.querySelectorAll(n);case r:case u:var A=s(e).querySelectorAll(d);return a.test(e)&&i.test(e)?A[0].parentNode.childNodes:A;default:return h?h(e):(m=s(e,u).querySelector(u)).childNodes;var m}}},4152:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var u=r(n(2260)),o=n(1507),i=/<(![a-zA-Z\s]+)>/;t.default=function(e){if("string"!=typeof e)throw new TypeError("First argument must be a string");if(!e)return[];var t=e.match(i),n=t?t[1]:void 0;return(0,o.formatDOM)((0,u.default)(e),null,n)}},1507:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatDOM=t.formatAttributes=void 0;var r=n(4584),u=n(885);function o(e){for(var t={},n=0,r=e.length;n0?this.children[this.children.length-1]:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"childNodes",{get:function(){return this.children},set:function(e){this.children=e},enumerable:!1,configurable:!0}),t}(a);t.NodeWithChildren=d;var h=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.CDATA,t}return u(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 4},enumerable:!1,configurable:!0}),t}(d);t.CDATA=h;var f=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.Root,t}return u(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 9},enumerable:!1,configurable:!0}),t}(d);t.Document=f;var A=function(e){function t(t,n,r,u){void 0===r&&(r=[]),void 0===u&&(u="script"===t?i.ElementType.Script:"style"===t?i.ElementType.Style:i.ElementType.Tag);var o=e.call(this,r)||this;return o.name=t,o.attribs=n,o.type=u,o}return u(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 1},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"tagName",{get:function(){return this.name},set:function(e){this.name=e},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"attributes",{get:function(){var e=this;return Object.keys(this.attribs).map((function(t){var n,r;return{name:t,value:e.attribs[t],namespace:null===(n=e["x-attribsNamespace"])||void 0===n?void 0:n[t],prefix:null===(r=e["x-attribsPrefix"])||void 0===r?void 0:r[t]}}))},enumerable:!1,configurable:!0}),t}(d);function m(e){return(0,i.isTag)(e)}function E(e){return e.type===i.ElementType.CDATA}function g(e){return e.type===i.ElementType.Text}function C(e){return e.type===i.ElementType.Comment}function y(e){return e.type===i.ElementType.Directive}function v(e){return e.type===i.ElementType.Root}function F(e,t){var n;if(void 0===t&&(t=!1),g(e))n=new c(e.data);else if(C(e))n=new l(e.data);else if(m(e)){var r=t?_(e.children):[],u=new A(e.name,o({},e.attribs),r);r.forEach((function(e){return e.parent=u})),null!=e.namespace&&(u.namespace=e.namespace),e["x-attribsNamespace"]&&(u["x-attribsNamespace"]=o({},e["x-attribsNamespace"])),e["x-attribsPrefix"]&&(u["x-attribsPrefix"]=o({},e["x-attribsPrefix"])),n=u}else if(E(e)){r=t?_(e.children):[];var i=new h(r);r.forEach((function(e){return e.parent=i})),n=i}else if(v(e)){r=t?_(e.children):[];var a=new f(r);r.forEach((function(e){return e.parent=a})),e["x-mode"]&&(a["x-mode"]=e["x-mode"]),n=a}else{if(!y(e))throw new Error("Not implemented yet: ".concat(e.type));var s=new p(e.name,e.data);null!=e["x-name"]&&(s["x-name"]=e["x-name"],s["x-publicId"]=e["x-publicId"],s["x-systemId"]=e["x-systemId"]),n=s}return n.startIndex=e.startIndex,n.endIndex=e.endIndex,null!=e.sourceCodeLocation&&(n.sourceCodeLocation=e.sourceCodeLocation),n}function _(e){for(var t=e.map((function(e){return F(e,!0)})),n=1;n1&&(E=p(E,{key:E.key||A})),r.push(c(E,m,A));continue}}if("text"!==m.type){var g=m,C={};s(g)?((0,i.setStyleProp)(g.attribs.style,g.attribs),C=g.attribs):g.attribs&&(C=(0,o.default)(g.attribs,g.name));var y=void 0;switch(m.type){case"script":case"style":m.children[0]&&(C.dangerouslySetInnerHTML={__html:m.children[0].data});break;case"tag":"textarea"===m.name&&m.children[0]?C.defaultValue=m.children[0].data:m.children&&m.children.length&&(y=e(m.children,n));break;default:continue}f>1&&(C.key=A),r.push(c(d(m.name,C,y),m,A))}else{var v=!m.data.trim().length;if(v&&m.parent&&!(0,i.canTextBeChildOfNode)(m.parent))continue;if((null==n?void 0:n.trim)&&v)continue;r.push(c(m.data,m,A))}}return 1===r.length?r[0]:r}},3426:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.htmlToDOM=t.domToReact=t.attributesToProps=t.Text=t.ProcessingInstruction=t.Element=t.Comment=void 0;var u=r(n(4152));t.htmlToDOM=u.default;var o=r(n(484));t.attributesToProps=o.default;var i=r(n(3670));t.domToReact=i.default;var a=n(7384);Object.defineProperty(t,"Comment",{enumerable:!0,get:function(){return a.Comment}}),Object.defineProperty(t,"Element",{enumerable:!0,get:function(){return a.Element}}),Object.defineProperty(t,"ProcessingInstruction",{enumerable:!0,get:function(){return a.ProcessingInstruction}}),Object.defineProperty(t,"Text",{enumerable:!0,get:function(){return a.Text}});var s={lowerCaseAttributeNames:!1};t.default=function(e,t){if("string"!=typeof e)throw new TypeError("First argument must be a string");return e?(0,i.default)((0,u.default)(e,(null==t?void 0:t.htmlparser2)||s),t):[]}},4606:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.returnFirstArg=t.canTextBeChildOfNode=t.ELEMENTS_WITH_NO_TEXT_CHILDREN=t.PRESERVE_CUSTOM_ATTRIBUTES=t.setStyleProp=t.isCustomComponent=void 0;var u=n(9196),o=r(n(1476)),i=new Set(["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"]);t.isCustomComponent=function(e,t){return e.includes("-")?!i.has(e):Boolean(t&&"string"==typeof t.is)};var a={reactCompat:!0};t.setStyleProp=function(e,t){if("string"==typeof e)if(e.trim())try{t.style=(0,o.default)(e,a)}catch(e){t.style={}}else t.style={}},t.PRESERVE_CUSTOM_ATTRIBUTES=Number(u.version.split(".")[0])>=16,t.ELEMENTS_WITH_NO_TEXT_CHILDREN=new Set(["tr","tbody","thead","tfoot","colgroup","table","head","html","frameset"]),t.canTextBeChildOfNode=function(e){return!t.ELEMENTS_WITH_NO_TEXT_CHILDREN.has(e.name)},t.returnFirstArg=function(e){return e}},7384:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var u=Object.getOwnPropertyDescriptor(t,n);u&&!("get"in u?!t.__esModule:u.writable||u.configurable)||(u={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,u)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),u=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),t.DomHandler=void 0;var o=n(9960),i=n(5079);u(n(5079),t);var a={withStartIndices:!1,withEndIndices:!1,xmlMode:!1},s=function(){function e(e,t,n){this.dom=[],this.root=new i.Document(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null,"function"==typeof t&&(n=t,t=a),"object"==typeof e&&(t=e,e=void 0),this.callback=null!=e?e:null,this.options=null!=t?t:a,this.elementCB=null!=n?n:null}return e.prototype.onparserinit=function(e){this.parser=e},e.prototype.onreset=function(){this.dom=[],this.root=new i.Document(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null},e.prototype.onend=function(){this.done||(this.done=!0,this.parser=null,this.handleCallback(null))},e.prototype.onerror=function(e){this.handleCallback(e)},e.prototype.onclosetag=function(){this.lastNode=null;var e=this.tagStack.pop();this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),this.elementCB&&this.elementCB(e)},e.prototype.onopentag=function(e,t){var n=this.options.xmlMode?o.ElementType.Tag:void 0,r=new i.Element(e,t,void 0,n);this.addNode(r),this.tagStack.push(r)},e.prototype.ontext=function(e){var t=this.lastNode;if(t&&t.type===o.ElementType.Text)t.data+=e,this.options.withEndIndices&&(t.endIndex=this.parser.endIndex);else{var n=new i.Text(e);this.addNode(n),this.lastNode=n}},e.prototype.oncomment=function(e){if(this.lastNode&&this.lastNode.type===o.ElementType.Comment)this.lastNode.data+=e;else{var t=new i.Comment(e);this.addNode(t),this.lastNode=t}},e.prototype.oncommentend=function(){this.lastNode=null},e.prototype.oncdatastart=function(){var e=new i.Text(""),t=new i.CDATA([e]);this.addNode(t),e.parent=t,this.lastNode=e},e.prototype.oncdataend=function(){this.lastNode=null},e.prototype.onprocessinginstruction=function(e,t){var n=new i.ProcessingInstruction(e,t);this.addNode(n)},e.prototype.handleCallback=function(e){if("function"==typeof this.callback)this.callback(e,this.dom);else if(e)throw e},e.prototype.addNode=function(e){var t=this.tagStack[this.tagStack.length-1],n=t.children[t.children.length-1];this.options.withStartIndices&&(e.startIndex=this.parser.startIndex),this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),t.children.push(e),n&&(e.prev=n,n.next=e),e.parent=t,this.lastNode=null},e}();t.DomHandler=s,t.default=s},5079:function(e,t,n){"use strict";var r,u=this&&this.__extends||(r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},r(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function __(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)}),o=this&&this.__assign||function(){return o=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0?this.children[this.children.length-1]:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"childNodes",{get:function(){return this.children},set:function(e){this.children=e},enumerable:!1,configurable:!0}),t}(a);t.NodeWithChildren=d;var h=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.CDATA,t}return u(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 4},enumerable:!1,configurable:!0}),t}(d);t.CDATA=h;var f=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.Root,t}return u(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 9},enumerable:!1,configurable:!0}),t}(d);t.Document=f;var A=function(e){function t(t,n,r,u){void 0===r&&(r=[]),void 0===u&&(u="script"===t?i.ElementType.Script:"style"===t?i.ElementType.Style:i.ElementType.Tag);var o=e.call(this,r)||this;return o.name=t,o.attribs=n,o.type=u,o}return u(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 1},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"tagName",{get:function(){return this.name},set:function(e){this.name=e},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"attributes",{get:function(){var e=this;return Object.keys(this.attribs).map((function(t){var n,r;return{name:t,value:e.attribs[t],namespace:null===(n=e["x-attribsNamespace"])||void 0===n?void 0:n[t],prefix:null===(r=e["x-attribsPrefix"])||void 0===r?void 0:r[t]}}))},enumerable:!1,configurable:!0}),t}(d);function m(e){return(0,i.isTag)(e)}function E(e){return e.type===i.ElementType.CDATA}function g(e){return e.type===i.ElementType.Text}function C(e){return e.type===i.ElementType.Comment}function y(e){return e.type===i.ElementType.Directive}function v(e){return e.type===i.ElementType.Root}function F(e,t){var n;if(void 0===t&&(t=!1),g(e))n=new c(e.data);else if(C(e))n=new l(e.data);else if(m(e)){var r=t?_(e.children):[],u=new A(e.name,o({},e.attribs),r);r.forEach((function(e){return e.parent=u})),null!=e.namespace&&(u.namespace=e.namespace),e["x-attribsNamespace"]&&(u["x-attribsNamespace"]=o({},e["x-attribsNamespace"])),e["x-attribsPrefix"]&&(u["x-attribsPrefix"]=o({},e["x-attribsPrefix"])),n=u}else if(E(e)){r=t?_(e.children):[];var i=new h(r);r.forEach((function(e){return e.parent=i})),n=i}else if(v(e)){r=t?_(e.children):[];var a=new f(r);r.forEach((function(e){return e.parent=a})),e["x-mode"]&&(a["x-mode"]=e["x-mode"]),n=a}else{if(!y(e))throw new Error("Not implemented yet: ".concat(e.type));var s=new p(e.name,e.data);null!=e["x-name"]&&(s["x-name"]=e["x-name"],s["x-publicId"]=e["x-publicId"],s["x-systemId"]=e["x-systemId"]),n=s}return n.startIndex=e.startIndex,n.endIndex=e.endIndex,null!=e.sourceCodeLocation&&(n.sourceCodeLocation=e.sourceCodeLocation),n}function _(e){for(var t=e.map((function(e){return F(e,!0)})),n=1;n1&&e.delimiter&&i(e.delimiter)))},semantic_and:o,semantic_not:o,rule_ref(t){const n=u.findRule(e,t.name);return n?i(n):void 0},literal(e){return""!==e.value},class:n,any:n});return i(t)}};e.exports=u},9203:function(module,__unused_webpack_exports,__webpack_require__){"use strict";const generateBytecode=__webpack_require__(2886),generateJS=__webpack_require__(5843),inferenceMatchResult=__webpack_require__(5412),removeProxyRules=__webpack_require__(2929),reportDuplicateLabels=__webpack_require__(6734),reportDuplicateRules=__webpack_require__(1117),reportInfiniteRecursion=__webpack_require__(730),reportInfiniteRepetition=__webpack_require__(9505),reportUndefinedRules=__webpack_require__(1442),reportIncorrectPlucking=__webpack_require__(6237),Session=__webpack_require__(425),visitor=__webpack_require__(8202),{base64:base64}=__webpack_require__(6443);function processOptions(e,t){const n={};return Object.keys(e).forEach((t=>{n[t]=e[t]})),Object.keys(t).forEach((e=>{Object.prototype.hasOwnProperty.call(n,e)||(n[e]=t[e])})),n}function isSourceMapCapable(e){return"string"==typeof e?e.length>0:e&&"function"==typeof e.offset}const compiler={visitor:visitor,passes:{check:[reportUndefinedRules,reportDuplicateRules,reportDuplicateLabels,reportInfiniteRecursion,reportInfiniteRepetition,reportIncorrectPlucking],transform:[removeProxyRules,inferenceMatchResult],generate:[generateBytecode,generateJS]},compile(ast,passes,options){if(options=void 0!==options?options:{},options=processOptions(options,{allowedStartRules:[ast.rules[0].name],cache:!1,dependencies:{},exportVar:null,format:"bare",output:"parser",trace:!1}),!Array.isArray(options.allowedStartRules))throw new Error("allowedStartRules must be an array");if(0===options.allowedStartRules.length)throw new Error("Must have at least one start rule");const allRules=ast.rules.map((e=>e.name));if(options.allowedStartRules.some((e=>"*"===e)))options.allowedStartRules=allRules;else for(const e of options.allowedStartRules)if(-1===allRules.indexOf(e))throw new Error(`Unknown start rule "${e}"`);if(("source-and-map"===options.output||"source-with-inline-map"===options.output)&&!isSourceMapCapable(options.grammarSource))throw new Error("Must provide grammarSource (as a string or GrammarLocation) in order to generate source maps");const session=new Session(options);switch(Object.keys(passes).forEach((e=>{session.stage=e,session.info(`Process stage ${e}`),passes[e].forEach((t=>{session.info(`Process pass ${e}.${t.name}`),t(ast,options,session)})),session.checkErrors()})),options.output){case"parser":return eval(ast.code.toString());case"source":return ast.code.toString();case"source-and-map":return ast.code;case"source-with-inline-map":{if("undefined"==typeof TextEncoder)throw new Error("TextEncoder is not supported by this platform");const e=ast.code.toStringWithSourceMap(),t=new TextEncoder,n=base64(t.encode(JSON.stringify(e.map.toJSON())));return e.code+`//# sourceMappingURL=data:application/json;charset=utf-8;base64,${n}\n`}case"ast":return ast;default:throw new Error("Invalid output format: "+options.output+".")}}};module.exports=compiler},6164:function(e){"use strict";e.exports={PUSH:0,PUSH_EMPTY_STRING:35,PUSH_UNDEFINED:1,PUSH_NULL:2,PUSH_FAILED:3,PUSH_EMPTY_ARRAY:4,PUSH_CURR_POS:5,POP:6,POP_CURR_POS:7,POP_N:8,NIP:9,APPEND:10,WRAP:11,TEXT:12,PLUCK:36,IF:13,IF_ERROR:14,IF_NOT_ERROR:15,IF_LT:30,IF_GE:31,IF_LT_DYNAMIC:32,IF_GE_DYNAMIC:33,WHILE_NOT_ERROR:16,MATCH_ANY:17,MATCH_STRING:18,MATCH_STRING_IC:19,MATCH_CHAR_CLASS:20,MATCH_REGEXP:20,ACCEPT_N:21,ACCEPT_STRING:22,FAIL:23,LOAD_SAVED_POS:24,UPDATE_SAVED_POS:25,CALL:26,RULE:27,SILENT_FAILS_ON:28,SILENT_FAILS_OFF:29,SOURCE_MAP_PUSH:37,SOURCE_MAP_POP:38,SOURCE_MAP_LABEL_PUSH:39,SOURCE_MAP_LABEL_POP:40}},2886:function(e,t,n){"use strict";const r=n(9861),u=n(6164),o=n(8202),{ALWAYS_MATCH:i,SOMETIMES_MATCH:a,NEVER_MATCH:s}=n(5412);e.exports=function(e,t){const n=[],c=[],l=[],p=[],d=[];function h(e){const t=n.indexOf(e);return-1===t?n.push(e)-1:t}function f(e){const t=JSON.stringify(e),n=l.findIndex((e=>JSON.stringify(e)===t));return-1===n?l.push(e)-1:n}function A(e,t,n){const r={predicate:e,params:t,body:n.code,location:n.codeLocation},u=JSON.stringify(r),o=p.findIndex((e=>JSON.stringify(e)===u));return-1===o?p.push(r)-1:o}function m(e){return d.push(e)-1}function E(e){const t={};return Object.keys(e).forEach((n=>{t[n]=e[n]})),t}function g(e,...t){return e.concat(...t)}function C(e,t,n,r){return e===i?n:e===s?r:t.concat([n.length,r.length],n,r)}function y(e,t,n,r){const o=Object.keys(n).map((e=>r-n[e]));return[u.CALL,e,t,o.length].concat(o)}function v(e,t,n){const r=0|e.match;return g([u.PUSH_CURR_POS],[u.SILENT_FAILS_ON],D(e,{sp:n.sp+1,env:E(n.env),action:null}),[u.SILENT_FAILS_OFF],C(t?-r:r,[t?u.IF_ERROR:u.IF_NOT_ERROR],g([u.POP],[t?u.POP:u.POP_CURR_POS],[u.PUSH_UNDEFINED]),g([u.POP],[t?u.POP_CURR_POS:u.POP],[u.PUSH_FAILED])))}function F(e,t,n){const r=A(!0,Object.keys(n.env),e);return g([u.UPDATE_SAVED_POS],y(r,0,n.env,n.sp),C(0|e.match,[u.IF],g([u.POP],t?[u.PUSH_FAILED]:[u.PUSH_UNDEFINED]),g([u.POP],t?[u.PUSH_UNDEFINED]:[u.PUSH_FAILED])))}function _(e){return t=[u.WHILE_NOT_ERROR],n=g([u.APPEND],e),t.concat([n.length],n);var t,n}function x(e,t,n,r){switch(e.type){case"constant":return{pre:[],post:[],sp:n};case"variable":return e.sp=r+n-t[e.value],{pre:[],post:[],sp:n};case"function":return e.sp=r,{pre:y(A(!0,Object.keys(t),{code:e.value,codeLocation:e.codeLocation}),0,t,n),post:[u.NIP],sp:n+1};default:throw new Error(`Unknown boundary type "${e.type}" for the "repeated" node`)}}function b(e,t){if(null!==t.value){const n="constant"===t.type?[u.IF_GE,t.value]:[u.IF_GE_DYNAMIC,t.sp];return C(a,n,[u.PUSH_FAILED],e)}return e}const D=(B={grammar(e){e.rules.forEach(D),e.literals=n,e.classes=c,e.expectations=l,e.functions=p,e.locations=d},rule(e){e.bytecode=D(e.expression,{sp:-1,env:{},pluck:[],action:null})},named(e,t){const n=0|e.match,r=n===s?null:f({type:"rule",value:e.name});return g([u.SILENT_FAILS_ON],D(e.expression,t),[u.SILENT_FAILS_OFF],C(n,[u.IF_ERROR],[u.FAIL,r],[]))},choice(e,t){return function e(t,n){const r=0|t[0].match,o=D(t[0],{sp:n.sp,env:E(n.env),action:null});return r===i?o:g(o,t.length>1?C(a,[u.IF_ERROR],g([u.POP],e(t.slice(1),n)),[]):[])}(e.alternatives,t)},action(e,t){const n=E(t.env),r="sequence"!==e.expression.type||0===e.expression.elements.length,o=D(e.expression,{sp:t.sp+(r?1:0),env:n,action:e}),i=0|e.expression.match,a=r&&i!==s?A(!1,Object.keys(n),e):null;return r?g([u.PUSH_CURR_POS],o,C(i,[u.IF_NOT_ERROR],g([u.LOAD_SAVED_POS,1],y(a,1,n,t.sp+2)),[]),[u.NIP]):o},sequence(e,t){return g([u.PUSH_CURR_POS],function t(n,r){if(n.length>0){const o=e.elements.length-n.length+1;return g(D(n[0],{sp:r.sp,env:r.env,pluck:r.pluck,action:null}),C(0|n[0].match,[u.IF_NOT_ERROR],t(n.slice(1),{sp:r.sp+1,env:r.env,pluck:r.pluck,action:r.action}),g(o>1?[u.POP_N,o]:[u.POP],[u.POP_CURR_POS],[u.PUSH_FAILED])))}if(r.pluck.length>0)return g([u.PLUCK,e.elements.length+1,r.pluck.length],r.pluck.map((e=>r.sp-e)));if(r.action){const t=A(!1,Object.keys(r.env),r.action);return g([u.LOAD_SAVED_POS,e.elements.length],y(t,e.elements.length+1,r.env,r.sp))}return g([u.WRAP,e.elements.length],[u.NIP])}(e.elements,{sp:t.sp+1,env:t.env,pluck:[],action:t.action}))},labeled(e,n){let r=n.env;const o=e.label,i=n.sp+1;o&&(r=E(n.env),n.env[e.label]=i),e.pick&&n.pluck.push(i);const a=D(e.expression,{sp:n.sp,env:r,action:null});return o&&e.labelLocation&&t&&"source-and-map"===t.output?g([u.SOURCE_MAP_LABEL_PUSH,i,h(o),m(e.labelLocation)],a,[u.SOURCE_MAP_LABEL_POP,i]):a},text(e,t){return g([u.PUSH_CURR_POS],D(e.expression,{sp:t.sp+1,env:E(t.env),action:null}),C(0|e.match,[u.IF_NOT_ERROR],g([u.POP],[u.TEXT]),[u.NIP]))},simple_and(e,t){return v(e.expression,!1,t)},simple_not(e,t){return v(e.expression,!0,t)},optional(e,t){return g(D(e.expression,{sp:t.sp,env:E(t.env),action:null}),C(-(0|e.expression.match),[u.IF_ERROR],g([u.POP],[u.PUSH_NULL]),[]))},zero_or_more(e,t){const n=D(e.expression,{sp:t.sp+1,env:E(t.env),action:null});return g([u.PUSH_EMPTY_ARRAY],n,_(n),[u.POP])},one_or_more(e,t){const n=D(e.expression,{sp:t.sp+1,env:E(t.env),action:null});return g([u.PUSH_EMPTY_ARRAY],n,C(0|e.expression.match,[u.IF_NOT_ERROR],g(_(n),[u.POP]),g([u.POP],[u.POP],[u.PUSH_FAILED])))},repeated(e,t){const n=e.min?e.min:e.max,r="constant"!==n.type||n.value>0,o="constant"!==e.max.type&&null!==e.max.value,i=r?2:1,s=e.min?x(e.min,t.env,t.sp,2+("function"===e.max.type?1:0)):{pre:[],post:[],sp:t.sp},c=x(e.max,t.env,s.sp,i),l=D(e.expression,{sp:c.sp+i,env:E(t.env),action:null}),p=null!==e.delimiter?D(e.expression,{sp:c.sp+i+1,env:E(t.env),action:null}):l,d=function(e,t,n,r,o){return e?g([u.PUSH_CURR_POS],D(e,{sp:r.sp+o+1,env:E(r.env),action:null}),C(0|e.match,[u.IF_NOT_ERROR],g([u.POP],n,C(-t,[u.IF_ERROR],[u.POP,u.POP_CURR_POS,u.PUSH_FAILED],[u.NIP])),[u.NIP])):n}(e.delimiter,0|e.expression.match,p,t,i),h=b(d,e.max),f=o?b(l,e.max):l,A=g(r?[u.PUSH_CURR_POS]:[],[u.PUSH_EMPTY_ARRAY],f,_(h),[u.POP]);return g(s.pre,c.pre,r?function(e,t){const n="constant"===t.type?[u.IF_LT,t.value]:[u.IF_LT_DYNAMIC,t.sp];return g(e,C(a,n,[u.POP,u.POP_CURR_POS,u.PUSH_FAILED],[u.NIP]))}(A,n):A,c.post,s.post)},group(e,t){return D(e.expression,{sp:t.sp,env:E(t.env),action:null})},semantic_and(e,t){return F(e,!1,t)},semantic_not(e,t){return F(e,!0,t)},rule_ref(t){return[u.RULE,r.indexOfRule(e,t.name)]},literal(e){if(e.value.length>0){const t=0|e.match,n=t===a||t===i&&!e.ignoreCase?h(e.ignoreCase?e.value.toLowerCase():e.value):null,r=t!==i?f({type:"literal",value:e.value,ignoreCase:e.ignoreCase}):null;return C(t,e.ignoreCase?[u.MATCH_STRING_IC,n]:[u.MATCH_STRING,n],e.ignoreCase?[u.ACCEPT_N,e.value.length]:[u.ACCEPT_STRING,n],[u.FAIL,r])}return[u.PUSH_EMPTY_STRING]},class(e){const t=0|e.match,n=t===a?function(e){const t={value:e.parts,inverted:e.inverted,ignoreCase:e.ignoreCase},n=JSON.stringify(t),r=c.findIndex((e=>JSON.stringify(e)===n));return-1===r?c.push(t)-1:r}(e):null,r=t!==i?f({type:"class",value:e.parts,inverted:e.inverted,ignoreCase:e.ignoreCase}):null;return C(t,[u.MATCH_CHAR_CLASS,n],[u.ACCEPT_N,1],[u.FAIL,r])},any(e){const t=0|e.match,n=t!==i?f({type:"any"}):null;return C(t,[u.MATCH_ANY],[u.ACCEPT_N,1],[u.FAIL,n])}},t&&"source-and-map"===t.output&&Object.entries(B).forEach((([e,t])=>{B[e]=function(e,...n){const r=t(e,...n);return void 0!==r&&e.location?g([u.SOURCE_MAP_PUSH,m(e.location)],r,[u.SOURCE_MAP_POP]):r}})),o.build(B));var B;D(e)}},5843:function(e,t,n){"use strict";const r=n(9861),u=n(6164),o=n(8013),i=n(244),{stringEscape:a,regexpClassEscape:s}=n(6443),{SourceNode:c}=n(4738),l=n(2190);function p(e,t,n){const r=l.offsetStart(t),u=r.line,o=r.column-1,i=e.split("\n");return 1===i.length?new c(u,o,String(t.source),e,n):new c(null,null,String(t.source),i.map(((e,r)=>new c(u+r,0===r?o:0,String(t.source),r===i.length-1?e:[e,"\n"],n))))}function d(e,t,n,r,u){if(n){const o=l.offsetEnd(n);return new c(null,null,String(n.source),[e,p(t,n,u),new c(o.line,o.column-1,String(n.source),r)])}return new c(null,null,null,[e,t,r])}e.exports=function(e,t){function n(e){let t=!0,n=0;return function e(r){return Array.isArray(r)?r.map(e):r instanceof c?(n++,r.children=e(r.children),n--,r):(r=t?r.replace(/^(.+)$/gm," $1"):r.replace(/\n(\s*\S)/g,"\n $1"),t=!n||r.endsWith("\n"),r)}(e)}function l(e){return"peg$c"+e}function h(e){return"peg$r"+e}function f(e){return"peg$e"+e}function A(e){return"peg$f"+e}function m(e){return"peg$parse"+e}function E(e){return e.codeLocation?p(e.code,e.codeLocation,"$"+e.type):e.code}e.code=function(e){function r(){return[`// Generated by Peggy ${i}.`,"//","// https://peggyjs.org/"]}function u(){return t.trace?["{"," SyntaxError: peg$SyntaxError,"," DefaultTracer: peg$DefaultTracer,"," parse: peg$parse","}"].join("\n"):["{"," SyntaxError: peg$SyntaxError,"," parse: peg$parse","}"].join("\n")}const o={bare(){return[...r(),"(function() {",' "use strict";',"",e,"",n("return "+u()+";"),"})()"]},commonjs(){const n=Object.keys(t.dependencies),o=r();return o.push("",'"use strict";',""),n.length>0&&(n.forEach((e=>{o.push("var "+e+' = require("'+a(t.dependencies[e])+'");')})),o.push("")),o.push(e,"","module.exports = "+u()+";"),o},es(){const n=Object.keys(t.dependencies),u=r();return u.push(""),n.length>0&&(n.forEach((e=>{u.push("import "+e+' from "'+a(t.dependencies[e])+'";')})),u.push("")),u.push(e,"","export {"," peg$SyntaxError as SyntaxError,",t.trace?" peg$DefaultTracer as DefaultTracer,":""," peg$parse as parse","};"),u},amd(){const o=Object.keys(t.dependencies),i="["+o.map((e=>t.dependencies[e])).map((e=>'"'+a(e)+'"')).join(", ")+"]",s=o.join(", ");return[...r(),"define("+i+", function("+s+") {",' "use strict";',"",e,"",n("return "+u()+";"),"});"]},globals(){return[...r(),"(function(root) {",' "use strict";',"",e,"",n("root."+t.exportVar+" = "+u()+";"),"})(this);"]},umd(){const o=Object.keys(t.dependencies),i=o.map((e=>t.dependencies[e])),s="["+i.map((e=>'"'+a(e)+'"')).join(", ")+"]",c=i.map((e=>'require("'+a(e)+'")')).join(", "),l=o.join(", "),p=r();return p.push("(function(root, factory) {",' if (typeof define === "function" && define.amd) {'," define("+s+", factory);",' } else if (typeof module === "object" && module.exports) {'," module.exports = factory("+c+");"),null!==t.exportVar&&p.push(" } else {"," root."+t.exportVar+" = factory();"),p.push(" }","})(this, function("+l+") {",' "use strict";',"",e,"",n("return "+u()+";"),"});"),p}}[t.format]();return new c(null,null,t.grammarSource,o.map((e=>e instanceof c?e:e+"\n")))}(function(){const i=[];e.topLevelInitializer&&(i.push(E(e.topLevelInitializer)),i.push("")),i.push("function peg$subclass(child, parent) {"," function C() { this.constructor = child; }"," C.prototype = parent.prototype;"," child.prototype = new C();","}","","function peg$SyntaxError(message, expected, found, location) {"," var self = Error.call(this, message);"," // istanbul ignore next Check is a necessary evil to support older environments"," if (Object.setPrototypeOf) {"," Object.setPrototypeOf(self, peg$SyntaxError.prototype);"," }"," self.expected = expected;"," self.found = found;"," self.location = location;",' self.name = "SyntaxError";'," return self;","}","","peg$subclass(peg$SyntaxError, Error);","","function peg$padEnd(str, targetLength, padString) {",' padString = padString || " ";'," if (str.length > targetLength) { return str; }"," targetLength -= str.length;"," padString += padString.repeat(targetLength);"," return str + padString.slice(0, targetLength);","}","","peg$SyntaxError.prototype.format = function(sources) {",' var str = "Error: " + this.message;'," if (this.location) {"," var src = null;"," var k;"," for (k = 0; k < sources.length; k++) {"," if (sources[k].source === this.location.source) {"," src = sources[k].text.split(/\\r\\n|\\n|\\r/g);"," break;"," }"," }"," var s = this.location.start;",' var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))'," ? this.location.source.offset(s)"," : s;",' var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;'," if (src) {"," var e = this.location.end;"," var filler = peg$padEnd(\"\", offset_s.line.toString().length, ' ');"," var line = src[s.line - 1];"," var last = s.line === e.line ? e.column : line.length + 1;"," var hatLen = (last - s.column) || 1;",' str += "\\n --\x3e " + loc + "\\n"',' + filler + " |\\n"',' + offset_s.line + " | " + line + "\\n"',' + filler + " | " + peg$padEnd("", s.column - 1, \' \')',' + peg$padEnd("", hatLen, "^");'," } else {",' str += "\\n at " + loc;'," }"," }"," return str;","};","","peg$SyntaxError.buildMessage = function(expected, found) {"," var DESCRIBE_EXPECTATION_FNS = {"," literal: function(expectation) {",' return "\\"" + literalEscape(expectation.text) + "\\"";'," },",""," class: function(expectation) {"," var escapedParts = expectation.parts.map(function(part) {"," return Array.isArray(part)",' ? classEscape(part[0]) + "-" + classEscape(part[1])'," : classEscape(part);"," });","",' return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";'," },",""," any: function() {",' return "any character";'," },",""," end: function() {",' return "end of input";'," },",""," other: function(expectation) {"," return expectation.description;"," }"," };",""," function hex(ch) {"," return ch.charCodeAt(0).toString(16).toUpperCase();"," }",""," function literalEscape(s) {"," return s",' .replace(/\\\\/g, "\\\\\\\\")',' .replace(/"/g, "\\\\\\"")',' .replace(/\\0/g, "\\\\0")',' .replace(/\\t/g, "\\\\t")',' .replace(/\\n/g, "\\\\n")',' .replace(/\\r/g, "\\\\r")',' .replace(/[\\x00-\\x0F]/g, function(ch) { return "\\\\x0" + hex(ch); })',' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return "\\\\x" + hex(ch); });'," }",""," function classEscape(s) {"," return s",' .replace(/\\\\/g, "\\\\\\\\")',' .replace(/\\]/g, "\\\\]")',' .replace(/\\^/g, "\\\\^")',' .replace(/-/g, "\\\\-")',' .replace(/\\0/g, "\\\\0")',' .replace(/\\t/g, "\\\\t")',' .replace(/\\n/g, "\\\\n")',' .replace(/\\r/g, "\\\\r")',' .replace(/[\\x00-\\x0F]/g, function(ch) { return "\\\\x0" + hex(ch); })',' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return "\\\\x" + hex(ch); });'," }",""," function describeExpectation(expectation) {"," return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);"," }",""," function describeExpected(expected) {"," var descriptions = expected.map(describeExpectation);"," var i, j;",""," descriptions.sort();",""," if (descriptions.length > 0) {"," for (i = 1, j = 1; i < descriptions.length; i++) {"," if (descriptions[i - 1] !== descriptions[i]) {"," descriptions[j] = descriptions[i];"," j++;"," }"," }"," descriptions.length = j;"," }",""," switch (descriptions.length) {"," case 1:"," return descriptions[0];",""," case 2:",' return descriptions[0] + " or " + descriptions[1];',""," default:",' return descriptions.slice(0, -1).join(", ")',' + ", or "'," + descriptions[descriptions.length - 1];"," }"," }",""," function describeFound(found) {",' return found ? "\\"" + literalEscape(found) + "\\"" : "end of input";'," }","",' return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";',"};",""),t.trace&&i.push("function peg$DefaultTracer() {"," this.indentLevel = 0;","}","","peg$DefaultTracer.prototype.trace = function(event) {"," var that = this;",""," function log(event) {"," function repeat(string, n) {",' var result = "", i;',""," for (i = 0; i < n; i++) {"," result += string;"," }",""," return result;"," }",""," function pad(string, length) {",' return string + repeat(" ", length - string.length);'," }","",' if (typeof console === "object") {'," console.log(",' event.location.start.line + ":" + event.location.start.column + "-"',' + event.location.end.line + ":" + event.location.end.column + " "',' + pad(event.type, 10) + " "',' + repeat(" ", that.indentLevel) + event.rule'," );"," }"," }",""," switch (event.type) {",' case "rule.enter":'," log(event);"," this.indentLevel++;"," break;","",' case "rule.match":'," this.indentLevel--;"," log(event);"," break;","",' case "rule.fail":'," this.indentLevel--;"," log(event);"," break;",""," default:",' throw new Error("Invalid event type: " + event.type + ".");'," }","};","");const p="{ "+t.allowedStartRules.map((e=>e+": "+m(e))).join(", ")+" }",g=m(t.allowedStartRules[0]);return i.push("function peg$parse(input, options) {"," options = options !== undefined ? options : {};",""," var peg$FAILED = {};"," var peg$source = options.grammarSource;",""," var peg$startRuleFunctions = "+p+";"," var peg$startRuleFunction = "+g+";","",new c(null,null,t.grammarSource,[e.literals.map(((e,t)=>" var "+l(t)+' = "'+a(e)+'";')).concat("",e.classes.map(((e,t)=>{return" var "+h(t)+" = /^["+((n=e).inverted?"^":"")+n.value.map((e=>Array.isArray(e)?s(e[0])+"-"+s(e[1]):s(e))).join("")+"]/"+(n.ignoreCase?"i":"")+";";var n}))).concat("",e.expectations.map(((e,t)=>" var "+f(t)+" = "+function(e){switch(e.type){case"rule":return'peg$otherExpectation("'+a(e.value)+'")';case"literal":return'peg$literalExpectation("'+a(e.value)+'", '+e.ignoreCase+")";case"class":return"peg$classExpectation(["+e.value.map((e=>Array.isArray(e)?'["'+a(e[0])+'", "'+a(e[1])+'"]':'"'+a(e)+'"')).join(", ")+"], "+e.inverted+", "+e.ignoreCase+")";case"any":return"peg$anyExpectation()";default:throw new Error("Unknown expectation type ("+JSON.stringify(e)+")")}}(e)+";"))).concat("").join("\n"),e.functions.map((function(e,t){return d(`\n var ${A(t)} = function(${e.params.join(", ")}) {`,e.body,e.location,"};")}))]),""," var peg$currPos = 0;"," var peg$savedPos = 0;"," var peg$posDetailsCache = [{ line: 1, column: 1 }];"," var peg$maxFailPos = 0;"," var peg$maxFailExpected = [];"," var peg$silentFails = 0;",""),t.cache&&i.push(" var peg$resultsCache = {};",""),t.trace&&i.push(' var peg$tracer = "tracer" in options ? options.tracer : new peg$DefaultTracer();',""),i.push(" var peg$result;","",' if ("startRule" in options) {'," if (!(options.startRule in peg$startRuleFunctions)) {",' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");'," }",""," peg$startRuleFunction = peg$startRuleFunctions[options.startRule];"," }",""," function text() {"," return input.substring(peg$savedPos, peg$currPos);"," }",""," function offset() {"," return peg$savedPos;"," }",""," function range() {"," return {"," source: peg$source,"," start: peg$savedPos,"," end: peg$currPos"," };"," }",""," function location() {"," return peg$computeLocation(peg$savedPos, peg$currPos);"," }",""," function expected(description, location) {"," location = location !== undefined"," ? location"," : peg$computeLocation(peg$savedPos, peg$currPos);",""," throw peg$buildStructuredError("," [peg$otherExpectation(description)],"," input.substring(peg$savedPos, peg$currPos),"," location"," );"," }",""," function error(message, location) {"," location = location !== undefined"," ? location"," : peg$computeLocation(peg$savedPos, peg$currPos);",""," throw peg$buildSimpleError(message, location);"," }",""," function peg$literalExpectation(text, ignoreCase) {",' return { type: "literal", text: text, ignoreCase: ignoreCase };'," }",""," function peg$classExpectation(parts, inverted, ignoreCase) {",' return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };'," }",""," function peg$anyExpectation() {",' return { type: "any" };'," }",""," function peg$endExpectation() {",' return { type: "end" };'," }",""," function peg$otherExpectation(description) {",' return { type: "other", description: description };'," }",""," function peg$computePosDetails(pos) {"," var details = peg$posDetailsCache[pos];"," var p;",""," if (details) {"," return details;"," } else {"," p = pos - 1;"," while (!peg$posDetailsCache[p]) {"," p--;"," }",""," details = peg$posDetailsCache[p];"," details = {"," line: details.line,"," column: details.column"," };",""," while (p < pos) {"," if (input.charCodeAt(p) === 10) {"," details.line++;"," details.column = 1;"," } else {"," details.column++;"," }",""," p++;"," }",""," peg$posDetailsCache[pos] = details;",""," return details;"," }"," }",""," function peg$computeLocation(startPos, endPos, offset) {"," var startPosDetails = peg$computePosDetails(startPos);"," var endPosDetails = peg$computePosDetails(endPos);",""," var res = {"," source: peg$source,"," start: {"," offset: startPos,"," line: startPosDetails.line,"," column: startPosDetails.column"," },"," end: {"," offset: endPos,"," line: endPosDetails.line,"," column: endPosDetails.column"," }"," };",' if (offset && peg$source && (typeof peg$source.offset === "function")) {'," res.start = peg$source.offset(res.start);"," res.end = peg$source.offset(res.end);"," }"," return res;"," }",""," function peg$fail(expected) {"," if (peg$currPos < peg$maxFailPos) { return; }",""," if (peg$currPos > peg$maxFailPos) {"," peg$maxFailPos = peg$currPos;"," peg$maxFailExpected = [];"," }",""," peg$maxFailExpected.push(expected);"," }",""," function peg$buildSimpleError(message, location) {"," return new peg$SyntaxError(message, null, null, location);"," }",""," function peg$buildStructuredError(expected, found, location) {"," return new peg$SyntaxError("," peg$SyntaxError.buildMessage(expected, found),"," expected,"," found,"," location"," );"," }",""),e.rules.forEach((s=>{i.push(...n(function(i){const s=[],c=new o(i.name,"s","var",i.bytecode),p=function t(r){let o=0;const a=r.length,s=[];let p;function d(e,u){const i=u+3,a=r[o+i-2],l=r[o+i-1];let p,d;c.checkedIf(o,(()=>{o+=i,p=t(r.slice(o,o+a)),o+=a}),l>0?()=>{d=t(r.slice(o,o+l)),o+=l}:null),s.push("if ("+e+") {"),s.push(...n(p)),l>0&&(s.push("} else {"),s.push(...n(d))),s.push("}")}function E(e){const u=r[o+2-1];let i;c.checkedLoop(o,(()=>{o+=2,i=t(r.slice(o,o+u)),o+=u})),s.push("while ("+e+") {"),s.push(...n(i)),s.push("}")}function g(e){const t=r[o+e-1];return A(r[o+1])+"("+r.slice(o+e,o+e+t).map((e=>c.index(e))).join(", ")+")"}for(;oc.index(e))).join(", ")} ]`,c.pop(r[o+1]),s.push(c.push(p)),o+=n;break}case u.IF:d(c.top(),0);break;case u.IF_ERROR:d(c.top()+" === peg$FAILED",0);break;case u.IF_NOT_ERROR:d(c.top()+" !== peg$FAILED",0);break;case u.IF_LT:d(c.top()+".length < "+r[o+1],1);break;case u.IF_GE:d(c.top()+".length >= "+r[o+1],1);break;case u.IF_LT_DYNAMIC:d(c.top()+".length < ("+c.index(r[o+1])+"|0)",1);break;case u.IF_GE_DYNAMIC:d(c.top()+".length >= ("+c.index(r[o+1])+"|0)",1);break;case u.WHILE_NOT_ERROR:E(c.top()+" !== peg$FAILED");break;case u.MATCH_ANY:d("input.length > peg$currPos",0);break;case u.MATCH_STRING:d(e.literals[r[o+1]].length>1?"input.substr(peg$currPos, "+e.literals[r[o+1]].length+") === "+l(r[o+1]):"input.charCodeAt(peg$currPos) === "+e.literals[r[o+1]].charCodeAt(0),1);break;case u.MATCH_STRING_IC:d("input.substr(peg$currPos, "+e.literals[r[o+1]].length+").toLowerCase() === "+l(r[o+1]),1);break;case u.MATCH_CHAR_CLASS:d(h(r[o+1])+".test(input.charAt(peg$currPos))",1);break;case u.ACCEPT_N:s.push(c.push(r[o+1]>1?"input.substr(peg$currPos, "+r[o+1]+")":"input.charAt(peg$currPos)")),s.push(r[o+1]>1?"peg$currPos += "+r[o+1]+";":"peg$currPos++;"),o+=2;break;case u.ACCEPT_STRING:s.push(c.push(l(r[o+1]))),s.push(e.literals[r[o+1]].length>1?"peg$currPos += "+e.literals[r[o+1]].length+";":"peg$currPos++;"),o+=2;break;case u.FAIL:s.push(c.push("peg$FAILED")),s.push("if (peg$silentFails === 0) { peg$fail("+f(r[o+1])+"); }"),o+=2;break;case u.LOAD_SAVED_POS:s.push("peg$savedPos = "+c.index(r[o+1])+";"),o+=2;break;case u.UPDATE_SAVED_POS:s.push("peg$savedPos = peg$currPos;"),o++;break;case u.CALL:p=g(4),c.pop(r[o+2]),s.push(c.push(p)),o+=4+r[o+3];break;case u.RULE:s.push(c.push(m(e.rules[r[o+1]].name)+"()")),o+=2;break;case u.SILENT_FAILS_ON:s.push("peg$silentFails++;"),o++;break;case u.SILENT_FAILS_OFF:s.push("peg$silentFails--;"),o++;break;case u.SOURCE_MAP_PUSH:c.sourceMapPush(s,e.locations[r[o+1]]),o+=2;break;case u.SOURCE_MAP_POP:c.sourceMapPop(),o++;break;case u.SOURCE_MAP_LABEL_PUSH:c.labels[r[o+1]]={label:e.literals[r[o+2]],location:e.locations[r[o+3]]},o+=4;break;case u.SOURCE_MAP_LABEL_POP:delete c.labels[r[o+1]],o+=2;break;default:throw new Error("Invalid opcode: "+r[o]+".",{rule:i.name,bytecode:r})}return s}(i.bytecode);return s.push(d("function ",m(i.name),i.nameLocation,"() {\n",i.name)),t.trace&&s.push(" var startPos = peg$currPos;"),s.push(n(c.defines())),s.push(...n(function(n,r){const u=[];return u.push(""),t.trace&&u.push("peg$tracer.trace({",' type: "rule.enter",'," rule: "+n+","," location: peg$computeLocation(startPos, startPos, true)","});",""),t.cache&&(u.push("var key = peg$currPos * "+e.rules.length+" + "+r+";","var cached = peg$resultsCache[key];","","if (cached) {"," peg$currPos = cached.nextPos;",""),t.trace&&u.push("if (cached.result !== peg$FAILED) {"," peg$tracer.trace({",' type: "rule.match",'," rule: "+n+","," result: cached.result,"," location: peg$computeLocation(startPos, peg$currPos, true)"," });","} else {"," peg$tracer.trace({",' type: "rule.fail",'," rule: "+n+","," location: peg$computeLocation(startPos, startPos, true)"," });","}",""),u.push(" return cached.result;","}","")),u}('"'+a(i.name)+'"',r.indexOfRule(e,i.name)))),s.push(...n(p)),s.push(...n(function(e,n){const r=[];return t.cache&&r.push("","peg$resultsCache[key] = { nextPos: peg$currPos, result: "+n+" };"),t.trace&&r.push("","if ("+n+" !== peg$FAILED) {"," peg$tracer.trace({",' type: "rule.match",'," rule: "+e+","," result: "+n+","," location: peg$computeLocation(startPos, peg$currPos, true)"," });","} else {"," peg$tracer.trace({",' type: "rule.fail",'," rule: "+e+","," location: peg$computeLocation(startPos, startPos, true)"," });","}"),r.push("","return "+n+";"),r}('"'+a(i.name)+'"',c.result()))),s.push("}"),s}(s))),i.push("")})),e.initializer&&(i.push(E(e.initializer)),i.push("")),i.push(" peg$result = peg$startRuleFunction();",""," if (peg$result !== peg$FAILED && peg$currPos === input.length) {"," return peg$result;"," } else {"," if (peg$result !== peg$FAILED && peg$currPos < input.length) {"," peg$fail(peg$endExpectation());"," }",""," throw peg$buildStructuredError("," peg$maxFailExpected,"," peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,"," peg$maxFailPos < input.length"," ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)"," : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)"," );"," }","}"),new c(null,null,t.grammarSource,i.map((e=>e instanceof c?e:e+"\n")))}())}},5412:function(e,t,n){"use strict";const r=n(8202),u=n(9861),o=n(4297),i=-1;function a(e){function t(e){return e.match=0}function n(e){return c(e.expression),e.match=1}function a(e){return e.match=c(e.expression)}function s(e,t){const n=e.length;let r=0,u=0;for(let t=0;t0?i:0}const c=r.build({rule(e){let t,n=0;if(void 0===e.match){e.match=0;do{if(t=e.match,e.match=c(e.expression),++n>6)throw new o("Infinity cycle detected when trying to evaluate node match result",e.location)}while(t!==e.match)}return e.match},named:a,choice(e){return e.match=s(e.alternatives,!0)},action:a,sequence(e){return e.match=s(e.elements,!1)},labeled:a,text:a,simple_and:a,simple_not(e){return e.match=-c(e.expression)},optional:n,zero_or_more:n,one_or_more:a,repeated(e){const t=c(e.expression),n=e.delimiter?c(e.delimiter):i,r=e.min?e.min:e.max;return"constant"!==r.type||"constant"!==e.max.type?e.match=0:0===e.max.value||null!==e.max.value&&r.value>e.max.value?e.match=i:t===i?e.match=0===r.value?1:i:1===t?e.delimiter&&r.value>=2?e.match=n:e.match=1:e.delimiter&&r.value>=2?e.match=n===i?i:0:e.match=0===r.value?1:0},group:a,semantic_and:t,semantic_not:t,rule_ref(t){const n=u.findRule(e,t.name);return t.match=c(n)},literal(e){const t=0===e.value.length?1:0;return e.match=t},class(e){const t=0===e.parts.length?i:0;return e.match=t},any:t});c(e)}a.ALWAYS_MATCH=1,a.SOMETIMES_MATCH=0,a.NEVER_MATCH=i,e.exports=a},2929:function(e,t,n){"use strict";const r=n(9861),u=n(8202);e.exports=function(e,t,n){const o=[];e.rules.forEach(((i,a)=>{var s;"rule"===(s=i).type&&"rule_ref"===s.expression.type&&(function(e,t,o){u.build({rule_ref(u){u.name===t&&(u.name=o,n.info(`Proxy rule "${t}" replaced by the rule "${o}"`,u.location,[{message:"This rule will be used",location:r.findRule(e,o).nameLocation}]))}})(e)}(e,i.name,i.expression.name),-1===t.allowedStartRules.indexOf(i.name)&&o.push(a))})),o.reverse(),o.forEach((t=>{e.rules.splice(t,1)}))}},6734:function(e,t,n){"use strict";const r=n(8202);e.exports=function(e,t,n){function u(e){const t={};return Object.keys(e).forEach((n=>{t[n]=e[n]})),t}function o(e,t){i(e.expression,u(t))}const i=r.build({rule(e){i(e.expression,{})},choice(e,t){e.alternatives.forEach((e=>{i(e,u(t))}))},action:o,labeled(e,t){const r=e.label;r&&Object.prototype.hasOwnProperty.call(t,r)&&n.error(`Label "${e.label}" is already defined`,e.labelLocation,[{message:"Original label location",location:t[r]}]),i(e.expression,t),t[e.label]=e.labelLocation},text:o,simple_and:o,simple_not:o,optional:o,zero_or_more:o,one_or_more:o,repeated(e,t){e.delimiter&&i(e.delimiter,u(t)),i(e.expression,u(t))},group:o});i(e)}},1117:function(e,t,n){"use strict";const r=n(8202);e.exports=function(e,t,n){const u={};r.build({rule(e){Object.prototype.hasOwnProperty.call(u,e.name)?n.error(`Rule "${e.name}" is already defined`,e.nameLocation,[{message:"Original rule location",location:u[e.name]}]):u[e.name]=e.nameLocation}})(e)}},6237:function(e,t,n){"use strict";const r=n(8202);e.exports=function(e,t,n){const u=r.build({action(e){u(e.expression,e)},labeled(e,t){e.pick&&t&&n.error('"@" cannot be used with an action block',e.labelLocation,[{message:"Action block location",location:t.codeLocation}]),u(e.expression)}});u(e)}},730:function(e,t,n){"use strict";const r=n(9861),u=n(8202);e.exports=function(e,t,n){const o=[],i=[],a=u.build({rule(e){o.push(e.name),a(e.expression),o.pop()},sequence(t){t.elements.every((t=>(a(t),!r.alwaysConsumesOnSuccess(e,t))))},repeated(t){a(t.expression),t.delimiter&&!r.alwaysConsumesOnSuccess(e,t.expression)&&a(t.delimiter)},rule_ref(t){i.push(t);const u=r.findRule(e,t.name);if(-1!==o.indexOf(t.name))return o.push(t.name),void n.error("Possible infinite loop when parsing (left recursion: "+o.join(" -> ")+")",u.nameLocation,i.map(((e,t,n)=>({message:t+1!==n.length?`Step ${t+1}: call of the rule "${e.name}" without input consumption`:`Step ${t+1}: call itself without input consumption - left recursion`,location:e.location}))));u&&a(u),i.pop()}});a(e)}},9505:function(e,t,n){"use strict";const r=n(9861),u=n(8202);e.exports=function(e,t,n){const o=u.build({zero_or_more(t){r.alwaysConsumesOnSuccess(e,t.expression)||n.error("Possible infinite loop when parsing (repetition used with an expression that may not consume any input)",t.location)},one_or_more(t){r.alwaysConsumesOnSuccess(e,t.expression)||n.error("Possible infinite loop when parsing (repetition used with an expression that may not consume any input)",t.location)},repeated(t){if(t.delimiter&&o(t.delimiter),!(r.alwaysConsumesOnSuccess(e,t.expression)||t.delimiter&&r.alwaysConsumesOnSuccess(e,t.delimiter)))if(null===t.max.value)n.error("Possible infinite loop when parsing (unbounded range repetition used with an expression that may not consume any input)",t.location);else{const e=t.min?t.min:t.max;n.warning("constant"===e.type&&"constant"===t.max.type?`An expression may not consume any input and may always match ${t.max.value} times`:"An expression may not consume any input and may always match with a maximum repetition count",t.location)}}});o(e)}},1442:function(e,t,n){"use strict";const r=n(9861),u=n(8202);e.exports=function(e,t,n){u.build({rule_ref(t){r.findRule(e,t.name)||n.error(`Rule "${t.name}" is not defined`,t.location)}})(e)}},425:function(e,t,n){"use strict";const r=n(4297);class u{constructor(e){"function"==typeof(e=void 0!==e?e:{}).error&&(this.error=e.error),"function"==typeof e.warning&&(this.warning=e.warning),"function"==typeof e.info&&(this.info=e.info)}error(){}warning(){}info(){}}e.exports=class{constructor(e){this._callbacks=new u(e),this._firstError=null,this.errors=0,this.problems=[],this.stage=null}error(...e){++this.errors,null===this._firstError&&(this._firstError=new r(...e),this._firstError.stage=this.stage,this._firstError.problems=this.problems),this.problems.push(["error",...e]),this._callbacks.error(this.stage,...e)}warning(...e){this.problems.push(["warning",...e]),this._callbacks.warning(this.stage,...e)}info(...e){this.problems.push(["info",...e]),this._callbacks.info(this.stage,...e)}checkErrors(){if(0!==this.errors)throw this._firstError}}},8013:function(e,t,n){"use strict";const{SourceNode:r}=n(4738),u=n(2190);class o{constructor(e,t,n,r){this.sp=-1,this.maxSp=-1,this.varName=t,this.ruleName=e,this.type=n,this.bytecode=r,this.labels={},this.sourceMapStack=[]}name(e){if(e<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack underflow: attempt to use a variable '${this.varName}' at an index ${e}.\nBytecode: ${this.bytecode}`);return this.varName+e}static sourceNode(e,t,n){const o=u.offsetStart(e);return new r(o.line,o.column?o.column-1:null,String(e.source),t,n)}push(e){++this.sp>this.maxSp&&(this.maxSp=this.sp);const t=this.labels[this.sp],n=[this.name(this.sp)," = ",e,";"];if(t){if(this.sourceMapStack.length){const e=o.sourceNode(t.location,n.splice(0,2),t.label),{parts:u,location:i}=this.sourceMapPopInternal(),a=i.start.offsetthis.name(this.sp+1+t)))):this.name(this.sp--)}top(){return this.name(this.sp)}index(e){if(e<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack overflow: attempt to get a variable at a negative index ${e}.\nBytecode: ${this.bytecode}`);return this.name(this.sp-e)}result(){if(this.maxSp<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack is empty, can't get the result.\nBytecode: ${this.bytecode}`);return this.name(0)}defines(){return this.maxSp<0?"":this.type+" "+Array.from({length:this.maxSp+1},((e,t)=>this.name(t))).join(", ")+";"}checkedIf(e,t,n){const r=this.sp;if(t(),n){const t=this.sp;if(this.sp=r,n(),t!==this.sp)throw new Error("Rule '"+this.ruleName+"', position "+e+": Branches of a condition can't move the stack pointer differently (before: "+r+", after then: "+t+", after else: "+this.sp+"). Bytecode: "+this.bytecode)}}checkedLoop(e,t){const n=this.sp;if(t(),n!==this.sp)throw new Error("Rule '"+this.ruleName+"', position "+e+": Body of a loop can't move the stack pointer (before: "+n+", after: "+this.sp+"). Bytecode: "+this.bytecode)}sourceMapPush(e,t){if(this.sourceMapStack.length){const e=this.sourceMapStack[this.sourceMapStack.length-1];e[2].start.offset===t.start.offset&&e[2].end.offset>t.end.offset&&(e[2]={start:t.end,end:e[2].end,source:e[2].source})}this.sourceMapStack.push([e,e.length,t])}sourceMapPopInternal(){const[e,t,n]=this.sourceMapStack.pop(),o=e.splice(t).map((e=>e instanceof r?e:e+"\n"));if(o.length){const t=u.offsetStart(n);e.push(new r(t.line,t.column-1,String(n.source),o))}return{parts:e,location:n}}sourceMapPop(e){const{location:t}=this.sourceMapPopInternal();if(this.sourceMapStack.length&&t.end.offset"\\x0"+n(e))).replace(/[\x10-\x1F\x7F-\xFF]/g,(e=>"\\x"+n(e))).replace(/[\u0100-\u0FFF]/g,(e=>"\\u0"+n(e))).replace(/[\u1000-\uFFFF]/g,(e=>"\\u"+n(e)))},t.regexpClassEscape=function(e){return e.replace(/\\/g,"\\\\").replace(/\//g,"\\/").replace(/]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\v/g,"\\v").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,(e=>"\\x0"+n(e))).replace(/[\x10-\x1F\x7F-\xFF]/g,(e=>"\\x"+n(e))).replace(/[\u0100-\u0FFF]/g,(e=>"\\u0"+n(e))).replace(/[\u1000-\uFFFF]/g,(e=>"\\u"+n(e)))},t.base64=function(e){const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=e.length%3,r=e.length-n;let u="";for(let n=0;n>2],u+=t[(3&e[n])<<4|e[n+1]>>4],u+=t[(15&e[n+1])<<2|e[n+2]>>6],u+=t[63&e[n+2]];return 1===n?(u+=t[e[r]>>2],u+=t[(3&e[r])<<4],u+="=="):2===n&&(u+=t[e[r]>>2],u+=t[(3&e[r])<<4|e[r+1]>>4],u+=t[(15&e[r+1])<<2],u+="="),u}},8202:function(e){"use strict";const t={build(e){function t(t,...n){return e[t.type](t,...n)}function n(){}function r(e,...n){return t(e.expression,...n)}function u(e){return function(n,...r){n[e].forEach((e=>t(e,...r)))}}const o={grammar(e,...n){e.topLevelInitializer&&t(e.topLevelInitializer,...n),e.initializer&&t(e.initializer,...n),e.rules.forEach((e=>t(e,...n)))},top_level_initializer:n,initializer:n,rule:r,named:r,choice:u("alternatives"),action:r,sequence:u("elements"),labeled:r,text:r,simple_and:r,simple_not:r,optional:r,zero_or_more:r,one_or_more:r,repeated(e,...n){return e.delimiter&&t(e.delimiter,...n),t(e.expression,...n)},group:r,semantic_and:n,semantic_not:n,rule_ref:n,literal:n,class:n,any:n};return Object.keys(o).forEach((t=>{Object.prototype.hasOwnProperty.call(e,t)||(e[t]=o[t])})),t}};e.exports=t},4297:function(e,t,n){"use strict";const r=n(2190),u=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(const n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])};class o extends Error{constructor(e,t,n){super(e),u(this,o.prototype),this.name="GrammarError",this.location=t,void 0===n&&(n=[]),this.diagnostics=n,this.stage=null,this.problems=[["error",e,t,n]]}toString(){let e=super.toString();this.location&&(e+="\n at ",void 0!==this.location.source&&null!==this.location.source&&(e+=`${this.location.source}:`),e+=`${this.location.start.line}:${this.location.start.column}`);for(const t of this.diagnostics)e+="\n from ",void 0!==t.location.source&&null!==t.location.source&&(e+=`${t.location.source}:`),e+=`${t.location.start.line}:${t.location.start.column}: ${t.message}`;return e}format(e){const t=e.map((({source:e,text:t})=>({source:e,text:null!=t?String(t).split(/\r\n|\n|\r/g):[]})));function n(e,n,u=""){let o="";const i=t.find((({source:t})=>t===e.source)),a=e.start,s=r.offsetStart(e);if(i){const t=e.end,r=i.text[a.line-1],c=(a.line===t.line?t.column:r.length+1)-a.column||1;u&&(o+=`\nnote: ${u}`),o+=`\n --\x3e ${e.source}:${s.line}:${s.column}\n${"".padEnd(n)} |\n${s.line.toString().padStart(n)} | ${r}\n${"".padEnd(n)} | ${"".padEnd(a.column-1)}${"".padEnd(c,"^")}`}else o+=`\n at ${e.source}:${s.line}:${s.column}`,u&&(o+=`: ${u}`);return o}return this.problems.filter((e=>"info"!==e[0])).map((e=>function(e,t,u,o=[]){let i=-1/0;i=u?o.reduce(((e,{location:t})=>Math.max(e,r.offsetStart(t).line)),u.start.line):Math.max.apply(null,o.map((e=>e.location.start.line))),i=i.toString().length;let a=`${e}: ${t}`;u&&(a+=n(u,i));for(const e of o)a+=n(e.location,i,e.message);return a}(...e))).join("\n\n")}}e.exports=o},2190:function(e){"use strict";e.exports=class{constructor(e,t){this.source=e,this.start=t}toString(){return String(this.source)}offset(e){return{line:e.line+this.start.line-1,column:1===e.line?e.column+this.start.column-1:e.column,offset:e.offset+this.start.offset}}static offsetStart(e){return e.source&&"function"==typeof e.source.offset?e.source.offset(e.start):e.start}static offsetEnd(e){return e.source&&"function"==typeof e.source.offset?e.source.offset(e.end):e.end}}},170:function(e){"use strict";const t={$:"text","&":"simple_and","!":"simple_not"},n={"?":"optional","*":"zero_or_more","+":"one_or_more"},r={"&":"semantic_and","!":"semantic_not"};function u(e,t,n,r){var o=Error.call(this,e);return Object.setPrototypeOf&&Object.setPrototypeOf(o,u.prototype),o.expected=t,o.found=n,o.location=r,o.name="SyntaxError",o}function o(e,t,n){return n=n||" ",e.length>t?e:(t-=e.length,e+(n+=n.repeat(t)).slice(0,t))}!function(e,t){function n(){this.constructor=e}n.prototype=t.prototype,e.prototype=new n}(u,Error),u.prototype.format=function(e){var t="Error: "+this.message;if(this.location){var n,r=null;for(n=0;n0){for(t=1,n=1;t0?{type:"choice",alternatives:[e].concat(t),location:qn()}:e},Qt=function(e,t){return null!==t?{type:"action",expression:e,code:t[0],codeLocation:t[1],location:qn()}:e},en=function(e,t){return t.length>0||"labeled"===e.type&&e.pick?{type:"sequence",elements:[e].concat(t),location:qn()}:e},tn=function(e,t,n){return n.type.startsWith("semantic_")&&zn('"@" cannot be used on a semantic predicate',e),{type:"labeled",label:null!==t?t[0]:null,labelLocation:null!==t?t[1]:e,pick:!0,expression:n,location:qn()}},nn=function(e,t){return{type:"labeled",label:e[0],labelLocation:e[1],expression:t,location:qn()}},rn=function(){return qn()},un=function(e){return kr.indexOf(e[0])>=0&&zn(`Label can't be a reserved word "${e[0]}"`,e[1]),e},on=function(e,n){return{type:t[e],expression:n,location:qn()}},an=function(e,t){return{type:n[t],expression:e,location:qn()}},sn=function(e,t,n){let r=t[0],u=t[1];return"constant"===u.type&&0===u.value&&zn("The maximum count of repetitions of the rule must be > 0",u.location),{type:"repeated",min:r,max:u,expression:e,delimiter:n,location:qn()}},cn=function(e,t){return[null!==e?e:{type:"constant",value:0},null!==t?t:{type:"constant",value:null}]},ln=function(e){return[null,e]},pn=function(e){return{type:"constant",value:e,location:qn()}},dn=function(e){return{type:"variable",value:e[0],location:qn()}},hn=function(e){return{type:"function",value:e[0],codeLocation:e[1],location:qn()}},fn=function(e){return"labeled"===e.type||"sequence"===e.type?{type:"group",expression:e,location:qn()}:e},An=function(e){return{type:"rule_ref",name:e[0],location:qn()}},mn=function(e,t){return{type:r[e],code:t[0],codeLocation:t[1],location:qn()}},En=function(e,t){return[e+t.join(""),qn()]},gn=function(e,t){return{type:"literal",value:e,ignoreCase:null!==t,location:qn()}},Cn=function(e){return e.join("")},yn=function(e){return e.join("")},vn=function(e,t,n){return{type:"class",parts:t.filter((e=>""!==e)),inverted:null!==e,ignoreCase:null!==n,location:qn()}},Fn=function(t,n){return t.charCodeAt(0)>n.charCodeAt(0)&&zn("Invalid character range: "+e.substring($n,Nn)+"."),[t,n]},xn=function(){return""},bn=function(){return"\0"},Dn=function(){return"\b"},Bn=function(){return"\f"},Sn=function(){return"\n"},Pn=function(){return"\r"},wn=function(){return"\t"},On=function(){return"\v"},kn=function(e){return String.fromCharCode(parseInt(e,16))},Tn=function(e){return String.fromCharCode(parseInt(e,16))},In=function(){return{type:"any",location:qn()}},Rn=function(e){return[e,qn()]},Ln=function(e){return parseInt(e,10)},Nn=0,$n=0,Mn=[{line:1,column:1}],jn=0,Un=[],Hn=0;if("startRule"in o){if(!(o.startRule in c))throw new Error("Can't start parsing from rule \""+o.startRule+'".');l=c[o.startRule]}function qn(){return Xn($n,Nn)}function zn(e,t){throw function(e,t){return new u(e,null,null,t)}(e,t=void 0!==t?t:Xn($n,Nn))}function Vn(e,t){return{type:"literal",text:e,ignoreCase:t}}function Gn(e,t,n){return{type:"class",parts:e,inverted:t,ignoreCase:n}}function Wn(e){return{type:"other",description:e}}function Yn(t){var n,r=Mn[t];if(r)return r;for(n=t-1;!Mn[n];)n--;for(r={line:(r=Mn[n]).line,column:r.column};njn&&(jn=Nn,Un=[]),Un.push(e))}function Zn(){var t,n,r,u,o,i;if(t=Nn,wr(),n=Nn,r=function(){var t,n,r,u;return t=Nn,123===e.charCodeAt(Nn)?(n=p,Nn++):(n=a,0===Hn&&Jn(be)),n!==a&&(r=Sr())!==a?(125===e.charCodeAt(Nn)?(u=d,Nn++):(u=a,0===Hn&&Jn(De)),u!==a&&Or()!==a?($n=t,t=Xt(r)):(Nn=t,t=a)):(Nn=t,t=a),t}(),r!==a?(u=wr(),n=r):(Nn=n,n=a),n===a&&(n=null),r=Nn,u=function(){var e,t;return e=Nn,(t=Sr())!==a&&Or()!==a?($n=e,e=Jt(t)):(Nn=e,e=a),e}(),u!==a?(o=wr(),r=u):(Nn=r,r=a),r===a&&(r=null),u=[],o=Nn,(i=Kn())!==a?(wr(),o=i):(Nn=o,o=a),o!==a)for(;o!==a;)u.push(o),o=Nn,(i=Kn())!==a?(wr(),o=i):(Nn=o,o=a);else u=a;return u!==a?($n=t,t=Yt(n,r,u)):(Nn=t,t=a),t}function Kn(){var t,n,r,u,o;return t=Nn,(n=fr())!==a?(wr(),r=Nn,(u=Er())!==a?(wr(),r=u):(Nn=r,r=a),r===a&&(r=null),61===e.charCodeAt(Nn)?(u=h,Nn++):(u=a,0===Hn&&Jn(Be)),u!==a?(wr(),(o=Qn())!==a&&Or()!==a?($n=t,t=Zt(n,r,o)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a),t}function Qn(){var t,n,r,u,o,i;if(t=Nn,(n=er())!==a){for(r=[],u=Nn,wr(),47===e.charCodeAt(Nn)?(o=f,Nn++):(o=a,0===Hn&&Jn(Se)),o!==a?(wr(),(i=er())!==a?u=i:(Nn=u,u=a)):(Nn=u,u=a);u!==a;)r.push(u),u=Nn,wr(),47===e.charCodeAt(Nn)?(o=f,Nn++):(o=a,0===Hn&&Jn(Se)),o!==a?(wr(),(i=er())!==a?u=i:(Nn=u,u=a)):(Nn=u,u=a);$n=t,t=Kt(n,r)}else Nn=t,t=a;return t}function er(){var e,t,n,r;return e=Nn,t=function(){var e,t,n,r,u;if(e=Nn,(t=tr())!==a){for(n=[],r=Nn,wr(),(u=tr())!==a?r=u:(Nn=r,r=a);r!==a;)n.push(r),r=Nn,wr(),(u=tr())!==a?r=u:(Nn=r,r=a);$n=e,e=en(t,n)}else Nn=e,e=a;return e}(),t!==a?(n=Nn,wr(),(r=Sr())!==a?n=r:(Nn=n,n=a),n===a&&(n=null),$n=e,e=Qt(t,n)):(Nn=e,e=a),e}function tr(){var t,n,r,u;return t=Nn,n=function(){var t,n;return t=Nn,64===e.charCodeAt(Nn)?(n=A,Nn++):(n=a,0===Hn&&Jn(Pe)),n!==a&&($n=t,n=rn()),t=n}(),n!==a?((r=nr())===a&&(r=null),(u=rr())!==a?($n=t,t=tn(n,r,u)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=Nn,(n=nr())!==a?(r=wr(),(u=rr())!==a?($n=t,t=nn(n,u)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=rr())),t}function nr(){var t,n,r;return t=Nn,(n=fr())!==a?(wr(),58===e.charCodeAt(Nn)?(r=m,Nn++):(r=a,0===Hn&&Jn(we)),r!==a?($n=t,t=un(n)):(Nn=t,t=a)):(Nn=t,t=a),t}function rr(){var t,n,r;return t=Nn,n=function(){var t;return 36===e.charCodeAt(Nn)?(t=E,Nn++):(t=a,0===Hn&&Jn(Oe)),t===a&&(38===e.charCodeAt(Nn)?(t=g,Nn++):(t=a,0===Hn&&Jn(ke)),t===a&&(33===e.charCodeAt(Nn)?(t=C,Nn++):(t=a,0===Hn&&Jn(Te)))),t}(),n!==a?(wr(),(r=ur())!==a?($n=t,t=on(n,r)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=ur()),t}function ur(){var t,n,r;return t=Nn,(n=ir())!==a?(wr(),r=function(){var t;return 63===e.charCodeAt(Nn)?(t=y,Nn++):(t=a,0===Hn&&Jn(Ie)),t===a&&(42===e.charCodeAt(Nn)?(t=v,Nn++):(t=a,0===Hn&&Jn(Re)),t===a&&(43===e.charCodeAt(Nn)?(t=F,Nn++):(t=a,0===Hn&&Jn(Le)))),t}(),r!==a?($n=t,t=an(n,r)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=function(){var t,n,r,u,o,i,s;return t=Nn,(n=ir())!==a?(wr(),124===e.charCodeAt(Nn)?(r=_,Nn++):(r=a,0===Hn&&Jn(Ne)),r!==a?(wr(),u=function(){var t,n,r,u;return t=Nn,(n=or())===a&&(n=null),wr(),e.substr(Nn,2)===b?(r=b,Nn+=2):(r=a,0===Hn&&Jn(Me)),r!==a?(wr(),(u=or())===a&&(u=null),$n=t,t=cn(n,u)):(Nn=t,t=a),t===a&&(t=Nn,(n=or())!==a&&($n=t,n=ln(n)),t=n),t}(),u!==a?(wr(),o=Nn,44===e.charCodeAt(Nn)?(i=x,Nn++):(i=a,0===Hn&&Jn($e)),i!==a?(wr(),(s=Qn())!==a?(wr(),o=s):(Nn=o,o=a)):(Nn=o,o=a),o===a&&(o=null),124===e.charCodeAt(Nn)?(i=_,Nn++):(i=a,0===Hn&&Jn(Ne)),i!==a?($n=t,t=sn(n,u,o)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=ir())),t}function or(){var t,n;return t=Nn,n=function(){var t,n,r,u;if(t=Nn,n=Nn,r=[],(u=Dr())!==a)for(;u!==a;)r.push(u),u=Dr();else r=a;return(n=r!==a?e.substring(n,Nn):r)!==a&&($n=t,n=Ln(n)),t=n}(),n!==a&&($n=t,n=pn(n)),(t=n)===a&&(t=Nn,(n=fr())!==a&&($n=t,n=dn(n)),(t=n)===a&&(t=Nn,(n=Sr())!==a&&($n=t,n=hn(n)),t=n)),t}function ir(){var t,n,r,u;return t=function(){var t,n,r;return Hn++,t=Nn,(n=Er())!==a?(105===e.charCodeAt(Nn)?(r=G,Nn++):(r=a,0===Hn&&Jn(ht)),r===a&&(r=null),$n=t,t=gn(n,r)):(Nn=t,t=a),Hn--,t===a&&(n=a,0===Hn&&Jn(dt)),t}(),t===a&&(t=function(){var t,n,r,u,o,i;if(Hn++,t=Nn,91===e.charCodeAt(Nn)?(n=X,Nn++):(n=a,0===Hn&&Jn(gt)),n!==a){for(94===e.charCodeAt(Nn)?(r=J,Nn++):(r=a,0===Hn&&Jn(Ct)),r===a&&(r=null),u=[],(o=yr())===a&&(o=vr());o!==a;)u.push(o),(o=yr())===a&&(o=vr());93===e.charCodeAt(Nn)?(o=Z,Nn++):(o=a,0===Hn&&Jn(yt)),o!==a?(105===e.charCodeAt(Nn)?(i=G,Nn++):(i=a,0===Hn&&Jn(ht)),i===a&&(i=null),$n=t,t=vn(r,u,i)):(Nn=t,t=a)}else Nn=t,t=a;return Hn--,t===a&&(n=a,0===Hn&&Jn(Et)),t}(),t===a&&(t=function(){var t,n;return t=Nn,46===e.charCodeAt(Nn)?(n=se,Nn++):(n=a,0===Hn&&Jn(Tt)),n!==a&&($n=t,n=In()),t=n}(),t===a&&(t=function(){var t,n,r,u,o,i,s;return t=Nn,(n=fr())!==a?(r=Nn,Hn++,u=Nn,o=wr(),i=Nn,(s=Er())!==a?i=s=[s,wr()]:(Nn=i,i=a),i===a&&(i=null),61===e.charCodeAt(Nn)?(s=h,Nn++):(s=a,0===Hn&&Jn(Be)),s!==a?u=o=[o,i,s]:(Nn=u,u=a),Hn--,u===a?r=void 0:(Nn=r,r=a),r!==a?($n=t,t=An(n)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=function(){var t,n,r;return t=Nn,n=function(){var t;return 38===e.charCodeAt(Nn)?(t=g,Nn++):(t=a,0===Hn&&Jn(ke)),t===a&&(33===e.charCodeAt(Nn)?(t=C,Nn++):(t=a,0===Hn&&Jn(Te))),t}(),n!==a?(wr(),(r=Sr())!==a?($n=t,t=mn(n,r)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=Nn,40===e.charCodeAt(Nn)?(n=D,Nn++):(n=a,0===Hn&&Jn(je)),n!==a?(wr(),(r=Qn())!==a?(wr(),41===e.charCodeAt(Nn)?(u=B,Nn++):(u=a,0===Hn&&Jn(Ue)),u!==a?($n=t,t=fn(r)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a)))))),t}function ar(){var t;return e.length>Nn?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(He)),t}function sr(){var t;return Hn++,9===e.charCodeAt(Nn)?(t=S,Nn++):(t=a,0===Hn&&Jn(ze)),t===a&&(11===e.charCodeAt(Nn)?(t=P,Nn++):(t=a,0===Hn&&Jn(Ve)),t===a&&(12===e.charCodeAt(Nn)?(t=w,Nn++):(t=a,0===Hn&&Jn(Ge)),t===a&&(32===e.charCodeAt(Nn)?(t=O,Nn++):(t=a,0===Hn&&Jn(We)),t===a&&(160===e.charCodeAt(Nn)?(t=k,Nn++):(t=a,0===Hn&&Jn(Ye)),t===a&&(65279===e.charCodeAt(Nn)?(t=T,Nn++):(t=a,0===Hn&&Jn(Xe)),t===a&&(t=function(){var t;return xe.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Gt)),t}())))))),Hn--,t===a&&0===Hn&&Jn(qe),t}function cr(){var t;return le.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Je)),t}function lr(){var t;return Hn++,10===e.charCodeAt(Nn)?(t=I,Nn++):(t=a,0===Hn&&Jn(Ke)),t===a&&(e.substr(Nn,2)===R?(t=R,Nn+=2):(t=a,0===Hn&&Jn(Qe)),t===a&&(13===e.charCodeAt(Nn)?(t=L,Nn++):(t=a,0===Hn&&Jn(et)),t===a&&(8232===e.charCodeAt(Nn)?(t=N,Nn++):(t=a,0===Hn&&Jn(tt)),t===a&&(8233===e.charCodeAt(Nn)?(t=$,Nn++):(t=a,0===Hn&&Jn(nt)))))),Hn--,t===a&&0===Hn&&Jn(Ze),t}function pr(){var t;return Hn++,(t=function(){var t,n,r,u,o,i;if(t=Nn,e.substr(Nn,2)===M?(n=M,Nn+=2):(n=a,0===Hn&&Jn(ut)),n!==a){for(r=[],u=Nn,o=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Jn(ot)),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);u!==a;)r.push(u),u=Nn,o=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Jn(ot)),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);e.substr(Nn,2)===j?(u=j,Nn+=2):(u=a,0===Hn&&Jn(ot)),u!==a?t=n=[n,r,u]:(Nn=t,t=a)}else Nn=t,t=a;return t}())===a&&(t=hr()),Hn--,t===a&&0===Hn&&Jn(rt),t}function dr(){var t,n,r,u,o,i;if(t=Nn,e.substr(Nn,2)===M?(n=M,Nn+=2):(n=a,0===Hn&&Jn(ut)),n!==a){for(r=[],u=Nn,o=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Jn(ot)),i===a&&(i=cr()),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);u!==a;)r.push(u),u=Nn,o=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Jn(ot)),i===a&&(i=cr()),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);e.substr(Nn,2)===j?(u=j,Nn+=2):(u=a,0===Hn&&Jn(ot)),u!==a?t=n=[n,r,u]:(Nn=t,t=a)}else Nn=t,t=a;return t}function hr(){var t,n,r,u,o,i;if(t=Nn,e.substr(Nn,2)===U?(n=U,Nn+=2):(n=a,0===Hn&&Jn(it)),n!==a){for(r=[],u=Nn,o=Nn,Hn++,i=cr(),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);u!==a;)r.push(u),u=Nn,o=Nn,Hn++,i=cr(),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);t=n=[n,r]}else Nn=t,t=a;return t}function fr(){var e,t,n,r;if(Hn++,e=Nn,(t=Ar())!==a){for(n=[],r=mr();r!==a;)n.push(r),r=mr();$n=e,e=En(t,n)}else Nn=e,e=a;return Hn--,e===a&&(t=a,0===Hn&&Jn(at)),e}function Ar(){var t,n,r;return(t=function(){var t;return(t=function(){var t;return ge.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(jt)),t}())===a&&(t=function(){var t;return fe.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Lt)),t}())===a&&(t=function(){var t;return Ee.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Mt)),t}())===a&&(t=function(){var t;return Ae.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Nt)),t}())===a&&(t=function(){var t;return me.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn($t)),t}())===a&&(t=function(){var t;return Fe.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(zt)),t}()),t}())===a&&(95===e.charCodeAt(Nn)?(t=H,Nn++):(t=a,0===Hn&&Jn(st)),t===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=q,Nn++):(n=a,0===Hn&&Jn(ct)),n!==a&&(r=br())!==a?t=r:(Nn=t,t=a))),t}function mr(){var t;return(t=Ar())===a&&(36===e.charCodeAt(Nn)?(t=E,Nn++):(t=a,0===Hn&&Jn(Oe)),t===a&&(t=function(){var t;return(t=function(){var t;return ye.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Ht)),t}())===a&&(t=function(){var t;return Ce.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Ut)),t}()),t}())===a&&(t=function(){var t;return ve.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(qt)),t}())===a&&(t=function(){var t;return _e.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Vt)),t}())===a&&(8204===e.charCodeAt(Nn)?(t=z,Nn++):(t=a,0===Hn&&Jn(lt)),t===a&&(8205===e.charCodeAt(Nn)?(t=V,Nn++):(t=a,0===Hn&&Jn(pt))))),t}function Er(){var t,n,r,u;if(Hn++,t=Nn,34===e.charCodeAt(Nn)?(n=W,Nn++):(n=a,0===Hn&&Jn(At)),n!==a){for(r=[],u=gr();u!==a;)r.push(u),u=gr();34===e.charCodeAt(Nn)?(u=W,Nn++):(u=a,0===Hn&&Jn(At)),u!==a?($n=t,t=Cn(r)):(Nn=t,t=a)}else Nn=t,t=a;if(t===a)if(t=Nn,39===e.charCodeAt(Nn)?(n=Y,Nn++):(n=a,0===Hn&&Jn(mt)),n!==a){for(r=[],u=Cr();u!==a;)r.push(u),u=Cr();39===e.charCodeAt(Nn)?(u=Y,Nn++):(u=a,0===Hn&&Jn(mt)),u!==a?($n=t,t=yn(r)):(Nn=t,t=a)}else Nn=t,t=a;return Hn--,t===a&&(n=a,0===Hn&&Jn(ft)),t}function gr(){var t,n,r,u;return t=Nn,n=Nn,r=Nn,Hn++,34===e.charCodeAt(Nn)?(u=W,Nn++):(u=a,0===Hn&&Jn(At)),u===a&&(92===e.charCodeAt(Nn)?(u=q,Nn++):(u=a,0===Hn&&Jn(ct)),u===a&&(u=cr())),Hn--,u===a?r=void 0:(Nn=r,r=a),r!==a&&(u=ar())!==a?n=r=[r,u]:(Nn=n,n=a),(t=n!==a?e.substring(t,Nn):n)===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=q,Nn++):(n=a,0===Hn&&Jn(ct)),n!==a&&(r=_r())!==a?t=r:(Nn=t,t=a),t===a&&(t=Fr())),t}function Cr(){var t,n,r,u;return t=Nn,n=Nn,r=Nn,Hn++,39===e.charCodeAt(Nn)?(u=Y,Nn++):(u=a,0===Hn&&Jn(mt)),u===a&&(92===e.charCodeAt(Nn)?(u=q,Nn++):(u=a,0===Hn&&Jn(ct)),u===a&&(u=cr())),Hn--,u===a?r=void 0:(Nn=r,r=a),r!==a&&(u=ar())!==a?n=r=[r,u]:(Nn=n,n=a),(t=n!==a?e.substring(t,Nn):n)===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=q,Nn++):(n=a,0===Hn&&Jn(ct)),n!==a&&(r=_r())!==a?t=r:(Nn=t,t=a),t===a&&(t=Fr())),t}function yr(){var t,n,r,u;return t=Nn,(n=vr())!==a?(45===e.charCodeAt(Nn)?(r=K,Nn++):(r=a,0===Hn&&Jn(vt)),r!==a&&(u=vr())!==a?($n=t,t=Fn(n,u)):(Nn=t,t=a)):(Nn=t,t=a),t}function vr(){var t,n,r,u;return t=Nn,n=Nn,r=Nn,Hn++,93===e.charCodeAt(Nn)?(u=Z,Nn++):(u=a,0===Hn&&Jn(yt)),u===a&&(92===e.charCodeAt(Nn)?(u=q,Nn++):(u=a,0===Hn&&Jn(ct)),u===a&&(u=cr())),Hn--,u===a?r=void 0:(Nn=r,r=a),r!==a&&(u=ar())!==a?n=r=[r,u]:(Nn=n,n=a),(t=n!==a?e.substring(t,Nn):n)===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=q,Nn++):(n=a,0===Hn&&Jn(ct)),n!==a&&(r=_r())!==a?t=r:(Nn=t,t=a),t===a&&(t=Fr())),t}function Fr(){var t,n;return t=Nn,92===e.charCodeAt(Nn)?(n=q,Nn++):(n=a,0===Hn&&Jn(ct)),n!==a&&lr()!==a?($n=t,t=xn()):(Nn=t,t=a),t}function _r(){var t,n,r,u;return t=function(){var t;return(t=xr())===a&&(t=function(){var t,n,r,u;return t=Nn,n=Nn,r=Nn,Hn++,u=function(){var t;return(t=xr())===a&&(t=Dr())===a&&(120===e.charCodeAt(Nn)?(t=ie,Nn++):(t=a,0===Hn&&Jn(Pt)),t===a&&(117===e.charCodeAt(Nn)?(t=ae,Nn++):(t=a,0===Hn&&Jn(wt)))),t}(),u===a&&(u=cr()),Hn--,u===a?r=void 0:(Nn=r,r=a),r!==a&&(u=ar())!==a?n=r=[r,u]:(Nn=n,n=a),t=n!==a?e.substring(t,Nn):n}()),t}(),t===a&&(t=Nn,48===e.charCodeAt(Nn)?(n=Q,Nn++):(n=a,0===Hn&&Jn(Ft)),n!==a?(r=Nn,Hn++,u=Dr(),Hn--,u===a?r=void 0:(Nn=r,r=a),r!==a?($n=t,t=bn()):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=function(){var t,n,r,u,o,i;return t=Nn,120===e.charCodeAt(Nn)?(n=ie,Nn++):(n=a,0===Hn&&Jn(Pt)),n!==a?(r=Nn,u=Nn,(o=Br())!==a&&(i=Br())!==a?u=o=[o,i]:(Nn=u,u=a),(r=u!==a?e.substring(r,Nn):u)!==a?($n=t,t=kn(r)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=br()))),t}function xr(){var t,n;return 39===e.charCodeAt(Nn)?(t=Y,Nn++):(t=a,0===Hn&&Jn(mt)),t===a&&(34===e.charCodeAt(Nn)?(t=W,Nn++):(t=a,0===Hn&&Jn(At)),t===a&&(92===e.charCodeAt(Nn)?(t=q,Nn++):(t=a,0===Hn&&Jn(ct)),t===a&&(t=Nn,98===e.charCodeAt(Nn)?(n=ee,Nn++):(n=a,0===Hn&&Jn(_t)),n!==a&&($n=t,n=Dn()),(t=n)===a&&(t=Nn,102===e.charCodeAt(Nn)?(n=te,Nn++):(n=a,0===Hn&&Jn(xt)),n!==a&&($n=t,n=Bn()),(t=n)===a&&(t=Nn,110===e.charCodeAt(Nn)?(n=ne,Nn++):(n=a,0===Hn&&Jn(bt)),n!==a&&($n=t,n=Sn()),(t=n)===a&&(t=Nn,114===e.charCodeAt(Nn)?(n=re,Nn++):(n=a,0===Hn&&Jn(Dt)),n!==a&&($n=t,n=Pn()),(t=n)===a&&(t=Nn,116===e.charCodeAt(Nn)?(n=ue,Nn++):(n=a,0===Hn&&Jn(Bt)),n!==a&&($n=t,n=wn()),(t=n)===a&&(t=Nn,118===e.charCodeAt(Nn)?(n=oe,Nn++):(n=a,0===Hn&&Jn(St)),n!==a&&($n=t,n=On()),t=n)))))))),t}function br(){var t,n,r,u,o,i,s,c;return t=Nn,117===e.charCodeAt(Nn)?(n=ae,Nn++):(n=a,0===Hn&&Jn(wt)),n!==a?(r=Nn,u=Nn,(o=Br())!==a&&(i=Br())!==a&&(s=Br())!==a&&(c=Br())!==a?u=o=[o,i,s,c]:(Nn=u,u=a),(r=u!==a?e.substring(r,Nn):u)!==a?($n=t,t=Tn(r)):(Nn=t,t=a)):(Nn=t,t=a),t}function Dr(){var t;return pe.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(Ot)),t}function Br(){var t;return de.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Jn(kt)),t}function Sr(){var t,n,r,u;return Hn++,t=Nn,123===e.charCodeAt(Nn)?(n=p,Nn++):(n=a,0===Hn&&Jn(be)),n!==a?(r=function(){var e,t;return e=Nn,t=Pr(),$n=e,e=t=Rn(t)}(),125===e.charCodeAt(Nn)?(u=d,Nn++):(u=a,0===Hn&&Jn(De)),u!==a?t=r:(Nn=t,t=a)):(Nn=t,t=a),Hn--,t===a&&(n=a,0===Hn&&Jn(It)),t}function Pr(){var t,n,r,u,o,i;if(t=Nn,n=[],r=[],u=Nn,o=Nn,Hn++,he.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Jn(Rt)),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a),u!==a)for(;u!==a;)r.push(u),u=Nn,o=Nn,Hn++,he.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Jn(Rt)),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);else r=a;for(r===a&&(r=Nn,123===e.charCodeAt(Nn)?(u=p,Nn++):(u=a,0===Hn&&Jn(be)),u!==a?(o=Pr(),125===e.charCodeAt(Nn)?(i=d,Nn++):(i=a,0===Hn&&Jn(De)),i!==a?r=u=[u,o,i]:(Nn=r,r=a)):(Nn=r,r=a));r!==a;){if(n.push(r),r=[],u=Nn,o=Nn,Hn++,he.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Jn(Rt)),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a),u!==a)for(;u!==a;)r.push(u),u=Nn,o=Nn,Hn++,he.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Jn(Rt)),Hn--,i===a?o=void 0:(Nn=o,o=a),o!==a&&(i=ar())!==a?u=o=[o,i]:(Nn=u,u=a);else r=a;r===a&&(r=Nn,123===e.charCodeAt(Nn)?(u=p,Nn++):(u=a,0===Hn&&Jn(be)),u!==a?(o=Pr(),125===e.charCodeAt(Nn)?(i=d,Nn++):(i=a,0===Hn&&Jn(De)),i!==a?r=u=[u,o,i]:(Nn=r,r=a)):(Nn=r,r=a))}return e.substring(t,Nn)}function wr(){var e,t;for(e=[],(t=sr())===a&&(t=lr())===a&&(t=pr());t!==a;)e.push(t),(t=sr())===a&&(t=lr())===a&&(t=pr());return e}function Or(){var t,n,r,u;if(t=[],n=Nn,r=wr(),59===e.charCodeAt(Nn)?(u=ce,Nn++):(u=a,0===Hn&&Jn(Wt)),u!==a?n=r=[r,u]:(Nn=n,n=a),n!==a)for(;n!==a;)t.push(n),n=Nn,r=wr(),59===e.charCodeAt(Nn)?(u=ce,Nn++):(u=a,0===Hn&&Jn(Wt)),u!==a?n=r=[r,u]:(Nn=n,n=a);else t=a;return t===a&&(t=Nn,n=function(){var e,t;for(e=[],(t=sr())===a&&(t=dr());t!==a;)e.push(t),(t=sr())===a&&(t=dr());return e}(),(r=hr())===a&&(r=null),(u=lr())!==a?t=n=[n,r,u]:(Nn=t,t=a),t===a&&(t=Nn,n=wr(),r=function(){var t,n;return t=Nn,Hn++,e.length>Nn?(n=e.charAt(Nn),Nn++):(n=a,0===Hn&&Jn(He)),Hn--,n===a?t=void 0:(Nn=t,t=a),t}(),r!==a?t=n=[n,r]:(Nn=t,t=a))),t}const kr=o.reservedWords||[];if((i=l())!==a&&Nn===e.length)return i;throw i!==a&&Nn{t[n]=e[n].slice()})),t}(a.compiler.passes),reservedWords:a.RESERVED_WORDS.slice()};return n.forEach((e=>{e.use(r,t)})),a.compiler.compile(r.parser.parse(e,{grammarSource:t.grammarSource,reservedWords:r.reservedWords}),r.passes,t)}};e.exports=a},244:function(e){"use strict";e.exports="3.0.2"},5726:function(e,t,n){"use strict";function r(e,t,n,r,u,o,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=u,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}const u={};["children","dangerouslySetInnerHTML","defaultValue","defaultChecked","innerHTML","suppressContentEditableWarning","suppressHydrationWarning","style"].forEach((e=>{u[e]=new r(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((([e,t])=>{u[e]=new r(e,1,!1,t,null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((e=>{u[e]=new r(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((e=>{u[e]=new r(e,2,!1,e,null,!1,!1)})),["allowFullScreen","async","autoFocus","autoPlay","controls","default","defer","disabled","disablePictureInPicture","disableRemotePlayback","formNoValidate","hidden","loop","noModule","noValidate","open","playsInline","readOnly","required","reversed","scoped","seamless","itemScope"].forEach((e=>{u[e]=new r(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((e=>{u[e]=new r(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((e=>{u[e]=new r(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((e=>{u[e]=new r(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((e=>{u[e]=new r(e,5,!1,e.toLowerCase(),null,!1,!1)}));const o=/[\-\:]([a-z])/g,i=e=>e[1].toUpperCase();["accent-height","alignment-baseline","arabic-form","baseline-shift","cap-height","clip-path","clip-rule","color-interpolation","color-interpolation-filters","color-profile","color-rendering","dominant-baseline","enable-background","fill-opacity","fill-rule","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","glyph-name","glyph-orientation-horizontal","glyph-orientation-vertical","horiz-adv-x","horiz-origin-x","image-rendering","letter-spacing","lighting-color","marker-end","marker-mid","marker-start","overline-position","overline-thickness","paint-order","panose-1","pointer-events","rendering-intent","shape-rendering","stop-color","stop-opacity","strikethrough-position","strikethrough-thickness","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-anchor","text-decoration","text-rendering","underline-position","underline-thickness","unicode-bidi","unicode-range","units-per-em","v-alphabetic","v-hanging","v-ideographic","v-mathematical","vector-effect","vert-adv-y","vert-origin-x","vert-origin-y","word-spacing","writing-mode","xmlns:xlink","x-height"].forEach((e=>{const t=e.replace(o,i);u[t]=new r(t,1,!1,e,null,!1,!1)})),["xlink:actuate","xlink:arcrole","xlink:role","xlink:show","xlink:title","xlink:type"].forEach((e=>{const t=e.replace(o,i);u[t]=new r(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((e=>{const t=e.replace(o,i);u[t]=new r(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((e=>{u[e]=new r(e,1,!1,e.toLowerCase(),null,!1,!1)})),u.xlinkHref=new r("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((e=>{u[e]=new r(e,1,!1,e.toLowerCase(),null,!0,!0)}));const{CAMELCASE:a,SAME:s,possibleStandardNames:c}=n(8229),l=RegExp.prototype.test.bind(new RegExp("^(data|aria)-[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$")),p=Object.keys(c).reduce(((e,t)=>{const n=c[t];return n===s?e[t]=t:n===a?e[t.toLowerCase()]=t:e[t]=n,e}),{});t.BOOLEAN=3,t.BOOLEANISH_STRING=2,t.NUMERIC=5,t.OVERLOADED_BOOLEAN=4,t.POSITIVE_NUMERIC=6,t.RESERVED=0,t.STRING=1,t.getPropertyInfo=function(e){return u.hasOwnProperty(e)?u[e]:null},t.isCustomAttribute=l,t.possibleStandardNames=p},8229:function(e,t){t.SAME=0,t.CAMELCASE=1,t.possibleStandardNames={accept:0,acceptCharset:1,"accept-charset":"acceptCharset",accessKey:1,action:0,allowFullScreen:1,alt:0,as:0,async:0,autoCapitalize:1,autoComplete:1,autoCorrect:1,autoFocus:1,autoPlay:1,autoSave:1,capture:0,cellPadding:1,cellSpacing:1,challenge:0,charSet:1,checked:0,children:0,cite:0,class:"className",classID:1,className:1,cols:0,colSpan:1,content:0,contentEditable:1,contextMenu:1,controls:0,controlsList:1,coords:0,crossOrigin:1,dangerouslySetInnerHTML:1,data:0,dateTime:1,default:0,defaultChecked:1,defaultValue:1,defer:0,dir:0,disabled:0,disablePictureInPicture:1,disableRemotePlayback:1,download:0,draggable:0,encType:1,enterKeyHint:1,for:"htmlFor",form:0,formMethod:1,formAction:1,formEncType:1,formNoValidate:1,formTarget:1,frameBorder:1,headers:0,height:0,hidden:0,high:0,href:0,hrefLang:1,htmlFor:1,httpEquiv:1,"http-equiv":"httpEquiv",icon:0,id:0,innerHTML:1,inputMode:1,integrity:0,is:0,itemID:1,itemProp:1,itemRef:1,itemScope:1,itemType:1,keyParams:1,keyType:1,kind:0,label:0,lang:0,list:0,loop:0,low:0,manifest:0,marginWidth:1,marginHeight:1,max:0,maxLength:1,media:0,mediaGroup:1,method:0,min:0,minLength:1,multiple:0,muted:0,name:0,noModule:1,nonce:0,noValidate:1,open:0,optimum:0,pattern:0,placeholder:0,playsInline:1,poster:0,preload:0,profile:0,radioGroup:1,readOnly:1,referrerPolicy:1,rel:0,required:0,reversed:0,role:0,rows:0,rowSpan:1,sandbox:0,scope:0,scoped:0,scrolling:0,seamless:0,selected:0,shape:0,size:0,sizes:0,span:0,spellCheck:1,src:0,srcDoc:1,srcLang:1,srcSet:1,start:0,step:0,style:0,summary:0,tabIndex:1,target:0,title:0,type:0,useMap:1,value:0,width:0,wmode:0,wrap:0,about:0,accentHeight:1,"accent-height":"accentHeight",accumulate:0,additive:0,alignmentBaseline:1,"alignment-baseline":"alignmentBaseline",allowReorder:1,alphabetic:0,amplitude:0,arabicForm:1,"arabic-form":"arabicForm",ascent:0,attributeName:1,attributeType:1,autoReverse:1,azimuth:0,baseFrequency:1,baselineShift:1,"baseline-shift":"baselineShift",baseProfile:1,bbox:0,begin:0,bias:0,by:0,calcMode:1,capHeight:1,"cap-height":"capHeight",clip:0,clipPath:1,"clip-path":"clipPath",clipPathUnits:1,clipRule:1,"clip-rule":"clipRule",color:0,colorInterpolation:1,"color-interpolation":"colorInterpolation",colorInterpolationFilters:1,"color-interpolation-filters":"colorInterpolationFilters",colorProfile:1,"color-profile":"colorProfile",colorRendering:1,"color-rendering":"colorRendering",contentScriptType:1,contentStyleType:1,cursor:0,cx:0,cy:0,d:0,datatype:0,decelerate:0,descent:0,diffuseConstant:1,direction:0,display:0,divisor:0,dominantBaseline:1,"dominant-baseline":"dominantBaseline",dur:0,dx:0,dy:0,edgeMode:1,elevation:0,enableBackground:1,"enable-background":"enableBackground",end:0,exponent:0,externalResourcesRequired:1,fill:0,fillOpacity:1,"fill-opacity":"fillOpacity",fillRule:1,"fill-rule":"fillRule",filter:0,filterRes:1,filterUnits:1,floodOpacity:1,"flood-opacity":"floodOpacity",floodColor:1,"flood-color":"floodColor",focusable:0,fontFamily:1,"font-family":"fontFamily",fontSize:1,"font-size":"fontSize",fontSizeAdjust:1,"font-size-adjust":"fontSizeAdjust",fontStretch:1,"font-stretch":"fontStretch",fontStyle:1,"font-style":"fontStyle",fontVariant:1,"font-variant":"fontVariant",fontWeight:1,"font-weight":"fontWeight",format:0,from:0,fx:0,fy:0,g1:0,g2:0,glyphName:1,"glyph-name":"glyphName",glyphOrientationHorizontal:1,"glyph-orientation-horizontal":"glyphOrientationHorizontal",glyphOrientationVertical:1,"glyph-orientation-vertical":"glyphOrientationVertical",glyphRef:1,gradientTransform:1,gradientUnits:1,hanging:0,horizAdvX:1,"horiz-adv-x":"horizAdvX",horizOriginX:1,"horiz-origin-x":"horizOriginX",ideographic:0,imageRendering:1,"image-rendering":"imageRendering",in2:0,in:0,inlist:0,intercept:0,k1:0,k2:0,k3:0,k4:0,k:0,kernelMatrix:1,kernelUnitLength:1,kerning:0,keyPoints:1,keySplines:1,keyTimes:1,lengthAdjust:1,letterSpacing:1,"letter-spacing":"letterSpacing",lightingColor:1,"lighting-color":"lightingColor",limitingConeAngle:1,local:0,markerEnd:1,"marker-end":"markerEnd",markerHeight:1,markerMid:1,"marker-mid":"markerMid",markerStart:1,"marker-start":"markerStart",markerUnits:1,markerWidth:1,mask:0,maskContentUnits:1,maskUnits:1,mathematical:0,mode:0,numOctaves:1,offset:0,opacity:0,operator:0,order:0,orient:0,orientation:0,origin:0,overflow:0,overlinePosition:1,"overline-position":"overlinePosition",overlineThickness:1,"overline-thickness":"overlineThickness",paintOrder:1,"paint-order":"paintOrder",panose1:0,"panose-1":"panose1",pathLength:1,patternContentUnits:1,patternTransform:1,patternUnits:1,pointerEvents:1,"pointer-events":"pointerEvents",points:0,pointsAtX:1,pointsAtY:1,pointsAtZ:1,prefix:0,preserveAlpha:1,preserveAspectRatio:1,primitiveUnits:1,property:0,r:0,radius:0,refX:1,refY:1,renderingIntent:1,"rendering-intent":"renderingIntent",repeatCount:1,repeatDur:1,requiredExtensions:1,requiredFeatures:1,resource:0,restart:0,result:0,results:0,rotate:0,rx:0,ry:0,scale:0,security:0,seed:0,shapeRendering:1,"shape-rendering":"shapeRendering",slope:0,spacing:0,specularConstant:1,specularExponent:1,speed:0,spreadMethod:1,startOffset:1,stdDeviation:1,stemh:0,stemv:0,stitchTiles:1,stopColor:1,"stop-color":"stopColor",stopOpacity:1,"stop-opacity":"stopOpacity",strikethroughPosition:1,"strikethrough-position":"strikethroughPosition",strikethroughThickness:1,"strikethrough-thickness":"strikethroughThickness",string:0,stroke:0,strokeDasharray:1,"stroke-dasharray":"strokeDasharray",strokeDashoffset:1,"stroke-dashoffset":"strokeDashoffset",strokeLinecap:1,"stroke-linecap":"strokeLinecap",strokeLinejoin:1,"stroke-linejoin":"strokeLinejoin",strokeMiterlimit:1,"stroke-miterlimit":"strokeMiterlimit",strokeWidth:1,"stroke-width":"strokeWidth",strokeOpacity:1,"stroke-opacity":"strokeOpacity",suppressContentEditableWarning:1,suppressHydrationWarning:1,surfaceScale:1,systemLanguage:1,tableValues:1,targetX:1,targetY:1,textAnchor:1,"text-anchor":"textAnchor",textDecoration:1,"text-decoration":"textDecoration",textLength:1,textRendering:1,"text-rendering":"textRendering",to:0,transform:0,typeof:0,u1:0,u2:0,underlinePosition:1,"underline-position":"underlinePosition",underlineThickness:1,"underline-thickness":"underlineThickness",unicode:0,unicodeBidi:1,"unicode-bidi":"unicodeBidi",unicodeRange:1,"unicode-range":"unicodeRange",unitsPerEm:1,"units-per-em":"unitsPerEm",unselectable:0,vAlphabetic:1,"v-alphabetic":"vAlphabetic",values:0,vectorEffect:1,"vector-effect":"vectorEffect",version:0,vertAdvY:1,"vert-adv-y":"vertAdvY",vertOriginX:1,"vert-origin-x":"vertOriginX",vertOriginY:1,"vert-origin-y":"vertOriginY",vHanging:1,"v-hanging":"vHanging",vIdeographic:1,"v-ideographic":"vIdeographic",viewBox:1,viewTarget:1,visibility:0,vMathematical:1,"v-mathematical":"vMathematical",vocab:0,widths:0,wordSpacing:1,"word-spacing":"wordSpacing",writingMode:1,"writing-mode":"writingMode",x1:0,x2:0,x:0,xChannelSelector:1,xHeight:1,"x-height":"xHeight",xlinkActuate:1,"xlink:actuate":"xlinkActuate",xlinkArcrole:1,"xlink:arcrole":"xlinkArcrole",xlinkHref:1,"xlink:href":"xlinkHref",xlinkRole:1,"xlink:role":"xlinkRole",xlinkShow:1,"xlink:show":"xlinkShow",xlinkTitle:1,"xlink:title":"xlinkTitle",xlinkType:1,"xlink:type":"xlinkType",xmlBase:1,"xml:base":"xmlBase",xmlLang:1,"xml:lang":"xmlLang",xmlns:0,"xml:space":"xmlSpace",xmlnsXlink:1,"xmlns:xlink":"xmlnsXlink",xmlSpace:1,y1:0,y2:0,y:0,yChannelSelector:1,z:0,zoomAndPan:1}},8276:function(e,t){class n{constructor(){this._array=[],this._set=new Map}static fromArray(e,t){const r=new n;for(let n=0,u=e.length;n=0)return t;throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e>>=5,u>0&&(t|=32),n+=r.encode(t)}while(u>0);return n}},6728:function(e,t){const n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");t.encode=function(e){if(0<=e&&en||u==n&&i>=o||r.compareByGeneratedPositionsInflated(e,t)<=0}(this._last,e)?(this._sorted=!1,this._array.push(e)):(this._last=e,this._array.push(e))}toArray(){return this._sorted||(this._array.sort(r.compareByGeneratedPositionsInflated),this._sorted=!0),this._array}}},1027:function(e,t,n){const r=n(2020),u=n(858),o=n(8276).I,i=n(2265).H;class a{constructor(e){e||(e={}),this._file=u.getArg(e,"file",null),this._sourceRoot=u.getArg(e,"sourceRoot",null),this._skipValidation=u.getArg(e,"skipValidation",!1),this._sources=new o,this._names=new o,this._mappings=new i,this._sourcesContents=null}static fromSourceMap(e){const t=e.sourceRoot,n=new a({file:e.file,sourceRoot:t});return e.eachMapping((function(e){const r={generated:{line:e.generatedLine,column:e.generatedColumn}};null!=e.source&&(r.source=e.source,null!=t&&(r.source=u.relative(t,r.source)),r.original={line:e.originalLine,column:e.originalColumn},null!=e.name&&(r.name=e.name)),n.addMapping(r)})),e.sources.forEach((function(r){let o=r;null!=t&&(o=u.relative(t,r)),n._sources.has(o)||n._sources.add(o);const i=e.sourceContentFor(r);null!=i&&n.setSourceContent(r,i)})),n}addMapping(e){const t=u.getArg(e,"generated"),n=u.getArg(e,"original",null);let r=u.getArg(e,"source",null),o=u.getArg(e,"name",null);this._skipValidation||this._validateMapping(t,n,r,o),null!=r&&(r=String(r),this._sources.has(r)||this._sources.add(r)),null!=o&&(o=String(o),this._names.has(o)||this._names.add(o)),this._mappings.add({generatedLine:t.line,generatedColumn:t.column,originalLine:n&&n.line,originalColumn:n&&n.column,source:r,name:o})}setSourceContent(e,t){let n=e;null!=this._sourceRoot&&(n=u.relative(this._sourceRoot,n)),null!=t?(this._sourcesContents||(this._sourcesContents=Object.create(null)),this._sourcesContents[u.toSetString(n)]=t):this._sourcesContents&&(delete this._sourcesContents[u.toSetString(n)],0===Object.keys(this._sourcesContents).length&&(this._sourcesContents=null))}applySourceMap(e,t,n){let r=t;if(null==t){if(null==e.file)throw new Error('SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, or the source map\'s "file" property. Both were omitted.');r=e.file}const i=this._sourceRoot;null!=i&&(r=u.relative(i,r));const a=this._mappings.toArray().length>0?new o:this._sources,s=new o;this._mappings.unsortedForEach((function(t){if(t.source===r&&null!=t.originalLine){const r=e.originalPositionFor({line:t.originalLine,column:t.originalColumn});null!=r.source&&(t.source=r.source,null!=n&&(t.source=u.join(n,t.source)),null!=i&&(t.source=u.relative(i,t.source)),t.originalLine=r.line,t.originalColumn=r.column,null!=r.name&&(t.name=r.name))}const o=t.source;null==o||a.has(o)||a.add(o);const c=t.name;null==c||s.has(c)||s.add(c)}),this),this._sources=a,this._names=s,e.sources.forEach((function(t){const r=e.sourceContentFor(t);null!=r&&(null!=n&&(t=u.join(n,t)),null!=i&&(t=u.relative(i,t)),this.setSourceContent(t,r))}),this)}_validateMapping(e,t,n,r){if(t&&"number"!=typeof t.line&&"number"!=typeof t.column)throw new Error("original.line and original.column are not numbers -- you probably meant to omit the original mapping entirely and only map the generated position. If so, pass null for the original mapping instead of an object with empty or null values.");if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!t&&!n&&!r);else if(!(e&&"line"in e&&"column"in e&&t&&"line"in t&&"column"in t&&e.line>0&&e.column>=0&&t.line>0&&t.column>=0&&n))throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:t,name:r}))}_serializeMappings(){let e,t,n,o,i=0,a=1,s=0,c=0,l=0,p=0,d="";const h=this._mappings.toArray();for(let f=0,A=h.length;f0){if(!u.compareByGeneratedPositionsInflated(t,h[f-1]))continue;e+=","}e+=r.encode(t.generatedColumn-i),i=t.generatedColumn,null!=t.source&&(o=this._sources.indexOf(t.source),e+=r.encode(o-p),p=o,e+=r.encode(t.originalLine-1-c),c=t.originalLine-1,e+=r.encode(t.originalColumn-s),s=t.originalColumn,null!=t.name&&(n=this._names.indexOf(t.name),e+=r.encode(n-l),l=n)),d+=e}return d}_generateSourcesContent(e,t){return e.map((function(e){if(!this._sourcesContents)return null;null!=t&&(e=u.relative(t,e));const n=u.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};return null!=this._file&&(e.file=this._file),null!=this._sourceRoot&&(e.sourceRoot=this._sourceRoot),this._sourcesContents&&(e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)),e}toString(){return JSON.stringify(this.toJSON())}}a.prototype._version=3,t.SourceMapGenerator=a},1018:function(e,t,n){const r=n(1027).SourceMapGenerator,u=n(858),o=/(\r?\n)/,i="$$$isSourceNode$$$";class a{constructor(e,t,n,r,u){this.children=[],this.sourceContents={},this.line=null==e?null:e,this.column=null==t?null:t,this.source=null==n?null:n,this.name=null==u?null:u,this[i]=!0,null!=r&&this.add(r)}static fromStringWithSourceMap(e,t,n){const r=new a,i=e.split(o);let s=0;const c=function(){return e()+(e()||"");function e(){return s=0;t--)this.prepend(e[t]);else{if(!e[i]&&"string"!=typeof e)throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e);this.children.unshift(e)}return this}walk(e){let t;for(let n=0,r=this.children.length;n0){for(t=[],n=0;n=0;n--)if(36!==e.charCodeAt(n))return!1;return!0}function o(e,t){return e===t?0:null===e?1:null===t?-1:e>t?1:-1}t.toSetString=n?r:function(e){return u(e)?"$"+e:e},t.fromSetString=n?r:function(e){return u(e)?e.slice(1):e},t.compareByGeneratedPositionsInflated=function(e,t){let n=e.generatedLine-t.generatedLine;return 0!==n?n:(n=e.generatedColumn-t.generatedColumn,0!==n?n:(n=o(e.source,t.source),0!==n?n:(n=e.originalLine-t.originalLine,0!==n?n:(n=e.originalColumn-t.originalColumn,0!==n?n:o(e.name,t.name)))))};const i="http://host";function a(e){return t=>{const n=p(t),r=c(t),u=new URL(t,r);e(u);const o=u.toString();return"absolute"===n?o:"scheme-relative"===n?o.slice(5):"path-absolute"===n?o.slice(i.length):d(r,o)}}function s(e,t){return new URL(e,t).toString()}function c(e){const t=e.split("..").length-1,n=function(e,t){let n=0;for(;;){const e="p"+n++;if(-1===t.indexOf(e))return e}}(0,e);let r=`${i}/`;for(let e=0;e0&&!r[r.length-1]&&r.pop();n.length>0&&r.length>0&&n[0]===r[0];)n.shift(),r.shift();return r.map((()=>"..")).concat(n).join("/")+t.search+t.hash}const h=a((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")})),f=a((e=>{}));t.normalize=f,t.join=function(e,t){const n=p(t),r=p(e);if(e=h(e),"absolute"===n)return s(t,void 0);if("absolute"===r)return s(t,e);if("scheme-relative"===n)return f(t);if("scheme-relative"===r)return s(t,s(e,i)).slice(5);if("path-absolute"===n)return f(t);if("path-absolute"===r)return s(t,s(e,i)).slice(i.length);const u=c(t+e);return d(u,s(t,s(e,u)))},t.relative=function(e,t){const n=function(e,t){if(p(e)!==p(t))return null;const n=c(e+t),r=new URL(e,n),u=new URL(t,n);try{new URL("",u.toString())}catch(e){return null}return u.protocol!==r.protocol||u.user!==r.user||u.password!==r.password||u.hostname!==r.hostname||u.port!==r.port?null:d(r,u)}(e,t);return"string"==typeof n?n:f(t)}},4738:function(e,t,n){t.SourceMapGenerator=n(1027).SourceMapGenerator,t.SourceNode=n(1018).SourceNode},1476:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var u=r(n(5174)),o=n(6678);t.default=function(e,t){var n={};return e&&"string"==typeof e?((0,u.default)(e,(function(e,r){e&&r&&(n[(0,o.camelCase)(e,t)]=r)})),n):n}},6678:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.camelCase=void 0;var n=/^--[a-zA-Z0-9-]+$/,r=/-([a-z])/g,u=/^[^-]+$/,o=/^-(webkit|moz|ms|o|khtml)-/,i=/^-(ms)-/,a=function(e,t){return t.toUpperCase()},s=function(e,t){return"".concat(t,"-")};t.camelCase=function(e,t){return void 0===t&&(t={}),function(e){return!e||u.test(e)||n.test(e)}(e)?e:(e=e.toLowerCase(),(e=t.reactCompat?e.replace(i,s):e.replace(o,s)).replace(r,a))}},5174:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var u=r(n(8139));t.default=function(e,t){var n=null;if(!e||"string"!=typeof e)return n;var r=(0,u.default)(e),o="function"==typeof t;return r.forEach((function(e){if("declaration"===e.type){var r=e.property,u=e.value;o?t(r,u,e):u&&((n=n||{})[r]=u)}})),n}},9196:function(e){"use strict";e.exports=window.React}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.exports}var __webpack_exports__={};!function(){"use strict";var e=window.wp.blocks,t=window.wp.element;const n=__webpack_require__(4193).generate('\n{{\n\tfunction evaluateUnaryExpression( operator, operand ) {\n\t\tswitch ( operator ) {\n\t\t\tcase \'!\':\n\t\t\t\treturn !operand;\n\t\t\t\tbreak;\n\t\t\tcase \'-\':\n\t\t\t\treturn -operand;\n\t\t\t\tbreak;\n\t\t\tcase \'+\':\n\t\t\t\treturn +operand;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tfunction evaluateBinaryExpression( head, tail ) {\n\t\treturn tail.reduce( ( leftOperand, tailElement ) => {\n\t\t\tconst operator = tailElement[ 1 ];\n\t\t\tconst rightOperand = tailElement[ 3 ];\n\n\t\t\tswitch ( operator ) {\n\t\t\t\tcase \'&&\':\n\t\t\t\t\treturn leftOperand && rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'||\':\n\t\t\t\t\treturn leftOperand || rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'===\':\n\t\t\t\t\treturn leftOperand === rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'!==\':\n\t\t\t\t\treturn leftOperand !== rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'==\':\n\t\t\t\t\treturn leftOperand == rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'!=\':\n\t\t\t\t\treturn leftOperand != rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'<=\':\n\t\t\t\t\treturn leftOperand <= rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'<\':\n\t\t\t\t\treturn leftOperand < rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'>=\':\n\t\t\t\t\treturn leftOperand >= rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'>\':\n\t\t\t\t\treturn leftOperand > rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'+\':\n\t\t\t\t\treturn leftOperand + rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'-\':\n\t\t\t\t\treturn leftOperand - rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'*\':\n\t\t\t\t\treturn leftOperand * rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'/\':\n\t\t\t\t\treturn leftOperand / rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'%\':\n\t\t\t\t\treturn leftOperand % rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn undefined;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}, head );\n\t}\n\n\tfunction getPropertyValue( obj, propertyName ) {\n\t\tif ( Object.hasOwn( obj, propertyName ) ) {\n\t\t\treturn obj[ propertyName ];\n\t\t} else if (\n\t\t\tArray.isArray( obj ) &&\n\t\t\tobj.length > 0 &&\n\t\t\tObject.hasOwn( obj[ 0 ], \'key\' ) &&\n\t\t\tObject.hasOwn( obj[ 0 ], \'value\' )\n\t\t) {\n\t\t\t// We likely dealing with an array of objects with key/value pairs (like post meta data)\n\t\t\tconst item = obj.find( ( item ) => item.key === propertyName );\n\t\t\treturn item?.value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}}\n\nStart\n\t= Expression\n\nSourceCharacter\n\t= .\n\nWhiteSpace\n\t= " "\n\t/ "\\t"\n\nLineTerminator\n\t= "\\n"\n\t/ "\\r"\n\t/ "\\u2028"\n\t/ "\\u2029"\n\nLineTerminatorSequence\n\t= "\\n"\n\t/ "\\r\\n"\n\t/ "\\r"\n\t/ "\\u2028"\n\t/ "\\u2029"\n\nComment "comment"\n\t= MultiLineComment\n\nMultiLineComment\n\t= "/*" (!"*/" SourceCharacter)* "*/"\n\n__ "skipped"\n\t= (WhiteSpace / LineTerminatorSequence / Comment)*\n\nIdentifierPath\n\t= variable:Identifier accessor:(__ "." __ Identifier)* {\n\t\tconst path = variable.split( \'.\' );\n\t\tlet result = path.reduce( getPropertyValue, options.context );\n\n\t\tfor ( let i = 0; i < accessor.length; i++ ) {\n\t\t\tresult = getPropertyValue( result, accessor[ i ][ 3 ] );\n\t\t}\n\n\t\treturn result;\n\t}\n\nIdentifier\n\t= !ReservedWord name:IdentifierName {\n\t\treturn name;\n\t}\n\nIdentifierName\n\t= first:IdentifierStart rest:IdentifierPart* {\n\t\treturn text();\n\t}\n\nIdentifierStart\n\t= [a-zA-Z]\n\t/ "_"\n\t/ "$"\n\nIdentifierPart\n\t= IdentifierStart\n\nReservedWord\n\t= NullLiteral\n\t/ BooleanLiteral\n\n// Literals\n\nLiteral\n\t= NullLiteral\n\t/ BooleanLiteral\n\t/ NumericLiteral\n\t/ StringLiteral\n\nNullLiteral\n\t= NullToken { return null; }\n\nBooleanLiteral\n\t= "true" { return true; }\n\t/ "false" { return false; }\n\nNumericLiteral\n\t= literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) {\n\t\treturn literal;\n\t}\n\t/ literal:DecimalLiteral !(IdentifierStart / DecimalDigit) {\n\t\treturn literal;\n\t}\n\nHexIntegerLiteral\n\t= "0x"i digits:$HexDigit+ {\n\t\treturn parseInt( digits, 16 );\n\t}\n\nHexDigit\n\t= [0-9a-f]i\n\nDecimalLiteral\n\t= DecimalIntegerLiteral "." DecimalDigit* ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\t/ "." DecimalDigit+ ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\t/ DecimalIntegerLiteral ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\nDecimalIntegerLiteral\n\t= "0"\n\t/ NonZeroDigit DecimalDigit*\n\nDecimalDigit\n\t= [0-9]\n\nNonZeroDigit\n\t= [1-9]\n\nExponentPart\n\t= ExponentIndicator SignedInteger\n\nExponentIndicator\n\t= "e"i\n\nSignedInteger\n\t= [+-]? DecimalDigit+\n\nStringLiteral\n\t= \'"\' chars:DoubleQuotedStringCharacter* \'"\' {\n\t\treturn chars.join( \'\' );\n\t}\n\t/ "\'" chars:SingleQuotedStringCharacter* "\'" {\n\t\treturn chars.join( \'\' );\n\t}\n\nDoubleQuotedStringCharacter\n\t= !(\'"\' / "\\\\" / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\t/ "\\\\" escapeSequence:EscapeSequence {\n\t\treturn escapeSequence;\n\t}\n\t/ LineContinuation\n\nSingleQuotedStringCharacter\n\t= !("\'" / "\\\\" / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\t/ "\\\\" escapeSequence:EscapeSequence {\n\t\treturn escapeSequence;\n\t}\n\t/ LineContinuation\n\nLineContinuation\n\t= "\\\\" LineTerminatorSequence {\n\t\treturn \'\';\n\t}\n\nEscapeSequence\n\t= CharacterEscapeSequence\n\t/ "0" !DecimalDigit {\n\t\treturn "\\0";\n\t}\n\t/ HexEscapeSequence\n\t/ UnicodeEscapeSequence\n\nCharacterEscapeSequence\n\t= SingleEscapeCharacter\n\t/ NonEscapeCharacter\n\nSingleEscapeCharacter\n\t= "\'"\n\t/ \'"\'\n\t/ "\\\\"\n\t/ "b" {\n\t\treturn "\\b";\n\t}\n\t/ "f" {\n\t\treturn "\\f";\n\t}\n\t/ "n" {\n\t\treturn "\\n";\n\t}\n\t/ "r" {\n\t\treturn "\\r";\n\t}\n\t/ "t" {\n\t\treturn "\\t";\n\t}\n\t/ "v" {\n\t\treturn "\\v";\n\t}\n\nNonEscapeCharacter\n\t= (!EscapeCharacter / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\nEscapeCharacter\n\t= SingleEscapeCharacter\n\t/ DecimalDigit\n\t/ "x"\n\t/ "u"\n\nHexEscapeSequence\n\t= "x" digits:$(HexDigit HexDigit) {\n\t\treturn String.fromCharCode( parseInt( digits, 16 ) );\n\t}\n\nUnicodeEscapeSequence\n\t= "u" digits:$(HexDigit HexDigit HexDigit HexDigit) {\n\t\treturn String.fromCharCode( parseInt( digits, 16 ) );\n\t}\n\n// Tokens\n\nNullToken\n\t= "null" !IdentifierPart\n\nTrueToken\n\t= "true" !IdentifierPart\n\nFalseToken\n\t= "false" !IdentifierPart\n\n// Expressions\n\nPrimaryExpression\n\t= IdentifierPath\n\t/ Literal\n\t/ "(" __ expression:Expression __ ")" {\n\t\treturn expression;\n\t}\n\nUnaryExpression\n\t= PrimaryExpression\n\t/ operator:UnaryOperator __ operand:UnaryExpression {\n\t\treturn evaluateUnaryExpression( operator, operand );\n\t}\n\nUnaryOperator\n\t= "!"\n\t/ "-"\n\t/ "+"\n\nMultiplicativeExpression\n\t= head:UnaryExpression tail:(__ MultiplicativeOperator __ UnaryExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nMultiplicativeOperator\n\t= "*"\n\t/ "/"\n\t/ "%"\n\nAdditiveExpression\n\t= head:MultiplicativeExpression tail:(__ AdditiveOperator __ MultiplicativeExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nAdditiveOperator\n\t= "+"\n\t/ "-"\n\nRelationalExpression\n\t= head:AdditiveExpression tail:(__ RelationalOperator __ AdditiveExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nRelationalOperator\n\t= "<="\n\t/ "<"\n\t/ ">="\n\t/ ">"\n\nEqualityExpression\n\t= head:RelationalExpression tail:(__ EqualityOperator __ RelationalExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nEqualityOperator\n\t= "==="\n\t/ "!=="\n\t/ "=="\n\t/ "!="\n\nLogicalAndExpression\n\t= head:EqualityExpression tail:(__ LogicalAndOperator __ EqualityExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nLogicalAndOperator\n\t= "&&"\n\nLogicalOrExpression\n\t= head:LogicalAndExpression tail:(__ LogicalOrOperator __ LogicalAndExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nLogicalOrOperator\n\t= "||"\n\nConditionalExpression\n\t= condition:LogicalOrExpression __ ConditionalTrueOperator __ expressionIfTrue:ConditionalExpression __ ConditionalFalseOperator __ expressionIfFalse:ConditionalExpression {\n\t\treturn condition ? expressionIfTrue : expressionIfFalse;\n\t}\n\t/ LogicalOrExpression\n\nConditionalTrueOperator\n\t= "?"\n\nConditionalFalseOperator\n\t= ":"\n\nExpression\n\t= __ expression:ConditionalExpression __ {\n\t\treturn expression;\n\t}\n');function r(e,t={}){return n.parse(e,{context:t})}var u=window.wp.data;function o(e){return{getEvaluationContext:()=>e}}function i(e,n){return o=>{const{context:i}=o,{_templateBlockHideConditions:a,_templateBlockDisableConditions:s}=o.attributes,{getEvaluationContext:c}=n(i),{shouldHide:l,shouldDisable:p}=(0,u.useSelect)((e=>{const t=c(e);return{shouldHide:a&&Array.isArray(a)&&a.some((e=>r(e.expression,t))),shouldDisable:s&&Array.isArray(s)&&s.some((e=>r(e.expression,t)))}}),[c,a,s]);return!e||l?null:(0,t.createElement)(e,{...o,attributes:{...o.attributes,disabled:o.attributes.disabled||p}})}}var a=window.wp.coreData;function s(e){const{postType:t}=e,n=(0,a.useEntityId)("postType",t);return{getEvaluationContext:r=>{const u=r("core").getEditedEntityRecord("postType",t,n);return{...e,editedProduct:u}}}}var c=__webpack_require__(9196),l=window.wp.blockEditor,p=__webpack_require__(3426),d=p.default||p,h=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"woocommerce-pre-orders/message-control-block","version":"0.1.0","title":"Message Block","category":"widgets","icon":"flag","description":"A block to display messages in plain-text or HTML.","attributes":{"content":{"type":"string","default":""}},"supports":{"html":true,"inserter":false},"textdomain":"woocommerce-pre-orders","editorScript":"file:./index.js"}');const{name:f,...A}=h;!function(t){const{metadata:n,settings:r,name:u}=t;var a;!function(t,n){if(!t)return;const{metadata:r,settings:u,name:a}=t,{edit:s}=u;if(!s)return;const c={...r,attributes:(l=r.attributes,{...l,_templateBlockId:{type:"string",__experimentalRole:"content"},_templateBlockOrder:{type:"integer",__experimentalRole:"content"},_templateBlockHideConditions:{type:"array",__experimentalRole:"content"},_templateBlockDisableConditions:{type:"array",__experimentalRole:"content"},disabled:l.disabled||{type:"boolean",__experimentalRole:"content"}})};var l;(0,e.registerBlockType)({name:a,...c},{...u,edit:i(s,null!=n?n:o)})}({name:u,metadata:{...n,usesContext:(a=n.usesContext,[...a||[],"postType"])},settings:r},s)}({name:f,metadata:A,settings:{example:{},edit:function({attributes:e,context:{postType:t}}){const n=((e,t={})=>{const n={"data-template-block-id":e._templateBlockId,"data-template-block-order":e._templateBlockOrder,tabIndex:-1,...t};return(0,l.useBlockProps)(n)})(e);let{content:r}=e;const[u]=(0,a.useEntityProp)("postType","product","id");return r=r.replace("postIdPlaceholder",u.toString()),(0,c.createElement)("div",{...n},(0,c.createElement)("div",{dangerouslySetInnerHTML:{__html:d(r)}}))}}})}()})();
\ No newline at end of file
diff --git a/build/admin/blocks/select-control/block.json b/build/admin/blocks/select-control/block.json
new file mode 100644
index 0000000..125e9d0
--- /dev/null
+++ b/build/admin/blocks/select-control/block.json
@@ -0,0 +1,38 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "woocommerce-pre-orders/select-control-block",
+ "version": "0.1.0",
+ "title": "Select Control",
+ "category": "widgets",
+ "icon": "flag",
+ "description": "A block to display a select control.",
+ "attributes": {
+ "property": {
+ "type": "string",
+ "default": ""
+ },
+ "title": {
+ "type": "string",
+ "default": ""
+ },
+ "help": {
+ "type": "string",
+ "default": ""
+ },
+ "options": {
+ "type": "array",
+ "default": []
+ },
+ "multiple": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "supports": {
+ "html": false,
+ "inserter": false
+ },
+ "textdomain": "woocommerce-pre-orders",
+ "editorScript": "file:./index.js"
+}
\ No newline at end of file
diff --git a/build/admin/blocks/select-control/index.asset.php b/build/admin/blocks/select-control/index.asset.php
new file mode 100644
index 0000000..7aa9913
--- /dev/null
+++ b/build/admin/blocks/select-control/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element'), 'version' => '74680c32b8e4367aeb3f54aac6d6ed2c');
\ No newline at end of file
diff --git a/build/admin/blocks/select-control/index.js b/build/admin/blocks/select-control/index.js
new file mode 100644
index 0000000..5449b9e
--- /dev/null
+++ b/build/admin/blocks/select-control/index.js
@@ -0,0 +1 @@
+(function(){var __webpack_modules__={4157:function(e,t){!function(){var e={814:function(e,t,n){var r;function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}!function(){"use strict";var u={}.hasOwnProperty;function i(){for(var e=[],t=0;t0?" ".concat(t[5]):""," {")),n+=e(t),r&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,r,o,u){"string"==typeof e&&(e=[[null,e,void 0]]);var i={};if(r)for(var a=0;a0?" ".concat(l[5]):""," {").concat(l[1],"}")),l[5]=u),n&&(l[2]?(l[1]="@media ".concat(l[2]," {").concat(l[1],"}"),l[2]=n):l[2]=n),o&&(l[4]?(l[1]="@supports (".concat(l[4],") {").concat(l[1],"}"),l[4]=o):l[4]="".concat(o)),t.push(l))}},t}},499:function(e){"use strict";e.exports=function(e){return e[1]}},245:function(e,t,n){"use strict";var r=n(499),o=n.n(r),u=n(922),i=n.n(u)()(o());i.push([e.id,':root{--wp-admin-theme-color: #007cba;--wp-admin-theme-color--rgb: 0,124,186;--wp-admin-theme-color-darker-10: #006ba1;--wp-admin-theme-color-darker-10--rgb: 0,107,160.5;--wp-admin-theme-color-darker-20: #005a87;--wp-admin-theme-color-darker-20--rgb: 0,90,135;--wp-admin-border-width-focus: 2px}@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi){:root{--wp-admin-border-width-focus: 1.5px}}.codeamp-components-multi-select-control__input-container{font-size:13px;line-height:normal}.codeamp-components-multi-select-control__input-container{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;padding:6px 8px;box-shadow:0 0 0 transparent;transition:box-shadow 0.1s linear;border-radius:2px;border:1px solid #757575;font-size:16px;line-height:normal;width:100%;margin:0 0 8px 0;padding:0;cursor:text}@media (prefers-reduced-motion: reduce){.codeamp-components-multi-select-control__input-container{transition-duration:0s;transition-delay:0s}}@media (min-width: 600px){.codeamp-components-multi-select-control__input-container{font-size:13px;line-height:normal}}.codeamp-components-multi-select-control__input-container:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 1px var(--wp-admin-theme-color);outline:2px solid transparent}.codeamp-components-multi-select-control__input-container::-webkit-input-placeholder{color:rgba(30,30,30,0.62)}.codeamp-components-multi-select-control__input-container::-moz-placeholder{opacity:1;color:rgba(30,30,30,0.62)}.codeamp-components-multi-select-control__input-container:-ms-input-placeholder{color:rgba(30,30,30,0.62)}.codeamp-components-multi-select-control__input-container.is-disabled{background:#ddd;border-color:#ddd}.codeamp-components-multi-select-control__input-container.is-active{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 1px var(--wp-admin-theme-color);outline:2px solid transparent}.codeamp-components-multi-select-control__input-container input[type="text"].codeamp-components-multi-select-control__input{display:inline-block;flex:1;font-family:inherit;font-size:16px;width:100%;max-width:100%;margin-left:4px;padding:0;min-height:24px;min-width:50px;background:inherit;border:0;color:#1e1e1e;box-shadow:none}@media (min-width: 600px){.codeamp-components-multi-select-control__input-container input[type="text"].codeamp-components-multi-select-control__input{font-size:13px}}.codeamp-components-multi-select-control__input-container input[type="text"].codeamp-components-multi-select-control__input:focus,.codeamp-components-multi-select-control.is-active .codeamp-components-multi-select-control__input-container input[type="text"].codeamp-components-multi-select-control__input{outline:none;box-shadow:none}.codeamp-components-multi-select-control__input-container .codeamp-components-multi-select-control__token+input[type="text"].codeamp-components-multi-select-control__input{width:auto}.codeamp-components-multi-select-control__help{font-size:12px;font-style:normal;color:#757575}.codeamp-components-multi-select-control__tokens-container{padding:4px}.codeamp-components-multi-select-control__token{font-size:13px;display:flex;color:#1e1e1e;max-width:100%}.codeamp-components-multi-select-control__token.is-borderless{position:relative;padding:0 24px 0 0}.codeamp-components-multi-select-control__token.is-borderless .codeamp-components-multi-select-control__token-text{background:transparent;color:var(--wp-admin-theme-color)}.codeamp-components-multi-select-control__token.is-borderless .codeamp-components-multi-select-control__remove-token{background:transparent;color:#757575;position:absolute;top:1px;right:0;padding:0}.codeamp-components-multi-select-control__token.is-borderless.is-success .codeamp-components-multi-select-control__token-text{color:#4ab866}.codeamp-components-multi-select-control__token.is-borderless.is-error .codeamp-components-multi-select-control__token-text{color:#cc1818;border-radius:4px 0 0 4px;padding:0 4px 0 6px}.codeamp-components-multi-select-control__token.is-borderless.is-validating .codeamp-components-multi-select-control__token-text{color:#1e1e1e}.codeamp-components-multi-select-control__token.is-disabled .codeamp-components-multi-select-control__remove-token{cursor:default}.codeamp-components-multi-select-control__token-text,.codeamp-components-multi-select-control__remove-token.components-button{display:inline-block;line-height:24px;height:auto;background:#ddd;min-width:unset;transition:all 0.2s cubic-bezier(0.4, 1, 0.4, 1)}@media (prefers-reduced-motion: reduce){.codeamp-components-multi-select-control__token-text,.codeamp-components-multi-select-control__remove-token.components-button{transition-duration:0s;transition-delay:0s;animation-duration:1ms;animation-delay:0s}}.codeamp-components-multi-select-control__token-text{border-radius:2px 0 0 2px;padding:0 0 0 8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.codeamp-components-multi-select-control__remove-token.components-button{cursor:pointer;border-radius:0 2px 2px 0;padding:0 2px;color:#1e1e1e;line-height:10px;overflow:initial}.codeamp-components-multi-select-control__remove-token.components-button:hover{color:#1e1e1e}.codeamp-components-multi-select-control__suggestions-list{flex:1 0 100%;min-width:100%;max-height:9em;overflow-y:auto;transition:all 0.15s ease-in-out;list-style:none;border-top:1px solid #757575;margin:0;padding:0}@media (prefers-reduced-motion: reduce){.codeamp-components-multi-select-control__suggestions-list{transition-duration:0s;transition-delay:0s}}.codeamp-components-multi-select-control__no-suggestions{color:#757575;font-size:13px;margin:0;display:block;padding:4px 8px}.codeamp-components-multi-select-control__suggestion{color:#757575;display:block;font-size:13px;padding:4px 8px;margin:0;cursor:pointer}.codeamp-components-multi-select-control__suggestion.is-selected{background:var(--wp-admin-theme-color);color:#fff}.codeamp-components-multi-select-control__suggestion-match{text-decoration:underline}\n',""]),t.Z=i},313:function(e,t,n){"use strict";var r=n(499),o=n.n(r),u=n(922),i=n.n(u)()(o());i.push([e.id,".codeamp-components-resource-select-control>.components-base-control__field{position:relative;display:flex;flex-wrap:wrap}.codeamp-components-resource-select-control>.components-base-control__field>.components-base-control__label{flex:2}.codeamp-components-resource-select-control__label{margin-bottom:8px}.codeamp-components-resource-select-control__add_button{padding:0;margin:0;min-height:revert;height:auto;color:var(--wp-admin-theme-color);align-self:center;justify-content:right;margin-bottom:8px}.codeamp-components-resource-select-control__add_button:hover{text-decoration:underline}.codeamp-components-resource-select-control__edit_button{height:auto;margin-bottom:8px}.codeamp-components-resource-select-control__select{width:auto;flex:1}.codeamp-components-resource-select-control .components-base-control{margin-bottom:8px}.codeamp-components-resource-select-control .components-base-control__field{margin-bottom:0}.codeamp-components-resource-select-control .components-base-control{flex:1}\n",""]),t.Z=i},379:function(e){"use strict";var t=[];function n(e){for(var n=-1,r=0;r0?" ".concat(n.layer):""," {")),r+=n.css,o&&(r+="}"),n.media&&(r+="}"),n.supports&&(r+="}");var u=n.sourceMap;u&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(u))))," */")),t.styleTagTransform(r,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:function(e){"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}}},n={};function r(t){var o=n[t];if(void 0!==o)return o.exports;var u=n[t]={id:t,exports:{}};return e[t](u,u.exports,r),u.exports}r.amdO={},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nc=void 0;var o={};!function(){"use strict";r.r(o),r.d(o,{MultiSelectControl:function(){return ye},ResourceSelectControl:function(){return x}});var e=window.wp.i18n,t=window.wp.components,n=window.wp.compose,u=r(379),i=r.n(u),a=r(795),s=r.n(a),c=r(569),l=r.n(c),p=r(565),d=r.n(p),f=r(216),h=r.n(f),m=r(589),g=r.n(m),A=r(313),E={};E.styleTagTransform=g(),E.setAttributes=d(),E.insert=l().bind(null,"head"),E.domAPI=s(),E.insertStyleElement=h(),i()(A.Z,E),A.Z&&A.Z.locals&&A.Z.locals;var v=r(814),y=r.n(v);function C(){return C=Object.assign?Object.assign.bind():function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}(e,T),p=function(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,u=[],i=!0,a=!1;try{for(n=n.call(e);!(i=(r=n.next()).done)&&(u.push(r.value),2!==u.length);i=!0);}catch(e){a=!0,o=e}finally{try{i||null==n.return||n.return()}finally{if(a)throw o}}return u}}(e)||function(e,t){if(e){if("string"==typeof e)return R(e,2);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?R(e,2):void 0}}(e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}((0,F.useState)(!1)),d=p[0],f=p[1],h=n?n.length+1:0;return React.createElement("input",I({ref:t,id:o,type:"text"},l,{value:n||"",onChange:function(e){a&&a({value:e.target.value})},onFocus:function(e){f(!0),null==s||s(e)},onBlur:function(e){f(!1),null==c||c(e)},size:h,className:y()(i,"codeamp-components-multi-select-control__input"),autoComplete:"off",role:"combobox","aria-expanded":r,"aria-autocomplete":"list","aria-owns":r?"".concat(o,"-suggestions"):void 0,"aria-activedescendant":d&&-1!==u&&r?"".concat(o,"-suggestions-").concat(u):void 0,"aria-describedby":"".concat(o,"-howto"),"data-lpignore":"true"}))}));function N(e){return N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},N(e)}function $(e){return $="function"==typeof Symbol&&"symbol"===N(Symbol.iterator)?function(e){return N(e)}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":N(e)},$(e)}function M(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function j(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function U(e,t){var n=e["page".concat(t?"Y":"X","Offset")],r="scroll".concat(t?"Top":"Left");if("number"!=typeof n){var o=e.document;"number"!=typeof(n=o.documentElement[r])&&(n=o.body[r])}return n}function H(e){return U(e)}function z(e){return U(e,!0)}function q(e){var t=function(e){var t,n,r,o=e.ownerDocument,u=o.body,i=o&&o.documentElement;return n=(t=e.getBoundingClientRect()).left,r=t.top,{left:n-=i.clientLeft||u.clientLeft||0,top:r-=i.clientTop||u.clientTop||0}}(e),n=e.ownerDocument,r=n.defaultView||n.parentWindow;return t.left+=H(r),t.top+=z(r),t}var V,W=new RegExp("^(".concat(/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,")(?!px)[a-z%]+$"),"i"),G=/^(top|right|bottom|left)$/;function Y(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n-1&&o&&e.children[r]&&(h(!0),function(e,t,n){n=n||{},9===t.nodeType&&(t=oe.getWindow(t));var r=n.allowHorizontalScroll,o=n.onlyScrollIfNeeded,u=n.alignWithTop,i=n.alignWithLeft,a=n.offsetTop||0,s=n.offsetLeft||0,c=n.offsetBottom||0,l=n.offsetRight||0;r=void 0===r||r;var p,d,f,h,m,g,A,E,v,y,C=oe.isWindow(t),b=oe.offset(e),_=oe.outerHeight(e),x=oe.outerWidth(e);C?(A=t,y=oe.height(A),v=oe.width(A),E={left:oe.scrollLeft(A),top:oe.scrollTop(A)},m={left:b.left-E.left-s,top:b.top-E.top-a},g={left:b.left+x-(E.left+v)+l,top:b.top+_-(E.top+y)+c},h=E):(p=oe.offset(t),d=t.clientHeight,f=t.clientWidth,h={left:t.scrollLeft,top:t.scrollTop},m={left:b.left-(p.left+(parseFloat(oe.css(t,"borderLeftWidth"))||0))-s,top:b.top-(p.top+(parseFloat(oe.css(t,"borderTopWidth"))||0))-a},g={left:b.left+x-(p.left+f+(parseFloat(oe.css(t,"borderRightWidth"))||0))+l,top:b.top+_-(p.top+d+(parseFloat(oe.css(t,"borderBottomWidth"))||0))+c}),m.top<0||g.top>0?!0===u?oe.scrollTop(t,h.top+m.top):!1===u?oe.scrollTop(t,h.top+g.top):m.top<0?oe.scrollTop(t,h.top+m.top):oe.scrollTop(t,h.top+g.top):o||((u=void 0===u||!!u)?oe.scrollTop(t,h.top+m.top):oe.scrollTop(t,h.top+g.top)),r&&(m.left<0||g.left>0?!0===i?oe.scrollLeft(t,h.left+m.left):!1===i?oe.scrollLeft(t,h.left+g.left):m.left<0?oe.scrollLeft(t,h.left+m.left):oe.scrollLeft(t,h.left+g.left):o||((i=void 0===i||!!i)?oe.scrollLeft(t,h.left+m.left):oe.scrollLeft(t,h.left+g.left)))}(e.children[r],e,{onlyScrollIfNeeded:!0}),t=requestAnimationFrame((function(){h(!1)}))),function(){void 0!==t&&cancelAnimationFrame(t)}}),[r,o]),g=function(e){return function(){f||null==i||i(e)}},A=function(e){return function(){null==a||a(e)}};return React.createElement("ul",{ref:m,className:"codeamp-components-multi-select-control__suggestions-list",id:"".concat(l,"-suggestions"),role:"listbox"},0===c.length&&React.createElement("li",{className:"codeamp-components-multi-select-control__no-suggestions",role:"option"},(0,e.__)("No results found.","codeamp-block-components")),c.map((function(e,t){var n,o=function(e){var t=e.label.toLocaleLowerCase().indexOf(u);return{suggestionBeforeMatch:e.label.substring(0,t),suggestionMatch:e.label.substring(t,t+u.length),suggestionAfterMatch:e.label.substring(t+u.length)}}(e),i=y()("codeamp-components-multi-select-control__suggestion",{"is-selected":t===r});return n="function"==typeof p?p({item:e}):o?React.createElement("span",{"aria-label":e.label},o.suggestionBeforeMatch,React.createElement("strong",{className:"codeamp-components-multi-select-control__suggestion-match"},o.suggestionMatch),o.suggestionAfterMatch):e.label,React.createElement("li",{id:"".concat(l,"-suggestions-").concat(t),role:"option",className:i,key:e.value,onMouseDown:ie,onClick:A(e),onMouseEnter:g(e),"aria-selected":t===r},n)})))},se=r(245),ce={};function le(){return le=Object.assign?Object.assign.bind():function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:[]).find((function(e){return-1!==e.label.toLocaleLowerCase().indexOf(t.trim().toLocaleLowerCase())}));return n}ce.styleTagTransform=g(),ce.setAttributes=d(),ce.insert=l().bind(null,"head"),ce.domAPI=s(),ce.insertStyleElement=h(),i()(se.Z,ce),se.Z&&se.Z.locals&&se.Z.locals;var ve=function(){};function ye(r){var o=r.autoCapitalize,u=r.autoComplete,i=r.maxLength,a=r.placeholder,s=r.label,c=void 0===s?(0,e.__)("Add item"):s,l=r.help,p=r.className,d=r.suggestions,f=void 0===d?[]:d,h=r.options,m=void 0===h?[]:h,g=r.maxSuggestions,A=void 0===g?100:g,E=r.value,v=void 0===E?[]:E,C=r.onChange,b=void 0===C?function(){}:C,_=r.onInputChange,x=void 0===_?function(){}:_,S=r.onFocus,B=void 0===S?void 0:S,P=(r.isBorderless,r.id),O=r.disabled,T=void 0!==O&&O,I=r.messages,R=void 0===I?{added:(0,e.__)("Item added."),removed:(0,e.__)("Item removed."),remove:(0,e.__)("Remove item"),__experimentalInvalid:(0,e.__)("Invalid item")}:I,N=r.__experimentalRenderItem,$=r.__experimentalAutoSelectFirstMatch,M=void 0===$||$,j=r.__experimentalValidateInput,U=void 0===j?function(){return!0}:j,H=r.__experimentalCloseSuggestionsOnSelect,z=void 0===H||H,q=r.__next36pxDefaultSize,V=void 0!==q&&q,W=(0,n.useInstanceId)(ye,"codeamp-components-multi-select-control");P&&(W=P);var G=me((0,F.useState)(""),2),Y=G[0],X=G[1],Z=me((0,F.useState)(0),2),J=Z[0],K=Z[1],Q=me((0,F.useState)(!1),2),ee=Q[0],te=Q[1],ne=me((0,F.useState)(!1),2),re=ne[0],oe=ne[1],ue=me((0,F.useState)(-1),2),ie=ue[0],se=ue[1],ce=me((0,F.useState)(!1),2),ge=ce[0],Ae=ce[1],Ce=(0,n.usePrevious)(f),be=(0,n.usePrevious)(v),_e=(0,F.useRef)(null),xe=(0,F.useRef)(null),Fe=(0,n.useDebounce)(D.speak,500);function De(){var e;null===(e=_e.current)||void 0===e||e.focus()}function Se(){var e;return _e.current===(null===(e=_e.current)||void 0===e?void 0:e.ownerDocument.activeElement)}function we(e){Se()||e.target===xe.current?(te(!0),oe(!0)):te(!1),"function"==typeof B&&B(e)}function Be(e){e.target===xe.current&&ee&&e.preventDefault()}function Pe(e){Re(e.value),De()}function Oe(e){var t=!1;return Se()&&je()&&(e(),t=!0),t}function ke(){var e=Me()-1;e>-1&&Re(v[e])}function Te(){var e=Me();e0){var t=he(v);t.splice.apply(t,[Me(),0].concat(he(e))),b(t)}}([e.value]),(0,D.speak)(R.added,"assertive"),X(""),Ae(!1),se(-1),z&&oe(!1),ee&&De()):(0,D.speak)(R.__experimentalInvalid,"assertive")}function Re(e){var t=v.filter((function(t){return Le(t)!==Le(e)}));b(t),(0,D.speak)(R.removed,"assertive")}function Le(e){return"object"===fe(e)?e.value:e}function Ne(){return m.filter((function(e){return-1===v.indexOf(e.value)}))}function $e(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Y,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Ne(),n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:A;if(""!==e.trim()){var r=[],o=[];t.forEach((function(t){var n=t.label.toLocaleLowerCase().indexOf(e.trim().toLocaleLowerCase());0===n?r.push(t):n>0&&o.push(t)})),t=r.concat(o)}return t.slice(0,n)}function Me(){return v.length-J}function je(){return 0===Y.length}function Ue(){var e,t;return(null===(e=Ee(Y))||void 0===e||null===(t=e.label)||void 0===t?void 0:t.length)>0}function He(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],n=$e(Y),r=n.length>0;t&&(M&&r?(se(0),Ae(!0)):(se(-1),Ae(!1))),se(0);var o=r?(0,e.sprintf)((0,e._n)("%d result found, use up and down arrow keys to navigate.","%d results found, use up and down arrow keys to navigate.",n.length),n.length):(0,e.__)("No results.");Fe(o,"assertive")}(0,F.useEffect)((function(){ee&&!Se()&&De()}),[ee]),(0,F.useEffect)((function(){var e=!w()(f,Ce||[]);(e||v!==be)&&He(e)}),[f,Ce,v,be]),(0,F.useEffect)((function(){He()}),[Y]),T&&ee&&(te(!1),X(""));var ze,qe,Ve=y()(p,"codeamp-components-multi-select-control__input-container",{"is-active":ee,"is-disabled":T}),We={className:"components-base-control codeamp-components-multi-select-control",tabIndex:-1},Ge=$e();return T||(We=Object.assign({},We,{onKeyDown:function(e){var t=!1;if(!e.defaultPrevented){switch(e.code){case"Backspace":t=Oe(ke);break;case"Enter":case"Space":t=function(){var e=!1,t=function(){if(-1!==ie)return $e()[ie]}();return t&&re?(Ie(t),e=!0):Ue()&&""!==Y.trim()&&(Ie(Y),e=!0),e}();break;case"ArrowLeft":t=function(){var e=!1;return je()&&(K((function(e){return Math.min(e+1,v.length)})),e=!0),e}();break;case"ArrowUp":t=re?(se((function(e){return(0===e?$e(Y,Ne(),v,A).length:e)-1})),Ae(!0),!0):(oe(!0),se(0),Ae(!0),!0);break;case"ArrowRight":t=function(){var e=!1;return je()&&(K((function(e){return Math.max(e-1,0)})),e=!0),e}();break;case"ArrowDown":t=re?(se((function(e){return(e+1)%$e(Y,Ne(),v,A).length})),Ae(!0),!0):(oe(!0),se(0),Ae(!0),!0);break;case"Delete":t=Oe(Te);break;case"Escape":t=function(e){return e.target instanceof HTMLInputElement&&(X(e.target.value),oe(!1),se(-1),Ae(!1)),!0}(e)}t&&e.preventDefault()}},onKeyPress:function(e){var t=!1;44===e.charCode&&(Ue()&&Ie(Y),t=!0),t&&e.preventDefault()},onFocus:we})),React.createElement(t.BaseControl,{id:W,label:c,help:l},React.createElement("div",We,React.createElement("div",{ref:xe,className:Ve,tabIndex:-1,onMouseDown:Be,onTouchStart:Be},React.createElement(t.Flex,{className:"codeamp-components-multi-select-control__tokens-container",justify:"flex-start",align:"flex-start",gap:"4px",wrap:!0,__next36pxDefaultSize:V,hasTokens:!!v.length},(qe=v.map((function(e){return m.find((function(t){return t.value===e}))||null})).map((function(e,n){return function(e,n){var r=e.value,o=e.label,u=e.onMouseEnter,i=void 0===u?ve:u,a=e.onMouseLeave,s=void 0===a?ve:a,c=e.isBorderless,l=void 0!==c&&c,p=r,d=n+1;return React.createElement(t.FlexItem,{key:"token-"+p},React.createElement(k,{value:p,label:o,title:"string"!=typeof token?o:void 0,onClickRemove:Pe,isBorderless:l,onMouseEnter:i,onMouseLeave:s,disabled:T,messages:R,termPosition:d,termsCount:v.length}))}(function(e){for(var t=1;t=i?void 0:function(e){var t=e.value;X(t),oe(!0),x(t)},ref:_e})))),qe)),re&&React.createElement(ae,{instanceId:W,match:Ee(Y,m),searchValue:Y.trim(),suggestions:Ge,selectedIndex:ie,scrollIntoView:ge,onHover:function(e){var t=$e().indexOf(e);t>=0&&(se(t),Ae(!1))},onSelect:function(e){Ie(e)},__experimentalRenderItem:N}))))}}();var u=t;for(var i in o)u[i]=o[i];o.__esModule&&Object.defineProperty(u,"__esModule",{value:!0})}()},9960:function(e,t){"use strict";var n;Object.defineProperty(t,"__esModule",{value:!0}),t.Doctype=t.CDATA=t.Tag=t.Style=t.Script=t.Comment=t.Directive=t.Text=t.Root=t.isTag=t.ElementType=void 0,function(e){e.Root="root",e.Text="text",e.Directive="directive",e.Comment="comment",e.Script="script",e.Style="style",e.Tag="tag",e.CDATA="cdata",e.Doctype="doctype"}(n=t.ElementType||(t.ElementType={})),t.isTag=function(e){return e.type===n.Tag||e.type===n.Script||e.type===n.Style},t.Root=n.Root,t.Text=n.Text,t.Directive=n.Directive,t.Comment=n.Comment,t.Script=n.Script,t.Style=n.Style,t.Tag=n.Tag,t.CDATA=n.CDATA,t.Doctype=n.Doctype},885:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CASE_SENSITIVE_TAG_NAMES_MAP=t.CASE_SENSITIVE_TAG_NAMES=void 0,t.CASE_SENSITIVE_TAG_NAMES=["animateMotion","animateTransform","clipPath","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","foreignObject","linearGradient","radialGradient","textPath"],t.CASE_SENSITIVE_TAG_NAMES_MAP=t.CASE_SENSITIVE_TAG_NAMES.reduce((function(e,t){return e[t.toLowerCase()]=t,e}),{})},2260:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="html",r="head",o="body",u=/<([a-zA-Z]+[0-9]?)/,i=//i,a=//i,s=function(e,t){throw new Error("This browser does not support `document.implementation.createHTMLDocument`")},c=function(e,t){throw new Error("This browser does not support `DOMParser.prototype.parseFromString`")},l="object"==typeof window&&window.DOMParser;if("function"==typeof l){var p=new l;s=c=function(e,t){return t&&(e="<".concat(t,">").concat(e,"").concat(t,">")),p.parseFromString(e,"text/html")}}if("object"==typeof document&&document.implementation){var d=document.implementation.createHTMLDocument();s=function(e,t){if(t){var n=d.documentElement.querySelector(t);return n&&(n.innerHTML=e),d}return d.documentElement.innerHTML=e,d}}var f,h="object"==typeof document&&document.createElement("template");h&&h.content&&(f=function(e){return h.innerHTML=e,h.content.childNodes}),t.default=function(e){var t,l,p=e.match(u),d=p&&p[1]?p[1].toLowerCase():"";switch(d){case n:var h=c(e);return i.test(e)||null===(t=null==(g=h.querySelector(r))?void 0:g.parentNode)||void 0===t||t.removeChild(g),a.test(e)||null===(l=null==(g=h.querySelector(o))?void 0:g.parentNode)||void 0===l||l.removeChild(g),h.querySelectorAll(n);case r:case o:var m=s(e).querySelectorAll(d);return a.test(e)&&i.test(e)?m[0].parentNode.childNodes:m;default:return f?f(e):(g=s(e,o).querySelector(o)).childNodes;var g}}},4152:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(2260)),u=n(1507),i=/<(![a-zA-Z\s]+)>/;t.default=function(e){if("string"!=typeof e)throw new TypeError("First argument must be a string");if(!e)return[];var t=e.match(i),n=t?t[1]:void 0;return(0,u.formatDOM)((0,o.default)(e),null,n)}},1507:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatDOM=t.formatAttributes=void 0;var r=n(4584),o=n(885);function u(e){for(var t={},n=0,r=e.length;n0?this.children[this.children.length-1]:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"childNodes",{get:function(){return this.children},set:function(e){this.children=e},enumerable:!1,configurable:!0}),t}(a);t.NodeWithChildren=d;var f=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.CDATA,t}return o(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 4},enumerable:!1,configurable:!0}),t}(d);t.CDATA=f;var h=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.Root,t}return o(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 9},enumerable:!1,configurable:!0}),t}(d);t.Document=h;var m=function(e){function t(t,n,r,o){void 0===r&&(r=[]),void 0===o&&(o="script"===t?i.ElementType.Script:"style"===t?i.ElementType.Style:i.ElementType.Tag);var u=e.call(this,r)||this;return u.name=t,u.attribs=n,u.type=o,u}return o(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 1},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"tagName",{get:function(){return this.name},set:function(e){this.name=e},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"attributes",{get:function(){var e=this;return Object.keys(this.attribs).map((function(t){var n,r;return{name:t,value:e.attribs[t],namespace:null===(n=e["x-attribsNamespace"])||void 0===n?void 0:n[t],prefix:null===(r=e["x-attribsPrefix"])||void 0===r?void 0:r[t]}}))},enumerable:!1,configurable:!0}),t}(d);function g(e){return(0,i.isTag)(e)}function A(e){return e.type===i.ElementType.CDATA}function E(e){return e.type===i.ElementType.Text}function v(e){return e.type===i.ElementType.Comment}function y(e){return e.type===i.ElementType.Directive}function C(e){return e.type===i.ElementType.Root}function b(e,t){var n;if(void 0===t&&(t=!1),E(e))n=new c(e.data);else if(v(e))n=new l(e.data);else if(g(e)){var r=t?_(e.children):[],o=new m(e.name,u({},e.attribs),r);r.forEach((function(e){return e.parent=o})),null!=e.namespace&&(o.namespace=e.namespace),e["x-attribsNamespace"]&&(o["x-attribsNamespace"]=u({},e["x-attribsNamespace"])),e["x-attribsPrefix"]&&(o["x-attribsPrefix"]=u({},e["x-attribsPrefix"])),n=o}else if(A(e)){r=t?_(e.children):[];var i=new f(r);r.forEach((function(e){return e.parent=i})),n=i}else if(C(e)){r=t?_(e.children):[];var a=new h(r);r.forEach((function(e){return e.parent=a})),e["x-mode"]&&(a["x-mode"]=e["x-mode"]),n=a}else{if(!y(e))throw new Error("Not implemented yet: ".concat(e.type));var s=new p(e.name,e.data);null!=e["x-name"]&&(s["x-name"]=e["x-name"],s["x-publicId"]=e["x-publicId"],s["x-systemId"]=e["x-systemId"]),n=s}return n.startIndex=e.startIndex,n.endIndex=e.endIndex,null!=e.sourceCodeLocation&&(n.sourceCodeLocation=e.sourceCodeLocation),n}function _(e){for(var t=e.map((function(e){return b(e,!0)})),n=1;n1&&(A=p(A,{key:A.key||m})),r.push(c(A,g,m));continue}}if("text"!==g.type){var E=g,v={};s(E)?((0,i.setStyleProp)(E.attribs.style,E.attribs),v=E.attribs):E.attribs&&(v=(0,u.default)(E.attribs,E.name));var y=void 0;switch(g.type){case"script":case"style":g.children[0]&&(v.dangerouslySetInnerHTML={__html:g.children[0].data});break;case"tag":"textarea"===g.name&&g.children[0]?v.defaultValue=g.children[0].data:g.children&&g.children.length&&(y=e(g.children,n));break;default:continue}h>1&&(v.key=m),r.push(c(d(g.name,v,y),g,m))}else{var C=!g.data.trim().length;if(C&&g.parent&&!(0,i.canTextBeChildOfNode)(g.parent))continue;if((null==n?void 0:n.trim)&&C)continue;r.push(c(g.data,g,m))}}return 1===r.length?r[0]:r}},3426:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.htmlToDOM=t.domToReact=t.attributesToProps=t.Text=t.ProcessingInstruction=t.Element=t.Comment=void 0;var o=r(n(4152));t.htmlToDOM=o.default;var u=r(n(484));t.attributesToProps=u.default;var i=r(n(3670));t.domToReact=i.default;var a=n(7384);Object.defineProperty(t,"Comment",{enumerable:!0,get:function(){return a.Comment}}),Object.defineProperty(t,"Element",{enumerable:!0,get:function(){return a.Element}}),Object.defineProperty(t,"ProcessingInstruction",{enumerable:!0,get:function(){return a.ProcessingInstruction}}),Object.defineProperty(t,"Text",{enumerable:!0,get:function(){return a.Text}});var s={lowerCaseAttributeNames:!1};t.default=function(e,t){if("string"!=typeof e)throw new TypeError("First argument must be a string");return e?(0,i.default)((0,o.default)(e,(null==t?void 0:t.htmlparser2)||s),t):[]}},4606:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.returnFirstArg=t.canTextBeChildOfNode=t.ELEMENTS_WITH_NO_TEXT_CHILDREN=t.PRESERVE_CUSTOM_ATTRIBUTES=t.setStyleProp=t.isCustomComponent=void 0;var o=n(9196),u=r(n(1476)),i=new Set(["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"]);t.isCustomComponent=function(e,t){return e.includes("-")?!i.has(e):Boolean(t&&"string"==typeof t.is)};var a={reactCompat:!0};t.setStyleProp=function(e,t){if("string"==typeof e)if(e.trim())try{t.style=(0,u.default)(e,a)}catch(e){t.style={}}else t.style={}},t.PRESERVE_CUSTOM_ATTRIBUTES=Number(o.version.split(".")[0])>=16,t.ELEMENTS_WITH_NO_TEXT_CHILDREN=new Set(["tr","tbody","thead","tfoot","colgroup","table","head","html","frameset"]),t.canTextBeChildOfNode=function(e){return!t.ELEMENTS_WITH_NO_TEXT_CHILDREN.has(e.name)},t.returnFirstArg=function(e){return e}},7384:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,o)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),t.DomHandler=void 0;var u=n(9960),i=n(5079);o(n(5079),t);var a={withStartIndices:!1,withEndIndices:!1,xmlMode:!1},s=function(){function e(e,t,n){this.dom=[],this.root=new i.Document(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null,"function"==typeof t&&(n=t,t=a),"object"==typeof e&&(t=e,e=void 0),this.callback=null!=e?e:null,this.options=null!=t?t:a,this.elementCB=null!=n?n:null}return e.prototype.onparserinit=function(e){this.parser=e},e.prototype.onreset=function(){this.dom=[],this.root=new i.Document(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null},e.prototype.onend=function(){this.done||(this.done=!0,this.parser=null,this.handleCallback(null))},e.prototype.onerror=function(e){this.handleCallback(e)},e.prototype.onclosetag=function(){this.lastNode=null;var e=this.tagStack.pop();this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),this.elementCB&&this.elementCB(e)},e.prototype.onopentag=function(e,t){var n=this.options.xmlMode?u.ElementType.Tag:void 0,r=new i.Element(e,t,void 0,n);this.addNode(r),this.tagStack.push(r)},e.prototype.ontext=function(e){var t=this.lastNode;if(t&&t.type===u.ElementType.Text)t.data+=e,this.options.withEndIndices&&(t.endIndex=this.parser.endIndex);else{var n=new i.Text(e);this.addNode(n),this.lastNode=n}},e.prototype.oncomment=function(e){if(this.lastNode&&this.lastNode.type===u.ElementType.Comment)this.lastNode.data+=e;else{var t=new i.Comment(e);this.addNode(t),this.lastNode=t}},e.prototype.oncommentend=function(){this.lastNode=null},e.prototype.oncdatastart=function(){var e=new i.Text(""),t=new i.CDATA([e]);this.addNode(t),e.parent=t,this.lastNode=e},e.prototype.oncdataend=function(){this.lastNode=null},e.prototype.onprocessinginstruction=function(e,t){var n=new i.ProcessingInstruction(e,t);this.addNode(n)},e.prototype.handleCallback=function(e){if("function"==typeof this.callback)this.callback(e,this.dom);else if(e)throw e},e.prototype.addNode=function(e){var t=this.tagStack[this.tagStack.length-1],n=t.children[t.children.length-1];this.options.withStartIndices&&(e.startIndex=this.parser.startIndex),this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),t.children.push(e),n&&(e.prev=n,n.next=e),e.parent=t,this.lastNode=null},e}();t.DomHandler=s,t.default=s},5079:function(e,t,n){"use strict";var r,o=this&&this.__extends||(r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},r(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function __(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)}),u=this&&this.__assign||function(){return u=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0?this.children[this.children.length-1]:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"childNodes",{get:function(){return this.children},set:function(e){this.children=e},enumerable:!1,configurable:!0}),t}(a);t.NodeWithChildren=d;var f=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.CDATA,t}return o(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 4},enumerable:!1,configurable:!0}),t}(d);t.CDATA=f;var h=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.type=i.ElementType.Root,t}return o(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 9},enumerable:!1,configurable:!0}),t}(d);t.Document=h;var m=function(e){function t(t,n,r,o){void 0===r&&(r=[]),void 0===o&&(o="script"===t?i.ElementType.Script:"style"===t?i.ElementType.Style:i.ElementType.Tag);var u=e.call(this,r)||this;return u.name=t,u.attribs=n,u.type=o,u}return o(t,e),Object.defineProperty(t.prototype,"nodeType",{get:function(){return 1},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"tagName",{get:function(){return this.name},set:function(e){this.name=e},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"attributes",{get:function(){var e=this;return Object.keys(this.attribs).map((function(t){var n,r;return{name:t,value:e.attribs[t],namespace:null===(n=e["x-attribsNamespace"])||void 0===n?void 0:n[t],prefix:null===(r=e["x-attribsPrefix"])||void 0===r?void 0:r[t]}}))},enumerable:!1,configurable:!0}),t}(d);function g(e){return(0,i.isTag)(e)}function A(e){return e.type===i.ElementType.CDATA}function E(e){return e.type===i.ElementType.Text}function v(e){return e.type===i.ElementType.Comment}function y(e){return e.type===i.ElementType.Directive}function C(e){return e.type===i.ElementType.Root}function b(e,t){var n;if(void 0===t&&(t=!1),E(e))n=new c(e.data);else if(v(e))n=new l(e.data);else if(g(e)){var r=t?_(e.children):[],o=new m(e.name,u({},e.attribs),r);r.forEach((function(e){return e.parent=o})),null!=e.namespace&&(o.namespace=e.namespace),e["x-attribsNamespace"]&&(o["x-attribsNamespace"]=u({},e["x-attribsNamespace"])),e["x-attribsPrefix"]&&(o["x-attribsPrefix"]=u({},e["x-attribsPrefix"])),n=o}else if(A(e)){r=t?_(e.children):[];var i=new f(r);r.forEach((function(e){return e.parent=i})),n=i}else if(C(e)){r=t?_(e.children):[];var a=new h(r);r.forEach((function(e){return e.parent=a})),e["x-mode"]&&(a["x-mode"]=e["x-mode"]),n=a}else{if(!y(e))throw new Error("Not implemented yet: ".concat(e.type));var s=new p(e.name,e.data);null!=e["x-name"]&&(s["x-name"]=e["x-name"],s["x-publicId"]=e["x-publicId"],s["x-systemId"]=e["x-systemId"]),n=s}return n.startIndex=e.startIndex,n.endIndex=e.endIndex,null!=e.sourceCodeLocation&&(n.sourceCodeLocation=e.sourceCodeLocation),n}function _(e){for(var t=e.map((function(e){return b(e,!0)})),n=1;n1&&e.delimiter&&i(e.delimiter)))},semantic_and:u,semantic_not:u,rule_ref(t){const n=o.findRule(e,t.name);return n?i(n):void 0},literal(e){return""!==e.value},class:n,any:n});return i(t)}};e.exports=o},9203:function(module,__unused_webpack_exports,__webpack_require__){"use strict";const generateBytecode=__webpack_require__(2886),generateJS=__webpack_require__(5843),inferenceMatchResult=__webpack_require__(5412),removeProxyRules=__webpack_require__(2929),reportDuplicateLabels=__webpack_require__(6734),reportDuplicateRules=__webpack_require__(1117),reportInfiniteRecursion=__webpack_require__(730),reportInfiniteRepetition=__webpack_require__(9505),reportUndefinedRules=__webpack_require__(1442),reportIncorrectPlucking=__webpack_require__(6237),Session=__webpack_require__(425),visitor=__webpack_require__(8202),{base64:base64}=__webpack_require__(6443);function processOptions(e,t){const n={};return Object.keys(e).forEach((t=>{n[t]=e[t]})),Object.keys(t).forEach((e=>{Object.prototype.hasOwnProperty.call(n,e)||(n[e]=t[e])})),n}function isSourceMapCapable(e){return"string"==typeof e?e.length>0:e&&"function"==typeof e.offset}const compiler={visitor:visitor,passes:{check:[reportUndefinedRules,reportDuplicateRules,reportDuplicateLabels,reportInfiniteRecursion,reportInfiniteRepetition,reportIncorrectPlucking],transform:[removeProxyRules,inferenceMatchResult],generate:[generateBytecode,generateJS]},compile(ast,passes,options){if(options=void 0!==options?options:{},options=processOptions(options,{allowedStartRules:[ast.rules[0].name],cache:!1,dependencies:{},exportVar:null,format:"bare",output:"parser",trace:!1}),!Array.isArray(options.allowedStartRules))throw new Error("allowedStartRules must be an array");if(0===options.allowedStartRules.length)throw new Error("Must have at least one start rule");const allRules=ast.rules.map((e=>e.name));if(options.allowedStartRules.some((e=>"*"===e)))options.allowedStartRules=allRules;else for(const e of options.allowedStartRules)if(-1===allRules.indexOf(e))throw new Error(`Unknown start rule "${e}"`);if(("source-and-map"===options.output||"source-with-inline-map"===options.output)&&!isSourceMapCapable(options.grammarSource))throw new Error("Must provide grammarSource (as a string or GrammarLocation) in order to generate source maps");const session=new Session(options);switch(Object.keys(passes).forEach((e=>{session.stage=e,session.info(`Process stage ${e}`),passes[e].forEach((t=>{session.info(`Process pass ${e}.${t.name}`),t(ast,options,session)})),session.checkErrors()})),options.output){case"parser":return eval(ast.code.toString());case"source":return ast.code.toString();case"source-and-map":return ast.code;case"source-with-inline-map":{if("undefined"==typeof TextEncoder)throw new Error("TextEncoder is not supported by this platform");const e=ast.code.toStringWithSourceMap(),t=new TextEncoder,n=base64(t.encode(JSON.stringify(e.map.toJSON())));return e.code+`//# sourceMappingURL=data:application/json;charset=utf-8;base64,${n}\n`}case"ast":return ast;default:throw new Error("Invalid output format: "+options.output+".")}}};module.exports=compiler},6164:function(e){"use strict";e.exports={PUSH:0,PUSH_EMPTY_STRING:35,PUSH_UNDEFINED:1,PUSH_NULL:2,PUSH_FAILED:3,PUSH_EMPTY_ARRAY:4,PUSH_CURR_POS:5,POP:6,POP_CURR_POS:7,POP_N:8,NIP:9,APPEND:10,WRAP:11,TEXT:12,PLUCK:36,IF:13,IF_ERROR:14,IF_NOT_ERROR:15,IF_LT:30,IF_GE:31,IF_LT_DYNAMIC:32,IF_GE_DYNAMIC:33,WHILE_NOT_ERROR:16,MATCH_ANY:17,MATCH_STRING:18,MATCH_STRING_IC:19,MATCH_CHAR_CLASS:20,MATCH_REGEXP:20,ACCEPT_N:21,ACCEPT_STRING:22,FAIL:23,LOAD_SAVED_POS:24,UPDATE_SAVED_POS:25,CALL:26,RULE:27,SILENT_FAILS_ON:28,SILENT_FAILS_OFF:29,SOURCE_MAP_PUSH:37,SOURCE_MAP_POP:38,SOURCE_MAP_LABEL_PUSH:39,SOURCE_MAP_LABEL_POP:40}},2886:function(e,t,n){"use strict";const r=n(9861),o=n(6164),u=n(8202),{ALWAYS_MATCH:i,SOMETIMES_MATCH:a,NEVER_MATCH:s}=n(5412);e.exports=function(e,t){const n=[],c=[],l=[],p=[],d=[];function f(e){const t=n.indexOf(e);return-1===t?n.push(e)-1:t}function h(e){const t=JSON.stringify(e),n=l.findIndex((e=>JSON.stringify(e)===t));return-1===n?l.push(e)-1:n}function m(e,t,n){const r={predicate:e,params:t,body:n.code,location:n.codeLocation},o=JSON.stringify(r),u=p.findIndex((e=>JSON.stringify(e)===o));return-1===u?p.push(r)-1:u}function g(e){return d.push(e)-1}function A(e){const t={};return Object.keys(e).forEach((n=>{t[n]=e[n]})),t}function E(e,...t){return e.concat(...t)}function v(e,t,n,r){return e===i?n:e===s?r:t.concat([n.length,r.length],n,r)}function y(e,t,n,r){const u=Object.keys(n).map((e=>r-n[e]));return[o.CALL,e,t,u.length].concat(u)}function C(e,t,n){const r=0|e.match;return E([o.PUSH_CURR_POS],[o.SILENT_FAILS_ON],D(e,{sp:n.sp+1,env:A(n.env),action:null}),[o.SILENT_FAILS_OFF],v(t?-r:r,[t?o.IF_ERROR:o.IF_NOT_ERROR],E([o.POP],[t?o.POP:o.POP_CURR_POS],[o.PUSH_UNDEFINED]),E([o.POP],[t?o.POP_CURR_POS:o.POP],[o.PUSH_FAILED])))}function b(e,t,n){const r=m(!0,Object.keys(n.env),e);return E([o.UPDATE_SAVED_POS],y(r,0,n.env,n.sp),v(0|e.match,[o.IF],E([o.POP],t?[o.PUSH_FAILED]:[o.PUSH_UNDEFINED]),E([o.POP],t?[o.PUSH_UNDEFINED]:[o.PUSH_FAILED])))}function _(e){return t=[o.WHILE_NOT_ERROR],n=E([o.APPEND],e),t.concat([n.length],n);var t,n}function x(e,t,n,r){switch(e.type){case"constant":return{pre:[],post:[],sp:n};case"variable":return e.sp=r+n-t[e.value],{pre:[],post:[],sp:n};case"function":return e.sp=r,{pre:y(m(!0,Object.keys(t),{code:e.value,codeLocation:e.codeLocation}),0,t,n),post:[o.NIP],sp:n+1};default:throw new Error(`Unknown boundary type "${e.type}" for the "repeated" node`)}}function F(e,t){if(null!==t.value){const n="constant"===t.type?[o.IF_GE,t.value]:[o.IF_GE_DYNAMIC,t.sp];return v(a,n,[o.PUSH_FAILED],e)}return e}const D=(S={grammar(e){e.rules.forEach(D),e.literals=n,e.classes=c,e.expectations=l,e.functions=p,e.locations=d},rule(e){e.bytecode=D(e.expression,{sp:-1,env:{},pluck:[],action:null})},named(e,t){const n=0|e.match,r=n===s?null:h({type:"rule",value:e.name});return E([o.SILENT_FAILS_ON],D(e.expression,t),[o.SILENT_FAILS_OFF],v(n,[o.IF_ERROR],[o.FAIL,r],[]))},choice(e,t){return function e(t,n){const r=0|t[0].match,u=D(t[0],{sp:n.sp,env:A(n.env),action:null});return r===i?u:E(u,t.length>1?v(a,[o.IF_ERROR],E([o.POP],e(t.slice(1),n)),[]):[])}(e.alternatives,t)},action(e,t){const n=A(t.env),r="sequence"!==e.expression.type||0===e.expression.elements.length,u=D(e.expression,{sp:t.sp+(r?1:0),env:n,action:e}),i=0|e.expression.match,a=r&&i!==s?m(!1,Object.keys(n),e):null;return r?E([o.PUSH_CURR_POS],u,v(i,[o.IF_NOT_ERROR],E([o.LOAD_SAVED_POS,1],y(a,1,n,t.sp+2)),[]),[o.NIP]):u},sequence(e,t){return E([o.PUSH_CURR_POS],function t(n,r){if(n.length>0){const u=e.elements.length-n.length+1;return E(D(n[0],{sp:r.sp,env:r.env,pluck:r.pluck,action:null}),v(0|n[0].match,[o.IF_NOT_ERROR],t(n.slice(1),{sp:r.sp+1,env:r.env,pluck:r.pluck,action:r.action}),E(u>1?[o.POP_N,u]:[o.POP],[o.POP_CURR_POS],[o.PUSH_FAILED])))}if(r.pluck.length>0)return E([o.PLUCK,e.elements.length+1,r.pluck.length],r.pluck.map((e=>r.sp-e)));if(r.action){const t=m(!1,Object.keys(r.env),r.action);return E([o.LOAD_SAVED_POS,e.elements.length],y(t,e.elements.length+1,r.env,r.sp))}return E([o.WRAP,e.elements.length],[o.NIP])}(e.elements,{sp:t.sp+1,env:t.env,pluck:[],action:t.action}))},labeled(e,n){let r=n.env;const u=e.label,i=n.sp+1;u&&(r=A(n.env),n.env[e.label]=i),e.pick&&n.pluck.push(i);const a=D(e.expression,{sp:n.sp,env:r,action:null});return u&&e.labelLocation&&t&&"source-and-map"===t.output?E([o.SOURCE_MAP_LABEL_PUSH,i,f(u),g(e.labelLocation)],a,[o.SOURCE_MAP_LABEL_POP,i]):a},text(e,t){return E([o.PUSH_CURR_POS],D(e.expression,{sp:t.sp+1,env:A(t.env),action:null}),v(0|e.match,[o.IF_NOT_ERROR],E([o.POP],[o.TEXT]),[o.NIP]))},simple_and(e,t){return C(e.expression,!1,t)},simple_not(e,t){return C(e.expression,!0,t)},optional(e,t){return E(D(e.expression,{sp:t.sp,env:A(t.env),action:null}),v(-(0|e.expression.match),[o.IF_ERROR],E([o.POP],[o.PUSH_NULL]),[]))},zero_or_more(e,t){const n=D(e.expression,{sp:t.sp+1,env:A(t.env),action:null});return E([o.PUSH_EMPTY_ARRAY],n,_(n),[o.POP])},one_or_more(e,t){const n=D(e.expression,{sp:t.sp+1,env:A(t.env),action:null});return E([o.PUSH_EMPTY_ARRAY],n,v(0|e.expression.match,[o.IF_NOT_ERROR],E(_(n),[o.POP]),E([o.POP],[o.POP],[o.PUSH_FAILED])))},repeated(e,t){const n=e.min?e.min:e.max,r="constant"!==n.type||n.value>0,u="constant"!==e.max.type&&null!==e.max.value,i=r?2:1,s=e.min?x(e.min,t.env,t.sp,2+("function"===e.max.type?1:0)):{pre:[],post:[],sp:t.sp},c=x(e.max,t.env,s.sp,i),l=D(e.expression,{sp:c.sp+i,env:A(t.env),action:null}),p=null!==e.delimiter?D(e.expression,{sp:c.sp+i+1,env:A(t.env),action:null}):l,d=function(e,t,n,r,u){return e?E([o.PUSH_CURR_POS],D(e,{sp:r.sp+u+1,env:A(r.env),action:null}),v(0|e.match,[o.IF_NOT_ERROR],E([o.POP],n,v(-t,[o.IF_ERROR],[o.POP,o.POP_CURR_POS,o.PUSH_FAILED],[o.NIP])),[o.NIP])):n}(e.delimiter,0|e.expression.match,p,t,i),f=F(d,e.max),h=u?F(l,e.max):l,m=E(r?[o.PUSH_CURR_POS]:[],[o.PUSH_EMPTY_ARRAY],h,_(f),[o.POP]);return E(s.pre,c.pre,r?function(e,t){const n="constant"===t.type?[o.IF_LT,t.value]:[o.IF_LT_DYNAMIC,t.sp];return E(e,v(a,n,[o.POP,o.POP_CURR_POS,o.PUSH_FAILED],[o.NIP]))}(m,n):m,c.post,s.post)},group(e,t){return D(e.expression,{sp:t.sp,env:A(t.env),action:null})},semantic_and(e,t){return b(e,!1,t)},semantic_not(e,t){return b(e,!0,t)},rule_ref(t){return[o.RULE,r.indexOfRule(e,t.name)]},literal(e){if(e.value.length>0){const t=0|e.match,n=t===a||t===i&&!e.ignoreCase?f(e.ignoreCase?e.value.toLowerCase():e.value):null,r=t!==i?h({type:"literal",value:e.value,ignoreCase:e.ignoreCase}):null;return v(t,e.ignoreCase?[o.MATCH_STRING_IC,n]:[o.MATCH_STRING,n],e.ignoreCase?[o.ACCEPT_N,e.value.length]:[o.ACCEPT_STRING,n],[o.FAIL,r])}return[o.PUSH_EMPTY_STRING]},class(e){const t=0|e.match,n=t===a?function(e){const t={value:e.parts,inverted:e.inverted,ignoreCase:e.ignoreCase},n=JSON.stringify(t),r=c.findIndex((e=>JSON.stringify(e)===n));return-1===r?c.push(t)-1:r}(e):null,r=t!==i?h({type:"class",value:e.parts,inverted:e.inverted,ignoreCase:e.ignoreCase}):null;return v(t,[o.MATCH_CHAR_CLASS,n],[o.ACCEPT_N,1],[o.FAIL,r])},any(e){const t=0|e.match,n=t!==i?h({type:"any"}):null;return v(t,[o.MATCH_ANY],[o.ACCEPT_N,1],[o.FAIL,n])}},t&&"source-and-map"===t.output&&Object.entries(S).forEach((([e,t])=>{S[e]=function(e,...n){const r=t(e,...n);return void 0!==r&&e.location?E([o.SOURCE_MAP_PUSH,g(e.location)],r,[o.SOURCE_MAP_POP]):r}})),u.build(S));var S;D(e)}},5843:function(e,t,n){"use strict";const r=n(9861),o=n(6164),u=n(8013),i=n(244),{stringEscape:a,regexpClassEscape:s}=n(6443),{SourceNode:c}=n(4738),l=n(2190);function p(e,t,n){const r=l.offsetStart(t),o=r.line,u=r.column-1,i=e.split("\n");return 1===i.length?new c(o,u,String(t.source),e,n):new c(null,null,String(t.source),i.map(((e,r)=>new c(o+r,0===r?u:0,String(t.source),r===i.length-1?e:[e,"\n"],n))))}function d(e,t,n,r,o){if(n){const u=l.offsetEnd(n);return new c(null,null,String(n.source),[e,p(t,n,o),new c(u.line,u.column-1,String(n.source),r)])}return new c(null,null,null,[e,t,r])}e.exports=function(e,t){function n(e){let t=!0,n=0;return function e(r){return Array.isArray(r)?r.map(e):r instanceof c?(n++,r.children=e(r.children),n--,r):(r=t?r.replace(/^(.+)$/gm," $1"):r.replace(/\n(\s*\S)/g,"\n $1"),t=!n||r.endsWith("\n"),r)}(e)}function l(e){return"peg$c"+e}function f(e){return"peg$r"+e}function h(e){return"peg$e"+e}function m(e){return"peg$f"+e}function g(e){return"peg$parse"+e}function A(e){return e.codeLocation?p(e.code,e.codeLocation,"$"+e.type):e.code}e.code=function(e){function r(){return[`// Generated by Peggy ${i}.`,"//","// https://peggyjs.org/"]}function o(){return t.trace?["{"," SyntaxError: peg$SyntaxError,"," DefaultTracer: peg$DefaultTracer,"," parse: peg$parse","}"].join("\n"):["{"," SyntaxError: peg$SyntaxError,"," parse: peg$parse","}"].join("\n")}const u={bare(){return[...r(),"(function() {",' "use strict";',"",e,"",n("return "+o()+";"),"})()"]},commonjs(){const n=Object.keys(t.dependencies),u=r();return u.push("",'"use strict";',""),n.length>0&&(n.forEach((e=>{u.push("var "+e+' = require("'+a(t.dependencies[e])+'");')})),u.push("")),u.push(e,"","module.exports = "+o()+";"),u},es(){const n=Object.keys(t.dependencies),o=r();return o.push(""),n.length>0&&(n.forEach((e=>{o.push("import "+e+' from "'+a(t.dependencies[e])+'";')})),o.push("")),o.push(e,"","export {"," peg$SyntaxError as SyntaxError,",t.trace?" peg$DefaultTracer as DefaultTracer,":""," peg$parse as parse","};"),o},amd(){const u=Object.keys(t.dependencies),i="["+u.map((e=>t.dependencies[e])).map((e=>'"'+a(e)+'"')).join(", ")+"]",s=u.join(", ");return[...r(),"define("+i+", function("+s+") {",' "use strict";',"",e,"",n("return "+o()+";"),"});"]},globals(){return[...r(),"(function(root) {",' "use strict";',"",e,"",n("root."+t.exportVar+" = "+o()+";"),"})(this);"]},umd(){const u=Object.keys(t.dependencies),i=u.map((e=>t.dependencies[e])),s="["+i.map((e=>'"'+a(e)+'"')).join(", ")+"]",c=i.map((e=>'require("'+a(e)+'")')).join(", "),l=u.join(", "),p=r();return p.push("(function(root, factory) {",' if (typeof define === "function" && define.amd) {'," define("+s+", factory);",' } else if (typeof module === "object" && module.exports) {'," module.exports = factory("+c+");"),null!==t.exportVar&&p.push(" } else {"," root."+t.exportVar+" = factory();"),p.push(" }","})(this, function("+l+") {",' "use strict";',"",e,"",n("return "+o()+";"),"});"),p}}[t.format]();return new c(null,null,t.grammarSource,u.map((e=>e instanceof c?e:e+"\n")))}(function(){const i=[];e.topLevelInitializer&&(i.push(A(e.topLevelInitializer)),i.push("")),i.push("function peg$subclass(child, parent) {"," function C() { this.constructor = child; }"," C.prototype = parent.prototype;"," child.prototype = new C();","}","","function peg$SyntaxError(message, expected, found, location) {"," var self = Error.call(this, message);"," // istanbul ignore next Check is a necessary evil to support older environments"," if (Object.setPrototypeOf) {"," Object.setPrototypeOf(self, peg$SyntaxError.prototype);"," }"," self.expected = expected;"," self.found = found;"," self.location = location;",' self.name = "SyntaxError";'," return self;","}","","peg$subclass(peg$SyntaxError, Error);","","function peg$padEnd(str, targetLength, padString) {",' padString = padString || " ";'," if (str.length > targetLength) { return str; }"," targetLength -= str.length;"," padString += padString.repeat(targetLength);"," return str + padString.slice(0, targetLength);","}","","peg$SyntaxError.prototype.format = function(sources) {",' var str = "Error: " + this.message;'," if (this.location) {"," var src = null;"," var k;"," for (k = 0; k < sources.length; k++) {"," if (sources[k].source === this.location.source) {"," src = sources[k].text.split(/\\r\\n|\\n|\\r/g);"," break;"," }"," }"," var s = this.location.start;",' var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))'," ? this.location.source.offset(s)"," : s;",' var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;'," if (src) {"," var e = this.location.end;"," var filler = peg$padEnd(\"\", offset_s.line.toString().length, ' ');"," var line = src[s.line - 1];"," var last = s.line === e.line ? e.column : line.length + 1;"," var hatLen = (last - s.column) || 1;",' str += "\\n --\x3e " + loc + "\\n"',' + filler + " |\\n"',' + offset_s.line + " | " + line + "\\n"',' + filler + " | " + peg$padEnd("", s.column - 1, \' \')',' + peg$padEnd("", hatLen, "^");'," } else {",' str += "\\n at " + loc;'," }"," }"," return str;","};","","peg$SyntaxError.buildMessage = function(expected, found) {"," var DESCRIBE_EXPECTATION_FNS = {"," literal: function(expectation) {",' return "\\"" + literalEscape(expectation.text) + "\\"";'," },",""," class: function(expectation) {"," var escapedParts = expectation.parts.map(function(part) {"," return Array.isArray(part)",' ? classEscape(part[0]) + "-" + classEscape(part[1])'," : classEscape(part);"," });","",' return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";'," },",""," any: function() {",' return "any character";'," },",""," end: function() {",' return "end of input";'," },",""," other: function(expectation) {"," return expectation.description;"," }"," };",""," function hex(ch) {"," return ch.charCodeAt(0).toString(16).toUpperCase();"," }",""," function literalEscape(s) {"," return s",' .replace(/\\\\/g, "\\\\\\\\")',' .replace(/"/g, "\\\\\\"")',' .replace(/\\0/g, "\\\\0")',' .replace(/\\t/g, "\\\\t")',' .replace(/\\n/g, "\\\\n")',' .replace(/\\r/g, "\\\\r")',' .replace(/[\\x00-\\x0F]/g, function(ch) { return "\\\\x0" + hex(ch); })',' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return "\\\\x" + hex(ch); });'," }",""," function classEscape(s) {"," return s",' .replace(/\\\\/g, "\\\\\\\\")',' .replace(/\\]/g, "\\\\]")',' .replace(/\\^/g, "\\\\^")',' .replace(/-/g, "\\\\-")',' .replace(/\\0/g, "\\\\0")',' .replace(/\\t/g, "\\\\t")',' .replace(/\\n/g, "\\\\n")',' .replace(/\\r/g, "\\\\r")',' .replace(/[\\x00-\\x0F]/g, function(ch) { return "\\\\x0" + hex(ch); })',' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return "\\\\x" + hex(ch); });'," }",""," function describeExpectation(expectation) {"," return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);"," }",""," function describeExpected(expected) {"," var descriptions = expected.map(describeExpectation);"," var i, j;",""," descriptions.sort();",""," if (descriptions.length > 0) {"," for (i = 1, j = 1; i < descriptions.length; i++) {"," if (descriptions[i - 1] !== descriptions[i]) {"," descriptions[j] = descriptions[i];"," j++;"," }"," }"," descriptions.length = j;"," }",""," switch (descriptions.length) {"," case 1:"," return descriptions[0];",""," case 2:",' return descriptions[0] + " or " + descriptions[1];',""," default:",' return descriptions.slice(0, -1).join(", ")',' + ", or "'," + descriptions[descriptions.length - 1];"," }"," }",""," function describeFound(found) {",' return found ? "\\"" + literalEscape(found) + "\\"" : "end of input";'," }","",' return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";',"};",""),t.trace&&i.push("function peg$DefaultTracer() {"," this.indentLevel = 0;","}","","peg$DefaultTracer.prototype.trace = function(event) {"," var that = this;",""," function log(event) {"," function repeat(string, n) {",' var result = "", i;',""," for (i = 0; i < n; i++) {"," result += string;"," }",""," return result;"," }",""," function pad(string, length) {",' return string + repeat(" ", length - string.length);'," }","",' if (typeof console === "object") {'," console.log(",' event.location.start.line + ":" + event.location.start.column + "-"',' + event.location.end.line + ":" + event.location.end.column + " "',' + pad(event.type, 10) + " "',' + repeat(" ", that.indentLevel) + event.rule'," );"," }"," }",""," switch (event.type) {",' case "rule.enter":'," log(event);"," this.indentLevel++;"," break;","",' case "rule.match":'," this.indentLevel--;"," log(event);"," break;","",' case "rule.fail":'," this.indentLevel--;"," log(event);"," break;",""," default:",' throw new Error("Invalid event type: " + event.type + ".");'," }","};","");const p="{ "+t.allowedStartRules.map((e=>e+": "+g(e))).join(", ")+" }",E=g(t.allowedStartRules[0]);return i.push("function peg$parse(input, options) {"," options = options !== undefined ? options : {};",""," var peg$FAILED = {};"," var peg$source = options.grammarSource;",""," var peg$startRuleFunctions = "+p+";"," var peg$startRuleFunction = "+E+";","",new c(null,null,t.grammarSource,[e.literals.map(((e,t)=>" var "+l(t)+' = "'+a(e)+'";')).concat("",e.classes.map(((e,t)=>{return" var "+f(t)+" = /^["+((n=e).inverted?"^":"")+n.value.map((e=>Array.isArray(e)?s(e[0])+"-"+s(e[1]):s(e))).join("")+"]/"+(n.ignoreCase?"i":"")+";";var n}))).concat("",e.expectations.map(((e,t)=>" var "+h(t)+" = "+function(e){switch(e.type){case"rule":return'peg$otherExpectation("'+a(e.value)+'")';case"literal":return'peg$literalExpectation("'+a(e.value)+'", '+e.ignoreCase+")";case"class":return"peg$classExpectation(["+e.value.map((e=>Array.isArray(e)?'["'+a(e[0])+'", "'+a(e[1])+'"]':'"'+a(e)+'"')).join(", ")+"], "+e.inverted+", "+e.ignoreCase+")";case"any":return"peg$anyExpectation()";default:throw new Error("Unknown expectation type ("+JSON.stringify(e)+")")}}(e)+";"))).concat("").join("\n"),e.functions.map((function(e,t){return d(`\n var ${m(t)} = function(${e.params.join(", ")}) {`,e.body,e.location,"};")}))]),""," var peg$currPos = 0;"," var peg$savedPos = 0;"," var peg$posDetailsCache = [{ line: 1, column: 1 }];"," var peg$maxFailPos = 0;"," var peg$maxFailExpected = [];"," var peg$silentFails = 0;",""),t.cache&&i.push(" var peg$resultsCache = {};",""),t.trace&&i.push(' var peg$tracer = "tracer" in options ? options.tracer : new peg$DefaultTracer();',""),i.push(" var peg$result;","",' if ("startRule" in options) {'," if (!(options.startRule in peg$startRuleFunctions)) {",' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");'," }",""," peg$startRuleFunction = peg$startRuleFunctions[options.startRule];"," }",""," function text() {"," return input.substring(peg$savedPos, peg$currPos);"," }",""," function offset() {"," return peg$savedPos;"," }",""," function range() {"," return {"," source: peg$source,"," start: peg$savedPos,"," end: peg$currPos"," };"," }",""," function location() {"," return peg$computeLocation(peg$savedPos, peg$currPos);"," }",""," function expected(description, location) {"," location = location !== undefined"," ? location"," : peg$computeLocation(peg$savedPos, peg$currPos);",""," throw peg$buildStructuredError("," [peg$otherExpectation(description)],"," input.substring(peg$savedPos, peg$currPos),"," location"," );"," }",""," function error(message, location) {"," location = location !== undefined"," ? location"," : peg$computeLocation(peg$savedPos, peg$currPos);",""," throw peg$buildSimpleError(message, location);"," }",""," function peg$literalExpectation(text, ignoreCase) {",' return { type: "literal", text: text, ignoreCase: ignoreCase };'," }",""," function peg$classExpectation(parts, inverted, ignoreCase) {",' return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };'," }",""," function peg$anyExpectation() {",' return { type: "any" };'," }",""," function peg$endExpectation() {",' return { type: "end" };'," }",""," function peg$otherExpectation(description) {",' return { type: "other", description: description };'," }",""," function peg$computePosDetails(pos) {"," var details = peg$posDetailsCache[pos];"," var p;",""," if (details) {"," return details;"," } else {"," p = pos - 1;"," while (!peg$posDetailsCache[p]) {"," p--;"," }",""," details = peg$posDetailsCache[p];"," details = {"," line: details.line,"," column: details.column"," };",""," while (p < pos) {"," if (input.charCodeAt(p) === 10) {"," details.line++;"," details.column = 1;"," } else {"," details.column++;"," }",""," p++;"," }",""," peg$posDetailsCache[pos] = details;",""," return details;"," }"," }",""," function peg$computeLocation(startPos, endPos, offset) {"," var startPosDetails = peg$computePosDetails(startPos);"," var endPosDetails = peg$computePosDetails(endPos);",""," var res = {"," source: peg$source,"," start: {"," offset: startPos,"," line: startPosDetails.line,"," column: startPosDetails.column"," },"," end: {"," offset: endPos,"," line: endPosDetails.line,"," column: endPosDetails.column"," }"," };",' if (offset && peg$source && (typeof peg$source.offset === "function")) {'," res.start = peg$source.offset(res.start);"," res.end = peg$source.offset(res.end);"," }"," return res;"," }",""," function peg$fail(expected) {"," if (peg$currPos < peg$maxFailPos) { return; }",""," if (peg$currPos > peg$maxFailPos) {"," peg$maxFailPos = peg$currPos;"," peg$maxFailExpected = [];"," }",""," peg$maxFailExpected.push(expected);"," }",""," function peg$buildSimpleError(message, location) {"," return new peg$SyntaxError(message, null, null, location);"," }",""," function peg$buildStructuredError(expected, found, location) {"," return new peg$SyntaxError("," peg$SyntaxError.buildMessage(expected, found),"," expected,"," found,"," location"," );"," }",""),e.rules.forEach((s=>{i.push(...n(function(i){const s=[],c=new u(i.name,"s","var",i.bytecode),p=function t(r){let u=0;const a=r.length,s=[];let p;function d(e,o){const i=o+3,a=r[u+i-2],l=r[u+i-1];let p,d;c.checkedIf(u,(()=>{u+=i,p=t(r.slice(u,u+a)),u+=a}),l>0?()=>{d=t(r.slice(u,u+l)),u+=l}:null),s.push("if ("+e+") {"),s.push(...n(p)),l>0&&(s.push("} else {"),s.push(...n(d))),s.push("}")}function A(e){const o=r[u+2-1];let i;c.checkedLoop(u,(()=>{u+=2,i=t(r.slice(u,u+o)),u+=o})),s.push("while ("+e+") {"),s.push(...n(i)),s.push("}")}function E(e){const t=r[u+e-1];return m(r[u+1])+"("+r.slice(u+e,u+e+t).map((e=>c.index(e))).join(", ")+")"}for(;uc.index(e))).join(", ")} ]`,c.pop(r[u+1]),s.push(c.push(p)),u+=n;break}case o.IF:d(c.top(),0);break;case o.IF_ERROR:d(c.top()+" === peg$FAILED",0);break;case o.IF_NOT_ERROR:d(c.top()+" !== peg$FAILED",0);break;case o.IF_LT:d(c.top()+".length < "+r[u+1],1);break;case o.IF_GE:d(c.top()+".length >= "+r[u+1],1);break;case o.IF_LT_DYNAMIC:d(c.top()+".length < ("+c.index(r[u+1])+"|0)",1);break;case o.IF_GE_DYNAMIC:d(c.top()+".length >= ("+c.index(r[u+1])+"|0)",1);break;case o.WHILE_NOT_ERROR:A(c.top()+" !== peg$FAILED");break;case o.MATCH_ANY:d("input.length > peg$currPos",0);break;case o.MATCH_STRING:d(e.literals[r[u+1]].length>1?"input.substr(peg$currPos, "+e.literals[r[u+1]].length+") === "+l(r[u+1]):"input.charCodeAt(peg$currPos) === "+e.literals[r[u+1]].charCodeAt(0),1);break;case o.MATCH_STRING_IC:d("input.substr(peg$currPos, "+e.literals[r[u+1]].length+").toLowerCase() === "+l(r[u+1]),1);break;case o.MATCH_CHAR_CLASS:d(f(r[u+1])+".test(input.charAt(peg$currPos))",1);break;case o.ACCEPT_N:s.push(c.push(r[u+1]>1?"input.substr(peg$currPos, "+r[u+1]+")":"input.charAt(peg$currPos)")),s.push(r[u+1]>1?"peg$currPos += "+r[u+1]+";":"peg$currPos++;"),u+=2;break;case o.ACCEPT_STRING:s.push(c.push(l(r[u+1]))),s.push(e.literals[r[u+1]].length>1?"peg$currPos += "+e.literals[r[u+1]].length+";":"peg$currPos++;"),u+=2;break;case o.FAIL:s.push(c.push("peg$FAILED")),s.push("if (peg$silentFails === 0) { peg$fail("+h(r[u+1])+"); }"),u+=2;break;case o.LOAD_SAVED_POS:s.push("peg$savedPos = "+c.index(r[u+1])+";"),u+=2;break;case o.UPDATE_SAVED_POS:s.push("peg$savedPos = peg$currPos;"),u++;break;case o.CALL:p=E(4),c.pop(r[u+2]),s.push(c.push(p)),u+=4+r[u+3];break;case o.RULE:s.push(c.push(g(e.rules[r[u+1]].name)+"()")),u+=2;break;case o.SILENT_FAILS_ON:s.push("peg$silentFails++;"),u++;break;case o.SILENT_FAILS_OFF:s.push("peg$silentFails--;"),u++;break;case o.SOURCE_MAP_PUSH:c.sourceMapPush(s,e.locations[r[u+1]]),u+=2;break;case o.SOURCE_MAP_POP:c.sourceMapPop(),u++;break;case o.SOURCE_MAP_LABEL_PUSH:c.labels[r[u+1]]={label:e.literals[r[u+2]],location:e.locations[r[u+3]]},u+=4;break;case o.SOURCE_MAP_LABEL_POP:delete c.labels[r[u+1]],u+=2;break;default:throw new Error("Invalid opcode: "+r[u]+".",{rule:i.name,bytecode:r})}return s}(i.bytecode);return s.push(d("function ",g(i.name),i.nameLocation,"() {\n",i.name)),t.trace&&s.push(" var startPos = peg$currPos;"),s.push(n(c.defines())),s.push(...n(function(n,r){const o=[];return o.push(""),t.trace&&o.push("peg$tracer.trace({",' type: "rule.enter",'," rule: "+n+","," location: peg$computeLocation(startPos, startPos, true)","});",""),t.cache&&(o.push("var key = peg$currPos * "+e.rules.length+" + "+r+";","var cached = peg$resultsCache[key];","","if (cached) {"," peg$currPos = cached.nextPos;",""),t.trace&&o.push("if (cached.result !== peg$FAILED) {"," peg$tracer.trace({",' type: "rule.match",'," rule: "+n+","," result: cached.result,"," location: peg$computeLocation(startPos, peg$currPos, true)"," });","} else {"," peg$tracer.trace({",' type: "rule.fail",'," rule: "+n+","," location: peg$computeLocation(startPos, startPos, true)"," });","}",""),o.push(" return cached.result;","}","")),o}('"'+a(i.name)+'"',r.indexOfRule(e,i.name)))),s.push(...n(p)),s.push(...n(function(e,n){const r=[];return t.cache&&r.push("","peg$resultsCache[key] = { nextPos: peg$currPos, result: "+n+" };"),t.trace&&r.push("","if ("+n+" !== peg$FAILED) {"," peg$tracer.trace({",' type: "rule.match",'," rule: "+e+","," result: "+n+","," location: peg$computeLocation(startPos, peg$currPos, true)"," });","} else {"," peg$tracer.trace({",' type: "rule.fail",'," rule: "+e+","," location: peg$computeLocation(startPos, startPos, true)"," });","}"),r.push("","return "+n+";"),r}('"'+a(i.name)+'"',c.result()))),s.push("}"),s}(s))),i.push("")})),e.initializer&&(i.push(A(e.initializer)),i.push("")),i.push(" peg$result = peg$startRuleFunction();",""," if (peg$result !== peg$FAILED && peg$currPos === input.length) {"," return peg$result;"," } else {"," if (peg$result !== peg$FAILED && peg$currPos < input.length) {"," peg$fail(peg$endExpectation());"," }",""," throw peg$buildStructuredError("," peg$maxFailExpected,"," peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,"," peg$maxFailPos < input.length"," ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)"," : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)"," );"," }","}"),new c(null,null,t.grammarSource,i.map((e=>e instanceof c?e:e+"\n")))}())}},5412:function(e,t,n){"use strict";const r=n(8202),o=n(9861),u=n(4297),i=-1;function a(e){function t(e){return e.match=0}function n(e){return c(e.expression),e.match=1}function a(e){return e.match=c(e.expression)}function s(e,t){const n=e.length;let r=0,o=0;for(let t=0;t0?i:0}const c=r.build({rule(e){let t,n=0;if(void 0===e.match){e.match=0;do{if(t=e.match,e.match=c(e.expression),++n>6)throw new u("Infinity cycle detected when trying to evaluate node match result",e.location)}while(t!==e.match)}return e.match},named:a,choice(e){return e.match=s(e.alternatives,!0)},action:a,sequence(e){return e.match=s(e.elements,!1)},labeled:a,text:a,simple_and:a,simple_not(e){return e.match=-c(e.expression)},optional:n,zero_or_more:n,one_or_more:a,repeated(e){const t=c(e.expression),n=e.delimiter?c(e.delimiter):i,r=e.min?e.min:e.max;return"constant"!==r.type||"constant"!==e.max.type?e.match=0:0===e.max.value||null!==e.max.value&&r.value>e.max.value?e.match=i:t===i?e.match=0===r.value?1:i:1===t?e.delimiter&&r.value>=2?e.match=n:e.match=1:e.delimiter&&r.value>=2?e.match=n===i?i:0:e.match=0===r.value?1:0},group:a,semantic_and:t,semantic_not:t,rule_ref(t){const n=o.findRule(e,t.name);return t.match=c(n)},literal(e){const t=0===e.value.length?1:0;return e.match=t},class(e){const t=0===e.parts.length?i:0;return e.match=t},any:t});c(e)}a.ALWAYS_MATCH=1,a.SOMETIMES_MATCH=0,a.NEVER_MATCH=i,e.exports=a},2929:function(e,t,n){"use strict";const r=n(9861),o=n(8202);e.exports=function(e,t,n){const u=[];e.rules.forEach(((i,a)=>{var s;"rule"===(s=i).type&&"rule_ref"===s.expression.type&&(function(e,t,u){o.build({rule_ref(o){o.name===t&&(o.name=u,n.info(`Proxy rule "${t}" replaced by the rule "${u}"`,o.location,[{message:"This rule will be used",location:r.findRule(e,u).nameLocation}]))}})(e)}(e,i.name,i.expression.name),-1===t.allowedStartRules.indexOf(i.name)&&u.push(a))})),u.reverse(),u.forEach((t=>{e.rules.splice(t,1)}))}},6734:function(e,t,n){"use strict";const r=n(8202);e.exports=function(e,t,n){function o(e){const t={};return Object.keys(e).forEach((n=>{t[n]=e[n]})),t}function u(e,t){i(e.expression,o(t))}const i=r.build({rule(e){i(e.expression,{})},choice(e,t){e.alternatives.forEach((e=>{i(e,o(t))}))},action:u,labeled(e,t){const r=e.label;r&&Object.prototype.hasOwnProperty.call(t,r)&&n.error(`Label "${e.label}" is already defined`,e.labelLocation,[{message:"Original label location",location:t[r]}]),i(e.expression,t),t[e.label]=e.labelLocation},text:u,simple_and:u,simple_not:u,optional:u,zero_or_more:u,one_or_more:u,repeated(e,t){e.delimiter&&i(e.delimiter,o(t)),i(e.expression,o(t))},group:u});i(e)}},1117:function(e,t,n){"use strict";const r=n(8202);e.exports=function(e,t,n){const o={};r.build({rule(e){Object.prototype.hasOwnProperty.call(o,e.name)?n.error(`Rule "${e.name}" is already defined`,e.nameLocation,[{message:"Original rule location",location:o[e.name]}]):o[e.name]=e.nameLocation}})(e)}},6237:function(e,t,n){"use strict";const r=n(8202);e.exports=function(e,t,n){const o=r.build({action(e){o(e.expression,e)},labeled(e,t){e.pick&&t&&n.error('"@" cannot be used with an action block',e.labelLocation,[{message:"Action block location",location:t.codeLocation}]),o(e.expression)}});o(e)}},730:function(e,t,n){"use strict";const r=n(9861),o=n(8202);e.exports=function(e,t,n){const u=[],i=[],a=o.build({rule(e){u.push(e.name),a(e.expression),u.pop()},sequence(t){t.elements.every((t=>(a(t),!r.alwaysConsumesOnSuccess(e,t))))},repeated(t){a(t.expression),t.delimiter&&!r.alwaysConsumesOnSuccess(e,t.expression)&&a(t.delimiter)},rule_ref(t){i.push(t);const o=r.findRule(e,t.name);if(-1!==u.indexOf(t.name))return u.push(t.name),void n.error("Possible infinite loop when parsing (left recursion: "+u.join(" -> ")+")",o.nameLocation,i.map(((e,t,n)=>({message:t+1!==n.length?`Step ${t+1}: call of the rule "${e.name}" without input consumption`:`Step ${t+1}: call itself without input consumption - left recursion`,location:e.location}))));o&&a(o),i.pop()}});a(e)}},9505:function(e,t,n){"use strict";const r=n(9861),o=n(8202);e.exports=function(e,t,n){const u=o.build({zero_or_more(t){r.alwaysConsumesOnSuccess(e,t.expression)||n.error("Possible infinite loop when parsing (repetition used with an expression that may not consume any input)",t.location)},one_or_more(t){r.alwaysConsumesOnSuccess(e,t.expression)||n.error("Possible infinite loop when parsing (repetition used with an expression that may not consume any input)",t.location)},repeated(t){if(t.delimiter&&u(t.delimiter),!(r.alwaysConsumesOnSuccess(e,t.expression)||t.delimiter&&r.alwaysConsumesOnSuccess(e,t.delimiter)))if(null===t.max.value)n.error("Possible infinite loop when parsing (unbounded range repetition used with an expression that may not consume any input)",t.location);else{const e=t.min?t.min:t.max;n.warning("constant"===e.type&&"constant"===t.max.type?`An expression may not consume any input and may always match ${t.max.value} times`:"An expression may not consume any input and may always match with a maximum repetition count",t.location)}}});u(e)}},1442:function(e,t,n){"use strict";const r=n(9861),o=n(8202);e.exports=function(e,t,n){o.build({rule_ref(t){r.findRule(e,t.name)||n.error(`Rule "${t.name}" is not defined`,t.location)}})(e)}},425:function(e,t,n){"use strict";const r=n(4297);class o{constructor(e){"function"==typeof(e=void 0!==e?e:{}).error&&(this.error=e.error),"function"==typeof e.warning&&(this.warning=e.warning),"function"==typeof e.info&&(this.info=e.info)}error(){}warning(){}info(){}}e.exports=class{constructor(e){this._callbacks=new o(e),this._firstError=null,this.errors=0,this.problems=[],this.stage=null}error(...e){++this.errors,null===this._firstError&&(this._firstError=new r(...e),this._firstError.stage=this.stage,this._firstError.problems=this.problems),this.problems.push(["error",...e]),this._callbacks.error(this.stage,...e)}warning(...e){this.problems.push(["warning",...e]),this._callbacks.warning(this.stage,...e)}info(...e){this.problems.push(["info",...e]),this._callbacks.info(this.stage,...e)}checkErrors(){if(0!==this.errors)throw this._firstError}}},8013:function(e,t,n){"use strict";const{SourceNode:r}=n(4738),o=n(2190);class u{constructor(e,t,n,r){this.sp=-1,this.maxSp=-1,this.varName=t,this.ruleName=e,this.type=n,this.bytecode=r,this.labels={},this.sourceMapStack=[]}name(e){if(e<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack underflow: attempt to use a variable '${this.varName}' at an index ${e}.\nBytecode: ${this.bytecode}`);return this.varName+e}static sourceNode(e,t,n){const u=o.offsetStart(e);return new r(u.line,u.column?u.column-1:null,String(e.source),t,n)}push(e){++this.sp>this.maxSp&&(this.maxSp=this.sp);const t=this.labels[this.sp],n=[this.name(this.sp)," = ",e,";"];if(t){if(this.sourceMapStack.length){const e=u.sourceNode(t.location,n.splice(0,2),t.label),{parts:o,location:i}=this.sourceMapPopInternal(),a=i.start.offsetthis.name(this.sp+1+t)))):this.name(this.sp--)}top(){return this.name(this.sp)}index(e){if(e<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack overflow: attempt to get a variable at a negative index ${e}.\nBytecode: ${this.bytecode}`);return this.name(this.sp-e)}result(){if(this.maxSp<0)throw new RangeError(`Rule '${this.ruleName}': The variable stack is empty, can't get the result.\nBytecode: ${this.bytecode}`);return this.name(0)}defines(){return this.maxSp<0?"":this.type+" "+Array.from({length:this.maxSp+1},((e,t)=>this.name(t))).join(", ")+";"}checkedIf(e,t,n){const r=this.sp;if(t(),n){const t=this.sp;if(this.sp=r,n(),t!==this.sp)throw new Error("Rule '"+this.ruleName+"', position "+e+": Branches of a condition can't move the stack pointer differently (before: "+r+", after then: "+t+", after else: "+this.sp+"). Bytecode: "+this.bytecode)}}checkedLoop(e,t){const n=this.sp;if(t(),n!==this.sp)throw new Error("Rule '"+this.ruleName+"', position "+e+": Body of a loop can't move the stack pointer (before: "+n+", after: "+this.sp+"). Bytecode: "+this.bytecode)}sourceMapPush(e,t){if(this.sourceMapStack.length){const e=this.sourceMapStack[this.sourceMapStack.length-1];e[2].start.offset===t.start.offset&&e[2].end.offset>t.end.offset&&(e[2]={start:t.end,end:e[2].end,source:e[2].source})}this.sourceMapStack.push([e,e.length,t])}sourceMapPopInternal(){const[e,t,n]=this.sourceMapStack.pop(),u=e.splice(t).map((e=>e instanceof r?e:e+"\n"));if(u.length){const t=o.offsetStart(n);e.push(new r(t.line,t.column-1,String(n.source),u))}return{parts:e,location:n}}sourceMapPop(e){const{location:t}=this.sourceMapPopInternal();if(this.sourceMapStack.length&&t.end.offset"\\x0"+n(e))).replace(/[\x10-\x1F\x7F-\xFF]/g,(e=>"\\x"+n(e))).replace(/[\u0100-\u0FFF]/g,(e=>"\\u0"+n(e))).replace(/[\u1000-\uFFFF]/g,(e=>"\\u"+n(e)))},t.regexpClassEscape=function(e){return e.replace(/\\/g,"\\\\").replace(/\//g,"\\/").replace(/]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\v/g,"\\v").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,(e=>"\\x0"+n(e))).replace(/[\x10-\x1F\x7F-\xFF]/g,(e=>"\\x"+n(e))).replace(/[\u0100-\u0FFF]/g,(e=>"\\u0"+n(e))).replace(/[\u1000-\uFFFF]/g,(e=>"\\u"+n(e)))},t.base64=function(e){const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=e.length%3,r=e.length-n;let o="";for(let n=0;n>2],o+=t[(3&e[n])<<4|e[n+1]>>4],o+=t[(15&e[n+1])<<2|e[n+2]>>6],o+=t[63&e[n+2]];return 1===n?(o+=t[e[r]>>2],o+=t[(3&e[r])<<4],o+="=="):2===n&&(o+=t[e[r]>>2],o+=t[(3&e[r])<<4|e[r+1]>>4],o+=t[(15&e[r+1])<<2],o+="="),o}},8202:function(e){"use strict";const t={build(e){function t(t,...n){return e[t.type](t,...n)}function n(){}function r(e,...n){return t(e.expression,...n)}function o(e){return function(n,...r){n[e].forEach((e=>t(e,...r)))}}const u={grammar(e,...n){e.topLevelInitializer&&t(e.topLevelInitializer,...n),e.initializer&&t(e.initializer,...n),e.rules.forEach((e=>t(e,...n)))},top_level_initializer:n,initializer:n,rule:r,named:r,choice:o("alternatives"),action:r,sequence:o("elements"),labeled:r,text:r,simple_and:r,simple_not:r,optional:r,zero_or_more:r,one_or_more:r,repeated(e,...n){return e.delimiter&&t(e.delimiter,...n),t(e.expression,...n)},group:r,semantic_and:n,semantic_not:n,rule_ref:n,literal:n,class:n,any:n};return Object.keys(u).forEach((t=>{Object.prototype.hasOwnProperty.call(e,t)||(e[t]=u[t])})),t}};e.exports=t},4297:function(e,t,n){"use strict";const r=n(2190),o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(const n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])};class u extends Error{constructor(e,t,n){super(e),o(this,u.prototype),this.name="GrammarError",this.location=t,void 0===n&&(n=[]),this.diagnostics=n,this.stage=null,this.problems=[["error",e,t,n]]}toString(){let e=super.toString();this.location&&(e+="\n at ",void 0!==this.location.source&&null!==this.location.source&&(e+=`${this.location.source}:`),e+=`${this.location.start.line}:${this.location.start.column}`);for(const t of this.diagnostics)e+="\n from ",void 0!==t.location.source&&null!==t.location.source&&(e+=`${t.location.source}:`),e+=`${t.location.start.line}:${t.location.start.column}: ${t.message}`;return e}format(e){const t=e.map((({source:e,text:t})=>({source:e,text:null!=t?String(t).split(/\r\n|\n|\r/g):[]})));function n(e,n,o=""){let u="";const i=t.find((({source:t})=>t===e.source)),a=e.start,s=r.offsetStart(e);if(i){const t=e.end,r=i.text[a.line-1],c=(a.line===t.line?t.column:r.length+1)-a.column||1;o&&(u+=`\nnote: ${o}`),u+=`\n --\x3e ${e.source}:${s.line}:${s.column}\n${"".padEnd(n)} |\n${s.line.toString().padStart(n)} | ${r}\n${"".padEnd(n)} | ${"".padEnd(a.column-1)}${"".padEnd(c,"^")}`}else u+=`\n at ${e.source}:${s.line}:${s.column}`,o&&(u+=`: ${o}`);return u}return this.problems.filter((e=>"info"!==e[0])).map((e=>function(e,t,o,u=[]){let i=-1/0;i=o?u.reduce(((e,{location:t})=>Math.max(e,r.offsetStart(t).line)),o.start.line):Math.max.apply(null,u.map((e=>e.location.start.line))),i=i.toString().length;let a=`${e}: ${t}`;o&&(a+=n(o,i));for(const e of u)a+=n(e.location,i,e.message);return a}(...e))).join("\n\n")}}e.exports=u},2190:function(e){"use strict";e.exports=class{constructor(e,t){this.source=e,this.start=t}toString(){return String(this.source)}offset(e){return{line:e.line+this.start.line-1,column:1===e.line?e.column+this.start.column-1:e.column,offset:e.offset+this.start.offset}}static offsetStart(e){return e.source&&"function"==typeof e.source.offset?e.source.offset(e.start):e.start}static offsetEnd(e){return e.source&&"function"==typeof e.source.offset?e.source.offset(e.end):e.end}}},170:function(e){"use strict";const t={$:"text","&":"simple_and","!":"simple_not"},n={"?":"optional","*":"zero_or_more","+":"one_or_more"},r={"&":"semantic_and","!":"semantic_not"};function o(e,t,n,r){var u=Error.call(this,e);return Object.setPrototypeOf&&Object.setPrototypeOf(u,o.prototype),u.expected=t,u.found=n,u.location=r,u.name="SyntaxError",u}function u(e,t,n){return n=n||" ",e.length>t?e:(t-=e.length,e+(n+=n.repeat(t)).slice(0,t))}!function(e,t){function n(){this.constructor=e}n.prototype=t.prototype,e.prototype=new n}(o,Error),o.prototype.format=function(e){var t="Error: "+this.message;if(this.location){var n,r=null;for(n=0;n0){for(t=1,n=1;t0?{type:"choice",alternatives:[e].concat(t),location:zn()}:e},Qt=function(e,t){return null!==t?{type:"action",expression:e,code:t[0],codeLocation:t[1],location:zn()}:e},en=function(e,t){return t.length>0||"labeled"===e.type&&e.pick?{type:"sequence",elements:[e].concat(t),location:zn()}:e},tn=function(e,t,n){return n.type.startsWith("semantic_")&&qn('"@" cannot be used on a semantic predicate',e),{type:"labeled",label:null!==t?t[0]:null,labelLocation:null!==t?t[1]:e,pick:!0,expression:n,location:zn()}},nn=function(e,t){return{type:"labeled",label:e[0],labelLocation:e[1],expression:t,location:zn()}},rn=function(){return zn()},on=function(e){return kr.indexOf(e[0])>=0&&qn(`Label can't be a reserved word "${e[0]}"`,e[1]),e},un=function(e,n){return{type:t[e],expression:n,location:zn()}},an=function(e,t){return{type:n[t],expression:e,location:zn()}},sn=function(e,t,n){let r=t[0],o=t[1];return"constant"===o.type&&0===o.value&&qn("The maximum count of repetitions of the rule must be > 0",o.location),{type:"repeated",min:r,max:o,expression:e,delimiter:n,location:zn()}},cn=function(e,t){return[null!==e?e:{type:"constant",value:0},null!==t?t:{type:"constant",value:null}]},ln=function(e){return[null,e]},pn=function(e){return{type:"constant",value:e,location:zn()}},dn=function(e){return{type:"variable",value:e[0],location:zn()}},fn=function(e){return{type:"function",value:e[0],codeLocation:e[1],location:zn()}},hn=function(e){return"labeled"===e.type||"sequence"===e.type?{type:"group",expression:e,location:zn()}:e},mn=function(e){return{type:"rule_ref",name:e[0],location:zn()}},gn=function(e,t){return{type:r[e],code:t[0],codeLocation:t[1],location:zn()}},An=function(e,t){return[e+t.join(""),zn()]},En=function(e,t){return{type:"literal",value:e,ignoreCase:null!==t,location:zn()}},vn=function(e){return e.join("")},yn=function(e){return e.join("")},Cn=function(e,t,n){return{type:"class",parts:t.filter((e=>""!==e)),inverted:null!==e,ignoreCase:null!==n,location:zn()}},bn=function(t,n){return t.charCodeAt(0)>n.charCodeAt(0)&&qn("Invalid character range: "+e.substring($n,Nn)+"."),[t,n]},xn=function(){return""},Fn=function(){return"\0"},Dn=function(){return"\b"},Sn=function(){return"\f"},wn=function(){return"\n"},Bn=function(){return"\r"},Pn=function(){return"\t"},On=function(){return"\v"},kn=function(e){return String.fromCharCode(parseInt(e,16))},Tn=function(e){return String.fromCharCode(parseInt(e,16))},In=function(){return{type:"any",location:zn()}},Rn=function(e){return[e,zn()]},Ln=function(e){return parseInt(e,10)},Nn=0,$n=0,Mn=[{line:1,column:1}],jn=0,Un=[],Hn=0;if("startRule"in u){if(!(u.startRule in c))throw new Error("Can't start parsing from rule \""+u.startRule+'".');l=c[u.startRule]}function zn(){return Xn($n,Nn)}function qn(e,t){throw function(e,t){return new o(e,null,null,t)}(e,t=void 0!==t?t:Xn($n,Nn))}function Vn(e,t){return{type:"literal",text:e,ignoreCase:t}}function Wn(e,t,n){return{type:"class",parts:e,inverted:t,ignoreCase:n}}function Gn(e){return{type:"other",description:e}}function Yn(t){var n,r=Mn[t];if(r)return r;for(n=t-1;!Mn[n];)n--;for(r={line:(r=Mn[n]).line,column:r.column};njn&&(jn=Nn,Un=[]),Un.push(e))}function Jn(){var t,n,r,o,u,i;if(t=Nn,Pr(),n=Nn,r=function(){var t,n,r,o;return t=Nn,123===e.charCodeAt(Nn)?(n=p,Nn++):(n=a,0===Hn&&Zn(Fe)),n!==a&&(r=wr())!==a?(125===e.charCodeAt(Nn)?(o=d,Nn++):(o=a,0===Hn&&Zn(De)),o!==a&&Or()!==a?($n=t,t=Xt(r)):(Nn=t,t=a)):(Nn=t,t=a),t}(),r!==a?(o=Pr(),n=r):(Nn=n,n=a),n===a&&(n=null),r=Nn,o=function(){var e,t;return e=Nn,(t=wr())!==a&&Or()!==a?($n=e,e=Zt(t)):(Nn=e,e=a),e}(),o!==a?(u=Pr(),r=o):(Nn=r,r=a),r===a&&(r=null),o=[],u=Nn,(i=Kn())!==a?(Pr(),u=i):(Nn=u,u=a),u!==a)for(;u!==a;)o.push(u),u=Nn,(i=Kn())!==a?(Pr(),u=i):(Nn=u,u=a);else o=a;return o!==a?($n=t,t=Yt(n,r,o)):(Nn=t,t=a),t}function Kn(){var t,n,r,o,u;return t=Nn,(n=hr())!==a?(Pr(),r=Nn,(o=Ar())!==a?(Pr(),r=o):(Nn=r,r=a),r===a&&(r=null),61===e.charCodeAt(Nn)?(o=f,Nn++):(o=a,0===Hn&&Zn(Se)),o!==a?(Pr(),(u=Qn())!==a&&Or()!==a?($n=t,t=Jt(n,r,u)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a),t}function Qn(){var t,n,r,o,u,i;if(t=Nn,(n=er())!==a){for(r=[],o=Nn,Pr(),47===e.charCodeAt(Nn)?(u=h,Nn++):(u=a,0===Hn&&Zn(we)),u!==a?(Pr(),(i=er())!==a?o=i:(Nn=o,o=a)):(Nn=o,o=a);o!==a;)r.push(o),o=Nn,Pr(),47===e.charCodeAt(Nn)?(u=h,Nn++):(u=a,0===Hn&&Zn(we)),u!==a?(Pr(),(i=er())!==a?o=i:(Nn=o,o=a)):(Nn=o,o=a);$n=t,t=Kt(n,r)}else Nn=t,t=a;return t}function er(){var e,t,n,r;return e=Nn,t=function(){var e,t,n,r,o;if(e=Nn,(t=tr())!==a){for(n=[],r=Nn,Pr(),(o=tr())!==a?r=o:(Nn=r,r=a);r!==a;)n.push(r),r=Nn,Pr(),(o=tr())!==a?r=o:(Nn=r,r=a);$n=e,e=en(t,n)}else Nn=e,e=a;return e}(),t!==a?(n=Nn,Pr(),(r=wr())!==a?n=r:(Nn=n,n=a),n===a&&(n=null),$n=e,e=Qt(t,n)):(Nn=e,e=a),e}function tr(){var t,n,r,o;return t=Nn,n=function(){var t,n;return t=Nn,64===e.charCodeAt(Nn)?(n=m,Nn++):(n=a,0===Hn&&Zn(Be)),n!==a&&($n=t,n=rn()),t=n}(),n!==a?((r=nr())===a&&(r=null),(o=rr())!==a?($n=t,t=tn(n,r,o)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=Nn,(n=nr())!==a?(r=Pr(),(o=rr())!==a?($n=t,t=nn(n,o)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=rr())),t}function nr(){var t,n,r;return t=Nn,(n=hr())!==a?(Pr(),58===e.charCodeAt(Nn)?(r=g,Nn++):(r=a,0===Hn&&Zn(Pe)),r!==a?($n=t,t=on(n)):(Nn=t,t=a)):(Nn=t,t=a),t}function rr(){var t,n,r;return t=Nn,n=function(){var t;return 36===e.charCodeAt(Nn)?(t=A,Nn++):(t=a,0===Hn&&Zn(Oe)),t===a&&(38===e.charCodeAt(Nn)?(t=E,Nn++):(t=a,0===Hn&&Zn(ke)),t===a&&(33===e.charCodeAt(Nn)?(t=v,Nn++):(t=a,0===Hn&&Zn(Te)))),t}(),n!==a?(Pr(),(r=or())!==a?($n=t,t=un(n,r)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=or()),t}function or(){var t,n,r;return t=Nn,(n=ir())!==a?(Pr(),r=function(){var t;return 63===e.charCodeAt(Nn)?(t=y,Nn++):(t=a,0===Hn&&Zn(Ie)),t===a&&(42===e.charCodeAt(Nn)?(t=C,Nn++):(t=a,0===Hn&&Zn(Re)),t===a&&(43===e.charCodeAt(Nn)?(t=b,Nn++):(t=a,0===Hn&&Zn(Le)))),t}(),r!==a?($n=t,t=an(n,r)):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=function(){var t,n,r,o,u,i,s;return t=Nn,(n=ir())!==a?(Pr(),124===e.charCodeAt(Nn)?(r=_,Nn++):(r=a,0===Hn&&Zn(Ne)),r!==a?(Pr(),o=function(){var t,n,r,o;return t=Nn,(n=ur())===a&&(n=null),Pr(),e.substr(Nn,2)===F?(r=F,Nn+=2):(r=a,0===Hn&&Zn(Me)),r!==a?(Pr(),(o=ur())===a&&(o=null),$n=t,t=cn(n,o)):(Nn=t,t=a),t===a&&(t=Nn,(n=ur())!==a&&($n=t,n=ln(n)),t=n),t}(),o!==a?(Pr(),u=Nn,44===e.charCodeAt(Nn)?(i=x,Nn++):(i=a,0===Hn&&Zn($e)),i!==a?(Pr(),(s=Qn())!==a?(Pr(),u=s):(Nn=u,u=a)):(Nn=u,u=a),u===a&&(u=null),124===e.charCodeAt(Nn)?(i=_,Nn++):(i=a,0===Hn&&Zn(Ne)),i!==a?($n=t,t=sn(n,o,u)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=ir())),t}function ur(){var t,n;return t=Nn,n=function(){var t,n,r,o;if(t=Nn,n=Nn,r=[],(o=Dr())!==a)for(;o!==a;)r.push(o),o=Dr();else r=a;return(n=r!==a?e.substring(n,Nn):r)!==a&&($n=t,n=Ln(n)),t=n}(),n!==a&&($n=t,n=pn(n)),(t=n)===a&&(t=Nn,(n=hr())!==a&&($n=t,n=dn(n)),(t=n)===a&&(t=Nn,(n=wr())!==a&&($n=t,n=fn(n)),t=n)),t}function ir(){var t,n,r,o;return t=function(){var t,n,r;return Hn++,t=Nn,(n=Ar())!==a?(105===e.charCodeAt(Nn)?(r=W,Nn++):(r=a,0===Hn&&Zn(ft)),r===a&&(r=null),$n=t,t=En(n,r)):(Nn=t,t=a),Hn--,t===a&&(n=a,0===Hn&&Zn(dt)),t}(),t===a&&(t=function(){var t,n,r,o,u,i;if(Hn++,t=Nn,91===e.charCodeAt(Nn)?(n=X,Nn++):(n=a,0===Hn&&Zn(Et)),n!==a){for(94===e.charCodeAt(Nn)?(r=Z,Nn++):(r=a,0===Hn&&Zn(vt)),r===a&&(r=null),o=[],(u=yr())===a&&(u=Cr());u!==a;)o.push(u),(u=yr())===a&&(u=Cr());93===e.charCodeAt(Nn)?(u=J,Nn++):(u=a,0===Hn&&Zn(yt)),u!==a?(105===e.charCodeAt(Nn)?(i=W,Nn++):(i=a,0===Hn&&Zn(ft)),i===a&&(i=null),$n=t,t=Cn(r,o,i)):(Nn=t,t=a)}else Nn=t,t=a;return Hn--,t===a&&(n=a,0===Hn&&Zn(At)),t}(),t===a&&(t=function(){var t,n;return t=Nn,46===e.charCodeAt(Nn)?(n=se,Nn++):(n=a,0===Hn&&Zn(Tt)),n!==a&&($n=t,n=In()),t=n}(),t===a&&(t=function(){var t,n,r,o,u,i,s;return t=Nn,(n=hr())!==a?(r=Nn,Hn++,o=Nn,u=Pr(),i=Nn,(s=Ar())!==a?i=s=[s,Pr()]:(Nn=i,i=a),i===a&&(i=null),61===e.charCodeAt(Nn)?(s=f,Nn++):(s=a,0===Hn&&Zn(Se)),s!==a?o=u=[u,i,s]:(Nn=o,o=a),Hn--,o===a?r=void 0:(Nn=r,r=a),r!==a?($n=t,t=mn(n)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=function(){var t,n,r;return t=Nn,n=function(){var t;return 38===e.charCodeAt(Nn)?(t=E,Nn++):(t=a,0===Hn&&Zn(ke)),t===a&&(33===e.charCodeAt(Nn)?(t=v,Nn++):(t=a,0===Hn&&Zn(Te))),t}(),n!==a?(Pr(),(r=wr())!==a?($n=t,t=gn(n,r)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=Nn,40===e.charCodeAt(Nn)?(n=D,Nn++):(n=a,0===Hn&&Zn(je)),n!==a?(Pr(),(r=Qn())!==a?(Pr(),41===e.charCodeAt(Nn)?(o=S,Nn++):(o=a,0===Hn&&Zn(Ue)),o!==a?($n=t,t=hn(r)):(Nn=t,t=a)):(Nn=t,t=a)):(Nn=t,t=a)))))),t}function ar(){var t;return e.length>Nn?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(He)),t}function sr(){var t;return Hn++,9===e.charCodeAt(Nn)?(t=w,Nn++):(t=a,0===Hn&&Zn(qe)),t===a&&(11===e.charCodeAt(Nn)?(t=B,Nn++):(t=a,0===Hn&&Zn(Ve)),t===a&&(12===e.charCodeAt(Nn)?(t=P,Nn++):(t=a,0===Hn&&Zn(We)),t===a&&(32===e.charCodeAt(Nn)?(t=O,Nn++):(t=a,0===Hn&&Zn(Ge)),t===a&&(160===e.charCodeAt(Nn)?(t=k,Nn++):(t=a,0===Hn&&Zn(Ye)),t===a&&(65279===e.charCodeAt(Nn)?(t=T,Nn++):(t=a,0===Hn&&Zn(Xe)),t===a&&(t=function(){var t;return xe.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Wt)),t}())))))),Hn--,t===a&&0===Hn&&Zn(ze),t}function cr(){var t;return le.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Ze)),t}function lr(){var t;return Hn++,10===e.charCodeAt(Nn)?(t=I,Nn++):(t=a,0===Hn&&Zn(Ke)),t===a&&(e.substr(Nn,2)===R?(t=R,Nn+=2):(t=a,0===Hn&&Zn(Qe)),t===a&&(13===e.charCodeAt(Nn)?(t=L,Nn++):(t=a,0===Hn&&Zn(et)),t===a&&(8232===e.charCodeAt(Nn)?(t=N,Nn++):(t=a,0===Hn&&Zn(tt)),t===a&&(8233===e.charCodeAt(Nn)?(t=$,Nn++):(t=a,0===Hn&&Zn(nt)))))),Hn--,t===a&&0===Hn&&Zn(Je),t}function pr(){var t;return Hn++,(t=function(){var t,n,r,o,u,i;if(t=Nn,e.substr(Nn,2)===M?(n=M,Nn+=2):(n=a,0===Hn&&Zn(ot)),n!==a){for(r=[],o=Nn,u=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Zn(ut)),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);o!==a;)r.push(o),o=Nn,u=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Zn(ut)),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);e.substr(Nn,2)===j?(o=j,Nn+=2):(o=a,0===Hn&&Zn(ut)),o!==a?t=n=[n,r,o]:(Nn=t,t=a)}else Nn=t,t=a;return t}())===a&&(t=fr()),Hn--,t===a&&0===Hn&&Zn(rt),t}function dr(){var t,n,r,o,u,i;if(t=Nn,e.substr(Nn,2)===M?(n=M,Nn+=2):(n=a,0===Hn&&Zn(ot)),n!==a){for(r=[],o=Nn,u=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Zn(ut)),i===a&&(i=cr()),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);o!==a;)r.push(o),o=Nn,u=Nn,Hn++,e.substr(Nn,2)===j?(i=j,Nn+=2):(i=a,0===Hn&&Zn(ut)),i===a&&(i=cr()),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);e.substr(Nn,2)===j?(o=j,Nn+=2):(o=a,0===Hn&&Zn(ut)),o!==a?t=n=[n,r,o]:(Nn=t,t=a)}else Nn=t,t=a;return t}function fr(){var t,n,r,o,u,i;if(t=Nn,e.substr(Nn,2)===U?(n=U,Nn+=2):(n=a,0===Hn&&Zn(it)),n!==a){for(r=[],o=Nn,u=Nn,Hn++,i=cr(),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);o!==a;)r.push(o),o=Nn,u=Nn,Hn++,i=cr(),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);t=n=[n,r]}else Nn=t,t=a;return t}function hr(){var e,t,n,r;if(Hn++,e=Nn,(t=mr())!==a){for(n=[],r=gr();r!==a;)n.push(r),r=gr();$n=e,e=An(t,n)}else Nn=e,e=a;return Hn--,e===a&&(t=a,0===Hn&&Zn(at)),e}function mr(){var t,n,r;return(t=function(){var t;return(t=function(){var t;return Ee.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(jt)),t}())===a&&(t=function(){var t;return he.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Lt)),t}())===a&&(t=function(){var t;return Ae.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Mt)),t}())===a&&(t=function(){var t;return me.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Nt)),t}())===a&&(t=function(){var t;return ge.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn($t)),t}())===a&&(t=function(){var t;return be.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(qt)),t}()),t}())===a&&(95===e.charCodeAt(Nn)?(t=H,Nn++):(t=a,0===Hn&&Zn(st)),t===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=z,Nn++):(n=a,0===Hn&&Zn(ct)),n!==a&&(r=Fr())!==a?t=r:(Nn=t,t=a))),t}function gr(){var t;return(t=mr())===a&&(36===e.charCodeAt(Nn)?(t=A,Nn++):(t=a,0===Hn&&Zn(Oe)),t===a&&(t=function(){var t;return(t=function(){var t;return ye.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Ht)),t}())===a&&(t=function(){var t;return ve.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Ut)),t}()),t}())===a&&(t=function(){var t;return Ce.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(zt)),t}())===a&&(t=function(){var t;return _e.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Vt)),t}())===a&&(8204===e.charCodeAt(Nn)?(t=q,Nn++):(t=a,0===Hn&&Zn(lt)),t===a&&(8205===e.charCodeAt(Nn)?(t=V,Nn++):(t=a,0===Hn&&Zn(pt))))),t}function Ar(){var t,n,r,o;if(Hn++,t=Nn,34===e.charCodeAt(Nn)?(n=G,Nn++):(n=a,0===Hn&&Zn(mt)),n!==a){for(r=[],o=Er();o!==a;)r.push(o),o=Er();34===e.charCodeAt(Nn)?(o=G,Nn++):(o=a,0===Hn&&Zn(mt)),o!==a?($n=t,t=vn(r)):(Nn=t,t=a)}else Nn=t,t=a;if(t===a)if(t=Nn,39===e.charCodeAt(Nn)?(n=Y,Nn++):(n=a,0===Hn&&Zn(gt)),n!==a){for(r=[],o=vr();o!==a;)r.push(o),o=vr();39===e.charCodeAt(Nn)?(o=Y,Nn++):(o=a,0===Hn&&Zn(gt)),o!==a?($n=t,t=yn(r)):(Nn=t,t=a)}else Nn=t,t=a;return Hn--,t===a&&(n=a,0===Hn&&Zn(ht)),t}function Er(){var t,n,r,o;return t=Nn,n=Nn,r=Nn,Hn++,34===e.charCodeAt(Nn)?(o=G,Nn++):(o=a,0===Hn&&Zn(mt)),o===a&&(92===e.charCodeAt(Nn)?(o=z,Nn++):(o=a,0===Hn&&Zn(ct)),o===a&&(o=cr())),Hn--,o===a?r=void 0:(Nn=r,r=a),r!==a&&(o=ar())!==a?n=r=[r,o]:(Nn=n,n=a),(t=n!==a?e.substring(t,Nn):n)===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=z,Nn++):(n=a,0===Hn&&Zn(ct)),n!==a&&(r=_r())!==a?t=r:(Nn=t,t=a),t===a&&(t=br())),t}function vr(){var t,n,r,o;return t=Nn,n=Nn,r=Nn,Hn++,39===e.charCodeAt(Nn)?(o=Y,Nn++):(o=a,0===Hn&&Zn(gt)),o===a&&(92===e.charCodeAt(Nn)?(o=z,Nn++):(o=a,0===Hn&&Zn(ct)),o===a&&(o=cr())),Hn--,o===a?r=void 0:(Nn=r,r=a),r!==a&&(o=ar())!==a?n=r=[r,o]:(Nn=n,n=a),(t=n!==a?e.substring(t,Nn):n)===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=z,Nn++):(n=a,0===Hn&&Zn(ct)),n!==a&&(r=_r())!==a?t=r:(Nn=t,t=a),t===a&&(t=br())),t}function yr(){var t,n,r,o;return t=Nn,(n=Cr())!==a?(45===e.charCodeAt(Nn)?(r=K,Nn++):(r=a,0===Hn&&Zn(Ct)),r!==a&&(o=Cr())!==a?($n=t,t=bn(n,o)):(Nn=t,t=a)):(Nn=t,t=a),t}function Cr(){var t,n,r,o;return t=Nn,n=Nn,r=Nn,Hn++,93===e.charCodeAt(Nn)?(o=J,Nn++):(o=a,0===Hn&&Zn(yt)),o===a&&(92===e.charCodeAt(Nn)?(o=z,Nn++):(o=a,0===Hn&&Zn(ct)),o===a&&(o=cr())),Hn--,o===a?r=void 0:(Nn=r,r=a),r!==a&&(o=ar())!==a?n=r=[r,o]:(Nn=n,n=a),(t=n!==a?e.substring(t,Nn):n)===a&&(t=Nn,92===e.charCodeAt(Nn)?(n=z,Nn++):(n=a,0===Hn&&Zn(ct)),n!==a&&(r=_r())!==a?t=r:(Nn=t,t=a),t===a&&(t=br())),t}function br(){var t,n;return t=Nn,92===e.charCodeAt(Nn)?(n=z,Nn++):(n=a,0===Hn&&Zn(ct)),n!==a&&lr()!==a?($n=t,t=xn()):(Nn=t,t=a),t}function _r(){var t,n,r,o;return t=function(){var t;return(t=xr())===a&&(t=function(){var t,n,r,o;return t=Nn,n=Nn,r=Nn,Hn++,o=function(){var t;return(t=xr())===a&&(t=Dr())===a&&(120===e.charCodeAt(Nn)?(t=ie,Nn++):(t=a,0===Hn&&Zn(Bt)),t===a&&(117===e.charCodeAt(Nn)?(t=ae,Nn++):(t=a,0===Hn&&Zn(Pt)))),t}(),o===a&&(o=cr()),Hn--,o===a?r=void 0:(Nn=r,r=a),r!==a&&(o=ar())!==a?n=r=[r,o]:(Nn=n,n=a),t=n!==a?e.substring(t,Nn):n}()),t}(),t===a&&(t=Nn,48===e.charCodeAt(Nn)?(n=Q,Nn++):(n=a,0===Hn&&Zn(bt)),n!==a?(r=Nn,Hn++,o=Dr(),Hn--,o===a?r=void 0:(Nn=r,r=a),r!==a?($n=t,t=Fn()):(Nn=t,t=a)):(Nn=t,t=a),t===a&&(t=function(){var t,n,r,o,u,i;return t=Nn,120===e.charCodeAt(Nn)?(n=ie,Nn++):(n=a,0===Hn&&Zn(Bt)),n!==a?(r=Nn,o=Nn,(u=Sr())!==a&&(i=Sr())!==a?o=u=[u,i]:(Nn=o,o=a),(r=o!==a?e.substring(r,Nn):o)!==a?($n=t,t=kn(r)):(Nn=t,t=a)):(Nn=t,t=a),t}(),t===a&&(t=Fr()))),t}function xr(){var t,n;return 39===e.charCodeAt(Nn)?(t=Y,Nn++):(t=a,0===Hn&&Zn(gt)),t===a&&(34===e.charCodeAt(Nn)?(t=G,Nn++):(t=a,0===Hn&&Zn(mt)),t===a&&(92===e.charCodeAt(Nn)?(t=z,Nn++):(t=a,0===Hn&&Zn(ct)),t===a&&(t=Nn,98===e.charCodeAt(Nn)?(n=ee,Nn++):(n=a,0===Hn&&Zn(_t)),n!==a&&($n=t,n=Dn()),(t=n)===a&&(t=Nn,102===e.charCodeAt(Nn)?(n=te,Nn++):(n=a,0===Hn&&Zn(xt)),n!==a&&($n=t,n=Sn()),(t=n)===a&&(t=Nn,110===e.charCodeAt(Nn)?(n=ne,Nn++):(n=a,0===Hn&&Zn(Ft)),n!==a&&($n=t,n=wn()),(t=n)===a&&(t=Nn,114===e.charCodeAt(Nn)?(n=re,Nn++):(n=a,0===Hn&&Zn(Dt)),n!==a&&($n=t,n=Bn()),(t=n)===a&&(t=Nn,116===e.charCodeAt(Nn)?(n=oe,Nn++):(n=a,0===Hn&&Zn(St)),n!==a&&($n=t,n=Pn()),(t=n)===a&&(t=Nn,118===e.charCodeAt(Nn)?(n=ue,Nn++):(n=a,0===Hn&&Zn(wt)),n!==a&&($n=t,n=On()),t=n)))))))),t}function Fr(){var t,n,r,o,u,i,s,c;return t=Nn,117===e.charCodeAt(Nn)?(n=ae,Nn++):(n=a,0===Hn&&Zn(Pt)),n!==a?(r=Nn,o=Nn,(u=Sr())!==a&&(i=Sr())!==a&&(s=Sr())!==a&&(c=Sr())!==a?o=u=[u,i,s,c]:(Nn=o,o=a),(r=o!==a?e.substring(r,Nn):o)!==a?($n=t,t=Tn(r)):(Nn=t,t=a)):(Nn=t,t=a),t}function Dr(){var t;return pe.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(Ot)),t}function Sr(){var t;return de.test(e.charAt(Nn))?(t=e.charAt(Nn),Nn++):(t=a,0===Hn&&Zn(kt)),t}function wr(){var t,n,r,o;return Hn++,t=Nn,123===e.charCodeAt(Nn)?(n=p,Nn++):(n=a,0===Hn&&Zn(Fe)),n!==a?(r=function(){var e,t;return e=Nn,t=Br(),$n=e,e=t=Rn(t)}(),125===e.charCodeAt(Nn)?(o=d,Nn++):(o=a,0===Hn&&Zn(De)),o!==a?t=r:(Nn=t,t=a)):(Nn=t,t=a),Hn--,t===a&&(n=a,0===Hn&&Zn(It)),t}function Br(){var t,n,r,o,u,i;if(t=Nn,n=[],r=[],o=Nn,u=Nn,Hn++,fe.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Zn(Rt)),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a),o!==a)for(;o!==a;)r.push(o),o=Nn,u=Nn,Hn++,fe.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Zn(Rt)),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);else r=a;for(r===a&&(r=Nn,123===e.charCodeAt(Nn)?(o=p,Nn++):(o=a,0===Hn&&Zn(Fe)),o!==a?(u=Br(),125===e.charCodeAt(Nn)?(i=d,Nn++):(i=a,0===Hn&&Zn(De)),i!==a?r=o=[o,u,i]:(Nn=r,r=a)):(Nn=r,r=a));r!==a;){if(n.push(r),r=[],o=Nn,u=Nn,Hn++,fe.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Zn(Rt)),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a),o!==a)for(;o!==a;)r.push(o),o=Nn,u=Nn,Hn++,fe.test(e.charAt(Nn))?(i=e.charAt(Nn),Nn++):(i=a,0===Hn&&Zn(Rt)),Hn--,i===a?u=void 0:(Nn=u,u=a),u!==a&&(i=ar())!==a?o=u=[u,i]:(Nn=o,o=a);else r=a;r===a&&(r=Nn,123===e.charCodeAt(Nn)?(o=p,Nn++):(o=a,0===Hn&&Zn(Fe)),o!==a?(u=Br(),125===e.charCodeAt(Nn)?(i=d,Nn++):(i=a,0===Hn&&Zn(De)),i!==a?r=o=[o,u,i]:(Nn=r,r=a)):(Nn=r,r=a))}return e.substring(t,Nn)}function Pr(){var e,t;for(e=[],(t=sr())===a&&(t=lr())===a&&(t=pr());t!==a;)e.push(t),(t=sr())===a&&(t=lr())===a&&(t=pr());return e}function Or(){var t,n,r,o;if(t=[],n=Nn,r=Pr(),59===e.charCodeAt(Nn)?(o=ce,Nn++):(o=a,0===Hn&&Zn(Gt)),o!==a?n=r=[r,o]:(Nn=n,n=a),n!==a)for(;n!==a;)t.push(n),n=Nn,r=Pr(),59===e.charCodeAt(Nn)?(o=ce,Nn++):(o=a,0===Hn&&Zn(Gt)),o!==a?n=r=[r,o]:(Nn=n,n=a);else t=a;return t===a&&(t=Nn,n=function(){var e,t;for(e=[],(t=sr())===a&&(t=dr());t!==a;)e.push(t),(t=sr())===a&&(t=dr());return e}(),(r=fr())===a&&(r=null),(o=lr())!==a?t=n=[n,r,o]:(Nn=t,t=a),t===a&&(t=Nn,n=Pr(),r=function(){var t,n;return t=Nn,Hn++,e.length>Nn?(n=e.charAt(Nn),Nn++):(n=a,0===Hn&&Zn(He)),Hn--,n===a?t=void 0:(Nn=t,t=a),t}(),r!==a?t=n=[n,r]:(Nn=t,t=a))),t}const kr=u.reservedWords||[];if((i=l())!==a&&Nn===e.length)return i;throw i!==a&&Nn{t[n]=e[n].slice()})),t}(a.compiler.passes),reservedWords:a.RESERVED_WORDS.slice()};return n.forEach((e=>{e.use(r,t)})),a.compiler.compile(r.parser.parse(e,{grammarSource:t.grammarSource,reservedWords:r.reservedWords}),r.passes,t)}};e.exports=a},244:function(e){"use strict";e.exports="3.0.2"},5726:function(e,t,n){"use strict";function r(e,t,n,r,o,u,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=u,this.removeEmptyString=i}const o={};["children","dangerouslySetInnerHTML","defaultValue","defaultChecked","innerHTML","suppressContentEditableWarning","suppressHydrationWarning","style"].forEach((e=>{o[e]=new r(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((([e,t])=>{o[e]=new r(e,1,!1,t,null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((e=>{o[e]=new r(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((e=>{o[e]=new r(e,2,!1,e,null,!1,!1)})),["allowFullScreen","async","autoFocus","autoPlay","controls","default","defer","disabled","disablePictureInPicture","disableRemotePlayback","formNoValidate","hidden","loop","noModule","noValidate","open","playsInline","readOnly","required","reversed","scoped","seamless","itemScope"].forEach((e=>{o[e]=new r(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((e=>{o[e]=new r(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((e=>{o[e]=new r(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((e=>{o[e]=new r(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((e=>{o[e]=new r(e,5,!1,e.toLowerCase(),null,!1,!1)}));const u=/[\-\:]([a-z])/g,i=e=>e[1].toUpperCase();["accent-height","alignment-baseline","arabic-form","baseline-shift","cap-height","clip-path","clip-rule","color-interpolation","color-interpolation-filters","color-profile","color-rendering","dominant-baseline","enable-background","fill-opacity","fill-rule","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","glyph-name","glyph-orientation-horizontal","glyph-orientation-vertical","horiz-adv-x","horiz-origin-x","image-rendering","letter-spacing","lighting-color","marker-end","marker-mid","marker-start","overline-position","overline-thickness","paint-order","panose-1","pointer-events","rendering-intent","shape-rendering","stop-color","stop-opacity","strikethrough-position","strikethrough-thickness","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-anchor","text-decoration","text-rendering","underline-position","underline-thickness","unicode-bidi","unicode-range","units-per-em","v-alphabetic","v-hanging","v-ideographic","v-mathematical","vector-effect","vert-adv-y","vert-origin-x","vert-origin-y","word-spacing","writing-mode","xmlns:xlink","x-height"].forEach((e=>{const t=e.replace(u,i);o[t]=new r(t,1,!1,e,null,!1,!1)})),["xlink:actuate","xlink:arcrole","xlink:role","xlink:show","xlink:title","xlink:type"].forEach((e=>{const t=e.replace(u,i);o[t]=new r(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((e=>{const t=e.replace(u,i);o[t]=new r(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((e=>{o[e]=new r(e,1,!1,e.toLowerCase(),null,!1,!1)})),o.xlinkHref=new r("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((e=>{o[e]=new r(e,1,!1,e.toLowerCase(),null,!0,!0)}));const{CAMELCASE:a,SAME:s,possibleStandardNames:c}=n(8229),l=RegExp.prototype.test.bind(new RegExp("^(data|aria)-[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$")),p=Object.keys(c).reduce(((e,t)=>{const n=c[t];return n===s?e[t]=t:n===a?e[t.toLowerCase()]=t:e[t]=n,e}),{});t.BOOLEAN=3,t.BOOLEANISH_STRING=2,t.NUMERIC=5,t.OVERLOADED_BOOLEAN=4,t.POSITIVE_NUMERIC=6,t.RESERVED=0,t.STRING=1,t.getPropertyInfo=function(e){return o.hasOwnProperty(e)?o[e]:null},t.isCustomAttribute=l,t.possibleStandardNames=p},8229:function(e,t){t.SAME=0,t.CAMELCASE=1,t.possibleStandardNames={accept:0,acceptCharset:1,"accept-charset":"acceptCharset",accessKey:1,action:0,allowFullScreen:1,alt:0,as:0,async:0,autoCapitalize:1,autoComplete:1,autoCorrect:1,autoFocus:1,autoPlay:1,autoSave:1,capture:0,cellPadding:1,cellSpacing:1,challenge:0,charSet:1,checked:0,children:0,cite:0,class:"className",classID:1,className:1,cols:0,colSpan:1,content:0,contentEditable:1,contextMenu:1,controls:0,controlsList:1,coords:0,crossOrigin:1,dangerouslySetInnerHTML:1,data:0,dateTime:1,default:0,defaultChecked:1,defaultValue:1,defer:0,dir:0,disabled:0,disablePictureInPicture:1,disableRemotePlayback:1,download:0,draggable:0,encType:1,enterKeyHint:1,for:"htmlFor",form:0,formMethod:1,formAction:1,formEncType:1,formNoValidate:1,formTarget:1,frameBorder:1,headers:0,height:0,hidden:0,high:0,href:0,hrefLang:1,htmlFor:1,httpEquiv:1,"http-equiv":"httpEquiv",icon:0,id:0,innerHTML:1,inputMode:1,integrity:0,is:0,itemID:1,itemProp:1,itemRef:1,itemScope:1,itemType:1,keyParams:1,keyType:1,kind:0,label:0,lang:0,list:0,loop:0,low:0,manifest:0,marginWidth:1,marginHeight:1,max:0,maxLength:1,media:0,mediaGroup:1,method:0,min:0,minLength:1,multiple:0,muted:0,name:0,noModule:1,nonce:0,noValidate:1,open:0,optimum:0,pattern:0,placeholder:0,playsInline:1,poster:0,preload:0,profile:0,radioGroup:1,readOnly:1,referrerPolicy:1,rel:0,required:0,reversed:0,role:0,rows:0,rowSpan:1,sandbox:0,scope:0,scoped:0,scrolling:0,seamless:0,selected:0,shape:0,size:0,sizes:0,span:0,spellCheck:1,src:0,srcDoc:1,srcLang:1,srcSet:1,start:0,step:0,style:0,summary:0,tabIndex:1,target:0,title:0,type:0,useMap:1,value:0,width:0,wmode:0,wrap:0,about:0,accentHeight:1,"accent-height":"accentHeight",accumulate:0,additive:0,alignmentBaseline:1,"alignment-baseline":"alignmentBaseline",allowReorder:1,alphabetic:0,amplitude:0,arabicForm:1,"arabic-form":"arabicForm",ascent:0,attributeName:1,attributeType:1,autoReverse:1,azimuth:0,baseFrequency:1,baselineShift:1,"baseline-shift":"baselineShift",baseProfile:1,bbox:0,begin:0,bias:0,by:0,calcMode:1,capHeight:1,"cap-height":"capHeight",clip:0,clipPath:1,"clip-path":"clipPath",clipPathUnits:1,clipRule:1,"clip-rule":"clipRule",color:0,colorInterpolation:1,"color-interpolation":"colorInterpolation",colorInterpolationFilters:1,"color-interpolation-filters":"colorInterpolationFilters",colorProfile:1,"color-profile":"colorProfile",colorRendering:1,"color-rendering":"colorRendering",contentScriptType:1,contentStyleType:1,cursor:0,cx:0,cy:0,d:0,datatype:0,decelerate:0,descent:0,diffuseConstant:1,direction:0,display:0,divisor:0,dominantBaseline:1,"dominant-baseline":"dominantBaseline",dur:0,dx:0,dy:0,edgeMode:1,elevation:0,enableBackground:1,"enable-background":"enableBackground",end:0,exponent:0,externalResourcesRequired:1,fill:0,fillOpacity:1,"fill-opacity":"fillOpacity",fillRule:1,"fill-rule":"fillRule",filter:0,filterRes:1,filterUnits:1,floodOpacity:1,"flood-opacity":"floodOpacity",floodColor:1,"flood-color":"floodColor",focusable:0,fontFamily:1,"font-family":"fontFamily",fontSize:1,"font-size":"fontSize",fontSizeAdjust:1,"font-size-adjust":"fontSizeAdjust",fontStretch:1,"font-stretch":"fontStretch",fontStyle:1,"font-style":"fontStyle",fontVariant:1,"font-variant":"fontVariant",fontWeight:1,"font-weight":"fontWeight",format:0,from:0,fx:0,fy:0,g1:0,g2:0,glyphName:1,"glyph-name":"glyphName",glyphOrientationHorizontal:1,"glyph-orientation-horizontal":"glyphOrientationHorizontal",glyphOrientationVertical:1,"glyph-orientation-vertical":"glyphOrientationVertical",glyphRef:1,gradientTransform:1,gradientUnits:1,hanging:0,horizAdvX:1,"horiz-adv-x":"horizAdvX",horizOriginX:1,"horiz-origin-x":"horizOriginX",ideographic:0,imageRendering:1,"image-rendering":"imageRendering",in2:0,in:0,inlist:0,intercept:0,k1:0,k2:0,k3:0,k4:0,k:0,kernelMatrix:1,kernelUnitLength:1,kerning:0,keyPoints:1,keySplines:1,keyTimes:1,lengthAdjust:1,letterSpacing:1,"letter-spacing":"letterSpacing",lightingColor:1,"lighting-color":"lightingColor",limitingConeAngle:1,local:0,markerEnd:1,"marker-end":"markerEnd",markerHeight:1,markerMid:1,"marker-mid":"markerMid",markerStart:1,"marker-start":"markerStart",markerUnits:1,markerWidth:1,mask:0,maskContentUnits:1,maskUnits:1,mathematical:0,mode:0,numOctaves:1,offset:0,opacity:0,operator:0,order:0,orient:0,orientation:0,origin:0,overflow:0,overlinePosition:1,"overline-position":"overlinePosition",overlineThickness:1,"overline-thickness":"overlineThickness",paintOrder:1,"paint-order":"paintOrder",panose1:0,"panose-1":"panose1",pathLength:1,patternContentUnits:1,patternTransform:1,patternUnits:1,pointerEvents:1,"pointer-events":"pointerEvents",points:0,pointsAtX:1,pointsAtY:1,pointsAtZ:1,prefix:0,preserveAlpha:1,preserveAspectRatio:1,primitiveUnits:1,property:0,r:0,radius:0,refX:1,refY:1,renderingIntent:1,"rendering-intent":"renderingIntent",repeatCount:1,repeatDur:1,requiredExtensions:1,requiredFeatures:1,resource:0,restart:0,result:0,results:0,rotate:0,rx:0,ry:0,scale:0,security:0,seed:0,shapeRendering:1,"shape-rendering":"shapeRendering",slope:0,spacing:0,specularConstant:1,specularExponent:1,speed:0,spreadMethod:1,startOffset:1,stdDeviation:1,stemh:0,stemv:0,stitchTiles:1,stopColor:1,"stop-color":"stopColor",stopOpacity:1,"stop-opacity":"stopOpacity",strikethroughPosition:1,"strikethrough-position":"strikethroughPosition",strikethroughThickness:1,"strikethrough-thickness":"strikethroughThickness",string:0,stroke:0,strokeDasharray:1,"stroke-dasharray":"strokeDasharray",strokeDashoffset:1,"stroke-dashoffset":"strokeDashoffset",strokeLinecap:1,"stroke-linecap":"strokeLinecap",strokeLinejoin:1,"stroke-linejoin":"strokeLinejoin",strokeMiterlimit:1,"stroke-miterlimit":"strokeMiterlimit",strokeWidth:1,"stroke-width":"strokeWidth",strokeOpacity:1,"stroke-opacity":"strokeOpacity",suppressContentEditableWarning:1,suppressHydrationWarning:1,surfaceScale:1,systemLanguage:1,tableValues:1,targetX:1,targetY:1,textAnchor:1,"text-anchor":"textAnchor",textDecoration:1,"text-decoration":"textDecoration",textLength:1,textRendering:1,"text-rendering":"textRendering",to:0,transform:0,typeof:0,u1:0,u2:0,underlinePosition:1,"underline-position":"underlinePosition",underlineThickness:1,"underline-thickness":"underlineThickness",unicode:0,unicodeBidi:1,"unicode-bidi":"unicodeBidi",unicodeRange:1,"unicode-range":"unicodeRange",unitsPerEm:1,"units-per-em":"unitsPerEm",unselectable:0,vAlphabetic:1,"v-alphabetic":"vAlphabetic",values:0,vectorEffect:1,"vector-effect":"vectorEffect",version:0,vertAdvY:1,"vert-adv-y":"vertAdvY",vertOriginX:1,"vert-origin-x":"vertOriginX",vertOriginY:1,"vert-origin-y":"vertOriginY",vHanging:1,"v-hanging":"vHanging",vIdeographic:1,"v-ideographic":"vIdeographic",viewBox:1,viewTarget:1,visibility:0,vMathematical:1,"v-mathematical":"vMathematical",vocab:0,widths:0,wordSpacing:1,"word-spacing":"wordSpacing",writingMode:1,"writing-mode":"writingMode",x1:0,x2:0,x:0,xChannelSelector:1,xHeight:1,"x-height":"xHeight",xlinkActuate:1,"xlink:actuate":"xlinkActuate",xlinkArcrole:1,"xlink:arcrole":"xlinkArcrole",xlinkHref:1,"xlink:href":"xlinkHref",xlinkRole:1,"xlink:role":"xlinkRole",xlinkShow:1,"xlink:show":"xlinkShow",xlinkTitle:1,"xlink:title":"xlinkTitle",xlinkType:1,"xlink:type":"xlinkType",xmlBase:1,"xml:base":"xmlBase",xmlLang:1,"xml:lang":"xmlLang",xmlns:0,"xml:space":"xmlSpace",xmlnsXlink:1,"xmlns:xlink":"xmlnsXlink",xmlSpace:1,y1:0,y2:0,y:0,yChannelSelector:1,z:0,zoomAndPan:1}},8276:function(e,t){class n{constructor(){this._array=[],this._set=new Map}static fromArray(e,t){const r=new n;for(let n=0,o=e.length;n=0)return t;throw new Error('"'+e+'" is not in the set.')}at(e){if(e>=0&&e>>=5,o>0&&(t|=32),n+=r.encode(t)}while(o>0);return n}},6728:function(e,t){const n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");t.encode=function(e){if(0<=e&&en||o==n&&i>=u||r.compareByGeneratedPositionsInflated(e,t)<=0}(this._last,e)?(this._sorted=!1,this._array.push(e)):(this._last=e,this._array.push(e))}toArray(){return this._sorted||(this._array.sort(r.compareByGeneratedPositionsInflated),this._sorted=!0),this._array}}},1027:function(e,t,n){const r=n(2020),o=n(858),u=n(8276).I,i=n(2265).H;class a{constructor(e){e||(e={}),this._file=o.getArg(e,"file",null),this._sourceRoot=o.getArg(e,"sourceRoot",null),this._skipValidation=o.getArg(e,"skipValidation",!1),this._sources=new u,this._names=new u,this._mappings=new i,this._sourcesContents=null}static fromSourceMap(e){const t=e.sourceRoot,n=new a({file:e.file,sourceRoot:t});return e.eachMapping((function(e){const r={generated:{line:e.generatedLine,column:e.generatedColumn}};null!=e.source&&(r.source=e.source,null!=t&&(r.source=o.relative(t,r.source)),r.original={line:e.originalLine,column:e.originalColumn},null!=e.name&&(r.name=e.name)),n.addMapping(r)})),e.sources.forEach((function(r){let u=r;null!=t&&(u=o.relative(t,r)),n._sources.has(u)||n._sources.add(u);const i=e.sourceContentFor(r);null!=i&&n.setSourceContent(r,i)})),n}addMapping(e){const t=o.getArg(e,"generated"),n=o.getArg(e,"original",null);let r=o.getArg(e,"source",null),u=o.getArg(e,"name",null);this._skipValidation||this._validateMapping(t,n,r,u),null!=r&&(r=String(r),this._sources.has(r)||this._sources.add(r)),null!=u&&(u=String(u),this._names.has(u)||this._names.add(u)),this._mappings.add({generatedLine:t.line,generatedColumn:t.column,originalLine:n&&n.line,originalColumn:n&&n.column,source:r,name:u})}setSourceContent(e,t){let n=e;null!=this._sourceRoot&&(n=o.relative(this._sourceRoot,n)),null!=t?(this._sourcesContents||(this._sourcesContents=Object.create(null)),this._sourcesContents[o.toSetString(n)]=t):this._sourcesContents&&(delete this._sourcesContents[o.toSetString(n)],0===Object.keys(this._sourcesContents).length&&(this._sourcesContents=null))}applySourceMap(e,t,n){let r=t;if(null==t){if(null==e.file)throw new Error('SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, or the source map\'s "file" property. Both were omitted.');r=e.file}const i=this._sourceRoot;null!=i&&(r=o.relative(i,r));const a=this._mappings.toArray().length>0?new u:this._sources,s=new u;this._mappings.unsortedForEach((function(t){if(t.source===r&&null!=t.originalLine){const r=e.originalPositionFor({line:t.originalLine,column:t.originalColumn});null!=r.source&&(t.source=r.source,null!=n&&(t.source=o.join(n,t.source)),null!=i&&(t.source=o.relative(i,t.source)),t.originalLine=r.line,t.originalColumn=r.column,null!=r.name&&(t.name=r.name))}const u=t.source;null==u||a.has(u)||a.add(u);const c=t.name;null==c||s.has(c)||s.add(c)}),this),this._sources=a,this._names=s,e.sources.forEach((function(t){const r=e.sourceContentFor(t);null!=r&&(null!=n&&(t=o.join(n,t)),null!=i&&(t=o.relative(i,t)),this.setSourceContent(t,r))}),this)}_validateMapping(e,t,n,r){if(t&&"number"!=typeof t.line&&"number"!=typeof t.column)throw new Error("original.line and original.column are not numbers -- you probably meant to omit the original mapping entirely and only map the generated position. If so, pass null for the original mapping instead of an object with empty or null values.");if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!t&&!n&&!r);else if(!(e&&"line"in e&&"column"in e&&t&&"line"in t&&"column"in t&&e.line>0&&e.column>=0&&t.line>0&&t.column>=0&&n))throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:t,name:r}))}_serializeMappings(){let e,t,n,u,i=0,a=1,s=0,c=0,l=0,p=0,d="";const f=this._mappings.toArray();for(let h=0,m=f.length;h0){if(!o.compareByGeneratedPositionsInflated(t,f[h-1]))continue;e+=","}e+=r.encode(t.generatedColumn-i),i=t.generatedColumn,null!=t.source&&(u=this._sources.indexOf(t.source),e+=r.encode(u-p),p=u,e+=r.encode(t.originalLine-1-c),c=t.originalLine-1,e+=r.encode(t.originalColumn-s),s=t.originalColumn,null!=t.name&&(n=this._names.indexOf(t.name),e+=r.encode(n-l),l=n)),d+=e}return d}_generateSourcesContent(e,t){return e.map((function(e){if(!this._sourcesContents)return null;null!=t&&(e=o.relative(t,e));const n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)}toJSON(){const e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};return null!=this._file&&(e.file=this._file),null!=this._sourceRoot&&(e.sourceRoot=this._sourceRoot),this._sourcesContents&&(e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)),e}toString(){return JSON.stringify(this.toJSON())}}a.prototype._version=3,t.SourceMapGenerator=a},1018:function(e,t,n){const r=n(1027).SourceMapGenerator,o=n(858),u=/(\r?\n)/,i="$$$isSourceNode$$$";class a{constructor(e,t,n,r,o){this.children=[],this.sourceContents={},this.line=null==e?null:e,this.column=null==t?null:t,this.source=null==n?null:n,this.name=null==o?null:o,this[i]=!0,null!=r&&this.add(r)}static fromStringWithSourceMap(e,t,n){const r=new a,i=e.split(u);let s=0;const c=function(){return e()+(e()||"");function e(){return s=0;t--)this.prepend(e[t]);else{if(!e[i]&&"string"!=typeof e)throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e);this.children.unshift(e)}return this}walk(e){let t;for(let n=0,r=this.children.length;n0){for(t=[],n=0;n=0;n--)if(36!==e.charCodeAt(n))return!1;return!0}function u(e,t){return e===t?0:null===e?1:null===t?-1:e>t?1:-1}t.toSetString=n?r:function(e){return o(e)?"$"+e:e},t.fromSetString=n?r:function(e){return o(e)?e.slice(1):e},t.compareByGeneratedPositionsInflated=function(e,t){let n=e.generatedLine-t.generatedLine;return 0!==n?n:(n=e.generatedColumn-t.generatedColumn,0!==n?n:(n=u(e.source,t.source),0!==n?n:(n=e.originalLine-t.originalLine,0!==n?n:(n=e.originalColumn-t.originalColumn,0!==n?n:u(e.name,t.name)))))};const i="http://host";function a(e){return t=>{const n=p(t),r=c(t),o=new URL(t,r);e(o);const u=o.toString();return"absolute"===n?u:"scheme-relative"===n?u.slice(5):"path-absolute"===n?u.slice(i.length):d(r,u)}}function s(e,t){return new URL(e,t).toString()}function c(e){const t=e.split("..").length-1,n=function(e,t){let n=0;for(;;){const e="p"+n++;if(-1===t.indexOf(e))return e}}(0,e);let r=`${i}/`;for(let e=0;e0&&!r[r.length-1]&&r.pop();n.length>0&&r.length>0&&n[0]===r[0];)n.shift(),r.shift();return r.map((()=>"..")).concat(n).join("/")+t.search+t.hash}const f=a((e=>{e.pathname=e.pathname.replace(/\/?$/,"/")})),h=a((e=>{}));t.normalize=h,t.join=function(e,t){const n=p(t),r=p(e);if(e=f(e),"absolute"===n)return s(t,void 0);if("absolute"===r)return s(t,e);if("scheme-relative"===n)return h(t);if("scheme-relative"===r)return s(t,s(e,i)).slice(5);if("path-absolute"===n)return h(t);if("path-absolute"===r)return s(t,s(e,i)).slice(i.length);const o=c(t+e);return d(o,s(t,s(e,o)))},t.relative=function(e,t){const n=function(e,t){if(p(e)!==p(t))return null;const n=c(e+t),r=new URL(e,n),o=new URL(t,n);try{new URL("",o.toString())}catch(e){return null}return o.protocol!==r.protocol||o.user!==r.user||o.password!==r.password||o.hostname!==r.hostname||o.port!==r.port?null:d(r,o)}(e,t);return"string"==typeof n?n:h(t)}},4738:function(e,t,n){t.SourceMapGenerator=n(1027).SourceMapGenerator,t.SourceNode=n(1018).SourceNode},1476:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(5174)),u=n(6678);t.default=function(e,t){var n={};return e&&"string"==typeof e?((0,o.default)(e,(function(e,r){e&&r&&(n[(0,u.camelCase)(e,t)]=r)})),n):n}},6678:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.camelCase=void 0;var n=/^--[a-zA-Z0-9-]+$/,r=/-([a-z])/g,o=/^[^-]+$/,u=/^-(webkit|moz|ms|o|khtml)-/,i=/^-(ms)-/,a=function(e,t){return t.toUpperCase()},s=function(e,t){return"".concat(t,"-")};t.camelCase=function(e,t){return void 0===t&&(t={}),function(e){return!e||o.test(e)||n.test(e)}(e)?e:(e=e.toLowerCase(),(e=t.reactCompat?e.replace(i,s):e.replace(u,s)).replace(r,a))}},5174:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(8139));t.default=function(e,t){var n=null;if(!e||"string"!=typeof e)return n;var r=(0,o.default)(e),u="function"==typeof t;return r.forEach((function(e){if("declaration"===e.type){var r=e.property,o=e.value;u?t(r,o,e):o&&((n=n||{})[r]=o)}})),n}},9196:function(e){"use strict";e.exports=window.React}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.exports}var __webpack_exports__={};!function(){"use strict";var e=window.wp.blocks,t=window.wp.element;const n=__webpack_require__(4193).generate('\n{{\n\tfunction evaluateUnaryExpression( operator, operand ) {\n\t\tswitch ( operator ) {\n\t\t\tcase \'!\':\n\t\t\t\treturn !operand;\n\t\t\t\tbreak;\n\t\t\tcase \'-\':\n\t\t\t\treturn -operand;\n\t\t\t\tbreak;\n\t\t\tcase \'+\':\n\t\t\t\treturn +operand;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tfunction evaluateBinaryExpression( head, tail ) {\n\t\treturn tail.reduce( ( leftOperand, tailElement ) => {\n\t\t\tconst operator = tailElement[ 1 ];\n\t\t\tconst rightOperand = tailElement[ 3 ];\n\n\t\t\tswitch ( operator ) {\n\t\t\t\tcase \'&&\':\n\t\t\t\t\treturn leftOperand && rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'||\':\n\t\t\t\t\treturn leftOperand || rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'===\':\n\t\t\t\t\treturn leftOperand === rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'!==\':\n\t\t\t\t\treturn leftOperand !== rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'==\':\n\t\t\t\t\treturn leftOperand == rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'!=\':\n\t\t\t\t\treturn leftOperand != rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'<=\':\n\t\t\t\t\treturn leftOperand <= rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'<\':\n\t\t\t\t\treturn leftOperand < rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'>=\':\n\t\t\t\t\treturn leftOperand >= rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'>\':\n\t\t\t\t\treturn leftOperand > rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'+\':\n\t\t\t\t\treturn leftOperand + rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'-\':\n\t\t\t\t\treturn leftOperand - rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'*\':\n\t\t\t\t\treturn leftOperand * rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'/\':\n\t\t\t\t\treturn leftOperand / rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \'%\':\n\t\t\t\t\treturn leftOperand % rightOperand;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn undefined;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}, head );\n\t}\n\n\tfunction getPropertyValue( obj, propertyName ) {\n\t\tif ( Object.hasOwn( obj, propertyName ) ) {\n\t\t\treturn obj[ propertyName ];\n\t\t} else if (\n\t\t\tArray.isArray( obj ) &&\n\t\t\tobj.length > 0 &&\n\t\t\tObject.hasOwn( obj[ 0 ], \'key\' ) &&\n\t\t\tObject.hasOwn( obj[ 0 ], \'value\' )\n\t\t) {\n\t\t\t// We likely dealing with an array of objects with key/value pairs (like post meta data)\n\t\t\tconst item = obj.find( ( item ) => item.key === propertyName );\n\t\t\treturn item?.value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}}\n\nStart\n\t= Expression\n\nSourceCharacter\n\t= .\n\nWhiteSpace\n\t= " "\n\t/ "\\t"\n\nLineTerminator\n\t= "\\n"\n\t/ "\\r"\n\t/ "\\u2028"\n\t/ "\\u2029"\n\nLineTerminatorSequence\n\t= "\\n"\n\t/ "\\r\\n"\n\t/ "\\r"\n\t/ "\\u2028"\n\t/ "\\u2029"\n\nComment "comment"\n\t= MultiLineComment\n\nMultiLineComment\n\t= "/*" (!"*/" SourceCharacter)* "*/"\n\n__ "skipped"\n\t= (WhiteSpace / LineTerminatorSequence / Comment)*\n\nIdentifierPath\n\t= variable:Identifier accessor:(__ "." __ Identifier)* {\n\t\tconst path = variable.split( \'.\' );\n\t\tlet result = path.reduce( getPropertyValue, options.context );\n\n\t\tfor ( let i = 0; i < accessor.length; i++ ) {\n\t\t\tresult = getPropertyValue( result, accessor[ i ][ 3 ] );\n\t\t}\n\n\t\treturn result;\n\t}\n\nIdentifier\n\t= !ReservedWord name:IdentifierName {\n\t\treturn name;\n\t}\n\nIdentifierName\n\t= first:IdentifierStart rest:IdentifierPart* {\n\t\treturn text();\n\t}\n\nIdentifierStart\n\t= [a-zA-Z]\n\t/ "_"\n\t/ "$"\n\nIdentifierPart\n\t= IdentifierStart\n\nReservedWord\n\t= NullLiteral\n\t/ BooleanLiteral\n\n// Literals\n\nLiteral\n\t= NullLiteral\n\t/ BooleanLiteral\n\t/ NumericLiteral\n\t/ StringLiteral\n\nNullLiteral\n\t= NullToken { return null; }\n\nBooleanLiteral\n\t= "true" { return true; }\n\t/ "false" { return false; }\n\nNumericLiteral\n\t= literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) {\n\t\treturn literal;\n\t}\n\t/ literal:DecimalLiteral !(IdentifierStart / DecimalDigit) {\n\t\treturn literal;\n\t}\n\nHexIntegerLiteral\n\t= "0x"i digits:$HexDigit+ {\n\t\treturn parseInt( digits, 16 );\n\t}\n\nHexDigit\n\t= [0-9a-f]i\n\nDecimalLiteral\n\t= DecimalIntegerLiteral "." DecimalDigit* ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\t/ "." DecimalDigit+ ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\t/ DecimalIntegerLiteral ExponentPart? {\n\t\treturn parseFloat( text() );\n\t}\n\nDecimalIntegerLiteral\n\t= "0"\n\t/ NonZeroDigit DecimalDigit*\n\nDecimalDigit\n\t= [0-9]\n\nNonZeroDigit\n\t= [1-9]\n\nExponentPart\n\t= ExponentIndicator SignedInteger\n\nExponentIndicator\n\t= "e"i\n\nSignedInteger\n\t= [+-]? DecimalDigit+\n\nStringLiteral\n\t= \'"\' chars:DoubleQuotedStringCharacter* \'"\' {\n\t\treturn chars.join( \'\' );\n\t}\n\t/ "\'" chars:SingleQuotedStringCharacter* "\'" {\n\t\treturn chars.join( \'\' );\n\t}\n\nDoubleQuotedStringCharacter\n\t= !(\'"\' / "\\\\" / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\t/ "\\\\" escapeSequence:EscapeSequence {\n\t\treturn escapeSequence;\n\t}\n\t/ LineContinuation\n\nSingleQuotedStringCharacter\n\t= !("\'" / "\\\\" / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\t/ "\\\\" escapeSequence:EscapeSequence {\n\t\treturn escapeSequence;\n\t}\n\t/ LineContinuation\n\nLineContinuation\n\t= "\\\\" LineTerminatorSequence {\n\t\treturn \'\';\n\t}\n\nEscapeSequence\n\t= CharacterEscapeSequence\n\t/ "0" !DecimalDigit {\n\t\treturn "\\0";\n\t}\n\t/ HexEscapeSequence\n\t/ UnicodeEscapeSequence\n\nCharacterEscapeSequence\n\t= SingleEscapeCharacter\n\t/ NonEscapeCharacter\n\nSingleEscapeCharacter\n\t= "\'"\n\t/ \'"\'\n\t/ "\\\\"\n\t/ "b" {\n\t\treturn "\\b";\n\t}\n\t/ "f" {\n\t\treturn "\\f";\n\t}\n\t/ "n" {\n\t\treturn "\\n";\n\t}\n\t/ "r" {\n\t\treturn "\\r";\n\t}\n\t/ "t" {\n\t\treturn "\\t";\n\t}\n\t/ "v" {\n\t\treturn "\\v";\n\t}\n\nNonEscapeCharacter\n\t= (!EscapeCharacter / LineTerminator) SourceCharacter {\n\t\treturn text();\n\t}\n\nEscapeCharacter\n\t= SingleEscapeCharacter\n\t/ DecimalDigit\n\t/ "x"\n\t/ "u"\n\nHexEscapeSequence\n\t= "x" digits:$(HexDigit HexDigit) {\n\t\treturn String.fromCharCode( parseInt( digits, 16 ) );\n\t}\n\nUnicodeEscapeSequence\n\t= "u" digits:$(HexDigit HexDigit HexDigit HexDigit) {\n\t\treturn String.fromCharCode( parseInt( digits, 16 ) );\n\t}\n\n// Tokens\n\nNullToken\n\t= "null" !IdentifierPart\n\nTrueToken\n\t= "true" !IdentifierPart\n\nFalseToken\n\t= "false" !IdentifierPart\n\n// Expressions\n\nPrimaryExpression\n\t= IdentifierPath\n\t/ Literal\n\t/ "(" __ expression:Expression __ ")" {\n\t\treturn expression;\n\t}\n\nUnaryExpression\n\t= PrimaryExpression\n\t/ operator:UnaryOperator __ operand:UnaryExpression {\n\t\treturn evaluateUnaryExpression( operator, operand );\n\t}\n\nUnaryOperator\n\t= "!"\n\t/ "-"\n\t/ "+"\n\nMultiplicativeExpression\n\t= head:UnaryExpression tail:(__ MultiplicativeOperator __ UnaryExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nMultiplicativeOperator\n\t= "*"\n\t/ "/"\n\t/ "%"\n\nAdditiveExpression\n\t= head:MultiplicativeExpression tail:(__ AdditiveOperator __ MultiplicativeExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nAdditiveOperator\n\t= "+"\n\t/ "-"\n\nRelationalExpression\n\t= head:AdditiveExpression tail:(__ RelationalOperator __ AdditiveExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nRelationalOperator\n\t= "<="\n\t/ "<"\n\t/ ">="\n\t/ ">"\n\nEqualityExpression\n\t= head:RelationalExpression tail:(__ EqualityOperator __ RelationalExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nEqualityOperator\n\t= "==="\n\t/ "!=="\n\t/ "=="\n\t/ "!="\n\nLogicalAndExpression\n\t= head:EqualityExpression tail:(__ LogicalAndOperator __ EqualityExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nLogicalAndOperator\n\t= "&&"\n\nLogicalOrExpression\n\t= head:LogicalAndExpression tail:(__ LogicalOrOperator __ LogicalAndExpression)* {\n\t\treturn evaluateBinaryExpression( head, tail );\n\t}\n\nLogicalOrOperator\n\t= "||"\n\nConditionalExpression\n\t= condition:LogicalOrExpression __ ConditionalTrueOperator __ expressionIfTrue:ConditionalExpression __ ConditionalFalseOperator __ expressionIfFalse:ConditionalExpression {\n\t\treturn condition ? expressionIfTrue : expressionIfFalse;\n\t}\n\t/ LogicalOrExpression\n\nConditionalTrueOperator\n\t= "?"\n\nConditionalFalseOperator\n\t= ":"\n\nExpression\n\t= __ expression:ConditionalExpression __ {\n\t\treturn expression;\n\t}\n');function r(e,t={}){return n.parse(e,{context:t})}var o=window.wp.data;function u(e){return{getEvaluationContext:()=>e}}function i(e,n){return u=>{const{context:i}=u,{_templateBlockHideConditions:a,_templateBlockDisableConditions:s}=u.attributes,{getEvaluationContext:c}=n(i),{shouldHide:l,shouldDisable:p}=(0,o.useSelect)((e=>{const t=c(e);return{shouldHide:a&&Array.isArray(a)&&a.some((e=>r(e.expression,t))),shouldDisable:s&&Array.isArray(s)&&s.some((e=>r(e.expression,t)))}}),[c,a,s]);return!e||l?null:(0,t.createElement)(e,{...u,attributes:{...u.attributes,disabled:u.attributes.disabled||p}})}}var a=window.wp.coreData;function s(e){const{postType:t}=e,n=(0,a.useEntityId)("postType",t);return{getEvaluationContext:r=>{const o=r("core").getEditedEntityRecord("postType",t,n);return{...e,editedProduct:o}}}}var c=__webpack_require__(9196),l=window.wp.blockEditor,p=window.wp.components,d=__webpack_require__(4157),f=__webpack_require__(3426),h=f.default||f,m=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"woocommerce-pre-orders/select-control-block","version":"0.1.0","title":"Select Control","category":"widgets","icon":"flag","description":"A block to display a select control.","attributes":{"property":{"type":"string","default":""},"title":{"type":"string","default":""},"help":{"type":"string","default":""},"options":{"type":"array","default":[]},"multiple":{"type":"boolean","default":false}},"supports":{"html":false,"inserter":false},"textdomain":"woocommerce-pre-orders","editorScript":"file:./index.js"}');const{name:g,...A}=m;!function(t){const{metadata:n,settings:r,name:o}=t;var a;!function(t,n){if(!t)return;const{metadata:r,settings:o,name:a}=t,{edit:s}=o;if(!s)return;const c={...r,attributes:(l=r.attributes,{...l,_templateBlockId:{type:"string",__experimentalRole:"content"},_templateBlockOrder:{type:"integer",__experimentalRole:"content"},_templateBlockHideConditions:{type:"array",__experimentalRole:"content"},_templateBlockDisableConditions:{type:"array",__experimentalRole:"content"},disabled:l.disabled||{type:"boolean",__experimentalRole:"content"}})};var l;(0,e.registerBlockType)({name:a,...c},{...o,edit:i(s,null!=n?n:u)})}({name:o,metadata:{...n,usesContext:(a=n.usesContext,[...a||[],"postType"])},settings:r},s)}({name:g,metadata:A,settings:{example:{},edit:function({attributes:e,context:{postType:t}}){const n=((e,t={})=>{const n={"data-template-block-id":e._templateBlockId,"data-template-block-order":e._templateBlockOrder,tabIndex:-1,...t};return(0,l.useBlockProps)(n)})(e),{title:r,property:o,options:u,help:i,multiple:s,disabled:f}=e,[m,g]=function(e,t){var n;const r=e.startsWith("meta_data."),o=e.replace("meta_data.",""),[u,i]=(0,a.useEntityProp)("postType",(null==t?void 0:t.postType)||"product",e),[s,c]=(0,a.useEntityProp)("postType",(null==t?void 0:t.postType)||"product","meta_data");return[r?(null===(n=s.find((e=>e.key===o)))||void 0===n?void 0:n.value)||(null==t?void 0:t.fallbackValue):u,r?e=>{const t=s.find((e=>e.key===o)),n=t?{...t,value:e}:{key:o,value:e};c([...s.filter((e=>e.key!==o)),n])}:i]}(o,{postType:t}),A=s?d.MultiSelectControl:p.SelectControl;return(0,c.createElement)("div",{...n},(0,c.createElement)(A,{label:r,options:u,value:m||[],onChange:function(e){Array.isArray(e)&&e.every((e=>!isNaN(e)))?g(e.map(Number)):g(e)},help:h(i),disabled:f}))}}})}()})();
\ No newline at end of file
diff --git a/build/gateway/index.asset.php b/build/gateway/index.asset.php
new file mode 100644
index 0000000..ec83618
--- /dev/null
+++ b/build/gateway/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wc-blocks-checkout', 'wc-blocks-registry', 'wc-settings', 'wp-html-entities', 'wp-i18n'), 'version' => 'a23409949a049dc510f51860a50e7b9a');
\ No newline at end of file
diff --git a/build/gateway/index.css b/build/gateway/index.css
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/build/gateway/index.css
@@ -0,0 +1 @@
+
diff --git a/build/gateway/index.js b/build/gateway/index.js
new file mode 100644
index 0000000..a421551
--- /dev/null
+++ b/build/gateway/index.js
@@ -0,0 +1,3 @@
+!function(){"use strict";var e=window.wc.wcBlocksRegistry,t=window.wc.blocksCheckout,r=window.wp.i18n,n=window.React,o=window.wc.wcSettings,s=window.wp.htmlEntities;const a=(0,o.getSetting)("pre_orders_pay_later_data",{}),c=(0,s.decodeEntities)(a.title),i=(0,s.decodeEntities)(a.order_button_text),d=()=>(0,s.decodeEntities)(a.description||"");var l={name:"pre_orders_pay_later",content:(0,n.createElement)(d,null),label:(0,n.createElement)((e=>{const{PaymentMethodLabel:t}=e.components;return(0,n.createElement)(t,{text:c})}),null),edit:(0,n.createElement)(d,null),canMakePayment:()=>!0,ariaLabel:c,supports:{features:a.supports},placeOrderButtonLabel:i};(0,e.registerPaymentMethod)(l),(0,t.__experimentalRegisterCheckoutFilters)("woocommerce-pre-order",{totalLabel:(e,t,{cart:n})=>{if((e=>e.cartItemsCount>0&&(e.cartItems[0].extensions?.preorders?.charged_upfront||e.cartItems[0].extensions?.preorders?.charged_upon_release))(n)){const t=(e=>{const t=e.cartItems[0].extensions?.preorders?.charged_upfront,n=e.cartItems[0].extensions?.preorders?.charged_upon_release;if(t)return(0,r.__)("charged upfront.","woocommerce-pre-orders");if(n){const t=(e=>{if(e.cartItemsCount>0)return e.cartItems[0].extensions?.preorders?.availability})(e);return(0,r.sprintf)(/* translators: 1:Pre-order product date */
+(0,r.__)("charged %1$s","woocommerce-pre-orders"),t)}return""})(n);return(0,r.sprintf)(/* translators: 1: Label, 2: Additional information */
+(0,r._x)("%1$s %2$s","label and additional info","woocommerce-pre-orders"),e,t)}return e}})}();
\ No newline at end of file
diff --git a/changelog.txt b/changelog.txt
new file mode 100644
index 0000000..c6cba8b
--- /dev/null
+++ b/changelog.txt
@@ -0,0 +1,405 @@
+*** WooCommerce Pre-Orders Plugin ***
+
+2024-03-04 - version 2.1.0
+* Add - Support for the new Product Block Editor.
+* Dev - Bump WooCommerce "tested up to" version 8.6.
+* Dev - Bump WooCommerce minimum supported version to 8.4.
+* Dev - Bump PHP minimum supported version to 7.4.
+
+2024-02-05 - version 2.0.9
+* Fix - Block errors while editing the Cart and Checkout pages.
+* Dev - Added E2E tests for the "Enable pre-orders for products that get out of stock" setting.
+* Dev - Bump WooCommerce "tested up to" version 8.5.
+* Dev - Bump WooCommerce minimum supported version to 8.3.
+* Dev - Bump WordPress minimum supported version to 6.3.
+
+2024-01-10 - version 2.0.8
+* Dev - Add E2E tests coverage for Block Cart and Checkout.
+* Dev - Bump WooCommerce "tested up to" version 8.4.
+* Dev - Bump WooCommerce minimum supported version to 8.2.
+* Dev - Bump PHP minimum supported version to 7.4.
+* Dev - Bump PHP "tested up to" version 8.3.
+
+2023-12-11 - version 2.0.7
+* Dev - Add Playwright end-to-end tests.
+* Dev - Bump WooCommerce "tested up to" version 8.3.
+* Dev - Bump WooCommerce minimum supported version to 8.1.
+* Dev - Bump WordPress "tested up to" version 6.4.
+* Dev - Bump WordPress minimum supported version to 6.2.
+* Tweak - Admin settings colour to match admin theme colour scheme.
+
+2023-11-20 - version 2.0.6
+* Dev - Update PHPCS and PHPCompatibility GitHub Actions.
+* Dev - Implement ESLint.
+* Add - Compatibility with WooPayments.
+
+2023-09-12 - version 2.0.5
+* Dev - Bump WooCommerce "tested up to" version 7.9.
+* Dev - Bump WooCommerce minimum supported version from 7.2 to 7.7.
+* Dev - Bump PHP minimum supported version from 7.2 to 7.3.
+
+2023-08-30 - version 2.0.4
+* Fix - Set order status to pre-ordered when processing failed order if the product can be pre-ordered.
+* Dev - Bump WordPress "tested up to" version from 6.2 to 6.3.
+* Add - Introduced filter wc_pre_orders_product_can_be_pre_ordered within WC_Pre_Orders_Product::product_can_be_pre_ordered().
+* Tweak - Use variation ID for determining if cart contains a pre-order product.
+
+2023-07-04 - version 2.0.3
+* Fix - Hide Pre-Orders option for unsupported product types.
+* Fix - Adjust the logic before performing pre-orders actions.
+* Dev - Bump WooCommerce "tested up to" version 7.8.
+* Dev - Bump WooCommerce minimum supported version from 6.8 to 7.2.
+* Dev - Bump WordPress minimum supported version from 5.8 to 6.1.
+* Dev - Update like statement preparation in pre-order searches.
+* Dev - Wrap the contents of the countdown shortcode without WC_Shortcodes::shortcode_wrapper.
+
+2023-05-24 - version 2.0.2
+* Dev – Bump WooCommerce “tested up to” version 7.6.
+* Dev – Bump WordPress minimum supported version from 5.6 to 5.8.
+* Dev – Bump WordPress “tested up to” version 6.2.
+* Fix – Prevent countdowns of trashed products from showing up.
+* Update – Improve escaping of the URLs for the different Pre-Order statuses.
+* Update – Replace the use of “extract” for retrieving the attributes of the countdown shortcode.
+
+2023-04-14 - version 2.0.1
+* Fix - Layout attribute in the countdown timer.
+* Fix - Improve the "Shop loop product message" description.
+
+2023-04-04 - version 2.0.0
+* Add - Order types filter in the order list when HPOS is enabled.
+* Add - Implement support for automatic translation files delivery.
+* Fix - Improve failed pre-order status transition logic.
+* Fix - Countdown timer output issue.
+* Dev - Bump PHP minimum supported version from 7.0 to 7.2.
+* Dev - Bump WooCommerce minimum supported version from 6.0 to 6.8.
+* Dev - Bump WooCommerce "tested up to" version 7.4.
+* Dev - Export _wc_pre_orders_availability_datetime metadata in human readable date format (mysql format).
+* Dev - Resolve linting issues.
+
+2023-01-24 - version 1.9.0
+* Add - Support for High-performance Order Storage ("HPOS") (formerly known as Custom Order Tables, "COT").
+* Add - Declare compatibility with High-Performance Order Storage ("HPOS").
+* Fix - Ensure custom messages get added to the pre-order completion email.
+* Fix - Improve variable type checking.
+* Fix - Set correct order status to when complete payment for failed pre-order.
+* Tweak - Bump minimum WP version to 5.6.
+* Tweak - Bump minimum PHP version to 7.0.
+* Tweak - Bump minimum WC version to 6.0.
+* Tweak - Bump WC tested up to version to 6.8.
+* Fix - Pre-Orders list table filters.
+* Fix - Sanitize product filter
+* Update - Use is_checkout() instead of WOOCOMMERCE_CHECKOUT when removing unsupported gateways.
+* Add - Show private pre-order products list to perform the pre-order actions.
+* Fix - Pre-Orders list table filters.
+* Tweak - Additional HPOS compatibility updates.
+* Tweak - Bump WordPress “Tested up to” version to 6.1.
+* Tweak - Nonce validation and redirection logic
+
+2022-10-31 - version 1.8.0
+* Tweak – Switch to global functions to remove deprecation warnings coming from WooCommerce Blocks.
+* Fix – Ensure store admins receive notifications of any pre-order cancellations.
+* Add – New column to the Pre-Orders admin table to show the linked order status.
+
+2022-09-20 - version 1.7.3
+* Fix - My Account > Pre-Orders template change to display text when customer has no pre-orders. PR#336.
+* Fix - Ensure all pre-orders don't show up when filtering by a product without pre-orders.
+* Update - Function load_block_classes() was renamed to woocommerce_pre_orders_load_block_classes() on the root file of the plugin.
+* Fix - Fatal Error in Pre-orders listing page which occurred when a filtered product is deleted and page reloaded.
+* Fix - Translation of plugin strings/texts.
+* Fix - Title, label, description strings are written in sentence case.
+* Fix - Strings are being translated using the wrong domain.
+
+2022-06-27 - version 1.7.2
+* Tweak – Bump supported WC Version.
+* Tweak - Bump tested up to WP Version.
+
+2022-04-11 - version 1.7.1
+* Fix – Order type filter duplicated when WooCommerce Payments is installed.
+
+2022-02-15 - version 1.7.0
+* Add - Blocks integration.
+* Tweak - Bump supported WC Version.
+* Tweak - Bump tested up to WP Version.
+
+2022-01-10 - version 1.6.0
+* Fix - Jquery deprecated code.
+* Tweak - Jquery 3.0 compatibility.
+* Tweak - Improve performance of scheduled action that completes orders after product is released.
+* Fix - Use WooCommerce order details template instead of a custom one.
+* Fix - "Your previous cart was emptied" message does not show when using ajax cart.
+* Fix - Error message on Pre-Orders list when a product pre-order is disabled.
+* Fix - Broken email links when sending links via WooCommerce > Pre-Orders > Actions.
+* Tweak - Pre-Orders table under My Account > Pre Orders responsiveness.
+* Fix - Stock inventory is not replenished when a pre-order that's set to charge "Upon Release" is canceled.
+* Tweak - Pre-load product when clicking on "Use the actions menu" to change the release date.
+* Add - Allow to search for Pre orders only and Regular orders only on WooCommerce > Orders.
+* Fix - Refunded orders are counted as Net Sales in WC > Reports when Pre-Orders is active.
+* Tweak - Prevent listing pre-orders when they must be paid upfront and the payment fails.
+* Tweak - Rename the .pot file so it matches the registered text domain.
+* Add - Add fees to order when creating via admin.
+* Fix - Reduce inventory for 100% coupon payments.
+* Fix - Complete the product's release process when the release date is updated to the past and pre-orders exist.
+* Tweak - Make the notice for when the cart contains a pre-order be of the 'error' type.
+* Add - Add an option to enable product Pre-Order automatically when stock hits zero.
+* Fix - Email message when order is on-hold.
+* Tweak - Prevent multiple pre-order products to be added on order created via admin.
+* Fix - "Release Date Changed" email mentions it changed to a future date when it's set to the past.
+* Tweak - Pre-Orders status counter performance improvement.
+
+
+2021-02-15 - version 1.5.30
+* Fix - Prevent fatal errors when loading WC Subscriptions admin reports. PR#272
+
+2020-09-30 - version 1.5.29
+* Fix - Fatal Error when checking out with Checkout Field Editor extension active.
+* Fix - Pre-Order fee not applying to variable products.
+* Fix - Fatal error when trashing some products.
+* Fix - Prevent fatal errors when switching an order to "Pre ordered" without a pre-order product.
+* Tweak - Fix wording of release date within confirmation emails when no release date is set.
+* Tweak - Add Additional Content text to applicable Pre-Order emails.
+* Tweak - Add "Pre-ordered" status to WC reports statuses for revenue reporting.
+* Tweak - Use native wp_timezone_string() to retrieve WP timezone setting.
+* Tweak - Check that order exists when updating payment complete status to avoid fatal errors.
+
+2020-08-20 - version 1.5.28
+* Fix - Replace usage of deprecated get_product_from_item() method.
+* Tweak - WordPress 5.5 compatibility.
+
+2020-07-07 - version 1.5.27
+* Fix - Escape output for selectWoo fields.
+
+2020-06-10 - version 1.5.26
+* Tweak - WC 4.2 compatibility.
+
+2020-04-30 - version 1.5.25
+* Tweak - Remove legacy code.
+* Tweak - WC 4.1 compatibility.
+
+2020-03-04 - version 1.5.24
+* Fix - Remove usage of deprecated filters.
+* Tweak - WC 4.0 compatibility.
+
+2020-02-04 - version 1.5.23
+* Fix - Use proper escape for attributes.
+* Fix - "Pre-Order Available" Action didn't send an email.
+
+2020-01-21 - version 1.5.22
+* Fix - Rendering pre-order products in WooCommerce Gutenberg blocks.
+
+2020-01-14 - version 1.5.21
+* Tweak - Update pot files as part of the build process.
+* Fix - Stock message not correct for variable products.
+* Update - WC 3.9 compatibility.
+
+2019-11-04 - version 1.5.20
+* Update - WC 3.8 compatibility.
+
+2019-10-23 - version 1.5.19
+* Tweak - Added currency symbol to Pre-Order Fee settings
+* Tweak - Added HTML span to pre-order text to make it easier to style
+
+2019-10-15 - version 1.5.18
+* Tweak - Added Settings link to the plugin activation card
+
+2019-08-08 - version 1.5.17
+* Update - WC 3.7 compatibility.
+
+2019-07-12 - version 1.5.16
+* Fix - Fix missing js assets.
+
+2019-07-10 - version 1.5.15
+* Fix - Errors in the build process with uglify.
+
+2019-07-02 - version 1.5.14
+* Fix - Downloadable products link not included in Pre-order Available email.
+
+2019-04-16 - version 1.5.13
+* Tweak - WC Tested up to 3.6
+
+2019-02-25 - version 1.5.12
+* Fix - Increase coupon usage for the pre-ordered status ( works for WC>=3.0 )
+
+2019-01-07 - version 1.5.11
+* Fix - Preorders processed a few hours too early/ too late due to a bug in timezone calculations.
+
+2018-09-25 - version 1.5.10
+* Update - WC 3.5 compatibility.
+
+2018-05-23 - version 1.5.9
+* Fix - Check for empty timezone_id before fallback to timezone, and Fallback to correct offset if no timezone was found.
+* Fix - Countdown shortcode "format" parameter not working correctly.
+* Update - Privacy policy notification.
+* Update - WC 3.4 compatibility.
+
+2018-03-12 - version 1.5.8
+* Fix - When the Order is set to `completed` then the Pre-order should be in `completed` as well.
+* Fix - Pre-Orders uses UTC instead of Local Time for cron.
+* Fix - Rebuilt POT file.
+
+2018-01-24 - version 1.5.7
+* Fix - Cannot process payment of Completed Pre-Order if product is Out of Stock.
+* Fix - Pre-Orders with a payment token present are displaying the wrong message.
+* Fix - Variable product pre-orders not completing.
+
+2018-01-11 - version 1.5.6
+* Fix - Checking for zero cost order needs to account for floats.
+* Tweak - Change pre-order complete interval to 1h instead of 5min.
+
+2017-12-12 - version 1.5.5
+* Update - WC tested up to version.
+
+2017-10-16 - version 1.5.4
+* Fix - Issue where Shop Loop Product Message setting is not applied to product taxonomy page.
+* Fix - Stock is not reducing when a Pre Order is charge upon release and using Pay Later option.
+* Fix - Charge upon release date not shown on Thank You page.
+* Fix - Email site name token not correctly replaced.
+* Update - Email templates to include $email object as variable.
+
+2017-08-14 - version 1.5.3
+* Fix - Issue where updating non pre-order orders' status may throws an error.
+* Fix - Missing space between custom message and status transition message.
+* Fix - Issue where pre-order orders may not be processed when there's pre-order product without availability date/time.
+
+2017-06-28 - version 1.5.2
+* Fix - Prevent error if pre order becomes disabled before payment has been made.
+* Fix - Removed line item modification for WC3.0+ that could cause issues in some cases.
+
+2017-06-08 - version 1.5.1
+* Fix - Zero cost pre-orders were not processed correctly.
+* Fix - Using pay later, payment process does not go through.
+* Fix - In rare cases, orphaned order metas causing canceled/completed pre orders to still show active.
+
+2017-05-25 - version 1.5.0
+* Add - Staging/test disable automated pre order processing option.
+
+2017-05-17 - version 1.4.11
+* Fix - Additional updates for WC 3.0 compatibility.
+
+2017-04-18 - version 1.4.10
+* Fix - Error when attempting to perform some actions (e.g. Resend New Order Email) from Edit Order screen.
+* Fix - Error when cancelling a subscription.
+* Fix - Notices thrown by WC 3.0 where properties were accessed directly.
+
+2017-04-03 - version 1.4.9
+* Fix - Update for WC 3.0 compatibility.
+
+2016-12-02 - version 1.4.8
+* Fix - Prevent issues with order item meta.
+
+2016-11-12 - version 1.4.7
+* Fix - Ensure page processing actions happens on pre order pages only.
+* Fix - Using cash on delivery at checkout for pay upfront pre order did not change to pre order status.
+* Add - Filter "wc_pre_orders_remove_unsupported_gateways" to remove unwanted gateways.
+* Tweak - Update all deprecated WooCommerce function calls.
+* Fix - Issue where cancel pre-order also cancel other pre-orders with the same pre-order product
+* Tweak - Added Pre-Orders menu in My Account page
+
+2016-08-26 - version 1.4.6
+* Fix - Clicking cancel on pre order list table did not have any effect.
+* Fix - Email template deprecated notices.
+* Fix - Invalid customer note link in the action admin section.
+* Fix - Taxes not refundable because line taxes are not showing up on the edit order screen.
+
+2015-12-09 - version 1.4.5
+* Fix - Textdomain path for translations
+* Fix - Unable to set a blank pre-order fee
+* Tweak - Display a message under all the "action" options if no products are configured for pre-orders
+* Tweak - Add a drop-down heading option
+* Tweak - Add required attribute on each fields of Pre Orders Action forms
+* Tweak - Make actions handling (from Manage and Actions tabs) code more readable
+
+2015-06-03 - version 1.4.4
+* Fix - Orders links in My Pre-Orders table
+* Fix - Completed pre-order items in My Pre-Orders table
+* Tweak - Improved the texts that show the product stock availability.
+
+2015-05-14 - version 1.4.3
+* Fix - Deprecated shortcodes wrapper function
+
+2015-04-21 - version 1.4.2
+* Fix - Potential XSS vulnerability
+* Fix - Strict standards warning
+* Fix - Change pre orders release date not triggering
+
+2015-02-16 - version 1.4.1
+* Fix - Fatal Error in admin settings
+
+2015-02-11 - version 1.4.0
+* New - Option to enable and disable the "Pay Later" payment gateway
+* New - wc_pre_orders_supported_product_types filter to declare support to Pre-orders
+* New - Show/hide the Pre-orders tab when support or not Pre-orders.
+* Fix - Pre-orders fees in WooCommerce 2.3
+
+2015-01-29 - version 1.3.3
+* Fix - Backwards compatibility
+
+2015-01-28 - version 1.3.2
+* Fix - WC 2.3 support
+
+2015-01-27 - version 1.3.1
+* New - WC 2.3 compatibility (chosen -> select2)
+
+2014-10-06 - version 1.3.0
+* New - Suport for WooCommerce Composite Products & WooCommerce Product Bundles
+* New - .pot file for custom translations
+* Fix - Emails actions in WooCommerce 2.1 and 2.2
+
+2014-09-04 - version 1.2.5
+* Fix - Support for WooCommerce 2.1 and 2.2
+
+2014-09-01 - version 1.2.4
+* New - Support for WooCommerce 2.2
+
+2014-05-22 - version 1.2.3
+* Fix - Fire actions and emails at earlier hook
+
+2014-05-20 - version 1.2.2
+* Fix - Check for existing term on both install and upgrade
+
+2014-05-16 - version 1.2.1
+* Fix - Activation function
+
+2014-05-14 - version 1.2
+* New - Initial integration with WooCommerce Bookings
+* New - The product Pre-Orders are canceled when the product is deleted
+* Fix - During the plugin installation the default options are saved
+* Fix - Are now displayed correctly the save/edit messages in Manage Pre-Orders page
+* Fix - Stopped the errors while saving the email settings
+* Fix - No longer caused errors in Manage Pre-Orders page when a product is deleted
+* Tweak - Improved the plugin log for WooCommerce 2.1
+
+2014-05-02 - version 1.1.4
+* Fix - saving issues
+
+2014-04-24 - version 1.1.3
+* Fix - Fixed fatal error upon pre order updates or sending out emails
+
+2014-04-10 - version 1.1.2
+* Fix - WooCommerce 2.1 support for change of add to cart button text for pre order products
+* Fix - Pay Page unsetting payment gateways incorrectly if order contains products that need to be paid upfront
+
+2014-02-11 - version 1.1.1
+* Fix - Make sure right gateways are loaded for not pre order product orders
+
+2014-02-06 - version 1.1
+* WooCommerce 2.1 compatibility
+* Requires WooCommerce 2.1 and WordPress 3.8 for full graphical compatibility
+
+2013-11-19 - version 1.0.5
+* Fix - Pre order products that didn't get any pre orders are now also automatically marked as available
+
+2013-10-24 - version 1.0.4
+* Fix - Manual made pre orders from admin panel are now correctly flagged as being a pre order
+
+2013-09-16 - version 1.0.3
+* Fix - Cancel pre-order button now has correct listener
+
+2013-06-21 - version 1.0.2
+* Fix - The availability date/time shown on the single product page and countdown timer is now properly adjusted for the site timezone
+* Fix - Remove deprecated nocache() function
+
+2013-04-25 - version 1.0.1
+* Fix - PHP 5.2 compatibility
+
+2013-04-11 - version 1.0
+* Initial Release
diff --git a/includes/admin/class-wc-pre-orders-admin-ajax.php b/includes/admin/class-wc-pre-orders-admin-ajax.php
new file mode 100644
index 0000000..84a4614
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-admin-ajax.php
@@ -0,0 +1,151 @@
+get_items();
+ $is_added_product_pre_order = WC_Pre_Orders_Product::product_can_be_pre_ordered( $product );
+
+ foreach ( $items as $item ) {
+ if ( ! WC_Pre_Orders_Product::product_can_be_pre_ordered( $item->get_product() ) && ! $is_added_product_pre_order ) {
+ continue;
+ }
+
+ if ( $item->get_product()->get_id() === $product->get_id() ) {
+ $validation_error->add( 'multiple-pre-order-products', __( "You can't add multiple products on a pre-order. Change the quantity of the item instead of adding more items.", 'woocommerce-pre-orders' ) );
+ break;
+ }
+
+ if ( $item->get_product()->get_id() !== $product->get_id() ) {
+ $validation_error->add( 'multiple-pre-order-products', __( "You can't add multiple products on a pre-order", 'woocommerce-pre-orders' ) );
+ break;
+ }
+ }
+
+ return $validation_error;
+ }
+
+ /**
+ * Add pre-order fee when a pre-order product is added
+ *
+ * @param WC_Order_Item[] $added_items
+ * @param WC_Order $order
+ *
+ * @since 1.6.0
+ */
+ public function maybe_add_pre_order_fee_admin( $added_items, $order ) {
+ $wc_pre_order_cart = new WC_Pre_Orders_Cart();
+
+ foreach ( $added_items as $item_id => $item ) {
+ $fee = $wc_pre_order_cart->generate_fee( $item->get_product() );
+
+ if ( ! $fee ) {
+ continue;
+ }
+
+ $item_fee = new WC_Order_Item_Fee();
+ $item_fee->set_name( $fee['label'] );
+ $item_fee->set_tax_status( $fee['tax_status'] );
+ $item_fee->set_total( $fee['amount'] * $item->get_quantity() );
+ $item_fee->add_meta_data( 'pre_order_parent_item_id', $item_id, true );
+ $item_fee->save();
+
+ $order->add_item( $item_fee );
+ }
+
+ $order->save();
+ }
+
+ /**
+ * Removes pre-order fees from the order when the pre-order product is removed
+ *
+ * @param int $item_id
+ *
+ * @since 1.6.0
+ */
+ public function maybe_remove_pre_order_fee_admin( $item_id ) {
+
+ $item = WC_Order_Factory::get_order_item( absint( $item_id ) );
+
+ if ( ! $item || 'line_item' !== $item->get_type() || ! WC_Pre_Orders_Product::product_can_be_pre_ordered( $item->get_product() ) ) {
+ return;
+ }
+
+ $order = $item->get_order();
+ $fees = $order->get_fees();
+
+ foreach ( $fees as $fee_id => $fee ) {
+ if ( $item_id === (int) $fee->get_meta( 'pre_order_parent_item_id', true ) ) {
+ $order->remove_item( $fee_id );
+ $order->save();
+
+ return;
+ }
+ }
+ }
+
+ /**
+ * Adjusts pre-order fees when product quantity changes
+ *
+ * @param bool $and_taxes
+ * @param WC_Order $order
+ */
+ public function maybe_adjust_pre_order_fee_admin( $and_taxes, $order ) {
+
+ $items = $order->get_items();
+
+ foreach ( $items as $item ) {
+ if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $item->get_product() ) ) {
+ foreach ( $order->get_fees() as $item_fee ) {
+ if ( $item->get_id() === (int) $item_fee->get_meta( 'pre_order_parent_item_id' ) ) {
+ $wc_pre_order_cart = new WC_Pre_Orders_Cart();
+ $fee = $wc_pre_order_cart->generate_fee( $item->get_product() );
+
+ $item_fee->set_total( $fee['amount'] * $item->get_quantity() );
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+new WC_Pre_Orders_Admin_Ajax();
diff --git a/includes/admin/class-wc-pre-orders-admin-orders.php b/includes/admin/class-wc-pre-orders-admin-orders.php
new file mode 100644
index 0000000..86b3dc5
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-admin-orders.php
@@ -0,0 +1,277 @@
+= 3.2
+
+ // Hook to make sure pre order is properly set up when added through admin.
+ add_action( 'save_post', array( $this, 'check_manual_order_for_pre_order_products' ), 10, 1 );
+
+ if ( WC_Pre_Orders::is_hpos_enabled() && is_admin() ) {
+ add_action( 'woocommerce_update_order', array( $this, 'hpos_check_manual_order_for_pre_order_products' ) );
+ }
+
+ //Adds the filter on WooCommerce -> Orders page
+ add_action( 'admin_init', array( $this, 'add_order_page_filters' ) );
+ }
+
+ /**
+ * Add pre-order emails to the list of order emails that can be resent, based on the pre-order status.
+ *
+ * @param array $available_emails Simple array of WC_Email class IDs that can be resent.
+ *
+ * @return array
+ */
+ public function maybe_allow_resend_of_pre_order_emails( $available_emails ) {
+ global $theorder;
+
+ $emails = array();
+
+ if ( WC_Pre_Orders_Order::order_contains_pre_order( $theorder ) ) {
+
+ $emails[] = 'wc_pre_orders_pre_ordered';
+
+ $pre_order_status = WC_Pre_Orders_Order::get_pre_order_status( $theorder );
+
+ if ( 'cancelled' === $pre_order_status ) {
+ $emails[] = 'wc_pre_orders_pre_order_cancelled';
+ }
+
+ if ( 'completed' === $pre_order_status ) {
+ $emails[] = 'wc_pre_orders_pre_order_available';
+ }
+ }
+
+ $mailer = WC()->mailer();
+ $mails = $mailer->get_emails();
+ $new_emails = array();
+
+ foreach ( $mails as $mail ) {
+ if ( in_array( $mail->id, $emails ) && 'no' !== $mail->enabled ) {
+ /* translators: %s: email title */
+ $new_emails[ 'send_email_' . esc_attr( $mail->id ) ] = sprintf( __( 'Resend %s', 'woocommerce-pre-orders' ), esc_html( $mail->title ) );
+ }
+ }
+
+ $emails = $new_emails;
+
+ return array_merge( $available_emails, $emails );
+ }
+
+ /**
+ * Marks the order as being a pre order if it contains pre order products in
+ * case an order gets added manually from the administration panel.
+ *
+ * @param int $order_id ID of the newly saved order.
+ *
+ * @since 1.4.10
+ * @version 1.5.3
+ */
+ public function check_manual_order_for_pre_order_products( $order_id ) {
+
+ if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'update-post_' . $order_id ) ) {
+ return;
+ }
+
+ // Make sure we are in the administration panel and we're saving an order.
+ if ( ! is_admin() || ! isset( $_POST['post_type'] ) || 'shop_order' !== $_POST['post_type'] ) {
+ return;
+ }
+
+ return $this->maybe_set_pre_order_for_pre_order_products( $order_id );
+ }
+
+ /**
+ * Marks the order as being a pre order if it contains pre order products in
+ * case an order gets added manually from the administration panel. (for HPOS only)
+ *
+ * @param int $order_id ID of the newly saved order.
+ *
+ * @since 1.9.0
+ */
+ public function hpos_check_manual_order_for_pre_order_products( $order_id ) {
+ if ( ! is_admin() || ! isset( $_REQUEST['page'] ) || 'wc-orders' !== sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) ) {
+ return;
+ }
+
+ if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'update-order_' . $order_id ) ) {
+ return;
+ }
+
+ return $this->maybe_set_pre_order_for_pre_order_products( $order_id );
+ }
+
+ /**
+ * Set Manual order as pre-order if it contains pre-order products.
+ *
+ * @param int $order_id ID of the newly saved order.
+ *
+ * @since 1.9.0
+ */
+ public function maybe_set_pre_order_for_pre_order_products( $order_id ) {
+ $order = wc_get_order( $order_id );
+ if ( ! $order ) {
+ return;
+ }
+
+ // Check if the order hasn't been processed already.
+ if ( WC_Pre_Orders_Order::order_contains_pre_order( $order ) ) {
+ return;
+ }
+
+ foreach ( $order->get_items( 'line_item' ) as $item ) {
+ $product = null;
+ if ( is_array( $item ) && isset( $item['item_meta']['_product_id'][0] ) ) {
+ $product = wc_get_product( $item['item_meta']['_product_id'][0] );
+ } elseif ( is_object( $item ) && is_callable( array( $item, 'get_product' ) ) ) {
+ $product = $item->get_product();
+ }
+
+ if ( ! $product ) {
+ continue;
+ }
+
+ if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $product ) ) {
+ // Set correct flags for this order, making it a pre-order.
+ $order->update_meta_data( '_wc_pre_orders_is_pre_order', 1 );
+ $order->update_meta_data( '_wc_pre_orders_when_charged', get_post_meta( $product->get_id(), '_wc_pre_orders_when_to_charge', true ) );
+ $order->save();
+
+ return;
+ }
+ }
+ }
+
+ /**
+ * Adds Pre-Order Only and Non Pre-Order to the WooCommerce Subscriptions Order Subtype select
+ * Or create a new select if WooCommerce Subscriptions is not active
+ * @since 1.6.0
+ */
+ public function add_order_page_filters() {
+ //We only need to create a new select if the WooCommerce Subscriptions plugin is not active
+ // Otherwise we just add to the subscriptions filter
+ if ( class_exists( 'WC_Subscriptions_Core_Plugin' ) || class_exists( 'WC_Subscriptions' ) ) {
+ add_filter( 'woocommerce_subscriptions_order_type_dropdown', array( $this, 'add_pre_order_filter' ) );
+ } else {
+ // Add dropdown to admin orders screen to filter on order type
+ add_action( 'restrict_manage_posts', array( $this, 'restrict_manage_pre_order' ), 50 );
+
+ // Add dropdown to admin orders screen to filter on order type when HPOS is enabled.
+ add_action( 'woocommerce_order_list_table_restrict_manage_orders', array( $this, 'restrict_manage_pre_order' ) );
+ }
+
+ // Add filter to queries on admin orders screen to filter on order type. To avoid WC overriding our query args, we need to hook on after them on 10.
+ add_filter( 'request', array( $this, 'orders_by_type_query' ), 11 );
+
+ // Add filter to queries on admin orders screen to filter on order type when HPOS is enabled.
+ add_filter( 'woocommerce_shop_order_list_table_prepare_items_query_args', array( $this, 'orders_by_type_query' ) );
+ }
+
+ /**
+ * Add an admin dropdown for order types to Woocommerce -> Orders screen
+ *
+ * @param string $order_type The type of order.
+ *
+ * @since 1.6.0
+ */
+ public function restrict_manage_pre_order( $order_type = '' ) {
+ if ( '' === $order_type ) {
+ $order_type = isset( $GLOBALS['typenow'] ) ? wc_clean( $GLOBALS['typenow'] ) : '';
+ }
+
+ if ( 'shop_order' !== $order_type ) {
+ return;
+ }?>
+
+
+ _x( 'Non Pre-Orders', 'An order type', 'woocommerce-pre-orders' ),
+ 'pre-orders-only' => _x( 'Pre-Orders Only', 'An order type', 'woocommerce-pre-orders' ),
+ );
+
+ foreach ( $order_types as $order_type_key => $order_type_description ) {
+ echo '' . esc_html( $order_type_description ) . ' ';
+ }
+ ?>
+
+ Orders screen
+ *
+ * Orders that have _wc_pre_orders_is_pre_order meta are considered a pre order
+ * Orders that DO NOT have _wc_pre_orders_is_pre_order meta are NOT considered a pre order
+ *
+ * @since 1.6.0
+ * @param $vars array wp_query args
+ * @return array wp_query args
+ */
+ public function orders_by_type_query( $vars ) {
+ $order_type = isset( $GLOBALS['typenow'] ) ? wc_clean( $GLOBALS['typenow'] ) : '';
+ if ( '' === $order_type ) {
+ $order_type = isset( $vars['type'] ) ? wc_clean( $vars['type'] ) : '';
+ }
+
+ if ( 'shop_order' === $order_type && ! empty( $_GET['shop_order_subtype'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ switch ( $_GET['shop_order_subtype'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ case 'non-pre-orders':
+ $vars['meta_query'][] = array(
+ 'key' => '_wc_pre_orders_is_pre_order',
+ 'compare' => 'NOT EXISTS',
+ );
+ break;
+ case 'pre-orders-only':
+ $vars['meta_query'][] = array(
+ 'key' => '_wc_pre_orders_is_pre_order',
+ 'compare' => '=',
+ 'value' => '1',
+ );
+ break;
+ default:
+ break;
+ }
+ }
+
+ return $vars;
+ }
+}
+
+new WC_Pre_Orders_Admin_Orders();
diff --git a/includes/admin/class-wc-pre-orders-admin-pre-orders.php b/includes/admin/class-wc-pre-orders-admin-pre-orders.php
new file mode 100644
index 0000000..e6c9814
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-admin-pre-orders.php
@@ -0,0 +1,833 @@
+ __( 'Manage', 'woocommerce-pre-orders' ),
+ 'actions' => __( 'Actions', 'woocommerce-pre-orders' ),
+ );
+ }
+
+ /**
+ * Add 'Pre-Orders' sub-menu link under 'WooCommerce' top level menu.
+ */
+ public function add_menu_link() {
+
+ $hook = add_submenu_page(
+ 'woocommerce',
+ __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ 'manage_woocommerce',
+ 'wc_pre_orders',
+ array( $this, 'show_sub_menu_page' )
+ );
+
+ // add the Pre-Orders list Screen Options
+ add_action( 'load-woocommerce_page_wc_pre_orders', array( $this, 'add_pre_orders_list_options' ) );
+ add_action( 'load-' . $hook, array( $this, 'process_actions' ) );
+ }
+
+ /**
+ * Show Pre-Orders Manage/Actions page content.
+ */
+ public function show_sub_menu_page() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $current_tab = ( empty( $_GET['tab'] ) ) ? 'manage' : urldecode( sanitize_text_field( wp_unslash( $_GET['tab'] ) ) );
+
+ echo '';
+ echo '
';
+ echo '
';
+
+ // Display tabs.
+ foreach ( $this->get_tabs() as $tab_id => $tab_title ) {
+
+ $class = ( $tab_id === $current_tab ) ? 'nav-tab nav-tab-active' : 'nav-tab';
+ $url = add_query_arg( 'tab', $tab_id, admin_url( 'admin.php?page=wc_pre_orders' ) );
+
+ printf( '%s ', esc_url( $url ), esc_attr( $class ), esc_attr( $tab_title ) );
+ }
+
+ echo ' ';
+
+ // Show any messages.
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( ! empty( $_GET['success'] ) ) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ switch ( $_GET['success'] ) {
+
+ case 'email':
+ $message = __( 'Pre-order customers emailed successfully', 'woocommerce-pre-orders' );
+ break;
+
+ case 'change-date':
+ $message = __( 'Pre-order date changed', 'woocommerce-pre-orders' );
+ break;
+
+ case 'complete':
+ $message = __( 'Pre-orders completed', 'woocommerce-pre-orders' );
+ break;
+
+ case 'cancel':
+ $message = __( 'Pre-orders cancelled', 'woocommerce-pre-orders' );
+ break;
+
+ default:
+ $message = '';
+ break;
+ }
+
+ if ( $message ) {
+ echo '
' . wp_kses_post( $message ) . '
';
+ }
+ }
+
+ // Display tab content, default to 'Manage' tab.
+ if ( 'actions' === $current_tab ) {
+ $this->show_actions_tab();
+ } else {
+ $this->show_manage_tab();
+ }
+
+ echo '
';
+ }
+
+ /**
+ * Add the Pre-Orders list table Screen Options.
+ */
+ public function add_pre_orders_list_options() {
+ $args = array(
+ 'label' => __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ 'default' => 20,
+ 'option' => 'wc_pre_orders_edit_pre_orders_per_page',
+ );
+
+ add_screen_option( 'per_page', $args );
+ }
+
+ /**
+ * Processes the cancelling of individual pre-order.
+ *
+ * @since 1.4.6
+ * @version 1.4.7
+ * @return bool
+ */
+ public function process_cancel_pre_order_action() {
+ if ( empty( $_GET['action'] ) || 'cancel_pre_order' !== $_GET['action'] ) {
+ return;
+ }
+
+ if (
+ empty( $_GET['cancel_pre_order_nonce'] ) ||
+ ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['cancel_pre_order_nonce'] ) ), 'cancel_pre_order' )
+ ) {
+ wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce-pre-orders' ) );
+ }
+
+ // User check.
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ wp_die( esc_html__( 'You do not have the correct permissions to do this.', 'woocommerce-pre-orders' ) );
+ }
+
+ $order_id = ( ! empty( $_GET['order_id'] ) ) ? absint( $_GET['order_id'] ) : '';
+
+ WC_Pre_Orders_Manager::cancel_pre_order( $order_id );
+ /* translators: %s = order id */
+ $this->_redirect_with_notice( sprintf( __( 'Pre-order #%s cancelled.', 'woocommerce-pre-orders' ), $order_id ) );
+ }
+
+ /**
+ * Process the actions from the 'Actions' tab.
+ */
+ public function process_actions_tab() {
+ global $wc_pre_orders;
+
+ if ( empty( $_POST['wc_pre_orders_action'] ) ) {
+ return;
+ }
+
+ // Security check.
+ if (
+ ! isset( $_POST['_wpnonce'] ) ||
+ ! wp_verify_nonce( wp_unslash( $_POST['_wpnonce'] ), 'wc-pre-orders-process-actions' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ ) {
+ wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce-pre-orders' ) );
+ }
+
+ // User check.
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ wp_die( esc_html__( 'You do not have the correct permissions to do this.', 'woocommerce-pre-orders' ) );
+ }
+
+ // Get parameters.
+ $action = ( in_array( $_POST['wc_pre_orders_action'], array( 'email', 'change-date', 'complete', 'cancel' ), true ) ) ? wc_clean( wp_unslash( $_POST['wc_pre_orders_action'] ) ) : '';
+ $product_id = ( ! empty( $_POST['wc_pre_orders_action_product'] ) ) ? absint( $_POST['wc_pre_orders_action_product'] ) : '';
+ $send_email = ( isset( $_POST['wc_pre_orders_action_enable_email_notification'] ) && '1' === $_POST['wc_pre_orders_action_enable_email_notification'] ) ? true : false;
+ $email_message = ( ! empty( $_POST['wc_pre_orders_action_email_message'] ) ) ? wp_kses_post( wp_unslash( $_POST['wc_pre_orders_action_email_message'] ) ) : '';
+ $new_availability_date = ( ! empty( $_POST['wc_pre_orders_action_new_availability_date'] ) ) ? sanitize_text_field( wp_unslash( $_POST['wc_pre_orders_action_new_availability_date'] ) ) : '';
+
+ if ( ! $action || ! $product_id ) {
+ return;
+ }
+
+ switch ( $action ) {
+
+ // Email all pre-ordered customers.
+ case 'email':
+ WC_Pre_Orders_Manager::email_all_pre_order_customers( $product_id, $email_message );
+
+ break;
+
+ // Change the release date for all pre-orders.
+ case 'change-date':
+ // Remove email notification if disabled.
+ if ( ! $send_email ) {
+ remove_action( 'wc_pre_orders_pre_order_date_changed', array( $wc_pre_orders, 'send_transactional_email' ), 10 );
+ }
+
+ WC_Pre_Orders_Manager::change_release_date_for_all_pre_orders( $product_id, $new_availability_date, $email_message );
+
+ break;
+
+ // Complete all pre-orders.
+ case 'complete':
+ // Remove email notification if disabled.
+ if ( ! $send_email ) {
+ remove_action( 'wc_pre_order_status_completed', array( $wc_pre_orders, 'send_transactional_email' ), 10 );
+ }
+
+ WC_Pre_Orders_Manager::complete_all_pre_orders( $product_id, $email_message );
+
+ break;
+
+ // Cancel all pre-orders.
+ case 'cancel':
+ // Remove email notification if disabled.
+ if ( ! $send_email ) {
+ remove_action( 'wc_pre_order_status_active_to_cancelled', array( $wc_pre_orders, 'send_transactional_email' ), 10 );
+ }
+
+ WC_Pre_Orders_Manager::cancel_all_pre_orders( $product_id, $email_message );
+
+ break;
+
+ default:
+ break;
+ }
+
+ wp_safe_redirect( esc_url_raw( remove_query_arg( 'action_default_product', add_query_arg( 'success', sanitize_text_field( wp_unslash( $_POST['wc_pre_orders_action'] ) ) ) ) ) );
+ exit;
+ }
+
+ /**
+ * Process the actions from the 'Manage' tab.
+ */
+ public function process_manage_tab() {
+ if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-pre-orders' ) ) {
+ return;
+ }
+
+ // Get the current action (if any).
+ $action = $this->current_action();
+
+ // Cancellation of individual pre-order should be handled by
+ // self::process_cancel_pre_order_action.
+ if ( 'cancel_pre_order' === $action ) {
+ return;
+ }
+
+ // Get the set of orders to operate on.
+ $order_ids = isset( $_REQUEST['order_id'] ) ? array_map( 'absint', $_REQUEST['order_id'] ) : array();
+
+ $message = $this->get_current_customer_message();
+
+ // No action, or invalid action.
+ if ( isset( $_GET['page'] ) && 'wc_pre_orders' === $_GET['page'] ) {
+
+ if ( false === $action || empty( $order_ids ) ) {
+ if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
+ // remove _wp_http_referer/_wp_nonce/action params
+ wp_redirect(
+ esc_url_raw(
+ remove_query_arg(
+ array( '_wp_http_referer', '_wpnonce', 'action', 'action2' ),
+ ! empty( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : false
+ )
+ )
+ );
+ exit;
+ }
+ return;
+ }
+
+ $success_count = 0;
+ $error_count = 0;
+
+ // Process the orders
+ foreach ( $order_ids as $order_id ) {
+
+ $order = new WC_Order( $order_id );
+
+ // Perform the action.
+ switch ( $action ) {
+ case 'cancel':
+ if ( WC_Pre_Orders_Manager::can_pre_order_be_changed_to( 'cancelled', $order ) ) {
+ $success_count++;
+ WC_Pre_Orders_Manager::cancel_pre_order( $order, $message );
+ } else {
+ $error_count++;
+ }
+ break;
+
+ case 'complete':
+ if ( WC_Pre_Orders_Manager::can_pre_order_be_changed_to( 'completed', $order ) ) {
+ $success_count++;
+ WC_Pre_Orders_Manager::complete_pre_order( $order, $message );
+ } else {
+ $error_count++;
+ }
+ break;
+
+ case 'message':
+ WC_Pre_Orders_Manager::email_pre_order_customer( $order_id, $message );
+ break;
+ }
+ }
+
+ $messages = array();
+
+ switch ( $action ) {
+ case 'cancel':
+ if ( $success_count > 0 ) {
+ /* translators: %d = success count */
+ $messages[] = sprintf( _n( '%d pre-order cancelled.', '%d pre-orders cancelled.', $success_count, 'woocommerce-pre-orders' ), $success_count );
+ }
+ if ( $error_count > 0 ) {
+ /* translators: %d = error count */
+ $messages[] = sprintf( _n( '%d pre-order could not be cancelled.', '%d pre-orders could not be cancelled.', $error_count, 'woocommerce-pre-orders' ), $error_count );
+ }
+ break;
+
+ case 'complete':
+ if ( $success_count > 0 ) {
+ /* translators: %d = success count */
+ $messages[] = sprintf( _n( '%d pre-order completed.', '%d pre-orders completed.', $success_count, 'woocommerce-pre-orders' ), $success_count );
+ }
+ if ( $error_count > 0 ) {
+ /* translators: %d = error count */
+ $messages[] = sprintf( _n( '%d pre-order could not be completed.', '%d pre-orders could not be completed.', $error_count, 'woocommerce-pre-orders' ), $error_count );
+ }
+ break;
+
+ case 'message':
+ /* translators: %d = The count of emails dispatched */
+ $messages[] = sprintf( _n( '%d email dispatched.', '%d emails dispatched.', count( $order_ids ), 'woocommerce-pre-orders' ), count( $order_ids ) );
+ break;
+ }
+
+ $this->_redirect_with_notice( implode( ' ', $messages ) );
+ }
+ }
+
+ /**
+ * Get the current action selected from the bulk actions dropdown, verifying
+ * that it's a valid action to perform.
+ *
+ * @see WP_List_Table::current_action()
+ *
+ * @return string|bool The action name or False if no action was selected.
+ */
+ public function current_action() {
+ $current_action = false;
+
+ if ( isset( $_REQUEST['action'] ) && -1 !== sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $current_action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ }
+
+ if ( isset( $_REQUEST['action2'] ) && -1 !== sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $current_action = sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ }
+
+ $valid_actions = array_keys( $this->get_bulk_actions() );
+ $valid_actions[] = 'cancel_pre_order';
+
+ if ( $current_action && ! in_array( $current_action, $valid_actions ) ) {
+ return false;
+ }
+
+ return $current_action;
+ }
+
+ /**
+ * Dispatch actions from Manage tab and Actions tab.
+ *
+ * @since 1.0
+ */
+ public function process_actions() {
+ $this->process_actions_tab();
+ $this->process_manage_tab();
+ $this->process_cancel_pre_order_action();
+ }
+
+ /**
+ * Gets the bulk actions available for pre-orders: complete, cancel or message.
+ *
+ * @see WP_List_Table::get_bulk_actions()
+ *
+ * @return array associative array of action_slug => action_title.
+ */
+ public function get_bulk_actions() {
+ $actions = array(
+ 'cancel' => __( 'Cancel', 'woocommerce-pre-orders' ),
+ 'complete' => __( 'Complete', 'woocommerce-pre-orders' ),
+ 'message' => __( 'Customer message', 'woocommerce-pre-orders' ),
+ );
+
+ return $actions;
+ }
+
+ /**
+ * Gets the current customer message which is used for bulk actions.
+ *
+ * @return string the current customer message.
+ */
+ public function get_current_customer_message() {
+ if ( isset( $_REQUEST['customer_message'] ) && sanitize_text_field( wp_unslash( $_REQUEST['customer_message'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return sanitize_text_field( wp_unslash( $_REQUEST['customer_message'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ }
+
+ if ( isset( $_REQUEST['customer_message2'] ) && sanitize_text_field( wp_unslash( $_REQUEST['customer_message2'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return sanitize_text_field( wp_unslash( $_REQUEST['customer_message2'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ }
+
+ return null;
+ }
+
+ /**
+ * Loads the pre-orders list table so the columns can be hidden/shown from
+ * the page Screen Options dropdown (this must be done prior to Screen Options
+ * being rendered).
+ */
+ public function load_pre_orders_list_table() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_GET['page'] ) && 'wc_pre_orders' === $_GET['page'] ) {
+ $this->get_pre_orders_list_table();
+ }
+ }
+
+ /**
+ * Gets the pre-orders list table object.
+ *
+ * @return WC_Pre_Orders_List_Table the pre-orders list table object
+ */
+ private function get_pre_orders_list_table() {
+ global $wc_pre_orders;
+
+ if ( ! isset( $this->pre_orders_list_table ) ) {
+
+ $class_name = apply_filters( 'wc_pre_orders_list_table_class_name', 'WC_Pre_Orders_List_Table' );
+
+ require $wc_pre_orders->get_plugin_path() . '/includes/class-wc-pre-orders-list-table.php';
+ $this->pre_orders_list_table = new $class_name();
+ }
+
+ return $this->pre_orders_list_table;
+ }
+
+ /**
+ * Show the Pre-Orders > Actions tab content.
+ */
+ private function show_actions_tab() {
+ global $woocommerce;
+
+ // Load file for woocommerce_admin_fields() usage.
+ if ( file_exists( $woocommerce->plugin_path() . '/includes/admin/wc-admin-functions.php' ) ) {
+ require_once $woocommerce->plugin_path() . '/includes/admin/wc-admin-functions.php';
+ } else {
+ require_once $woocommerce->plugin_path() . '/admin/woocommerce-admin-settings.php';
+ }
+
+ // TODO: cache this results? this will be called again when form is rendered.
+ $pre_order_products = WC_Pre_Orders_Manager::get_all_pre_order_enabled_products();
+ if ( empty( $pre_order_products ) ) {
+ ?>
+
+ __( 'Email', 'woocommerce-pre-orders' ),
+ 'change-date' => __( 'Change release date', 'woocommerce-pre-orders' ),
+ 'complete' => __( 'Complete', 'woocommerce-pre-orders' ),
+ 'cancel' => __( 'Cancel', 'woocommerce-pre-orders' ),
+ );
+
+ foreach ( $actions as $action_id => $action_title ) {
+ $current = ( $action_id === $current_section ) ? ' class="current"' : '';
+
+ $links[] = sprintf( '%s ', add_query_arg( array( 'section' => $action_id ), admin_url( 'admin.php?page=wc_pre_orders&tab=actions' ) ), $current, $action_title );
+ }
+
+ echo '' . wp_kses_post( implode( ' | ', $links ) ) . ' ';
+ echo '';
+ }
+
+ /**
+ * Show the Pre-Orders > Manage tab content.
+ */
+ private function show_manage_tab() {
+ // Setup 'Manage Pre-Orders' list table and prepare the data.
+ $manage_table = $this->get_pre_orders_list_table();
+ $manage_table->prepare_items();
+
+ echo '';
+ }
+
+ /**
+ * Get the fields to display for the selected action, in the format required by woocommerce_admin_fields().
+ *
+ * @param string $section The current section to get fields for.
+ *
+ * @return array
+ */
+ private function get_action_fields( $section ) {
+
+ $products = array( '' => __( 'Select a product', 'woocommerce-pre-orders' ) );
+
+ foreach ( WC_Pre_Orders_Manager::get_all_pre_order_enabled_products() as $product ) {
+ $products[ $product->get_id() ] = $product->get_formatted_name();
+ }
+
+ $fields = array(
+
+ 'email' => array(
+
+ array(
+ 'name' => __( 'Email pre-order customers', 'woocommerce-pre-orders' ),
+ /* translators: %1$s = Opening anchor tag for WooCommerce email customer note, %2$s = Closing anchor tag */
+ 'desc' => sprintf( __( 'You may send an email message to all customers who have pre-ordered a specific product. This will use the default template specified for the %1$sCustomer Note%2$s Email.', 'wc-pre-orders' ), '', ' ' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_product',
+ 'name' => __( 'Product', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Select which product to email all pre-ordered customers.', 'woocommerce-pre-orders' ),
+ 'default' => ' ',
+ 'options' => $products,
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'custom_attributes' => array(
+ 'required' => 'required',
+ ),
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_email_message',
+ 'name' => __( 'Message', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Enter a message to include in the email notification to customer. Limited HTML allowed.', 'woocommerce-pre-orders' ),
+ 'css' => 'min-width: 300px;',
+ 'default' => '',
+ 'type' => 'textarea',
+ 'custom_attributes' => array(
+ 'required' => 'required',
+ ),
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'name' => __( 'Send emails', 'woocommerce-pre-orders' ),
+ 'type' => 'submit_button',
+ ),
+ ),
+
+ 'change-date' => array(
+
+ array(
+ 'name' => __( 'Change the pre-order release date', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'You may change the release date for all pre-orders of a specific product. This will send an email notification to each customer informing them that the pre-order release date was changed, along with the new release date.', 'woocommerce-pre-orders' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_product',
+ 'name' => __( 'Product', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Select which product to change the release date for.', 'woocommerce-pre-orders' ),
+ 'default' => ( ! empty( $_GET['action_default_product'] ) ) ? absint( $_GET['action_default_product'] ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ 'options' => $products,
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'custom_attributes' => array(
+ 'required' => 'required',
+ ),
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_new_availability_date',
+ 'name' => __( 'New availability date', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'The new availability date for the product. This must be later than the current availability date.', 'woocommerce-pre-orders' ),
+ 'default' => '',
+ 'type' => 'text',
+ 'custom_attributes' => array(
+ 'required' => 'required',
+ ),
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_enable_email_notification',
+ 'name' => __( 'Send email notification', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'Uncheck this to prevent email notifications from being sent to customers.', 'woocommerce-pre-orders' ),
+ 'default' => 'yes',
+ 'type' => 'checkbox',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_email_message',
+ 'name' => __( 'Message', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Enter a message to include in the email notification to customer.', 'woocommerce-pre-orders' ),
+ 'default' => '',
+ 'css' => 'min-width: 300px;',
+ 'type' => 'textarea',
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'name' => __( 'Change release date', 'woocommerce-pre-orders' ),
+ 'type' => 'submit_button',
+ ),
+ ),
+
+ 'complete' => array(
+
+ array(
+ 'name' => __( 'Complete pre-orders', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'You may complete all pre-orders for a specific product. This will charge the customer\'s card the pre-ordered amount, change their order status to completed, and send them an email notification.', 'woocommerce-pre-orders' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_product',
+ 'name' => __( 'Product', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Select which product to complete all pre-orders for.', 'woocommerce-pre-orders' ),
+ 'default' => ' ',
+ 'options' => $products,
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'custom_attributes' => array(
+ 'required' => 'required',
+ ),
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_enable_email_notification',
+ 'name' => __( 'Send email notification', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'Uncheck this to prevent email notifications from being sent to customers.', 'woocommerce-pre-orders' ),
+ 'default' => 'yes',
+ 'type' => 'checkbox',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_email_message',
+ 'name' => __( 'Message', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Enter a message to include in the email notification to customer.', 'woocommerce-pre-orders' ),
+ 'default' => '',
+ 'css' => 'min-width: 300px;',
+ 'type' => 'textarea',
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'name' => __( 'Complete pre-orders', 'woocommerce-pre-orders' ),
+ 'type' => 'submit_button',
+ ),
+ ),
+
+ 'cancel' => array(
+ array(
+ 'name' => __( 'Cancel pre-orders', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'You may cancel all pre-orders for a specific product. This will mark the order as cancelled and send the customer an email notification. If pre-orders were charged upfront, you must manually refund the orders.', 'woocommerce-pre-orders' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_product',
+ 'name' => __( 'Product', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Select which product to cancel all pre-orders for.', 'woocommerce-pre-orders' ),
+ 'default' => ' ',
+ 'options' => $products,
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'custom_attributes' => array(
+ 'required' => 'required',
+ ),
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_enable_email_notification',
+ 'name' => __( 'Send email notification', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'Uncheck this to prevent email notifications from being sent to customers.', 'woocommerce-pre-orders' ),
+ 'default' => 'yes',
+ 'type' => 'checkbox',
+ ),
+
+ array(
+ 'id' => 'wc_pre_orders_action_email_message',
+ 'name' => __( 'Message', 'woocommerce-pre-orders' ),
+ 'desc_tip' => __( 'Enter a message to include in the email notification to customer.', 'woocommerce-pre-orders' ),
+ 'default' => '',
+ 'css' => 'min-width: 300px;',
+ 'type' => 'textarea',
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'name' => __( 'Cancel pre-orders', 'woocommerce-pre-orders' ),
+ 'type' => 'submit_button',
+ ),
+ ),
+ );
+
+ return ( isset( $fields[ $section ] ) ) ? $fields[ $section ] : array();
+ }
+
+ /**
+ * Generate a submit button, called via a do_action() inside woocommerce_admin_fields() for non-default field types.
+ *
+ * @param array $field The field info.
+ */
+ public function generate_submit_button( $field ) {
+ submit_button( $field['name'] );
+ }
+
+ /**
+ * Save our list option.
+ *
+ * @param string $status unknown.
+ * @param string $option the option name.
+ * @param string $value the option value.
+ *
+ * @return string
+ */
+ public function set_pre_orders_list_option( $status, $option, $value ) {
+ if ( 'wc_pre_orders_edit_pre_orders_per_page' === $option ) {
+ return $value;
+ }
+
+ return $status;
+ }
+
+ /**
+ * Redirect with message notice.
+ *
+ * @since 1.4.7
+ *
+ * @param string $message Message to display
+ */
+ protected function _redirect_with_notice( $message ) {
+ $message_nonce = wp_create_nonce( __FILE__ );
+
+ set_transient( $this->message_transient_prefix . $message_nonce, array( 'messages' => $message ), 60 * 60 );
+
+ // Get our next destination, stripping out all actions and other unneeded parameters.
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_REQUEST['_wp_http_referer'] ) ) {
+ $redirect_url = sanitize_text_field( wp_unslash( $_REQUEST['_wp_http_referer'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ } elseif ( isset( $_SERVER['REQUEST_URI'] ) ) {
+ $redirect_url = remove_query_arg( array( '_wp_http_referer', '_wpnonce', 'action', 'action2', 'order_id', 'customer_message', 'customer_message2' ), sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ }
+
+ wp_safe_redirect( esc_url_raw( add_query_arg( 'message', $message_nonce, $redirect_url ) ) );
+ exit;
+ }
+}
+
+new WC_Pre_Orders_Admin_Pre_Orders();
diff --git a/includes/admin/class-wc-pre-orders-admin-products.php b/includes/admin/class-wc-pre-orders-admin-products.php
new file mode 100644
index 0000000..d5d398b
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-admin-products.php
@@ -0,0 +1,182 @@
+ __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ 'target' => 'wc_pre_orders_data',
+ 'class' => $classes,
+ );
+
+ return $tabs;
+ }
+
+ /**
+ * Add pre-orders options to product writepanel.
+ */
+ public function add_product_tab_options() {
+ include 'views/html-product-tab-options.php';
+ }
+
+ /**
+ * Save pre-order options.
+ *
+ * @param int $post_id The ID of the product being saved.
+ */
+ public function save_product_tab_options( $post_id ) {
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
+ // Don't save any settings if there are active pre-orders.
+ if ( WC_Pre_Orders_Product::product_has_active_pre_orders( $post_id ) ) {
+ return;
+ }
+
+ // pre-orders enabled
+ $is_enabled = isset( $_POST['_wc_pre_orders_enabled'] ) && 'yes' === $_POST['_wc_pre_orders_enabled'];
+ update_post_meta( $post_id, '_wc_pre_orders_enabled', ( $is_enabled ? 'yes' : 'no' ) );
+
+ if ( ! empty( $_POST['_wc_pre_orders_availability_datetime'] ) ) {
+ self::save_availability_date_time(
+ $post_id,
+ sanitize_text_field(
+ wp_unslash(
+ $_POST['_wc_pre_orders_availability_datetime']
+ )
+ )
+ );
+ } else {
+ delete_post_meta( $post_id, '_wc_pre_orders_availability_datetime' );
+ }
+
+ // Pre-order fee.
+ if ( isset( $_POST['_wc_pre_orders_fee'] ) && is_numeric( $_POST['_wc_pre_orders_fee'] ) ) {
+ update_post_meta(
+ $post_id,
+ '_wc_pre_orders_fee',
+ floatval(
+ sanitize_text_field(
+ wp_unslash(
+ $_POST['_wc_pre_orders_fee']
+ )
+ )
+ )
+ );
+ } else {
+ update_post_meta( $post_id, '_wc_pre_orders_fee', '' );
+ }
+
+ // When to charge pre-order amount.
+ if ( isset( $_POST['_wc_pre_orders_when_to_charge'] ) && isset( $_POST['_wc_pre_orders_enabled'] ) && 'yes' === $_POST['_wc_pre_orders_enabled'] ) {
+ update_post_meta( $post_id, '_wc_pre_orders_when_to_charge', ( 'upon_release' === $_POST['_wc_pre_orders_when_to_charge'] ) ? 'upon_release' : 'upfront' );
+ }
+
+ do_action( 'wc_pre_orders_save_product_options', $post_id );
+ }
+
+ /**
+ * Save the availability date/time.
+ *
+ * The date/time a pre-order is released is saved as a unix timestamp adjusted for the site's timezone. For example,
+ * when an admin sets a pre-order to be released on 2013-06-25 12pm EST (UTC-4), it is saved as a timestamp equivalent
+ * to 2013-12-25 4pm UTC. This makes the pre-order release check much easier, as it's a simple timestamp comparison,
+ * because the release datetime and the current time are both in UTC.
+ *
+ * @param int $post_id The ID of the product being saved.
+ * @param string $value The value of the availability date/time.
+ */
+ public static function save_availability_date_time( $post_id, $value ) {
+ try {
+ // Get datetime object from site timezone.
+ $datetime = new DateTime( wp_unslash( $value ), new DateTimeZone( wc_timezone_string() ) );
+
+ // Get the unix timestamp (adjusted for the site's timezone already).
+ $timestamp = $datetime->format( 'U' );
+
+ // Don't allow availability dates in the past.
+ if ( $timestamp <= time() ) {
+ $timestamp = '';
+ }
+
+ // Set the availability datetime.
+ update_post_meta( $post_id, '_wc_pre_orders_availability_datetime', $timestamp );
+
+ } catch ( Exception $e ) {
+ global $wc_pre_orders;
+
+ $wc_pre_orders->log( $e->getMessage() );
+ }
+ }
+}
+
+new WC_Pre_Orders_Admin_Products();
diff --git a/includes/admin/class-wc-pre-orders-admin-settings.php b/includes/admin/class-wc-pre-orders-admin-settings.php
new file mode 100644
index 0000000..8c74948
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-admin-settings.php
@@ -0,0 +1,202 @@
+settings_tab_id, array( $this, 'show_settings' ) );
+
+ // Save settings.
+ add_action( 'woocommerce_update_options_' . $this->settings_tab_id, array( $this, 'save_settings' ) );
+ }
+
+ /**
+ * Add 'Pre-Orders' tab to WooCommerce Settings tabs
+ *
+ * @param array $settings_tabs Tabs array sans 'Pre-Orders' tab.
+ *
+ * @return array $settings_tabs Now with 100% more 'Pre-Orders' tab!
+ */
+ public function add_settings_tab( $settings_tabs ) {
+ $settings_tabs[ $this->settings_tab_id ] = __( 'Pre-Orders', 'woocommerce-pre-orders' );
+
+ return $settings_tabs;
+ }
+
+ /**
+ * Show the 'Pre-Orders' settings page.
+ */
+ public function show_settings() {
+ woocommerce_admin_fields( $this->get_settings() );
+ }
+
+ /**
+ * Save the 'Pre-Orders' settings page.
+ */
+ public function save_settings() {
+ woocommerce_update_options( $this->get_settings() );
+ }
+
+ /**
+ * Returns settings array for use by output/save functions.
+ *
+ * @return array Settings.
+ */
+ public function get_settings() {
+ return apply_filters(
+ 'wc_pre_orders_settings',
+ array(
+
+ array(
+ 'title' => __( 'Button text', 'woocommerce-pre-orders' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'title' => __( 'Add to cart button text', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'This controls the add to cart button text on single product pages for products that have pre-orders enabled.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_add_to_cart_button_text',
+ 'default' => __( 'Pre-order now', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ ),
+
+ array(
+ 'title' => __( 'Place Order Button Text', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'This controls the place order button text on the checkout when an order contains a pre-orders.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_place_order_button_text',
+ 'default' => __( 'Place pre-order now', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'title' => __( 'Product message', 'woocommerce-pre-orders' ),
+ /* translators: %1$s: Availability Time %2$s: Availability Date */
+ 'desc' => sprintf( __( 'Adjust the message by using %1$s{availability_date}%2$s and %1$s{availability_time}%2$s to represent the product\'s availability date and time.', 'woocommerce-pre-orders' ), '', '
' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'title' => __( 'Single product page message', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'Add an optional message to the single product page below the price. Use this to announce when the pre-order will be available by using {availability_date} and {availability_time}. Limited HTML is allowed. Leave blank to disable.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_single_product_message',
+ /* translators: %s: Availability Date */
+ 'default' => sprintf( __( 'This item will be released %s.', 'woocommerce-pre-orders' ), '{availability_date}' ),
+ 'type' => 'textarea',
+ ),
+
+ array(
+ 'title' => __( 'Shop loop product message', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'Add an optional message to each pre-order enabled product on the shop loop page below the product title. Use this to announce when the pre-order will be available by using {availability_date} and {availability_time}. Limited HTML is allowed. Leave blank to disable.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_shop_loop_product_message',
+ /* translators: %s: Availability Date */
+ 'default' => sprintf( __( 'Available %s.', 'woocommerce-pre-orders' ), '{availability_date}' ),
+ 'type' => 'textarea',
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'title' => __( 'Cart / Checkout display text', 'woocommerce-pre-orders' ),
+ /* translators: %1$s: Order Total %2$s: Availability Date */
+ 'desc' => sprintf( __( 'Adjust the display of the order total by using %1$s{order_total}%2$s to represent the order total and %1$s{availability_date}%2$s to represent the product\'s availability date.', 'woocommerce-pre-orders' ), '', '
' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'title' => __( 'Availability date title text', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'This controls the title of the availability date section on the cart/checkout page. Leave blank to disable display of the availability date in the cart.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_availability_date_cart_title_text',
+ 'default' => __( 'Available', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ ),
+
+ array(
+ 'title' => __( 'Charged upon release order total format', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'This controls the order total format when the cart contains a pre-order charged upon release. Use this to indicate when the customer will be charged for their pre-order by using {availability_date} and {order_total}.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_upon_release_order_total_format',
+ /* translators: %1$s: Order Total %2$s: Availability Date */
+ 'default' => sprintf( __( '%1$s charged %2$s', 'woocommerce-pre-orders' ), '{order_total}', '{availability_date}' ),
+ 'css' => 'min-width: 300px;',
+ 'type' => 'text',
+ ),
+
+ array(
+ 'title' => __( 'Charged upfront order total format', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'This controls the order total format when the cart contains a pre-order charged upfront. Use this to indicate how the customer is charged for their pre-order by using {availability_date} and {order_total}.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_upfront_order_total_format',
+ /* translators: %s: Order Total */
+ 'default' => sprintf( __( '%s charged upfront', 'woocommerce-pre-orders' ), '{order_total}' ),
+ 'css' => 'min-width: 150px;',
+ 'type' => 'text',
+ ),
+
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'title' => __( 'Out of stock', 'woocommerce-pre-orders' ),
+ 'type' => 'title',
+ ),
+ array(
+ 'title' => __( 'Enable pre-orders for products that get out of stock', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'When a product becomes out of stock customers will be able to pre-order it. Variable products need to have all variations out of stock.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_auto_pre_order_out_of_stock',
+ 'default' => 'no',
+ 'type' => 'checkbox',
+ ),
+ array( 'type' => 'sectionend' ),
+
+ array(
+ 'title' => __( 'Staging/Test', 'woocommerce-pre-orders' ),
+ 'type' => 'title',
+ ),
+
+ array(
+ 'title' => __( 'Disable automated pre-order processing.', 'woocommerce-pre-orders' ),
+ 'desc' => __( 'This is used for when you\'re on a staging/testing site and don\'t want any pre orders to be processed automatically.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'id' => 'wc_pre_orders_disable_auto_processing',
+ 'default' => 'no',
+ 'type' => 'checkbox',
+ ),
+ array( 'type' => 'sectionend' ),
+ )
+ );
+ }
+}
+
+new WC_Pre_Orders_Admin_Settings();
diff --git a/includes/admin/class-wc-pre-orders-admin.php b/includes/admin/class-wc-pre-orders-admin.php
new file mode 100644
index 0000000..777defa
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-admin.php
@@ -0,0 +1,123 @@
+includes();
+ }
+
+ /**
+ * Includes.
+ */
+ protected function includes() {
+ require_once 'class-wc-pre-orders-admin-pre-orders.php';
+ require_once 'class-wc-pre-orders-admin-orders.php';
+ require_once 'class-wc-pre-orders-admin-products.php';
+ require_once 'class-wc-pre-orders-admin-settings.php';
+ }
+
+ /**
+ * Set installed option and default settings / terms.
+ */
+ public function maybe_install() {
+ global $woocommerce;
+
+ $installed_version = get_option( 'wc_pre_orders_version' );
+
+ // Install.
+ if ( ! $installed_version ) {
+
+ $admin_settings = new WC_Pre_Orders_Admin_Settings();
+
+ // Install default settings.
+ foreach ( $admin_settings->get_settings() as $setting ) {
+
+ if ( isset( $setting['default'] ) ) {
+ update_option( $setting['id'], $setting['default'] );
+ }
+ }
+ }
+
+ // Upgrade - installed version lower than plugin version?
+ if ( -1 === version_compare( $installed_version, WC_PRE_ORDERS_VERSION ) ) {
+
+ // New version number.
+ update_option( 'wc_pre_orders_version', WC_PRE_ORDERS_VERSION );
+ }
+ }
+
+ /**
+ * Add Pre-orders screen to woocommerce_screen_ids.
+ *
+ * @param array $ids
+ *
+ * @return array
+ */
+ public function screen_ids( $ids ) {
+ $ids[] = 'woocommerce_page_wc_pre_orders';
+
+ return $ids;
+ }
+
+ /**
+ * Load admin styles & scripts only on needed pages.
+ *
+ * @param string $hook_suffix the menu/page identifier
+ */
+ public function load_styles_scripts( $hook_suffix ) {
+ global $woocommerce, $wc_pre_orders, $wp_scripts;
+
+ // Only load on settings / order / product pages.
+ if ( 'woocommerce_page_wc_pre_orders' === $hook_suffix || 'edit.php' === $hook_suffix || 'post.php' === $hook_suffix || 'post-new.php' === $hook_suffix ) {
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ // Admin CSS
+ wp_enqueue_style( 'wc_pre_orders_admin', $wc_pre_orders->get_plugin_url() . '/assets/css/wc-pre-orders-admin.css', array(), WC_PRE_ORDERS_VERSION );
+
+ // Admin JS
+ wp_enqueue_script( 'wc_pre_orders_admin', $wc_pre_orders->get_plugin_url() . '/assets/js/admin/wc-pre-orders-admin' . $suffix . '.js', WC_PRE_ORDERS_VERSION );
+
+ // Load jQuery UI Date/TimePicker on new/edit product page and pre-orders > actions page
+ if ( 'post.php' === $hook_suffix || 'post-new.php' === $hook_suffix || 'woocommerce_page_wc_pre_orders' === $hook_suffix ) {
+
+ // Get loaded jQuery version
+ $jquery_version = isset( $wp_scripts->registered['jquery-ui-core']->ver ) ? $wp_scripts->registered['jquery-ui-core']->ver : '1.8.2';
+
+ // Load jQuery UI CSS while respecting loaded jQuery version
+ wp_enqueue_style( 'jquery-ui-style', '//ajax.googleapis.com/ajax/libs/jqueryui/' . $jquery_version . '/themes/smoothness/jquery-ui.css' );
+
+ // Load TimePicker add-on which extends jQuery DatePicker
+ wp_enqueue_script( 'jquery_ui_timepicker', $wc_pre_orders->get_plugin_url() . '/assets/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon' . $suffix . '.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker' ), '1.2' );
+ }
+ }
+
+ }
+}
+
+new WC_Pre_Orders_Admin();
diff --git a/includes/admin/class-wc-pre-orders-product-editor-compatibility.php b/includes/admin/class-wc-pre-orders-product-editor-compatibility.php
new file mode 100644
index 0000000..9fc9d64
--- /dev/null
+++ b/includes/admin/class-wc-pre-orders-product-editor-compatibility.php
@@ -0,0 +1,293 @@
+register_block_type_from_metadata( WC_PRE_ORDERS_PLUGIN_PATH . '/build/admin/blocks/select-control' );
+ BlockRegistry::get_instance()->register_block_type_from_metadata( WC_PRE_ORDERS_PLUGIN_PATH . '/build/admin/blocks/date-time-picker' );
+ BlockRegistry::get_instance()->register_block_type_from_metadata( WC_PRE_ORDERS_PLUGIN_PATH . '/build/admin/blocks/message-control' );
+ }
+ }
+
+ /**
+ * Adds pre-orders meta to the product response.
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WC_Product $product The product object.
+ *
+ * @return WP_REST_Response
+ */
+ public function add_meta_to_response( $response, $product ) {
+ $data = $response->get_data();
+ $has_orders = WC_Pre_Orders_Product::product_has_active_pre_orders( $product->get_id() );
+ $availability_timestamp = WC_Pre_Orders_Product::get_localized_availability_datetime_timestamp( $product->get_id() );
+ $availability_timestamp = esc_attr( ( 0 === $availability_timestamp ) ? '' : gmdate( 'Y-m-d H:i', $availability_timestamp ) );
+
+ $data['pre_order_enabled'] = get_post_meta( $product->get_id(), '_wc_pre_orders_enabled', true );
+ $data['has_active_orders'] = $has_orders;
+ $data['availability_datetime'] = $availability_timestamp;
+
+ $response->set_data( $data );
+
+ return $response;
+ }
+
+ /**
+ * Saves custom data to product metadata.
+ *
+ * @param WC_Product $product The product object.
+ * @param WP_REST_Request $request The request object.
+ */
+ public function save_custom_data_to_product_metadata( $product, $request ) {
+ $product_id = $product->get_id();
+ $is_enabled = $request->get_param( 'pre_order_enabled' );
+ $datetime = $request->get_param( 'availability_datetime' );
+
+ require_once 'class-wc-pre-orders-admin-products.php';
+
+ if ( ! empty( $datetime ) ) {
+ WC_Pre_Orders_Admin_Products::save_availability_date_time( $product_id, $datetime );
+ } elseif ( ! is_null( $datetime ) ) {
+ delete_post_meta( $product_id, '_wc_pre_orders_availability_datetime' );
+ }
+
+ if ( $is_enabled ) {
+ update_post_meta( $product_id, '_wc_pre_orders_enabled', 'yes' );
+ } elseif ( ! is_null( $is_enabled ) && false === $is_enabled ) {
+ update_post_meta( $product_id, '_wc_pre_orders_enabled', '' );
+ }
+ }
+
+ /**
+ * Adds a Pre-orders section to the product editor under the 'General' group.
+ *
+ * @since 2.1.0
+ *
+ * @param ProductTemplates\Group $variation_group The group instance.
+ */
+ public function add_pre_orders_section( $variation_group ) {
+ $template = $variation_group->get_root_template();
+ $is_simple_product = $this->is_template_valid( $template, 'simple-product' );
+
+ if ( ! $is_simple_product ) {
+ return;
+ }
+
+ /**
+ * Template instance.
+ *
+ * @var ProductFormTemplateInterface $parent
+ */
+ $parent = $variation_group->get_parent();
+ $group = $parent->add_group(
+ array(
+ 'id' => 'woocommerce-pre-orders-group-tab',
+ 'attributes' => array(
+ 'title' => __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ ),
+ )
+ );
+
+ $section = $group->add_section(
+ array(
+ 'id' => 'woo-pre-orders-section',
+ 'attributes' => array(
+ 'title' => __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ ),
+ )
+ );
+
+ $section->add_block(
+ array(
+ 'id' => 'wc_pre_orders_active_pre_orders_message',
+ 'blockName' => 'woocommerce-pre-orders/message-control-block',
+ 'attributes' => array(
+ 'content' => sprintf(
+ /* translators: %s Actions menu page URL */
+ esc_html__(
+ 'There are active pre-orders for this product. To change the release date, use the Actions menu .',
+ 'woocommerce-pre-orders'
+ ),
+ esc_url( admin_url( 'admin.php?page=wc_pre_orders&tab=actions§ion=change-date&action_default_product=postIdPlaceholder' ) )
+ ),
+ ),
+ 'hideConditions' => array(
+ array(
+ 'expression' => '!editedProduct.has_active_orders',
+ ),
+ ),
+ )
+ );
+
+ $section->add_block(
+ array(
+ 'id' => 'wc_pre_orders_change_settings_message',
+ 'blockName' => 'woocommerce-pre-orders/message-control-block',
+ 'attributes' => array(
+ 'content' => sprintf(
+ /* translators: %s Pre orders admin page URL */
+ esc_html__(
+ 'To change other settings, please complete or cancel the active pre-orders first.',
+ 'woocommerce-pre-orders'
+ ),
+ esc_url( admin_url( 'admin.php?page=wc_pre_orders' ) )
+ ),
+ ),
+ 'hideConditions' => array(
+ array(
+ 'expression' => '!editedProduct.has_active_orders',
+ ),
+ ),
+ )
+ );
+
+ $section->add_block(
+ array(
+ 'id' => 'wc_pre_orders_enabled',
+ 'blockName' => 'woocommerce/product-checkbox-field',
+ 'attributes' => array(
+ 'title' => __( 'Enable pre-orders', 'woocommerce-deposits' ),
+ 'label' => sprintf(
+ __( 'Enable pre-orders for this product.', 'woocommerce-deposits' ),
+ ),
+ 'property' => 'pre_order_enabled',
+ 'checkedValue' => 'yes',
+ ),
+ 'disableConditions' => array(
+ array(
+ 'expression' => 'editedProduct.has_active_orders',
+ ),
+ ),
+ )
+ );
+
+ $section->add_block(
+ array(
+ 'id' => 'wc_pre_orders_fee',
+ 'blockName' => 'woocommerce/product-pricing-field',
+ 'attributes' => array(
+ 'property' => 'meta_data._wc_pre_orders_fee',
+ 'label' => __( 'Pre-order Fee', 'woocommerce-pre-orders' ),
+ 'help' => __( 'Set a fee to be charged when a pre-order is placed. Leave blank to not charge a pre-order fee.', 'woocommerce-pre-orders' ),
+ ),
+ 'disableConditions' => array(
+ array(
+ 'expression' => 'editedProduct.has_active_orders',
+ ),
+ ),
+ )
+ );
+
+ $section->add_block(
+ array(
+ 'id' => 'wc_pre_orders_availability_datetime',
+ 'blockName' => 'woocommerce-pre-orders/date-time-picker',
+ 'attributes' => array(
+ 'property' => 'availability_datetime',
+ 'title' => __( 'Availability date/time', 'woocommerce-pre-orders' ),
+ 'help' => __( 'Set the date & time that this pre-order will be available. The product will behave as a normal product when this date/time is reached.', 'woocommerce-pre-orders' ),
+ ),
+ 'disableConditions' => array(
+ array(
+ 'expression' => 'editedProduct.has_active_orders',
+ ),
+ ),
+ )
+ );
+
+ $section->add_block(
+ array(
+ 'id' => 'wc_pre_orders_when_to_charge',
+ 'blockName' => 'woocommerce-pre-orders/select-control-block',
+ 'attributes' => array(
+ 'property' => 'meta_data._wc_pre_orders_when_to_charge',
+ 'title' => __( 'When to Charge', 'woocommerce-pre-orders' ),
+ 'help' => __( 'Select "Upon Release" to charge the entire pre-order amount (the product price + pre-order fee if applicable) when the pre-order becomes available. Select "Upfront" to charge the pre-order amount during the initial checkout.', 'woocommerce-pre-orders' ),
+ 'options' => array(
+ array(
+ 'value' => 'upfront',
+ 'label' => __( 'Upfront', 'woocommerce-pre-orders' ),
+ ),
+ array(
+ 'value' => 'upon_release',
+ 'label' => __( 'Upon Release', 'woocommerce-pre-orders' ),
+ ),
+ ),
+ ),
+ 'disableConditions' => array(
+ array(
+ 'expression' => 'editedProduct.has_active_orders',
+ ),
+ ),
+ )
+ );
+ }
+
+ /**
+ * Returns true if the template is valid.
+ *
+ * @param SimpleProductTemplate|ProductVariationTemplate $template The template object.
+ * @param string $template_id The template ID.
+ *
+ * @return bool
+ */
+ private function is_template_valid( $template, $template_id ) {
+ return $template_id === $template->get_id();
+ }
+}
+
+new WC_Pre_Orders_Product_Editor_Compatibility();
diff --git a/includes/admin/filters.php b/includes/admin/filters.php
new file mode 100644
index 0000000..83863e8
--- /dev/null
+++ b/includes/admin/filters.php
@@ -0,0 +1,56 @@
+key ) {
+ $meta_value = date( 'Y-m-d H:i:s', $meta_value );
+ }
+
+ return $meta_value;
+ },
+ 10,
+ 2
+);
+
+add_filter(
+ 'woocommerce_product_import_process_item_data',
+
+ /**
+ * Should return date in timestamp date format for "_wc_pre_orders_availability_datetime" meta key.
+ *
+ * @since 2.0.0
+ *
+ * @param array $parsed_data Array of csv row data.
+ *
+ * @returns array
+ */
+ function ( $data ) {
+ if ( empty( $data['meta_data'] ) ) {
+ return $data;
+ }
+
+ $meta_keys = wp_list_pluck( $data['meta_data'], 'key' );
+ $index = array_search( '_wc_pre_orders_availability_datetime', $meta_keys, true );
+
+ if ( false !== $index && $data['meta_data'][ $index ]['value'] ) {
+ $data['meta_data'][ $index ] = array_merge(
+ $data['meta_data'][ $index ],
+ array( 'value' => strtotime( $data['meta_data'][ $index ]['value'] ) )
+ );
+ }
+
+ return $data;
+ }
+);
diff --git a/includes/admin/views/html-product-tab-options.php b/includes/admin/views/html-product-tab-options.php
new file mode 100644
index 0000000..605f3be
--- /dev/null
+++ b/includes/admin/views/html-product-tab-options.php
@@ -0,0 +1,87 @@
+
+
+
+
+ ID );
+ if ( $has_active_pre_orders ) {
+ // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
+ echo '
' . sprintf( esc_html__( 'There are active pre-orders for this product. To change the release date, %1$suse the Actions menu%2$s.', 'woocommerce-pre-orders' ), '', ' ' ) . '
';
+
+ // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
+ echo '
' . sprintf( esc_html__( 'To change other settings, please %1$scomplete or cancel the active pre-orders%2$s first.', 'woocommerce-pre-orders' ), '', ' ' ) . '
';
+ }
+
+ do_action( 'wc_pre_orders_product_options_start' );
+
+ // Enable pre-orders.
+ woocommerce_wp_checkbox(
+ array(
+ 'id' => '_wc_pre_orders_enabled',
+ 'label' => __( 'Enable pre-orders', 'woocommerce-pre-orders' ),
+ 'description' => __( 'Enable pre-orders for this product.', 'woocommerce-pre-orders' ),
+ )
+ );
+
+ // Availability date/time.
+ $availability_timestamp = WC_Pre_Orders_Product::get_localized_availability_datetime_timestamp( $post->ID );
+ ?>
+
+
+
+
+
+ '_wc_pre_orders_fee',
+ 'label' => __( 'Pre-order Fee', 'woocommerce-pre-orders' ) . ' (' . get_woocommerce_currency_symbol() . ') ',
+ 'description' => __( 'Set a fee to be charged when a pre-order is placed. Leave blank to not charge a pre-order fee.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ )
+ );
+
+ woocommerce_wp_select(
+ array(
+ 'id' => '_wc_pre_orders_when_to_charge',
+ 'class' => 'wc-enhanced-select',
+ 'label' => __( 'When to Charge', 'woocommerce-pre-orders' ),
+ 'description' => __( 'Select "Upon Release" to charge the entire pre-order amount (the product price + pre-order fee if applicable) when the pre-order becomes available. Select "Upfront" to charge the pre-order amount during the initial checkout.', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ 'default' => 'upon_release',
+ 'options' => array(
+ 'upon_release' => __( 'Upon release', 'woocommerce-pre-orders' ),
+ 'upfront' => __( 'Upfront', 'woocommerce-pre-orders' ),
+ ),
+ )
+ );
+
+ do_action( 'wc_pre_orders_product_options_end' );
+ ?>
+
+
+ $( 'input[name^=_wc_pre_orders_], select#_wc_pre_orders_when_to_charge' ).attr( 'disabled', true );
+ $( 'img.ui-datepicker-trigger' ).css( 'display', 'none' );
+ add_inline_js( ob_get_clean() );
+ }
+ }
+ ?>
+
diff --git a/includes/blocks/class-wc-pre-orders-blocks-gateway.php b/includes/blocks/class-wc-pre-orders-blocks-gateway.php
new file mode 100644
index 0000000..ae8244e
--- /dev/null
+++ b/includes/blocks/class-wc-pre-orders-blocks-gateway.php
@@ -0,0 +1,140 @@
+asset_api = $asset_api;
+ }
+
+ /**
+ * Initializes the payment method type.
+ */
+ public function initialize() {
+
+ $payment_gateways = WC()->payment_gateways->payment_gateways();
+ $is_enabled = isset( $payment_gateways['pre_orders_pay_later'] ) ? $payment_gateways['pre_orders_pay_later']->enabled : 'no';
+
+ $this->enabled = $is_enabled;
+ }
+
+ /**
+ * Returns if this payment method should be active. If false, the scripts will not be enqueued.
+ *
+ * @return boolean
+ */
+ public function is_active() {
+
+ if ( 'yes' !== $this->enabled ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns an array of scripts/handles to be registered for this payment method.
+ *
+ * @return array
+ */
+ public function get_payment_method_script_handles() {
+
+ $base_path = WC_PRE_ORDERS_PLUGIN_PATH;
+ $asset_url = WC_PRE_ORDERS_PLUGIN_URL . '/build/gateway/index.js';
+ $css_url = WC_PRE_ORDERS_PLUGIN_URL . '/build/gateway/index.css';
+ $version = WC_PRE_ORDERS_VERSION;
+ $asset_path = $base_path . '/build/index.asset.php';
+
+ $dependencies = array();
+ if ( file_exists( $asset_path ) ) {
+ $asset = require $asset_path;
+ $version = is_array( $asset ) && isset( $asset['version'] )
+ ? $asset['version']
+ : $version;
+ $dependencies = is_array( $asset ) && isset( $asset['dependencies'] )
+ ? $asset['dependencies']
+ : $dependencies;
+ }
+
+ wp_register_script(
+ 'pre_orders_pay_later',
+ $asset_url,
+ $dependencies,
+ $version,
+ true
+ );
+
+ wp_enqueue_style(
+ 'pre_orders_pay_later_css',
+ $css_url,
+ array(),
+ $version
+ );
+
+ return array( 'pre_orders_pay_later' );
+ }
+
+ /**
+ * Gets payment method supported features.
+ *
+ * @return array
+ */
+ public function get_supported_features() {
+ return array( 'products', 'pre-orders' );
+ }
+
+ /**
+ * Returns an array of key=>value pairs of data made available to the payment methods script.
+ *
+ * @return array
+ */
+ public function get_payment_method_data() {
+
+ return array(
+ 'title' => __( 'Pay later', 'woocommerce-pre-orders' ),
+ 'description' => __( 'You will receive an email when the pre-order is available along with instructions on how to complete your order.', 'woocommerce-pre-orders' ),
+ 'order_button_text' => get_option( 'wc_pre_orders_place_order_button_text', __( 'Place pre-order now', 'woocommerce-pre-orders' ) ),
+ 'supports' => $this->get_supported_features(),
+ 'is_enabled' => WC_Pre_Orders_Blocks_Integration::is_pre_order_and_charged_upon_release(),
+ );
+ }
+}
diff --git a/includes/blocks/class-wc-pre-orders-blocks-integration.php b/includes/blocks/class-wc-pre-orders-blocks-integration.php
new file mode 100644
index 0000000..6d7b44c
--- /dev/null
+++ b/includes/blocks/class-wc-pre-orders-blocks-integration.php
@@ -0,0 +1,119 @@
+includes();
+
+ // Add woocommerce blocks support.
+ $this->add_woocommerce_block_support();
+ }
+
+ /**
+ * Add payment method block support.
+ */
+ public function add_woocommerce_block_support() {
+
+ if ( class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) {
+ // Register payment method integrations.
+ add_action( 'woocommerce_blocks_payment_method_type_registration', array( $this, 'register_payment_method_integrations' ) );
+ $this->register_payment_methods();
+ $this->blocks_loaded();
+ }
+ }
+
+ /**
+ * Register payment method.
+ *
+ * @return WC_Pre_Orders_Blocks_Gateway $instance pre-orders gateway instance.
+ */
+ protected function register_payment_methods() {
+ $container = Package::container();
+
+ $container->register(
+ WC_Pre_Orders_Blocks_Gateway::class,
+ function( Container $container ) {
+ $asset_api = $container->get( AssetApi::class );
+ return new WC_Pre_Orders_Blocks_Gateway( $asset_api );
+ }
+ );
+ }
+
+ /**
+ * Register the payment requirements for blocks.
+ *
+ * @return void
+ */
+ public function blocks_loaded() {
+ $args = array(
+ 'data_callback' => array( $this, 'add_pre_order_availability_payment_requirement' ),
+ );
+ if ( function_exists( 'woocommerce_store_api_register_payment_requirements' ) ) {
+ woocommerce_store_api_register_payment_requirements( $args );
+ } else {
+ $extend = Package::container()->get( ExtendRestApi::class );
+ $extend->register_payment_requirements( $args );
+ }
+ WC_Pre_Orders_Extend_Store_API::init();
+ }
+
+ /**
+ * Check if is a pre-order and charged upon release.
+ *
+ * @return bool
+ */
+ public static function is_pre_order_and_charged_upon_release() {
+ return \WC_Pre_Orders_Cart::cart_contains_pre_order() && \WC_Pre_Orders_Product::product_is_charged_upon_release( \WC_Pre_Orders_Cart::get_pre_order_product() );
+ }
+
+ /**
+ * Adds pre_order availability payment requirement for carts that contain a product that requires it.
+ *
+ * @return array
+ */
+ public function add_pre_order_availability_payment_requirement() {
+ if ( $this->is_pre_order_and_charged_upon_release() ) {
+ return array( 'pre-orders' );
+ }
+ return array();
+ }
+
+ /**
+ * Register payment method integration.
+ *
+ * @param PaymentMethodRegistry $payment_method_registry Payment method registry object.
+ */
+ public function register_payment_method_integrations( PaymentMethodRegistry $payment_method_registry ) {
+
+ $payment_method_registry->register(
+ Package::container()->get( WC_Pre_Orders_Blocks_Gateway::class )
+ );
+ }
+
+ /**
+ * Include class that represents the gateway.
+ */
+ public function includes() {
+ require_once __DIR__ . '/class-wc-pre-orders-blocks-gateway.php';
+ }
+}
diff --git a/includes/blocks/class-wc-pre-orders-extend-store-api.php b/includes/blocks/class-wc-pre-orders-extend-store-api.php
new file mode 100644
index 0000000..39df5db
--- /dev/null
+++ b/includes/blocks/class-wc-pre-orders-extend-store-api.php
@@ -0,0 +1,107 @@
+ CartItemSchema::IDENTIFIER,
+ 'namespace' => self::IDENTIFIER,
+ 'data_callback' => array( 'WooCommerce\Pre_Orders\Blocks\WC_Pre_Orders_Extend_Store_API', 'extend_cart_item_data' ),
+ 'schema_callback' => array( 'WooCommerce\Pre_Orders\Blocks\WC_Pre_Orders_Extend_Store_API', 'extend_cart_item_schema' ),
+ 'schema_type' => ARRAY_A,
+ );
+
+ if ( function_exists( 'woocommerce_store_api_register_endpoint_data' ) ) {
+ woocommerce_store_api_register_endpoint_data( $args );
+ } else {
+ $extend = Package::container()->get( ExtendRestApi::class );
+ $extend->register_endpoint_data( $args );
+ }
+ }
+
+ /**
+ * Register pre-order product type data into cart/items endpoint.
+ *
+ * @param array $cart_item Current cart item data.
+ *
+ * @return array $item_data Registered data or empty array if condition is not satisfied.
+ */
+ public static function extend_cart_item_data( $cart_item ) {
+ $product = $cart_item['data'];
+ $item_data = array(
+ 'availability' => null,
+ 'charged_upon_release' => null,
+ 'charged_upfront' => null,
+ );
+
+ if ( \WC_Pre_Orders_Product::product_can_be_pre_ordered( $product->get_id() ) ) {
+ $item_data = array(
+ 'availability' => \WC_Pre_Orders_Product::get_localized_availability_date( $product ),
+ 'charged_upon_release' => \WC_Pre_Orders_Product::product_is_charged_upon_release( $product ),
+ 'charged_upfront' => \WC_Pre_Orders_Product::product_is_charged_upfront( $product ),
+ );
+ }
+
+ return $item_data;
+ }
+
+ /**
+ * Register pre-order product type schema into cart/items endpoint.
+ *
+ * @return array Registered schema.
+ */
+ public static function extend_cart_item_schema() {
+ return array(
+ 'availability' => array(
+ 'description' => __( 'Availability date for product.', 'woocommerce-pre-orders' ),
+ 'type' => array( 'string', 'null' ),
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'charged_upon_release' => array(
+ 'description' => __( 'Indicates if customer is going to be charged only when product is released.', 'woocommerce-pre-orders' ),
+ 'type' => array( 'boolean', 'null' ),
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ 'charged_upfront' => array(
+ 'description' => __( 'Indicates if customer is going to be charged upfront.', 'woocommerce-pre-orders' ),
+ 'type' => array( 'boolean', 'null' ),
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ ),
+ );
+ }
+}
diff --git a/includes/class-wc-pre-orders-cart.php b/includes/class-wc-pre-orders-cart.php
new file mode 100644
index 0000000..0723d91
--- /dev/null
+++ b/includes/class-wc-pre-orders-cart.php
@@ -0,0 +1,296 @@
+cart_contains_pre_order() ) {
+ $total = WC_Pre_Orders_Manager::get_formatted_pre_order_total( $total, self::get_pre_order_product() );
+ }
+
+ return $total;
+ }
+
+
+ /**
+ * Get item data to display on cart/checkout pages that shows the availability date of the pre-order
+ *
+ * @since 1.0
+ * @param array $item_data any existing item data
+ * @param array $cart_item the cart item
+ * @return array
+ */
+ public function get_item_data( $item_data, $cart_item ) {
+
+ // only modify pre-orders on cart/checkout page
+ if ( ! $this->cart_contains_pre_order() ) {
+ return $item_data;
+ }
+
+ // get title text
+ $name = get_option( 'wc_pre_orders_availability_date_cart_title_text' );
+
+ // don't add if empty
+ if ( ! $name ) {
+ return $item_data;
+ }
+
+ $pre_order_meta = apply_filters(
+ 'wc_pre_orders_cart_item_meta',
+ array(
+ 'name' => $name,
+ 'display' => WC_Pre_Orders_Product::get_localized_availability_date( $cart_item['data'] ),
+ ),
+ $cart_item
+ );
+
+ // add title and localized date
+ if ( ! empty( $pre_order_meta ) ) {
+ $item_data[] = $pre_order_meta;
+ }
+
+ return $item_data;
+ }
+
+ /**
+ * Redirect to the cart
+ */
+ public function redirect_to_cart() {
+
+ $data = array(
+ 'error' => true,
+ 'product_url' => wc_get_cart_url(),
+ );
+
+ wp_send_json( $data );
+ }
+
+ /**
+ * When a pre-order is added to the cart, remove any other products
+ *
+ * @since 1.0
+ * @param bool $valid
+ * @param $product_id
+ * @return bool
+ */
+ public function validate_cart( $valid, $product_id ) {
+ global $woocommerce;
+
+ if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $product_id ) ) {
+
+ // if a pre-order product is being added to cart, check if the cart already contains other products and empty it if it does
+ if ( $woocommerce->cart->get_cart_contents_count() >= 1 ) {
+
+ $woocommerce->cart->empty_cart();
+
+ $string = __( 'Your previous cart was emptied because pre-orders must be purchased separately.', 'woocommerce-pre-orders' );
+
+ // Backwards compatible (pre 2.1) for outputting notice
+ if ( function_exists( 'wc_add_notice' ) ) {
+ wc_add_notice( $string );
+ } else {
+ $woocommerce->add_message( $string );
+ }
+
+ // when adding via ajax, redirect to cart page so that above notices show up
+ add_action( 'woocommerce_ajax_added_to_cart', array( $this, 'redirect_to_cart' ) );
+ }
+
+ // return what was passed in, allowing the pre-order to be added
+ return $valid;
+
+ } else {
+
+ // if there's a pre-order in the cart already, prevent anything else from being added
+ if ( $this->cart_contains_pre_order() ) {
+
+ if ( function_exists( 'wc_add_notice' ) ) {
+ wc_add_notice( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'woocommerce-pre-orders' ), 'error' );
+ } else {
+ // Backwards compatible (pre 2.1) for outputting notice.
+ $woocommerce->add_error( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'woocommerce-pre-orders' ) );
+ }
+
+ $valid = false;
+ }
+ }
+
+ return $valid;
+ }
+
+
+ /**
+ * Add any applicable pre-order fees when calculating totals
+ *
+ * @since 1.0
+ */
+ public function maybe_add_pre_order_fee() {
+ global $woocommerce;
+
+ // Only add pre-order fees if the cart contains a pre-order
+ if ( ! $this->cart_contains_pre_order() ) {
+ return;
+ }
+
+ // Make sure the pre-order fee hasn't already been added
+ if ( $this->cart_contains_pre_order_fee() ) {
+ return;
+ }
+
+ $product = self::get_pre_order_product();
+ $fee = $this->generate_fee( $product );
+
+ if ( null !== $fee ) {
+ $woocommerce->cart->add_fee( $fee['label'], $fee['amount'], $fee['tax_status'] );
+ }
+
+ }
+
+ /**
+ * Generates fee
+ *
+ * @since 1.6.0
+ * @param WC_Product|int $product
+ * @return array|null
+ */
+ public function generate_fee( $product ) {
+
+ // Get pre-order amount
+ $amount = WC_Pre_Orders_Product::get_pre_order_fee( $product );
+
+ if ( 0 >= $amount ) {
+ return;
+ }
+
+ return apply_filters(
+ 'wc_pre_orders_fee',
+ array(
+ 'label' => __( 'Pre-order fee', 'woocommerce-pre-orders' ),
+ 'amount' => $amount,
+ 'tax_status' => WC_Pre_Orders_Product::get_pre_order_fee_tax_status( $product ), // pre order fee inherits tax status of product
+ )
+ );
+ }
+
+ /**
+ * Checks if the current cart contains a product with pre-orders enabled
+ *
+ * @since 1.0
+ * @return bool true if the cart contains a pre-order, false otherwise
+ */
+ public static function cart_contains_pre_order() {
+ global $woocommerce;
+
+ $contains_pre_order = false;
+
+ if ( ! empty( $woocommerce->cart->cart_contents ) ) {
+
+ foreach ( $woocommerce->cart->cart_contents as $cart_item ) {
+ $product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
+ if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $product_id ) ) {
+
+ $contains_pre_order = true;
+ break;
+ }
+ }
+ }
+
+ return $contains_pre_order;
+ }
+
+
+ /**
+ * Checks if the current cart contains a pre-order fee
+ *
+ * @since 1.0
+ * @return bool true if the cart contains a pre-order fee, false otherwise
+ */
+ public static function cart_contains_pre_order_fee() {
+ global $woocommerce;
+
+ foreach ( $woocommerce->cart->get_fees() as $fee ) {
+
+ if ( is_object( $fee ) && 'pre-order-fee' == $fee->id ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Since a cart may only contain a single pre-ordered product, this returns the pre-ordered product object or
+ * null if the cart does not contain a pre-order
+ *
+ * @since 1.0
+ * @return object|null the pre-ordered product object, or null if the cart does not contain a pre-order
+ */
+ public static function get_pre_order_product() {
+ global $woocommerce;
+
+ if ( self::cart_contains_pre_order() ) {
+
+ foreach ( $woocommerce->cart->cart_contents as $cart_item ) {
+
+ if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $cart_item['product_id'] ) ) {
+
+ // return the product object
+ return wc_get_product( $cart_item['product_id'] );
+ }
+ }
+ } else {
+
+ // cart doesn't contain pre-order
+ return null;
+ }
+ }
+
+} // end \WC_Pre_Orders_Cart class
diff --git a/includes/class-wc-pre-orders-checkout.php b/includes/class-wc-pre-orders-checkout.php
new file mode 100644
index 0000000..b4cad50
--- /dev/null
+++ b/includes/class-wc-pre-orders-checkout.php
@@ -0,0 +1,317 @@
+=' ) ) {
+ add_action( 'woocommerce_store_api_checkout_update_order_meta', array( $this, 'add_order_meta_by_order' ) );
+ } else {
+ add_action( 'woocommerce_blocks_checkout_update_order_meta', array( $this, 'add_order_meta_by_order' ) );
+ }
+
+ // change status to pre-ordered when payment is completed for a pre-order charged upfront
+ add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'update_payment_complete_order_status' ), 10, 2 );
+
+ // change status to pre-ordered when payment is completed for a pre-order charged upfront ( for gateways that do not call WC_Order::payment_complete() )
+ add_action( 'woocommerce_order_status_on-hold_to_processing', array( $this, 'update_manual_payment_complete_order_status' ) );
+ add_action( 'woocommerce_order_status_on-hold_to_completed', array( $this, 'update_manual_payment_complete_order_status' ) );
+ add_action( 'woocommerce_order_status_pending_to_processing', array( $this, 'update_manual_payment_complete_order_status' ) );
+
+ // change status to pre-ordered when payment is completed for a pre-order charged upfront that previously failed
+ add_action( 'woocommerce_order_status_failed_to_processing', array( $this, 'update_manual_payment_complete_order_status' ) );
+ add_action( 'woocommerce_order_status_failed_to_completed', array( $this, 'update_manual_payment_complete_order_status' ) );
+
+ // Remove the "is_pre_order" flag when the order is charged upfront and fails.
+ add_action( 'woocommerce_order_status_pending_to_failed', array( $this, 'remove_is_pre_order_on_failure' ) );
+
+ // Filter the thank you page to add release date message.
+ add_filter( 'woocommerce_thankyou_order_received_text', array( $this, 'add_release_date_message' ), 10, 2 );
+ }
+
+ /**
+ * Adds release date message to thank you page.
+ * Only shows for charge upon release.
+ *
+ * @since 1.5.4
+ * @version 1.5.4
+ * @param string $message Original message
+ * @param object $order
+ * @return string
+ */
+ public function add_release_date_message( $message, $order ) {
+ if ( ! WC_Pre_Orders_Order::get_pre_order_product( $order ) ) {
+ return $message;
+ }
+
+ if ( ! WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) ) {
+ return $message;
+ }
+
+ $availability_date = WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $order ) );
+
+ /* translators: %s: availability date */
+ $availability_date_text = ( ! empty( $availability_date ) ) ? sprintf( __( ' on %s.', 'woocommerce-pre-orders' ), $availability_date ) : '.';
+
+ /* translators: 1: availability date */
+ $message = sprintf( __( 'Your pre-order has been received. You will be prompted for payment for your order when your pre-order is released%s Your order details are shown below for your reference.', 'woocommerce-pre-orders' ), $availability_date_text ) . "\n\n";
+
+ if ( WC_Pre_Orders_Order::order_has_payment_token( $order ) ) {
+ /* translators: 1: availability date */
+ $message = sprintf( __( 'Your pre-order has been received. You will be automatically charged for your order via your selected payment method when your pre-order is released%s Your order details are shown below for your reference.', 'woocommerce-pre-orders' ), $availability_date_text ) . "\n\n";
+ }
+
+ return $message;
+ }
+
+ /**
+ * Check if is a pre-order and charged upon release
+ *
+ * @return bool
+ */
+ protected function is_pre_order_and_charged_upon_release() {
+ return WC_Pre_Orders_Cart::cart_contains_pre_order() && WC_Pre_Orders_Product::product_is_charged_upon_release( WC_Pre_Orders_Cart::get_pre_order_product() );
+ }
+
+ /**
+ * Conditionally remove any gateways that don't support pre-orders on the checkout page when the pre-order is charged
+ * upon release. This is done because payment info is not required in this case so displaying gateways/payment fields
+ * is not needed.
+ *
+ * @since 1.0
+ *
+ * @param array $available_gateways
+ *
+ * @return array
+ */
+ public function maybe_remove_unsupported_gateways( $available_gateways ) {
+
+ // Backwards compatibility checking for payment page
+ if ( function_exists( 'is_checkout_pay_page' ) ) {
+ $pay_page = is_checkout_pay_page();
+ } else {
+ $pay_page = is_page( wc_get_page_id( 'pay' ) );
+ }
+
+ // On checkout page
+ if (
+ ( $pay_page && $this->is_pre_order_and_charged_upon_release() ) ||
+ ( is_checkout() && $this->is_pre_order_and_charged_upon_release() )
+ ) {
+
+ // Remove any non-supported payment gateways
+ foreach ( $available_gateways as $gateway_id => $gateway ) {
+ if ( ! method_exists( $gateway, 'supports' ) || false === $gateway->supports( 'pre-orders' ) || 'no' == $gateway->enabled ) {
+ unset( $available_gateways[ $gateway_id ] );
+ }
+ }
+ }
+
+ return apply_filters( 'wc_pre_orders_remove_unsupported_gateways', $available_gateways, $this->is_pre_order_and_charged_upon_release() );
+ }
+
+ /**
+ * Modifies the 'Place Order' button text on the checkout page
+ *
+ * @since 1.0
+ * @param string $default_text default place order button text
+ * @return string
+ */
+ public function modify_place_order_button_text( $default_text ) {
+
+ // only modify button text if the cart contains a pre-order
+ if ( ! WC_Pre_Orders_Cart::cart_contains_pre_order() ) {
+ return $default_text;
+ }
+
+ // get custom text if set
+ $text = get_option( 'wc_pre_orders_place_order_button_text' );
+
+ if ( $text ) {
+ return $text;
+ } else {
+ return $default_text;
+ }
+ }
+
+ /**
+ * Adds order meta needed for pre-order functionality,
+ * when coming from an order using WooCommerce Blocks.
+ *
+ * @param WC_Order $order
+ */
+ public function add_order_meta_by_order( $order ) {
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ $this->add_order_meta( $order_id );
+ }
+ }
+
+ /**
+ * Add order meta needed for pre-order functionality
+ *
+ * @since 1.0
+ * @param int $order_id
+ */
+ public function add_order_meta( $order_id ) {
+
+ // don't add meta to orders that don't contain a pre-order
+ // note the cart is checked here instead of the order since WC_Pre_Orders_Order::order_contains_pre_order() checks the meta that is about to be set here :)
+ if ( ! WC_Pre_Orders_Cart::cart_contains_pre_order() ) {
+ return;
+ }
+
+ // get pre-ordered product
+ $product = WC_Pre_Orders_Cart::get_pre_order_product( $order_id );
+ $order = wc_get_order( $order_id );
+
+ // indicate the order contains a pre-order
+ $order->update_meta_data( '_wc_pre_orders_is_pre_order', 1 );
+
+ // save when the pre-order amount was charged (either upfront or upon release)
+ $order->update_meta_data( '_wc_pre_orders_when_charged', get_post_meta( $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(), '_wc_pre_orders_when_to_charge', true ) );
+
+ $order->save();
+ }
+
+ /**
+ * Update payment complete order status to pre-ordered for orders that are charged upfront. This handles gateways
+ * that call payment_complete() and prevents an awkward status change from pending->processing->pre-ordered, instead
+ * just showing a nice, clean pending->pre-ordered.
+ *
+ * @since 1.0.0
+ * @version 1.5.1
+ * @param string $new_status the status to change the order to.
+ * @param int $order_id the post ID of the order.
+ * @return string
+ */
+ public function update_payment_complete_order_status( $new_status, $order_id ) {
+
+ $order = wc_get_order( $order_id );
+ if ( ! $order || ! WC_Pre_Orders_Order::order_contains_pre_order( $order ) ) {
+ return $new_status;
+ }
+
+ $zero_cost_order = WC_Pre_Orders_Manager::is_zero_cost_order( $order );
+
+ // Don't change status if pre-order will be charged upon release.
+ if ( WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) && ! $zero_cost_order ) {
+ return $new_status;
+ }
+
+ return 'pre-ordered';
+ }
+
+ /**
+ * updates order status to pre-ordered for orders that are charged upfront. This handles gateways that don't call
+ * payment_complete(). Unfortunately status changes show like pending->processing/completed->pre-ordered
+ *
+ * @since 2.0.4 Check whether product can be pre-ordered when processing failed order.
+ * @since 1.9.1 Improve support for "Failed" orders.
+ * @since 1.9.0 Check whether the order item was pre-ordered to process failed pre-ordered order.
+ * @since 1.0
+ * @param int $order_id the post ID of the order
+ * @return string
+ */
+ public function update_manual_payment_complete_order_status( $order_id ) {
+
+ $order = new WC_Order( $order_id );
+ $order_item = WC_Pre_Orders_Order::get_pre_order_item( $order );
+ $product_id = $order_item ? wc_get_product( $order_item['product_id'] ) : null;
+
+ // Failed order does not have "_wc_pre_orders_is_pre_order" meta key.
+ // We remove this meta key to hide failed orders from the "Pre-orders" page.
+ // For this reason, we need to check whether order has a pre-ordered item.
+ $action_hooks = [
+ 'woocommerce_order_status_failed_to_processing',
+ 'woocommerce_order_status_failed_to_completed'
+ ];
+
+ $is_failed_pre_order = in_array( current_action(), $action_hooks ) &&
+ ( WC_Pre_Orders_Order::get_pre_order_item( $order ) instanceof WC_Order_Item ) &&
+ ( $product_id && WC_Pre_Orders_Product::product_can_be_pre_ordered( $product_id ) );
+
+
+ // don't update status for non pre-order orders
+ if ( ! $is_failed_pre_order && ! WC_Pre_Orders_Order::order_contains_pre_order( $order ) ) {
+ return;
+ }
+
+ // don't update if pre-order will be charged upon release
+ if ( WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) ) {
+ return;
+ }
+
+ // indicate the order contains a pre-order
+ $order->update_meta_data( '_wc_pre_orders_is_pre_order', 1 );
+
+ // change order status to pre-ordered
+ $order->update_status( 'pre-ordered' );
+
+ // Save order.
+ $order->save();
+ }
+
+ /**
+ * Removes the "_wc_pre_orders_is_pre_order" flag when charged ufront and the payment fails.
+ *
+ * This prevents the pre-order from showing up under the Pre-Orders
+ * table when the payment must be done upfront but fails.
+ *
+ * @since 1.5.31
+ * @param int $order_id the post ID of the order.
+ * @return void
+ */
+ public function remove_is_pre_order_on_failure( $order_id ) {
+ $order = wc_get_order( $order_id );
+
+ // Don't update status for non pre-order orders.
+ if ( ! WC_Pre_Orders_Order::order_contains_pre_order( $order ) ) {
+ return;
+ }
+
+ // Don't update if pre-order will be charged upon release.
+ if ( WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) ) {
+ return;
+ }
+
+ // Remove the pre-order flag on failure.
+ $order->delete_meta_data( '_wc_pre_orders_is_pre_order' );
+ $order->save();
+ }
+
+
+} // end \WC_Pre_Orders_Checkout class
diff --git a/includes/class-wc-pre-orders-cron.php b/includes/class-wc-pre-orders-cron.php
new file mode 100644
index 0000000..11ad754
--- /dev/null
+++ b/includes/class-wc-pre-orders-cron.php
@@ -0,0 +1,78 @@
+ $interval,
+ 'display' => sprintf( __( 'Every %d minutes', 'woocommerce-pre-orders' ), $interval / 60 ),
+ );
+
+ return $schedules;
+ }
+
+
+ /**
+ * Add scheduled events to wp-cron if not already added
+ *
+ * @since 1.0
+ * @return array
+ */
+ public function add_scheduled_events() {
+
+ // Schedule pre-order completion check with custom interval named 'wc_pre_orders_completion_check'
+ // note the next execution time if the plugin is deactivated then reactivated is the current time + 5 minutes
+ if ( ! wp_next_scheduled( 'wc_pre_orders_completion_check' ) ) {
+ wp_schedule_event( time() + 300, 'wc_pre_orders_completion_check', 'wc_pre_orders_completion_check' );
+ }
+ }
+
+
+} // end \WC_Pre_Orders_Cron class
diff --git a/includes/class-wc-pre-orders-list-table.php b/includes/class-wc-pre-orders-list-table.php
new file mode 100644
index 0000000..3286bca
--- /dev/null
+++ b/includes/class-wc-pre-orders-list-table.php
@@ -0,0 +1,856 @@
+ __( 'Pre-order', 'woocommerce-pre-orders' ),
+ 'plural' => __( 'Pre-orders', 'woocommerce-pre-orders' ),
+ 'ajax' => false,
+ )
+ );
+ }
+
+ /**
+ * Gets the bulk actions available for pre-orders: complete, cancel
+ * or message.
+ *
+ * @see WP_List_Table::get_bulk_actions()
+ * @since 1.0
+ * @return array associative array of action_slug => action_title
+ */
+ public function get_bulk_actions() {
+
+ $actions = array(
+ 'cancel' => __( 'Cancel', 'woocommerce-pre-orders' ),
+ 'complete' => __( 'Complete', 'woocommerce-pre-orders' ),
+ 'message' => __( 'Customer message', 'woocommerce-pre-orders' ),
+ );
+
+ return $actions;
+ }
+
+ /**
+ * Get list of views available (one per available pre-order status) plus
+ * default of 'all', with counts for each
+ *
+ * @see WP_List_Table::get_views()
+ * @since 1.0
+ * @return array
+ */
+ public function get_views() {
+ global $wpdb;
+
+ if ( ! isset( $this->views ) ) {
+ $this->views = array();
+
+ $_order_meta = $wpdb->postmeta;
+ $_order = $wpdb->posts;
+ $_order_id = 'ID';
+ $_order_meta_id = 'post_id';
+ $_cpt_clause = "AND _order.post_type = 'shop_order' AND _order.post_status != 'trash'";
+
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $_order_meta = $wpdb->prefix . 'wc_orders_meta';
+ $_order = $wpdb->prefix . 'wc_orders';
+ $_order_id = 'id';
+ $_order_meta_id = 'order_id';
+ $_cpt_clause = '';
+ }
+
+ $query = "
+ SELECT COUNT(_order_meta.meta_value) AS count, _order_meta.meta_value as status
+ FROM {$_order_meta} _order_meta
+ LEFT JOIN {$_order} _order ON (_order.{$_order_id} = _order_meta.{$_order_meta_id})
+ WHERE _order_meta.meta_key = '_wc_pre_orders_status'
+ {$_cpt_clause}
+ AND _order_meta.{$_order_meta_id} IN (
+ SELECT {$_order_meta_id} FROM {$_order_meta}
+ WHERE meta_key = '_wc_pre_orders_is_pre_order'
+ AND CAST(meta_value AS CHAR) = '1'
+ )
+ GROUP BY _order_meta.meta_value
+ ";
+
+ $results = $wpdb->get_results( $query );
+
+ // get the special all/trash counts and organize into status => count
+ $counts = array( 'all' => 0 );
+ $trash_count = 0;
+ foreach ( $results as $row ) {
+ if ( 'trash' === $row->status ) {
+ $trash_count += $row->count;
+ } else {
+ $counts[ $row->status ] = $row->count;
+ $counts['all'] += $row->count;
+ }
+ }
+ $counts['trash'] = $trash_count;
+
+ $base_url = admin_url( 'admin.php?page=wc_pre_orders' );
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_REQUEST['s'] ) ) {
+ $search_string = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+
+ // When an array is provided, sanitize_text_field returns an empty string.
+ if ( '' !== $search_string ) {
+ $base_url = add_query_arg( 's', rawurlencode( $search_string ), $base_url );
+ }
+ }
+
+ // build the set of views, if any
+ foreach ( $counts as $status => $count ) {
+ if ( $count > 0 ) {
+ if ( $this->get_current_pre_order_status( $counts ) === $status ) {
+ $class = ' class="current"';
+ } else {
+ $class = '';
+ }
+
+ $status_url = add_query_arg( 'pre_order_status', rawurlencode( $status ), $base_url );
+
+ $this->views[ $status ] = sprintf(
+ '%s (%s) ',
+ esc_url( $status_url ),
+ $class,
+ ucfirst( $status ),
+ $count
+ );
+ }
+ }
+ }
+
+ return $this->views;
+ }
+
+ /**
+ * Gest the currently selected pre-order status (the current view) if any.
+ * Defaults to 'all'. Status is verified to exist in $available_status if
+ * provided
+ *
+ * @since 1.0
+ * @param array $available_status optional array of status => count used for validation
+ * @return string the current pre-order status
+ */
+ public function get_current_pre_order_status( $available_status = null ) {
+ // is there a status view selected?
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $status = isset( $_GET['pre_order_status'] ) ? sanitize_text_field( wp_unslash( $_GET['pre_order_status'] ) ) : 'all';
+
+ // verify the status exists, otherwise default to 'all'
+ if ( ! is_null( $available_status ) && ! isset( $available_status[ $status ] ) ) {
+ return 'all';
+ }
+
+ // otherwise just return the status
+ return $status;
+ }
+
+ /**
+ * Returns the column slugs and titles
+ *
+ * @see WP_List_Table::get_columns()
+ * @since 1.0
+ * @return array of column slug => title
+ */
+ public function get_columns() {
+
+ $columns = array(
+ 'cb' => ' ',
+ 'status' => '' . __( 'Status', 'woocommerce-pre-orders' ) . ' ',
+ 'customer' => __( 'Customer', 'woocommerce-pre-orders' ),
+ 'product' => __( 'Product', 'woocommerce-pre-orders' ),
+ 'order' => __( 'Order', 'woocommerce-pre-orders' ),
+ 'order_status' => __( 'Order status', 'woocommerce-pre-orders' ),
+ 'order_date' => __( 'Order date', 'woocommerce-pre-orders' ),
+ 'availability_date' => __( 'Availability date', 'woocommerce-pre-orders' ),
+ );
+
+ return $columns;
+ }
+
+ /**
+ * Returns the sortable columns. We make order_date and order sortable
+ * because they're available right in the posts table, and they make sense
+ * to order over.
+ *
+ * @see WP_List_Table::get_sortable_columns()
+ * @since 1.0
+ * @return array of sortable column slug => array( 'orderby', boolean )
+ * where true indicates the initial sort is descending
+ */
+ public function get_sortable_columns() {
+
+ return array(
+ 'order_date' => array( 'date', false ), // false because the inital sort direction is DESC so we want the first column click to sort ASC
+ 'order' => array( 'ID', false ), // same logic as order_date
+ );
+ }
+
+ /**
+ * Get content for the special checkbox column
+ *
+ * @see WP_List_Table::single_row_columns()
+ * @since 1.0
+ * @param WC_Order $order one row (item) in the table
+ * @return string the checkbox column content
+ */
+ public function column_cb( $order ) {
+ return ' ';
+ }
+
+ /**
+ * Get column content, this is called once per column, per row item ($order)
+ * returns the content to be rendered within that cell.
+ *
+ * @see WP_List_Table::single_row_columns()
+ * @since 1.0
+ * @param WC_Order $order one row (item) in the table
+ * @param string $column_name the column slug
+ * @return string the column content
+ */
+ public function column_default( $order, $column_name ) {
+ $order_id = $order->get_id();
+
+ switch ( $column_name ) {
+
+ case 'status':
+ $actions = array();
+
+ // determine any available actions
+ if ( WC_Pre_Orders_Manager::can_pre_order_be_changed_to( 'cancelled', $order ) ) {
+ $cancel_url = add_query_arg(
+ array(
+ 'order_id' => $order_id,
+ 'action' => 'cancel_pre_order',
+ )
+ );
+ $cancel_url = wp_nonce_url( $cancel_url, 'cancel_pre_order', 'cancel_pre_order_nonce' );
+
+ $actions['cancel'] = sprintf( '%s ', esc_url( $cancel_url ), esc_html__( 'Cancel', 'woocommerce-pre-orders' ) );
+ }
+
+ $column_content = sprintf( '%s ', WC_Pre_Orders_Order::get_pre_order_status( $order ), wc_sanitize_tooltip( WC_Pre_Orders_Order::get_pre_order_status_to_display( $order ) ), WC_Pre_Orders_Order::get_pre_order_status_to_display( $order ) );
+ $column_content .= $this->row_actions( $actions );
+ break;
+
+ case 'customer':
+ $billing_email = $order->get_billing_email();
+ $user_id = $order->get_customer_id();
+
+ if ( 0 !== $user_id ) {
+ $column_content = sprintf( '%s ', get_edit_user_link( $user_id ), $billing_email );
+ } else {
+ $column_content = $billing_email;
+ }
+
+ break;
+
+ case 'product':
+ // Past pre-orders may contain products that are no longer marked as a pre-order product
+ // As only one product can exist in a pre-order, pick the first product
+ $items = $order->get_items();
+ $item = reset( $items );
+
+ if ( $item ) {
+ $product_edit = get_edit_post_link( $item['product_id'] );
+ $column_content = ( $product_edit ) ? sprintf( '%s ', $product_edit, $item['name'] ) : $item['name'];
+ } else {
+ $column_content = '';
+ }
+ break;
+
+ case 'order':
+ /* translators: %s: order number */
+ $column_content = sprintf( '%s ', $order->get_edit_order_url(), sprintf( __( 'Order %s', 'woocommerce-pre-orders' ), $order->get_order_number() ) );
+ break;
+
+ case 'order_date':
+ $column_content = date_i18n( wc_date_format(), strtotime( ( $order->get_date_created() ? gmdate( 'Y-m-d H:i:s', $order->get_date_created()->getOffsetTimestamp() ) : '' ) ) );
+ break;
+
+ case 'order_status':
+ $column_content = sprintf( '%s ', esc_attr( sanitize_html_class( 'status-' . $order->get_status() ) ), esc_html( wc_get_order_status_name( $order->get_status() ) ) );
+ break;
+
+ case 'availability_date':
+ $product = WC_Pre_Orders_Order::get_pre_order_product( $order );
+ $column_content = WC_Pre_Orders_Product::get_localized_availability_date( $product, '--' );
+ break;
+
+ default:
+ $column_content = '';
+ break;
+ }
+
+ return $column_content;
+ }
+
+ /**
+ * Output any messages from the bulk action handling
+ *
+ * @since 1.0
+ */
+ public function render_messages() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_GET['message'] ) ) {
+
+ $memo = get_transient( $this->message_transient_prefix . wp_kses_post( wp_unslash( $_GET['message'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+
+ if ( ! empty( $memo ) ) {
+
+ delete_transient( $this->message_transient_prefix . wp_kses_post( wp_unslash( $_GET['message'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+
+ if ( ! empty( $memo['messages'] ) ) {
+ echo '' . esc_html( $memo['messages'] ) . '
';
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the current orderby, defaulting to 'date' if none is selected
+ */
+ private function get_current_orderby() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'date';
+ }
+
+ /**
+ * Gets the current orderby, defaulting to 'DESC' if none is selected
+ */
+ private function get_current_order() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return isset( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : 'DESC';
+ }
+
+ /**
+ * Prepare the list of pre-order items for display
+ *
+ * @see WP_List_Table::prepare_items()
+ * @since 1.0
+ */
+ public function prepare_items() {
+
+ $per_page = $this->get_items_per_page( 'wc_pre_orders_edit_pre_orders_per_page' );
+
+ // main query args
+ $args = array(
+ 'post_type' => 'shop_order',
+ 'post_status' => array_keys( wc_get_order_statuses() ),
+ 'posts_per_page' => $per_page,
+ 'paged' => $this->get_pagenum(),
+ 'orderby' => $this->get_current_orderby(),
+ 'order' => $this->get_current_order(),
+ 'meta_query' => array(
+ array(
+ 'key' => '_wc_pre_orders_is_pre_order',
+ 'value' => 1,
+ ),
+ ),
+ );
+
+ // Pre-order status view
+ $args = $this->add_view_args( $args );
+
+ // Filter: pre-orders by customer
+ $args = $this->add_filter_args( $args );
+
+ // handle search
+ $args = $this->add_search_args( $args );
+
+ $args = apply_filters( 'wc_pre_orders_edit_pre_orders_request', $args );
+
+ $this->items = array();
+
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $args['paginate'] = true;
+ $results = wc_get_orders( $args );
+
+ foreach ( $results->orders as $order_post ) {
+ $this->items[] = new WC_Order( $order_post );
+ }
+
+ $total_count = $results->total;
+ } else {
+ $query = new WP_Query( $args );
+
+ foreach ( $query->posts as $order_post ) {
+ $this->items[] = new WC_Order( $order_post );
+ }
+
+ $total_count = $query->found_posts;
+ }
+
+ $this->set_pagination_args(
+ array(
+ 'total_items' => $total_count,
+ 'per_page' => $per_page,
+ 'total_pages' => ceil( $total_count / $per_page ),
+ )
+ );
+ }
+
+ /**
+ * Adds in any query arguments based on the current filters
+ *
+ * @since 1.0
+ * @param array $args associative array of WP_Query arguments used to query and populate the list table
+ * @return array associative array of WP_Query arguments used to query and populate the list table
+ */
+ private function add_filter_args( $args ) {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+
+ global $wpdb;
+
+ // filter by customer
+ if ( isset( $_GET['_customer_user'] ) && $_GET['_customer_user'] > 0 ) {
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $args['customer_id'] = (int) $_GET['_customer_user'];
+ } else {
+ $args['meta_query'][] = array(
+ 'key' => '_customer_user',
+ 'value' => (int) $_GET['_customer_user'],
+ );
+ }
+ }
+
+ $product_ids = array();
+
+ // filter by product
+ if ( isset( $_GET['_product'] ) && absint( wp_unslash( $_GET['_product'] ) > 0 ) ) {
+ $product_ids[] = absint( $_GET['_product'] );
+ }
+
+ // filter by availability months (find the corresponding products since availability date is set per product)
+ if ( isset( $_GET['availability_date'] ) && absint( wp_unslash( $_GET['availability_date'] ) ) ) {
+
+ $year = substr( absint( wp_unslash( $_GET['availability_date'] ) ), 0, 4 );
+ $month = ltrim( substr( absint( wp_unslash( $_GET['availability_date'] ) ), 4, 2 ), '0' );
+
+ $products = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ SELECT DISTINCT post_id
+ FROM {$wpdb->postmeta}
+ WHERE meta_key = '_wc_pre_orders_availability_datetime'
+ AND YEAR( FROM_UNIXTIME( meta_value ) ) = %s AND MONTH( FROM_UNIXTIME( meta_value ) ) = %s
+ ",
+ $year,
+ $month
+ )
+ );
+
+ $product_ids = ( ! empty( $product_ids ) ) ? array_intersect( $product_ids, $products ) : $products;
+ if ( empty( $product_ids ) ) {
+ $args['post__in'] = array( 0 );
+ }
+ }
+
+ // filtering by product id
+ if ( ! empty( $product_ids ) ) {
+ $product_ids = implode( ',', array_map( 'absint', $product_ids ) );
+ $order_ids = $wpdb->get_col(
+ "
+ SELECT order_id
+ FROM {$wpdb->prefix}woocommerce_order_items as order_items
+ JOIN {$wpdb->prefix}woocommerce_order_itemmeta as order_itemmeta
+ ON order_itemmeta.order_item_id = order_items.order_item_id
+ WHERE meta_key = '_product_id' AND meta_value IN (" . esc_sql( $product_ids ) . ")" // phpcs:ignore Squiz.Strings.DoubleQuoteUsage.NotRequired
+ );
+
+ $args['post__in'] = ! empty( $order_ids ) ? $order_ids : array( 0 );
+ }
+
+ return $args;
+ }
+
+ /**
+ * Adds in any query arguments based on the current view
+ *
+ * @since 1.0
+ * @param array $args associative array of WP_Query arguments used to query and populate the list table
+ * @return array associative array of WP_Query arguments used to query and populate the list table
+ */
+ private function add_view_args( $args ) {
+ $pre_order_status = $this->get_current_pre_order_status();
+
+ if ( 'all' !== $pre_order_status ) {
+ if ( ! isset( $args['meta_query'] ) ) {
+ $args['meta_query'] = array();
+ }
+
+ $args['meta_query'][] = array(
+ 'key' => '_wc_pre_orders_status',
+ 'value' => $pre_order_status,
+ );
+ }
+
+ return $args;
+ }
+
+ /**
+ * Adds in any query arguments based on the search term
+ *
+ * @see woocommerce_shop_order_search_custom_fields()
+ * @since 1.0
+ * @param array $args associative array of WP_Query arguments used to query and populate the list table
+ * @return array associative array of WP_Query arguments used to query and populate the list table
+ */
+ private function add_search_args( $args ) {
+
+ global $wpdb;
+
+ if ( isset( $_GET['s'] ) && ! empty( $_GET['s'] ) ) {
+ $search_query = sanitize_text_field( wp_unslash( $_GET['s'] ) );
+ $search_order_id = str_replace( 'Order #', '', $search_query );
+ if ( ! is_numeric( $search_order_id ) ) {
+ $search_order_id = 0;
+ }
+
+ $escaped_search_like_query = '%' . $wpdb->esc_like( $search_query ) . '%';
+ $search_ids_by_meta = array();
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $search_ids_by_meta = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ SELECT DISTINCT orders.id
+ FROM {$wpdb->prefix}wc_orders AS orders
+ INNER JOIN {$wpdb->prefix}wc_orders_meta AS meta0 ON ( orders.id = meta0.order_id )
+ INNER JOIN {$wpdb->prefix}wc_orders_meta AS meta1 ON ( orders.id = meta1.order_id )
+ INNER JOIN {$wpdb->prefix}wc_order_operational_data AS operational_data ON ( orders.id = operational_data.order_id )
+ WHERE ( orders.type = 'shop_order' )
+ AND ( meta0.meta_key = '_wc_pre_orders_is_pre_order' AND meta0.meta_value = '1' )
+ AND ( ( orders.billing_email LIKE %s )
+ OR ( meta1.meta_key = '_wc_pre_orders_status' AND meta1.meta_value LIKE %s )
+ OR ( operational_data.order_key LIKE %s ) )
+ ",
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query
+ )
+ );
+ } else {
+ $search_fields = array_map(
+ 'esc_attr',
+ apply_filters(
+ 'wc_pre_orders_search_fields',
+ array(
+ '_order_key',
+ '_billing_email',
+ '_wc_pre_orders_status',
+ )
+ )
+ );
+
+ $search_fields_string = implode( "','", esc_sql( $search_fields ) );
+ $search_ids_by_meta = $wpdb->get_col(
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
+ $wpdb->prepare(
+ "
+ SELECT post_id
+ FROM {$wpdb->postmeta}
+ WHERE meta_key IN ('" . $search_fields_string . "')
+ AND meta_value LIKE %s
+ ",
+ $escaped_search_like_query
+ )
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
+ );
+ }
+
+ // Order IDs by customer name
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $search_ids_by_customer = $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT _order.id
+ FROM {$wpdb->prefix}wc_orders as _order
+ LEFT JOIN {$wpdb->users} as users ON _order.customer_id = users.ID
+ WHERE
+ user_login LIKE %s OR
+ user_nicename LIKE %s OR
+ user_email LIKE %s OR
+ display_name LIKE %s",
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query
+ )
+ );
+ } else {
+ $search_ids_by_customer = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ SELECT posts.ID
+ FROM {$wpdb->posts} as posts
+ LEFT JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id
+ LEFT JOIN {$wpdb->users} as users ON postmeta.meta_value = users.ID
+ WHERE
+ post_excerpt LIKE %s OR
+ post_title LIKE %s OR
+ (
+ meta_key = '_customer_user' AND
+ (
+ user_login LIKE %s OR
+ user_nicename LIKE %s OR
+ user_email LIKE %s OR
+ display_name LIKE %s
+ )
+ )
+ ",
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query,
+ $escaped_search_like_query
+ )
+ );
+ }
+
+ // Search orders
+ $post_ids = array_merge(
+ $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ SELECT order_id
+ FROM {$wpdb->prefix}woocommerce_order_items as order_items
+ WHERE order_item_name LIKE %s
+ ",
+ $escaped_search_like_query
+ )
+ ),
+ $search_ids_by_customer,
+ $search_ids_by_meta,
+ array( $search_order_id )
+ );
+
+ if ( isset( $args['post__in'] ) && ! empty( $args['post__in'] ) ) {
+ $args['post__in'] = array_intersect( $args['post__in'], array_unique( $post_ids ) );
+ } else {
+ $args['post__in'] = array_unique( $post_ids );
+ }
+
+ if ( empty( $args['post__in'] ) ) {
+ $args['post__in'] = array( 0 );
+ }
+ }
+
+ return $args;
+ }
+
+ /**
+ * The text to display when there are no pre-orders
+ *
+ * @see WP_List_Table::no_items()
+ * @since 1.0
+ */
+ public function no_items() {
+
+ if ( isset( $_REQUEST['s'] ) ) : ?>
+
+
+
+
+ ', ' »
' );
+ ?>
+
+
+ ', ' »' );
+ ?>
+
+ ';
+
+ $user_string = '';
+ $user_id = '';
+ if ( ! empty( $_GET['_customer_user'] ) ) {
+ $user_id = absint( $_GET['_customer_user'] );
+ $user = get_user_by( 'id', $user_id );
+ $user_string = esc_html( $user->display_name ) . ' (#' . absint( $user->ID ) . ' – ' . esc_html( $user->user_email );
+ }
+
+ $product_name = '';
+ $product_id = '';
+ if ( ! empty( $_GET['_product'] ) ) {
+ $product_id = absint( $_GET['_product'] );
+ $product = wc_get_product( $product_id );
+ $product_name = ! empty( $product ) ? $product->get_formatted_name() : '';
+ }
+ ?>
+
+
+ ' . wp_kses_post( $user_string ) . '';
+ }
+ ?>
+
+
+
+ ' . wp_kses_post( $product_name ) . '';
+ }
+ ?>
+
+ render_availability_dates_dropdown();
+
+ submit_button( esc_html__( 'Filter', 'woocommerce-pre-orders' ), 'button', false, false, array( 'id' => 'post-query-submit' ) );
+ echo '';
+
+ // Bulk action fields
+ echo '';
+ echo '';
+ echo '
';
+
+ $javascript = "
+ $( 'select[name=\"action\"]' ).on( 'change', function() {
+ if ( -1 == $(this).val() ) {
+ $( '#bulk-action-fields' ).slideUp();
+ } else {
+ $( '#bulk-action-fields' ).slideDown();
+ }
+ }).trigger( 'change' );
+
+ $( 'select[name=\"action2\"]' ).on( 'change', function() {
+ if ( -1 == $(this).val() ) {
+ $('#bulk-action-fields2').slideUp();
+ } else {
+ $('#bulk-action-fields2').slideDown();
+ }
+ }).trigger( 'change' );
+
+ $( 'span.cancel' ).on( 'click', function( e ) {
+ if ( ! window.confirm( '" . __( 'Are you sure you want to cancel this pre-order?', 'woocommerce-pre-orders' ) . "' ) ) {
+ e.preventDefault();
+ }
+ });
+ ";
+
+ if ( function_exists( 'wc_enqueue_js' ) ) {
+ wc_enqueue_js( $javascript );
+ } else {
+ $woocommerce->add_inline_js( $javascript );
+ }
+ } elseif ( 'bottom' === $which ) {
+ // Bulk action fields
+ echo '';
+ echo '';
+ echo '
';
+ }
+ }
+
+ /**
+ * Display a monthly dropdown for filtering items by availability date
+ *
+ * @since 1.0
+ */
+ private function render_availability_dates_dropdown() {
+ global $wpdb, $wp_locale;
+
+ // Performance: we could always pull out the database order-by and sort in code to get rid of a 'filesort' from the query
+ $months = $wpdb->get_results(
+ "
+ SELECT DISTINCT YEAR( FROM_UNIXTIME( meta_value ) ) AS year, MONTH( FROM_UNIXTIME( meta_value ) ) AS month
+ FROM {$wpdb->postmeta}
+ WHERE meta_key = '_wc_pre_orders_availability_datetime'
+ AND meta_value > 0
+ ORDER BY meta_value+0 DESC
+ "
+ );
+
+ $month_count = count( $months );
+
+ if ( ! $month_count || ( 1 === $month_count && 0 === $months[0]->month ) ) {
+ return;
+ }
+
+ $availability_date = isset( $_GET['availability_date'] ) ? (int) $_GET['availability_date'] : 0;
+ ?>
+
+ value='0'>
+ year ) {
+ continue;
+ }
+
+ $month = zeroise( $arc_row->month, 2 );
+ $year = $arc_row->year;
+
+ printf(
+ "%s \n",
+ selected( $availability_date, $year . $month, false ),
+ esc_attr( $arc_row->year . $month ),
+ /* translators: %1$s month, %2$d year */
+ esc_html( sprintf( __( '%1$s %2$d', 'woocommerce-pre-orders' ), $wp_locale->get_month( $month ), $year ) )
+ );
+ }
+ ?>
+
+ has_scheduled_batch_processor( $product_ids, $batch_id ) ) {
+ $this->schedule_batch_processor( $product_ids, $batch_id );
+
+ // Now that we have scheduled the action to process these products. Disable further pre-orders for them.
+ $this->disable_pre_orders_for_products( $product_ids );
+ }
+ }
+
+ /**
+ * Schedules a batch processor for a given batch of product IDs.
+ *
+ * @param int[] $product_ids The product IDs to batch process pre-orders for.
+ * @param string $product_ids The unique batch ID for this set of products.
+ */
+ private function schedule_batch_processor( $product_ids, $batch_id ) {
+ // Schedule the batch to run as soon as possible. WC_Action_Queue::add() uses time().
+ WC()->queue()->add(
+ self::$scheduled_batch_processing_hook,
+ array(
+ 'products' => $product_ids,
+ 'batch_id' => $batch_id,
+ )
+ );
+ }
+
+ /**
+ * Checks if there's already a scheduled batch processor action for a given set of products.
+ *
+ * @param int[] $product_ids The product IDs to batch process pre-orders for.
+ * @param string $product_ids The unique batch ID for this set of products.
+ *
+ * @return bool True if there's a scheduled action already, otherwise false.
+ */
+ private function has_scheduled_batch_processor( $product_ids, $batch_id ) {
+ return null !== WC()->queue()->get_next(
+ self::$scheduled_batch_processing_hook,
+ array(
+ 'products' => $product_ids,
+ 'batch_id' => $batch_id,
+ )
+ );
+ }
+
+ /**
+ * Schedules a background job to process a single pre-order.
+ *
+ * @param WC_Order $order The order the schedule a completetion hook for.
+ */
+ private function schedule_pre_order_complete( $order ) {
+ $args = array( 'order_id' => $order->get_id() );
+
+ if ( null === WC()->queue()->get_next( self::$scheduled_pre_order_complete_hook, $args ) ) {
+ WC()->queue()->schedule_single( time() + MINUTE_IN_SECONDS, self::$scheduled_pre_order_complete_hook, $args );
+ }
+ }
+
+ /**
+ * Finds pre-orders for a batch of given products and schedules a background job to process them.
+ *
+ * @since 2.0.0
+ *
+ * @param int[] $product_ids The product IDs to schedule pre-order completion for.
+ * @param string $product_ids The unique batch ID for this set of products.
+ */
+ public function schedule_actions_to_complete_pre_orders( $product_ids, $batch_id ) {
+ // Generate a meta key flag which is stored on orders we have checked if they need processing by this batch so we can exclude them from future queries.
+ $meta_key_flag = "_wc_pre_handled_by_product_batch_{$batch_id}";
+ $batch_size = apply_filters( 'wc_pre_orders_complete_pre_orders_batch_size', 200 );
+
+ // Get pre-orders which haven't been handled by this batch ID.
+ $args = array(
+ 'post_status' => 'wc-pre-ordered',
+ 'post_type' => 'shop_order',
+ 'posts_per_page' => $batch_size,
+ 'fields' => 'ids',
+ 'meta_query' => array(
+ 'relation' => 'AND',
+ array(
+ 'key' => '_wc_pre_orders_is_pre_order',
+ 'value' => 1,
+ ),
+ array(
+ 'key' => $meta_key_flag,
+ 'compare' => 'NOT EXISTS',
+ ),
+ ),
+ );
+
+ $results = array();
+ if( WC_Pre_Orders::is_hpos_enabled() ) {
+ $results = wc_get_orders( $args );
+ } else {
+ $query = new WP_Query( $args );
+ $results = $query->posts;
+ }
+
+ // If we got a full batch of orders, we haven't finished.
+ $is_batch_complete = count( $results ) !== $batch_size;
+
+ // If we've finished processing these products, release the orders and clean up the meta flags.
+ if ( $is_batch_complete ) {
+ $this->release_orders_from_batch( $meta_key_flag );
+ } else {
+ // If we got a full batch of orders, schedule a followup action.
+ $this->schedule_batch_processor( $product_ids, $batch_id );
+ }
+
+ foreach ( $results as $order_id ) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order ) {
+ continue;
+ }
+
+ // Store meta on the order so we know it has been checked by this batch so it can be excluded by future batch queries.
+ // Skip setting this meta if this is the last batch, as we've deleted it from all previous orders at this point.
+ if ( ! $is_batch_complete ) {
+ $order->update_meta_data( $meta_key_flag, 'true' );
+ $order->save();
+ }
+
+ foreach ( $order->get_items() as $item ) {
+ // If this order contains a product we need to process. Schedule an action to process it in the future.
+ if ( in_array( $item->get_product_id(), $product_ids ) || in_array( $item->get_variation_id(), $product_ids ) ) {
+ $this->schedule_pre_order_complete( $order );
+ continue;
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes a batch ID flag stored on orders handled by a batch processor.
+ *
+ * @param string $meta_key_flag The unique meta key used to flag orders as being handled by a batch processor.
+ * @return int The number of orders updated.
+ */
+ private function release_orders_from_batch( $meta_key_flag ) {
+ global $wpdb;
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ return $wpdb->delete( "{$wpdb->prefix}wc_orders_meta", array( 'meta_key' => $meta_key_flag ) );
+ }
+ return $wpdb->delete( "{$wpdb->prefix}postmeta", array( 'meta_key' => $meta_key_flag ) );
+ }
+
+ /**
+ * Prevent completed pre-orders from being cancelled - Any new pre-orders that have not been processed yet
+ * (e.g. by checking out via PayPal but not completing purchase) should respect the default order cancel settings
+ *
+ * @since 1.0
+ * @param bool $cancel_order whether to cancel the pending order or not
+ * @param object $order the \WC_Order object
+ * @return bool true if the order should be cancelled, false otherwise
+ */
+ public function maybe_prevent_pending_order_cancel( $cancel_order, $order ) {
+ if ( WC_Pre_Orders_Order::order_contains_pre_order( $order ) && 'completed' === WC_Pre_Orders_Order::get_pre_order_status( $order ) ) {
+ $cancel_order = false;
+ }
+
+ return $cancel_order;
+ }
+
+ /**
+ * Prevent order stock reduction when WC_Order::payment_complete() is called for a pre-order charged upon release.
+ * Because order stock for pre-orders charged upon release is reduced during initial checkout, this prevents stock from
+ * being reduced twice.
+ *
+ * @since 1.0
+ * @param bool $reduce_stock whether to reduce stock for the order or not
+ * @param int $order_id the post ID of the order
+ * @return bool true if the order stock should be reduced, false otherwise
+ */
+ public function maybe_prevent_payment_complete_order_stock_reduction( $reduce_stock, $order_id ) {
+
+ $order = new WC_Order( $order_id );
+
+ $order_status = $order->get_status();
+
+ // stock reduction should only be prevented when order is being completed
+ // ie when current order status is 'processing'
+ if ( 'processing' !== $order_status ) {
+ return $reduce_stock;
+ }
+
+ if ( WC_Pre_Orders_Order::order_contains_pre_order( $order ) && WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) && ! self::is_order_pay_later( $order_id ) ) {
+ $reduce_stock = false;
+ }
+
+ return $reduce_stock;
+ }
+
+ /**
+ * Reduce the stock level for an order and record the stock reduction in data store
+ *
+ * @since 1.5.31
+ * @param object $order the \WC_Order object
+ */
+ public static function reduce_stock_level( $order ) {
+ $order_id = $order->get_id();
+
+ wc_reduce_stock_levels( $order->get_id() );
+ $order->get_data_store()->set_stock_reduced( $order_id, true );
+ }
+
+ /**
+ * Gets all pre-orders
+ *
+ * @since 1.0
+ * @return array
+ */
+ public static function get_all_pre_orders() {
+
+ $args = array(
+ 'post_type' => 'shop_order',
+ 'post_status' => array_keys( wc_get_order_statuses() ),
+ 'posts_per_page' => -1,
+ 'meta_key' => '_wc_pre_orders_is_pre_order',
+ 'meta_value' => 1,
+ );
+
+ $results = array();
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $results = wc_get_orders( $args );
+ } else {
+ $query = new WP_Query( $args );
+ if ( empty( $query->posts ) ) {
+ return array();
+ }
+ $results = $query->posts;
+ }
+
+ $orders = array();
+
+ foreach ( $results as $order_post ) {
+ $order = new WC_Order( $order_post );
+ $orders[] = $order;
+ }
+
+ return $orders;
+ }
+
+
+ /**
+ * Gets all pre-orders for a given product
+ *
+ * @since 1.0
+ * @param object|int $product
+ * @return array
+ */
+ public static function get_all_pre_orders_by_product( $product ) {
+ global $wpdb;
+
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return array();
+ }
+ }
+
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $order_ids = $wpdb->get_results(
+ $wpdb->prepare(
+ "
+ SELECT items.order_id AS id
+ FROM {$wpdb->prefix}woocommerce_order_items AS items
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS item_meta ON items.order_item_id = item_meta.order_item_id
+ LEFT JOIN {$wpdb->prefix}wc_orders_meta AS order_meta ON items.order_id = order_meta.order_id
+ WHERE
+ items.order_item_type = 'line_item' AND
+ item_meta.meta_key = '_product_id' AND
+ item_meta.meta_value = %s AND
+ order_meta.meta_key = '_wc_pre_orders_is_pre_order' AND
+ order_meta.meta_value = '1'
+ ",
+ $product->get_id()
+ )
+ );
+ } else {
+ $order_ids = $wpdb->get_results(
+ $wpdb->prepare(
+ "
+ SELECT items.order_id AS id
+ FROM {$wpdb->prefix}woocommerce_order_items AS items
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS item_meta ON items.order_item_id = item_meta.order_item_id
+ LEFT JOIN {$wpdb->postmeta} AS post_meta ON items.order_id = post_meta.post_id
+ WHERE
+ items.order_item_type = 'line_item' AND
+ item_meta.meta_key = '_product_id' AND
+ item_meta.meta_value = %s AND
+ post_meta.meta_key = '_wc_pre_orders_is_pre_order' AND
+ post_meta.meta_value = '1'
+ ",
+ $product->get_id()
+ )
+ );
+ }
+
+ if ( empty( $order_ids ) ) {
+ return array();
+ }
+
+ $orders = array();
+
+ foreach ( $order_ids as $order ) {
+ $orders[] = new WC_Order( $order->id );
+ }
+
+ return $orders;
+ }
+
+ /**
+ * Gets all pre-orders for the currently logged in user, or the user identified by $user_id
+ *
+ * @since 1.0
+ * @param int $user_id optional user id to return pre-orders for. Defaults to the currently logged in user.
+ * @return array of WC_Order objects
+ */
+ public static function get_users_pre_orders( $user_id = null ) {
+
+ if ( is_null( $user_id ) ) {
+ $user_id = get_current_user_id();
+ }
+
+ $args = array(
+ 'customer_id' => $user_id,
+ 'meta_key' => '_wc_pre_orders_is_pre_order',
+ 'meta_value' => 1,
+ 'meta_compare' => '=',
+ 'return' => 'ids',
+ );
+
+ $results = wc_get_orders( $args );
+ $orders = array();
+
+ foreach ( $results as $order_post ) {
+ $orders[] = new WC_Order( $order_post );
+ }
+
+ return apply_filters( 'wc_pre_orders_users_pre_orders', $orders, $user_id );
+ }
+
+ /**
+ * Returns true if the pre-order identified by $order/$item can be changed to
+ * $new_status
+ *
+ * @since 1.0
+ * @param string $new_status the new status
+ * @param WC_Order $order the order object
+ * @return boolean true if the status can be changed, false otherwise
+ */
+ public static function can_pre_order_be_changed_to( $new_status, $order ) {
+
+ $status = WC_Pre_Orders_Order::get_pre_order_status( $order );
+
+ // assume it can not be changed
+ $can_be_changed = false;
+
+ switch ( $new_status ) {
+ case 'cancelled':
+ if ( ! in_array( $status, array( 'cancelled', 'completed', 'trash' ) ) ) {
+ $can_be_changed = true;
+ }
+ break;
+ case 'completed':
+ if ( 'active' == $status ) {
+ $can_be_changed = true;
+ }
+ break;
+ }
+
+ return apply_filters( 'wc_pre_orders_status_can_be_changed_to_' . $new_status, $can_be_changed, $order );
+ }
+
+
+ /**
+ * Return a link for customers to change the status of their pre-order to $status
+ *
+ * @since 1.0
+ * @param string $new_status the new status
+ * @param WC_Order $order the order object
+ * @return string
+ */
+ public static function get_users_change_status_link( $new_status, $order ) {
+ $order_id = $order->get_id();
+ $action_link = add_query_arg(
+ array(
+ 'order_id' => $order_id,
+ 'status' => $new_status,
+ )
+ );
+ $action_link = wp_nonce_url( $action_link, $order_id );
+
+ return apply_filters( 'wc_pre_orders_users_action_link', $action_link, $order, $new_status );
+ }
+
+
+ /**
+ * Gets all products that are currently pre-order enabled
+ *
+ * @since 1.9.0 Return private and published pre-order products.
+ * @since 1.0
+ * @return array of WC_Product objects
+ */
+ public static function get_all_pre_order_enabled_products() {
+ $args = array(
+ 'fields' => 'ids',
+ 'post_type' => 'product',
+ 'post_status' => array( 'publish', 'private' ),
+ 'nopaging' => true,
+ 'meta_key' => '_wc_pre_orders_enabled',
+ 'meta_value' => 'yes',
+ );
+
+ $product_post_ids = get_posts( $args );
+
+ $products = array();
+
+ foreach ( $product_post_ids as $product_id ) {
+
+ $products[] = wc_get_product( $product_id );
+ }
+
+ return $products;
+ }
+
+
+ /**
+ * Sends a notification email (using the built-in 'Customer Note' email
+ * template) to all customers associated with the supplied $orders with an active pre-order
+ *
+ * @since 1.0
+ * @param int|WC_Order $order order object or identifier
+ * @param string $message required message to include in notification email to customer
+ */
+ public static function email_pre_order_customer( $order, $message ) {
+ global $woocommerce;
+
+ // load email classes
+ $woocommerce->mailer();
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ if ( 'active' !== WC_Pre_Orders_Order::get_pre_order_status( $order ) ) {
+ return;
+ }
+
+ // set email args
+ $args = array(
+ 'order_id' => $order->get_id(),
+ 'customer_note' => $message,
+ );
+
+ // fire the notification, which sends the emails
+ do_action( 'woocommerce_new_customer_note_notification', $args );
+ }
+
+
+ /**
+ * Sends a notification email (using the built-in 'Customer Note' email
+ * template) to all customers associated with the supplied $orders with an active pre-order
+ *
+ * @since 1.0
+ * @param array $orders array of post ID or WC_Order objects
+ * @param string $message required message to include in notification email to customer
+ */
+ public static function email_pre_order_customers( $orders, $message ) {
+ foreach ( $orders as $order ) {
+ self::email_pre_order_customer( $order, $message );
+ }
+ }
+
+ /**
+ * Sends a notification email (using the built-in 'Customer Note' email template) to all customers who have pre-ordered
+ * the given product
+ *
+ * @since 1.0
+ * @param object|int $product the product to email all pre-ordered customers for
+ * @param string $message required message to include in notification email to customer
+ */
+ public static function email_all_pre_order_customers( $product, $message ) {
+
+ $orders = self::get_all_pre_orders_by_product( $product );
+
+ if ( empty( $orders ) ) {
+ return;
+ }
+
+ self::email_pre_order_customers( $orders, $message );
+ }
+
+ /**
+ * Change the release date for pre-orders by updating the availability date for the pre-ordered product to a new date in the future
+ *
+ * @since 1.0
+ * @param object|int $product the product to change the release date for all pre-orders for
+ * @param string $new_availability_date the new availability date
+ * @param string $message an optional message to include in communications to the customer
+ */
+ public static function change_release_date_for_all_pre_orders( $product, $new_availability_date, $message = '' ) {
+
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return;
+ }
+ }
+
+ // get new availability date timestamp
+ try {
+
+ // get datetime object from site timezone
+ $datetime = new DateTime( $new_availability_date, new DateTimeZone( wc_timezone_string() ) );
+
+ // get the unix timestamp (adjusted for the site's timezone already)
+ $timestamp = $datetime->format( 'U' );
+
+ // Whether the product's release date passed.
+ $is_past_date = $timestamp <= time();
+
+ } catch ( Exception $e ) {
+ global $wc_pre_orders;
+ $wc_pre_orders->log( $e->getMessage() );
+ $timestamp = '';
+ }
+
+ // set new availability date for product
+ update_post_meta( $product->get_id(), '_wc_pre_orders_availability_datetime', $timestamp );
+
+ // get associated orders
+ $orders = self::get_all_pre_orders_by_product( $product );
+
+ // fire action for each order
+ foreach ( $orders as $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ // only delay active pre-orders
+ if ( 'active' !== WC_Pre_Orders_Order::get_pre_order_status( $order ) ) {
+ continue;
+ }
+
+ // When the product's release date passed and the order
+ // status is set to 'pre-ordered', mark pre-orders as complete.
+ if ( $is_past_date && 'pre-ordered' === $order->get_status() ) {
+ // Doing this now to not to wait for the 'wc_pre_orders_completion_check' cron job.
+ self::complete_pre_order( $order );
+ }
+
+ // Add 'release date changed' order note for admins.
+ /* translators: %s: Availability date */
+ $order->add_order_note( sprintf( __( 'Pre-order release date changed to %s', 'woocommerce-pre-orders' ), WC_Pre_Orders_Product::get_localized_availability_date( $product, __( 'N/A', 'woocommerce-pre-orders' ) ) ) );
+
+ do_action(
+ 'wc_pre_orders_pre_order_date_changed',
+ array(
+ 'order' => $order,
+ 'availability_date' => $new_availability_date,
+ 'message' => $message,
+ )
+ );
+ }
+
+ // Doing this after the pre_order_date_changed emails are sent
+ // so the availability date in the email isn't "at a future date".
+ if ( $is_past_date ) {
+ // Unmark the product as a pre-order now that it's released.
+ update_post_meta( $product->get_id(), '_wc_pre_orders_enabled', 'no' );
+
+ do_action( 'wc_pre_orders_pre_orders_disabled_for_product', $product->get_id() );
+ }
+ }
+
+ /**
+ * Checks to see if order is zero cost.
+ *
+ * @version 1.5.1
+ * @since 1.5.1
+ * @param object $order
+ * @return bool
+ */
+ public static function is_zero_cost_order( $order = null ) {
+ if ( is_a( $order, 'WC_Order' ) ) {
+ return 0 >= $order->get_total();
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks to see if order is initially using pay later gateway.
+ * This is needed because payment method will change later in the process
+ * when customer goes to pay when product is available. But we need to
+ * preserve what the order was originally used so we can know if we need
+ * to reduce stock or not based on that.
+ *
+ * @version 1.5.1
+ * @since 1.5.1
+ * @param object $order
+ * @return bool
+ */
+ public static function is_order_pay_later( $order_id = null ) {
+ if ( ! $order_id ) {
+ return false;
+ }
+
+ $order = wc_get_order( $order_id );
+ return is_object( $order ) && 'yes' === $order->get_meta( '_wc_pre_orders_is_pay_later', true );
+ }
+
+ /**
+ * Completes the pre-order by updating the pre-order status to 'completed' and following this process for handling payment :
+ *
+ * - for a pre-order charged upon release AND containing a payment token, an action is fired for the supported gateway
+ * to hook into an charge the total payment amount. Note that the supported gateway will then call WC_Order::payment_complete()
+ * upon successful charge
+ *
+ * - for a pre-order charged upon release with no payment token, the order status is changed to 'pending' and an email
+ * is sent containing a link for the customer to come back to and pay for their order
+ *
+ * - for a pre-order charged upfront, the order status is changed to 'completed' or 'processing' based on the same rules
+ * from WC_Order::payment_complete() -- this is because payment_complete() has already occurred for these order
+ *
+ * @since 1.0
+ * @param int|WC_Order $order post IDs or order object to complete the pre-order for
+ * @param string $message optional message to include in 'pre-order completed' email to customer
+ */
+ public static function complete_pre_order( $order, $message = '' ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ if ( ! self::can_pre_order_be_changed_to( 'completed', $order ) ) {
+ return;
+ }
+
+ // Save custom customer message in transient to be used in customer email.
+ // This is needed for orders which get completed directly and updates pre-order status to completed (without message) before we update it in this function (eg: Virtual/downloadable product orders).
+ // See https://github.com/woocommerce/woocommerce-pre-orders/issues/345
+ $transient_key = 'wc_pre_orders_pre_order_completed_message_' . $order->get_id();
+ if ( ! empty( $message ) ) {
+ set_transient( $transient_key, $message, 60 );
+ }
+
+ // complete pre-order charged upon release.
+ if ( WC_Pre_Orders_Order::order_will_be_charged_upon_release( $order ) ) {
+ $zero_cost_order = self::is_zero_cost_order( $order );
+
+ $order_id = $order->get_id();
+
+ if ( ! $zero_cost_order ) {
+ // Suppress stock increase when status update to pending
+ remove_action( 'woocommerce_order_status_pending', 'wc_maybe_increase_stock_levels' );
+ // update order status to pending so it can be paid by automatic payment,
+ // or on pay page by customer if 'pay later' gateway was used.
+ $order->update_status( 'pending' );
+ add_action( 'woocommerce_order_status_pending', 'wc_maybe_increase_stock_levels' );
+
+ if ( WC_Pre_Orders_Order::order_has_payment_token( $order ) || self::is_order_pay_later( $order_id ) ) {
+ // load payment gateways.
+ WC()->payment_gateways();
+
+ // fire action for payment gateway to charge pre-order.
+ do_action( 'wc_pre_orders_process_pre_order_completion_payment_' . $order->get_payment_method(), $order );
+ }
+ } else {
+ $product = WC_Pre_Orders_Order::get_pre_order_product( $order );
+
+ // update order status to completed or processing - based on same process from WC_Order::payment_complete()
+ if ( ( $product->is_downloadable() && $product->is_virtual() ) || ! apply_filters( 'woocommerce_order_item_needs_processing', true, $product, $order_id ) ) {
+ $order->update_status( 'completed' );
+ } else {
+ $order->update_status( 'processing' );
+ }
+
+ self::reduce_stock_level( $order );
+
+ }
+ } else { // Complete pre-order charged upfront.
+
+ $product = WC_Pre_Orders_Order::get_pre_order_product( $order );
+
+ // update order status to completed or processing - based on same process from WC_Order::payment_complete()
+ if ( ( $product->is_downloadable() && $product->is_virtual() ) || ! apply_filters( 'woocommerce_order_item_needs_processing', true, $product, $order->get_id() ) ) {
+ $order->update_status( 'completed' );
+ } else {
+ $order->update_status( 'processing' );
+ }
+ }
+
+ if ( ! empty( $message ) ) {
+ delete_transient( $transient_key );
+ }
+ // update pre-order status to completed
+ WC_Pre_Orders_Order::update_pre_order_status( $order, 'completed', $message );
+
+ do_action( 'wc_pre_orders_pre_order_completed', $order, $message );
+ }
+
+ /**
+ * Completes the provided pre-orders
+ *
+ * @since 1.0
+ * @param array $orders an array of orders containing a pre-order to complete
+ * @param string $message optional message to include in 'pre-order completed' email to customer
+ */
+ public static function complete_pre_orders( $orders, $message = '' ) {
+ foreach ( $orders as $order ) {
+ self::complete_pre_order( $order, $message );
+ }
+ }
+
+ /**
+ * Helper function to complete all the pre-orders for a given product
+ *
+ * @since 1.0
+ * @param object|int $product the product to complete all pre-orders for
+ * @param string $message an optional message to include in communications to the customer
+ */
+ public static function complete_all_pre_orders( $product, $message ) {
+
+ $orders = self::get_all_pre_orders_by_product( $product );
+
+ if ( empty( $orders ) ) {
+ return;
+ }
+
+ self::complete_pre_orders( $orders, $message );
+ }
+
+ /**
+ * Cancel a pre-orders by changing its order status / pre-order status to 'cancelled'
+ *
+ * @since 1.0
+ * @param int|WC_Order $order post IDs or order object to cancel the pre-order for
+ * @param string $message an optional message to include in communications to the customer
+ */
+ public static function cancel_pre_order( $order, $message = '' ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ if ( ! WC_Pre_Orders_Order::order_contains_pre_order( $order ) ) {
+ return;
+ }
+
+ if ( ! self::can_pre_order_be_changed_to( 'cancelled', $order ) ) {
+ return;
+ }
+
+ // update the pre-order status
+ WC_Pre_Orders_Order::update_pre_order_status( $order, 'cancelled', $message );
+
+ // add 'cancelled' order note for admins
+ $order->add_order_note( __( 'Pre-order cancelled', 'woocommerce-pre-orders' ) );
+
+ // update the order status
+ $order->update_status( 'cancelled' );
+
+ do_action( 'wc_pre_orders_pre_order_cancelled', $order, $message );
+ }
+
+ /**
+ * Cancels pre-orders by changing their order status / pre-order status to 'cancelled'
+ *
+ * @since 1.0
+ * @param array $orders array of post IDs or order objects to cancel pre-orders for
+ * @param string $message an optional message to include in communications to the customer
+ */
+ public static function cancel_pre_orders( $orders, $message = '' ) {
+ foreach ( $orders as $order ) {
+ self::cancel_pre_order( $order, $message );
+ }
+ }
+
+ /**
+ * Helper function to cancel all pre-orders for a given product
+ *
+ * @see WC_Pre_Orders_Manager::cancel_pre_orders()
+ *
+ * @since 1.0
+ * @param object|int $product the product to complete all pre-orders for
+ * @param string $message an optional message to include in communications to the customer
+ */
+ public static function cancel_all_pre_orders( $product, $message ) {
+
+ $orders = self::get_all_pre_orders_by_product( $product );
+
+ if ( empty( $orders ) ) {
+ return;
+ }
+
+ self::cancel_pre_orders( $orders, $message );
+ }
+
+ /**
+ * Helper function to return a formatted pre-order order total, e.g. '$99 charged on Dec 1, 2014'
+ *
+ * @since 1.0
+ * @param string $total formatted order total to modify
+ * @param object|int $product the product that the pre-order contains
+ * @return string the new formatted order total
+ */
+ public static function get_formatted_pre_order_total( $total, $product ) {
+
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return $total;
+ }
+ }
+
+ // get order total format
+ if ( WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
+ $formatted_total = get_option( 'wc_pre_orders_upon_release_order_total_format' );
+ } else {
+ $formatted_total = get_option( 'wc_pre_orders_upfront_order_total_format' );
+ }
+
+ // bail if no format is set
+ if ( ! $formatted_total ) {
+ return $total;
+ }
+
+ // add localized availability date if needed
+ $formatted_total = str_replace( '{availability_date}', WC_Pre_Orders_Product::get_localized_availability_date( $product ), $formatted_total );
+
+ // add order total
+ $formatted_total = str_replace( '{order_total}', $total, $formatted_total );
+
+ return apply_filters( 'wc_pre_orders_pre_order_order_total', $formatted_total, $product );
+ }
+
+ /**
+ * Helper method to disable pre-orders for a product, called after the availability date for a pre-order has been reached
+ * and pre-orders are completed
+ *
+ * @since 1.0
+ * @param array|int $product_ids product IDs to disable pre-orders for
+ */
+ private function disable_pre_orders_for_products( $product_ids ) {
+
+ if ( ! is_array( $product_ids ) ) {
+ $product_ids = array( $product_ids );
+ }
+
+ foreach ( $product_ids as $product_id ) {
+ update_post_meta( $product_id, '_wc_pre_orders_enabled', 'no' );
+
+ do_action( 'wc_pre_orders_pre_orders_disabled_for_product', $product_id );
+ }
+ }
+
+ /**
+ * Checks for action to cancel an existing pre order and if needed it gets executed
+ *
+ * @since 1.0.3
+ */
+ public function check_cancel_pre_order() {
+ global $woocommerce;
+
+ if ( ! isset( $_GET['order_id'] ) || ! isset( $_GET['status'] ) ) {
+ return;
+ }
+
+ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), absint( $_GET['order_id'] ) ) ) {
+ return;
+ }
+
+ self::cancel_pre_order( absint( $_GET['order_id'] ) );
+
+ $string = __( 'Your pre-order has been cancelled.', 'woocommerce-pre-orders' );
+
+ // Backwards compatible (pre 2.1) for outputting notice
+ if ( function_exists( 'wc_add_notice' ) ) {
+ wc_add_notice( $string );
+ } else {
+ $woocommerce->add_message( $string );
+ }
+ }
+
+ /**
+ * Generates a unique key used to recognise if an order has been handled by a batch processeor.
+ *
+ * @param int[] $product_ids An array of product IDs to generate the hash for.
+ * @return string A hash of the product IDs.
+ */
+ private static function generate_batch_id( $product_ids ) {
+ // Sort the product IDs so a consistant hash is generated.
+ sort( $product_ids );
+ return md5( implode( array_values( $product_ids ) ) );
+ }
+
+ /**
+ * When the setting is enabled makes out of stock products into pre-order products
+ *
+ * @param int $product_id
+ * @param string $stock_status
+ * @param WC_Product $product
+ */
+ public function maybe_activate_preorder( $product_id, $stock_status, $product ) {
+ global $typenow;
+
+ if ( 'product' !== $typenow && 'outofstock' === $stock_status && 'yes' === get_option( 'wc_pre_orders_auto_pre_order_out_of_stock' ) ) {
+
+ foreach ( $product->get_children() as $child ) {
+ $child = wc_get_product( $child );
+ $child->set_stock_status( 'instock' );
+ $child->set_manage_stock( false );
+ $child->save();
+ }
+
+ update_post_meta( $product->get_id(), '_wc_pre_orders_enabled', 'yes' );
+ $product->set_manage_stock( false );
+ $product->set_stock_status( 'instock' );
+ $product->save();
+ }
+ }
+
+} // end \WC_Pre_Orders_Manager class
diff --git a/includes/class-wc-pre-orders-my-pre-orders.php b/includes/class-wc-pre-orders-my-pre-orders.php
new file mode 100644
index 0000000..9690a04
--- /dev/null
+++ b/includes/class-wc-pre-orders-my-pre-orders.php
@@ -0,0 +1,189 @@
+is_pre_orders_endpoint() ) {
+ $title = __( 'Pre-orders', 'woocommerce-pre-orders' );
+ remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
+ }
+
+ return $title;
+ }
+
+ /**
+ * Checks if current page is pre-orders endpoint.
+ *
+ * @since 1.4.7
+ *
+ * @return bool Returns true if current page is pre-orders endpoint
+ */
+ public function is_pre_orders_endpoint() {
+ global $wp_query;
+
+ return ( isset( $wp_query->query_vars['pre-orders'] )
+ && ! is_admin()
+ && is_main_query()
+ && in_the_loop()
+ && is_account_page()
+ );
+ }
+
+ /**
+ * Insert Pre-Ordres menu into My Account menus.
+ *
+ * @since 1.4.7
+ *
+ * @param array $items Menu items
+ *
+ * @return array Menu items
+ */
+ public function menu_items( $items ) {
+ // Insert Pre-Orders menu.
+ $new_items = array();
+ $new_items['pre-orders'] = __( 'Pre-orders', 'woocommerce-pre-orders' );
+
+ return $this->_insert_new_items_after( $items, $new_items, 'dashboard' );
+ }
+
+ /**
+ * Helper to add new items into an array after a selected item.
+ *
+ * @since 1.4.7
+ *
+ * @param array $items Menu items
+ * @param array $new_items New menu items
+ * @param string $after Key in items
+ *
+ * @return array Menu items
+ */
+ protected function _insert_new_items_after( $items, $new_items, $after ) {
+ // Search for the item position and +1 since is after the selected item key.
+ $position = array_search( $after, array_keys( $items ) ) + 1;
+
+ // Insert the new item.
+ $array = array_slice( $items, 0, $position, true );
+ $array += $new_items;
+ $array += array_slice( $items, $position, count( $items ) - $position, true );
+
+ return $array;
+ }
+
+ /**
+ * Output "My Pre-Orders" table in the user's My Account page
+ */
+ public function my_pre_orders() {
+ global $wc_pre_orders;
+
+ $pre_orders = WC_Pre_Orders_Manager::get_users_pre_orders();
+ $items = array();
+ $actions = array();
+
+ foreach ( $pre_orders as $order ) {
+ $_actions = array();
+ $order_item = WC_Pre_Orders_Order::get_pre_order_item( $order );
+
+ // Stop if the pre-order is complete
+ if ( is_null( $order_item ) ) {
+ continue;
+ }
+
+ // Set the items for the table
+ $items[] = array(
+ 'order' => $order,
+ 'data' => $order_item,
+ );
+
+ // Determine the available actions (Cancel)
+ if ( WC_Pre_Orders_Manager::can_pre_order_be_changed_to( 'cancelled', $order ) ) {
+ $_actions['cancel'] = array(
+ 'url' => WC_Pre_Orders_Manager::get_users_change_status_link( 'cancelled', $order ),
+ 'name' => __( 'Cancel', 'woocommerce-pre-orders' ),
+ );
+ }
+
+ $actions[ $order->get_id() ] = $_actions;
+ }
+
+ // Load the template
+ wc_get_template(
+ 'myaccount/my-pre-orders.php',
+ array(
+ 'pre_orders' => $pre_orders,
+ 'items' => $items,
+ 'actions' => $actions,
+ ),
+ '',
+ $wc_pre_orders->get_plugin_path() . '/templates/'
+ );
+ }
+}
+
+new WC_Pre_Orders_My_Pre_Orders();
diff --git a/includes/class-wc-pre-orders-order.php b/includes/class-wc-pre-orders-order.php
new file mode 100644
index 0000000..671aa1c
--- /dev/null
+++ b/includes/class-wc-pre-orders-order.php
@@ -0,0 +1,474 @@
+ _x( 'Pre-ordered', 'Order status', 'woocommerce-pre-orders' ),
+ 'public' => true,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of pre-orders */
+ 'label_count' => _n_noop( 'Pre-ordered (%s) ', 'Pre-ordered (%s) ', 'woocommerce-pre-orders' ),
+ )
+ );
+ }
+
+ /**
+ * Set wc-pre-ordered in WooCommerce order statuses.
+ *
+ * @param array $order_statuses
+ * @return array
+ */
+ public function order_statuses( $order_statuses ) {
+ $order_statuses['wc-pre-ordered'] = _x( 'Pre-ordered', 'Order status', 'woocommerce-pre-orders' );
+
+ return $order_statuses;
+ }
+
+ /**
+ * Add "pre-ordered" order status to WC Reports for tracking order revenue.
+ *
+ * @param array|bool $order_statuses
+ * @return array
+ */
+ public function add_pre_orders_to_report_statuses( $order_statuses ) {
+ return is_array( $order_statuses ) ? array_merge( $order_statuses, array( 'pre-ordered' ) ) : $order_statuses;
+ }
+
+ /**
+ * Get the order total formatted to show when the order will be (or was) charged
+ *
+ * @since 1.0
+ * @param string $formatted_total price string ( note: this is already formatted by woocommerce_price() )
+ * @param object $order the WC_Order object
+ * @return string the formatted order total price string
+ */
+ public function get_formatted_order_total( $formatted_total, $order ) {
+ $product = self::get_pre_order_product( $order );
+
+ if ( ! empty( $product ) ) {
+ // only modify the order total on the frontend when the order contains an active pre-order
+ if ( ! is_admin() && 'active' !== $this->get_pre_order_status( $order ) ) {
+ $formatted_total = WC_Pre_Orders_Manager::get_formatted_pre_order_total( $formatted_total, $product );
+ }
+ }
+
+ return $formatted_total;
+ }
+
+ /**
+ * Checks if an order contains a pre-order
+ *
+ * @since 1.0
+ * @param object|int $order Preferably the order object, or order ID if
+ * object is inconvenient to provide.
+ * @return bool true if the order contains a pre-order, false otherwise
+ */
+ public static function order_contains_pre_order( $order ) {
+ $order = wc_get_order( $order );
+ if ( ! is_object( $order ) ) {
+ return false;
+ }
+
+ return (bool) $order->get_meta( '_wc_pre_orders_is_pre_order', true );
+ }
+
+ /**
+ * Checks if an order will be charged upon release
+ *
+ * @since 1.0
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ * @return bool true if the order will be charged upon , false otherwise
+ */
+ public static function order_will_be_charged_upon_release( $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ $orders_when_charged = $order->get_meta( '_wc_pre_orders_when_charged', true );
+
+ if ( ! empty( $orders_when_charged ) ) {
+ return 'upon_release' === $orders_when_charged;
+ }
+
+ return WC_Pre_Orders_Product::product_is_charged_upon_release( self::get_pre_order_product( $order ) );
+ }
+
+ /**
+ * Checks if an order requires payment tokenization. For a pre-order charged upon release, a customer has the option
+ * to use the 'pay later' gateway, and then return and pay for the pre-order with a supported gateway. Because the
+ * pre-order is still marked as being charged upon release, this helps the supported gateway know how to process the
+ * payment.
+ *
+ * @since 1.0
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ * @return bool true if the order requires payment tokenization , false otherwise
+ */
+ public static function order_requires_payment_tokenization( $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ // if order already has a payment token, tokenization is not required
+ if ( self::order_has_payment_token( $order ) ) {
+ return false;
+ }
+
+ $order_id = $order->get_id();
+
+ // if the order is charged upon release and no payment token exists then it requires payment tokenization
+ return ( self::order_will_be_charged_upon_release( $order ) && ! WC_Pre_Orders_Manager::is_order_pay_later( $order_id ) );
+ }
+
+ /**
+ * Checks if an order has an existing payment token that can be used by the original gateway to charge the pre-order
+ * upon release
+ *
+ * @since 1.0
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ * @return bool true if the order contains a payment token , false otherwise
+ */
+ public static function order_has_payment_token( $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ return (bool) $order->get_meta( '_wc_pre_orders_has_payment_token', true );
+ }
+
+ /**
+ * Changes the status for an unpaid, but payment-tokenized order to pre-ordered and adds meta to indicate the order
+ * has a payment token. Should be used by supported gateways when processing a pre-order charged upon release, instead of calling
+ * $order->payment_complete(), this will be used. Note that if the order used pay later, this does not apply.
+ *
+ * @since 1.0
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ */
+ public static function mark_order_as_pre_ordered( $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ $order_id = $order->get_id();
+
+ if ( WC_Pre_Orders_Manager::is_order_pay_later( $order_id ) ) {
+ return;
+ }
+
+ // mark as having a payment token, which will be used upon release to charge pre-order total amount
+ $order->update_meta_data( '_wc_pre_orders_has_payment_token', 1 );
+
+ // update status
+ $order->update_status( 'pre-ordered' );
+
+ // Save order.
+ $order->save();
+
+ // reduce order stock
+ WC_Pre_Orders_Manager::reduce_stock_level( $order );
+ }
+
+ /**
+ * Since an order may only contain a single pre-ordered item, this returns
+ * the pre-ordered item array. This method assumes that $order is a pre-order
+ *
+ * @since 1.0
+ * @version 1.5.3
+ * @param object|int $order the order object or order ID
+ * @return object|bool the pre-ordered order item array
+ */
+ public static function get_pre_order_item( $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ foreach ( $order->get_items( 'line_item' ) as $order_item ) {
+
+ if ( ! empty( $order_item['product_id'] ) ) {
+ // Avoid running heavy queries via WC_Pre_Orders_Product::product_has_active_pre_orders() that check if any order exists with an active pre-order status to this product if we know the order provided is active.
+ if ( 'active' === self::get_pre_order_status( $order ) ) {
+ return $order_item;
+ } elseif ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $order_item['product_id'] ) || WC_Pre_Orders_Product::product_has_active_pre_orders( $order_item['product_id'] ) ) {
+ return $order_item;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Since an order may only contain a single pre-ordered product, this returns the pre-ordered product object
+ *
+ * @since 1.0
+ * @version 1.5.3
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ * @return object|bool the pre-ordered product object, or false if the cart does not contain a pre-order
+ */
+ public static function get_pre_order_product( $order ) {
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ if ( ! self::order_contains_pre_order( $order ) ) {
+ return null;
+ }
+
+ foreach ( $order->get_items( 'line_item' ) as $order_item ) {
+ if ( ! empty( $order_item['product_id'] ) ) {
+ // Avoid running heavy queries via WC_Pre_Orders_Product::product_has_active_pre_orders() that check if any order exists with an active pre-order status to this product if we know the order provided is active.
+ if ( 'active' === self::get_pre_order_status( $order ) ) {
+ return $order_item->get_product();
+ } elseif ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $order_item['product_id'] ) || WC_Pre_Orders_Product::product_has_active_pre_orders( $order_item['product_id'] ) ) {
+ // return the product object
+ return $order_item->get_product();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the pre-order status for an order
+ * - Active = awaiting release
+ * - Completed = availability date was reached or admin manually completed
+ * - Cancelled = order and/or pre-order was cancelled
+ *
+ * @since 1.0
+ * @param object|int $order Preferably the order object, or order ID if
+ * object is inconvenient to provide.
+ * @return bool|string The pre-order status or false if order is not valid.
+ */
+ public static function get_pre_order_status( $order ) {
+ $order = wc_get_order( $order );
+ return is_object( $order ) ? $order->get_meta( '_wc_pre_orders_status', true ) : false;
+ }
+
+ /**
+ * Returns a pre-order status to display
+ *
+ * @since 1.0
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ * @return string the pre-order status for display
+ */
+ public static function get_pre_order_status_to_display( $order ) {
+
+ $status = self::get_pre_order_status( $order );
+
+ switch ( $status ) {
+ case 'active':
+ $status_string = __( 'Active', 'woocommerce-pre-orders' );
+ break;
+ case 'completed':
+ $status_string = __( 'Completed', 'woocommerce-pre-orders' );
+ break;
+ case 'cancelled':
+ $status_string = __( 'Cancelled', 'woocommerce-pre-orders' );
+ break;
+ default:
+ $status_string = apply_filters( 'wc_pre_orders_custom_status_string', ucfirst( $status ), $order );
+ break;
+ }
+
+ return apply_filters( 'wc_pre_orders_status_string', $status_string, $status, $order );
+ }
+
+ /**
+ * Automatically change the pre-order status when the order status changes.
+ *
+ * @since 1.0
+ * @param int $order_id post ID of the order
+ * @param string $old_order_status the prior order status
+ * @param string $new_order_status the new order status
+ */
+ public function auto_update_pre_order_status( $order_id, $old_order_status, $new_order_status ) {
+
+ $order = wc_get_order( $order_id );
+
+ if ( 'pre-ordered' === $new_order_status && $this->order_contains_pre_order( $order_id ) ) {
+ $this->update_pre_order_status( $order_id, 'active' );
+ }
+
+ if ( 'on-hold' === $new_order_status && $this->order_contains_pre_order( $order_id ) ) {
+ $this->update_pre_order_status( $order_id, 'active' );
+ }
+
+ if ( 'completed' === $new_order_status && $this->order_contains_pre_order( $order_id ) ) {
+ // Get message to send it to customer email.
+ $transient_key = 'wc_pre_orders_pre_order_completed_message_' . $order_id;
+ $message = get_transient( $transient_key );
+ if ( ! empty( $message ) ) {
+ delete_transient( $transient_key );
+ } else {
+ $message = '';
+ }
+ $this->update_pre_order_status( $order_id, 'completed', $message );
+ }
+
+ // change to 'cancelled' when changing order status to 'cancelled', except when the pre-order status is already cancelled. this prevents sending double emails when bulk-cancelling pre-orders
+ if ( 'cancelled' === $new_order_status && self::order_contains_pre_order( $order_id ) && 'cancelled' !== $order->get_meta( '_wc_pre_orders_status', true ) ) {
+ $this->update_pre_order_status( $order_id, 'cancelled' );
+ }
+ }
+
+ /**
+ * Update the pre-order status for an order
+ *
+ * @since 1.0
+ * @param object|int $order preferably the order object, or order ID if object is inconvenient to provide
+ * @param string $new_status the new pre-order status
+ * @param string $message an optional message to include in the email to customer
+ */
+ public static function update_pre_order_status( $order, $new_status, $message = '' ) {
+ if ( ! $new_status ) {
+ return;
+ }
+
+ if ( ! is_object( $order ) ) {
+ $order = new WC_Order( $order );
+ }
+
+ $order_id = $order->get_id();
+
+ $old_status = $order->get_meta( '_wc_pre_orders_status', true );
+
+ if ( $old_status === $new_status ) {
+ return;
+ }
+
+ if ( ! $old_status ) {
+ $old_status = 'new';
+ }
+
+ $order->update_meta_data( '_wc_pre_orders_status', $new_status );
+
+ // actions for status changes
+ do_action( 'wc_pre_order_status_' . $new_status, $order_id, $message );
+ do_action( 'wc_pre_order_status_' . $old_status . '_to_' . $new_status, $order_id, $message );
+ do_action( 'wc_pre_order_status_changed', $order_id, $old_status, $new_status, $message );
+
+ // Make sure message ends with punctuation and concatenates with status
+ // transition string.
+ $message = rtrim( $message );
+ if ( ! empty( $message ) ) {
+ $message .= ! in_array( substr( $message, -1 ), array( '!', '?', '.', ';', ':' ) ) ? '.' : '';
+ $message .= ' ';
+ }
+
+ // add order note
+ /* translators: %1$s: old pre-order status %2$s: new pre-order status */
+ $order->add_order_note( $message . sprintf( __( 'Pre-order status changed from %1$s to %2$s.', 'woocommerce-pre-orders' ), $old_status, $new_status ) );
+
+ // Save order data
+ $order->save();
+ }
+
+ /**
+ * Automatically cancel a pre-order if it's parent order is moved to the trash. Note that un-trashing the order does
+ * not change the pre-order back to it's original status
+ *
+ * @since 1.0
+ * @param int $order_id the order post ID.
+ */
+ public function maybe_cancel_trashed_pre_order( $order_id ) {
+ $order = wc_get_order( $order_id );
+ if ( ! is_object( $order ) ) {
+ return;
+ }
+
+ if ( $this->order_contains_pre_order( $order ) && WC_Pre_Orders_Manager::can_pre_order_be_changed_to( 'cancelled', $order ) ) {
+ $this->update_pre_order_status( $order, 'cancelled' );
+ }
+ }
+
+ /**
+ * Product is in stock for orders which are pre-orders (stock reduced during pre-order)
+ *
+ * @param bool $in_stock
+ * @param WC_Product $product
+ * @param WC_Order $order
+ *
+ * @return bool
+ */
+ public static function product_in_stock( $in_stock, $product, $order ) {
+ if ( self::order_contains_pre_order( $order ) ) {
+ $in_stock = true;
+ }
+
+ return $in_stock;
+ }
+
+} // end \WC_Pre_Orders_Order class
diff --git a/includes/class-wc-pre-orders-privacy.php b/includes/class-wc-pre-orders-privacy.php
new file mode 100644
index 0000000..823e66c
--- /dev/null
+++ b/includes/class-wc-pre-orders-privacy.php
@@ -0,0 +1,24 @@
+Learn more about how this works, including what you may want to include in your privacy policy.', 'woocommerce-pre-orders' ), 'https://docs.woocommerce.com/document/marketplace-privacy/#woocommerce-pre-orders' ) );
+ }
+}
+
+new WC_Pre_Orders_Privacy();
diff --git a/includes/class-wc-pre-orders-product.php b/includes/class-wc-pre-orders-product.php
new file mode 100644
index 0000000..43a03e7
--- /dev/null
+++ b/includes/class-wc-pre-orders-product.php
@@ -0,0 +1,589 @@
+get_pre_order_product_message( $product, true );
+
+ return "
+ permalink}\" class=\"wc-block-grid__product-link\">
+ {$data->image}
+ {$data->title}
+
+ {$data->badge}
+ {$data->price}
+ {$data->rating}
+ {$pre_order_message}
+ {$data->button}
+ ";
+ }
+
+ /**
+ * Add a customizable message to product's on the shop loop page and / or on the single product page immediately
+ * after the price
+ *
+ * @since 1.0
+ */
+ public function add_pre_order_product_message() {
+ global $product;
+
+ $product_grid = 'woocommerce_after_shop_loop_item_title' === current_filter();
+
+ $message = $this->get_pre_order_product_message( $product, $product_grid );
+
+ echo wp_kses_post( $message );
+ }
+
+ /**
+ * Get message of when product will be available.
+ *
+ * @param WC_Product $product Current product.
+ * @param bool $product_grid We are currently displaying a grid of products.
+ *
+ * @return string
+ */
+ private function get_pre_order_product_message( $product, $product_grid = false ) {
+ // Only modify products with pre-orders enabled
+ if ( ! self::product_can_be_pre_ordered( $product ) ) {
+ return '';
+ }
+
+ // Get custom message
+ if ( $product_grid ) {
+ $message = get_option( 'wc_pre_orders_shop_loop_product_message' );
+ } else {
+ $message = get_option( 'wc_pre_orders_single_product_message' );
+ }
+
+ // Bail if none available
+ if ( ! $message ) {
+ return '';
+ }
+
+ // Add localized availability date if needed
+ $message = str_replace( '{availability_date}', $this->get_localized_availability_date( $product ), $message );
+
+ // Add localized availability time if needed
+ $message = str_replace( '{availability_time}', $this->get_localized_availability_time( $product ), $message );
+
+ $message = apply_filters( 'wc_pre_orders_product_message', $message, $product );
+
+ $message = '' . $message . ' ';
+
+ return $message;
+ }
+
+ /**
+ * Modifies the add to cart button text on product loop page & single product page
+ *
+ * @since 1.0
+ * @param string $default_text default add to cart button text
+ * @param WC_Product $product
+ * @return string
+ */
+ public function modify_add_to_cart_button_text( $default_text, $product ) {
+ // Only modify products with pre-orders enabled
+ if ( ! self::product_can_be_pre_ordered( $product ) ) {
+ return $default_text;
+ }
+
+ // Get custom text if set
+ $text = get_option( 'wc_pre_orders_add_to_cart_button_text' );
+
+ if ( $text ) {
+ return $text;
+ } else {
+ return $default_text;
+ }
+ }
+
+ /**
+ * Modify availability text
+ *
+ * @param array $data
+ * @param WC_Product $product
+ *
+ * @return array
+ */
+ public function modify_availability_text( $data, $product ) {
+ if ( self::product_can_be_pre_ordered( $product ) ) {
+ $availability = $class = '';
+
+ if ( $product->managing_stock() ) {
+ if ( sizeof( $product->get_children() ) > 0 ) {
+ $product_total_stock = max( 0, $product->get_stock_quantity() );
+
+ foreach ( $product->get_children() as $child_id ) {
+ if ( 'yes' === get_post_meta( $child_id, '_manage_stock', true ) ) {
+ $stock = get_post_meta( $child_id, '_stock', true );
+ $product_total_stock += max( 0, wc_stock_amount( $stock ) );
+ }
+ }
+ } else {
+ $product_total_stock = $product->get_stock_quantity();
+ }
+
+ $product_total_stock = wc_stock_amount( $product_total_stock );
+
+ if ( $product->is_in_stock() && $product_total_stock > get_option( 'woocommerce_notify_no_stock_amount' ) ) {
+ switch ( get_option( 'woocommerce_stock_format' ) ) {
+ case 'no_amount':
+ $availability = __( 'Available for pre-ordering', 'woocommerce-pre-orders' );
+ break;
+ case 'low_amount':
+ if ( $product_total_stock <= get_option( 'woocommerce_notify_low_stock_amount' ) ) {
+ /* translators: 1: product total stock */
+ $availability = sprintf( __( 'Only %s left available for pre-ordering', 'woocommerce-pre-orders' ), $product_total_stock );
+
+ if ( $product->backorders_allowed() && $product->backorders_require_notification() ) {
+ $availability .= ' ' . __( '(can be backordered)', 'woocommerce-pre-orders' );
+ }
+ } else {
+ $availability = __( 'Available for pre-ordering', 'woocommerce-pre-orders' );
+ }
+ break;
+
+ default:
+ /* translators: 1: product total stock */
+ $availability = sprintf( __( '%s available for pre-ordering', 'woocommerce-pre-orders' ), $product_total_stock );
+
+ if ( $product->backorders_allowed() && $product->backorders_require_notification() ) {
+ $availability .= ' ' . __( '(can be backordered)', 'woocommerce-pre-orders' );
+ }
+ break;
+ }
+
+ $class = 'in-stock';
+ } elseif ( $product->backorders_allowed() && $product->backorders_require_notification() ) {
+ $availability = __( 'Available on backorder', 'woocommerce-pre-orders' );
+ $class = 'available-on-backorder';
+ } elseif ( $product->backorders_allowed() ) {
+ $availability = __( 'Available for pre-ordering', 'woocommerce-pre-orders' );
+ $class = 'in-stock';
+ } else {
+ $availability = __( 'No longer available for pre-ordering', 'woocommerce-pre-orders' );
+ $class = 'out-of-stock';
+ }
+ } elseif ( ! $product->is_in_stock() ) {
+ $availability = __( 'No longer available for pre-ordering', 'woocommerce-pre-orders' );
+ $class = 'out-of-stock';
+ }
+
+ $data = array(
+ 'availability' => $availability,
+ 'class' => $class,
+ );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Checks if a given product can be pre-ordered by verifying pre-orders are enabled for it
+ *
+ * @since 2.0.2 Validate compatible pre-order product types.
+ * @since 1.0
+ *
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ *
+ * @return bool true if product can be pre-ordered, false otherwise
+ */
+ public static function product_can_be_pre_ordered( $product ) {
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return false;
+ }
+ }
+
+ if ( $product->is_type( 'variation' ) ) {
+ $variant = clone $product;
+ $product = wc_get_product( $variant->get_parent_id() );
+ if ( ! is_object( $product ) ) {
+ return false;
+ }
+ $product_id = $product->get_id();
+ } else {
+ $variant = null;
+ $product_id = $product->get_id();
+ }
+
+ $can_be_pre_ordered = 'yes' === get_post_meta( $product_id, '_wc_pre_orders_enabled', true ) &&
+ in_array( $product->get_type(), WC_Pre_Orders::get_supported_product_types(), true );
+
+ /**
+ * Filter whether a product can be pre-ordered.
+ *
+ * The result of this filter is cast to a boolean to ensure the method
+ * WC_Pre_Orders_Product::product_can_be_pre_ordered() returns the correct type.
+ *
+ * @since 2.0.4
+ *
+ * @param bool $can_be_pre_ordered Whether the product can be pre-ordered.
+ * @param WC_Product $product The product object. For variants, this is the parent product.
+ * @param WC_Product|null $variant The variant product object. Null for non-variants.
+ */
+ return (bool) apply_filters( 'wc_pre_orders_product_can_be_pre_ordered', $can_be_pre_ordered, $product, $variant );
+ }
+
+ /**
+ * Checks if a given product has active pre-orders
+ *
+ * @since 1.0.0
+ * @version 1.5.1
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @return bool true if product can be pre-ordered, false otherwise
+ */
+ public static function product_has_active_pre_orders( $product ) {
+ global $wpdb;
+
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return false;
+ }
+ }
+
+ if ( WC_Pre_Orders::is_hpos_enabled() ) {
+ $order_ids = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ SELECT orders.id
+ FROM {$wpdb->prefix}wc_orders AS orders
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_items AS items ON orders.id = items.order_id
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS item_meta ON items.order_item_id = item_meta.order_item_id
+ LEFT JOIN {$wpdb->prefix}wc_orders_meta AS order_meta ON items.order_id = order_meta.order_id
+ WHERE
+ items.order_item_type = 'line_item' AND
+ item_meta.meta_key = '_product_id' AND
+ item_meta.meta_value = '%s' AND
+ order_meta.meta_key = '_wc_pre_orders_status' AND
+ order_meta.meta_value = 'active'
+ LIMIT 1
+ ",
+ $product->get_id()
+ )
+ );
+ } else {
+ $order_ids = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ SELECT ID
+ FROM {$wpdb->posts} AS posts
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_items AS items ON posts.ID = items.order_id
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS item_meta ON items.order_item_id = item_meta.order_item_id
+ LEFT JOIN {$wpdb->postmeta} AS post_meta ON items.order_id = post_meta.post_id
+ WHERE
+ items.order_item_type = 'line_item' AND
+ item_meta.meta_key = '_product_id' AND
+ item_meta.meta_value = '%s' AND
+ post_meta.meta_key = '_wc_pre_orders_status' AND
+ post_meta.meta_value = 'active'
+ ",
+ $product->get_id()
+ )
+ );
+ }
+
+ return ( ! empty( $order_ids ) );
+ }
+
+ /**
+ * Checks if a given pre-order-enabled product is charged upon release
+ *
+ * @since 1.0
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @return bool true if pre-order is charged upon release, false otherwise
+ */
+ public static function product_is_charged_upon_release( $product ) {
+
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return false;
+ }
+ }
+
+ return 'upon_release' === get_post_meta( $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(), '_wc_pre_orders_when_to_charge', true );
+ }
+
+ /**
+ * Checks if a given pre-order-enabled product is charged upfront
+ *
+ * @since 1.0
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @return bool true if pre-order is charged upfront, false otherwise
+ */
+ public static function product_is_charged_upfront( $product ) {
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return false;
+ }
+ }
+
+ return 'upfront' === get_post_meta( $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(), '_wc_pre_orders_when_to_charge', true );
+ }
+
+ /**
+ * Gets the pre-order fee for a given product
+ *
+ * @since 1.0
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @return string the pre-order fee amount
+ */
+ public static function get_pre_order_fee( $product ) {
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return;
+ }
+ }
+
+ return get_post_meta( $product->get_id(), '_wc_pre_orders_fee', true );
+ }
+
+ /**
+ * Gets the tax status of a pre-order fee by checking the tax status of the product
+ *
+ * @since 1.0
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @return bool true if the pre-order fee is taxable, false otherwise
+ */
+ public static function get_pre_order_fee_tax_status( $product ) {
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return false;
+ }
+ }
+
+ return 'taxable' === $product->get_tax_status();
+ }
+
+ /**
+ * Gets the availability date of the product localized to the site's date format
+ *
+ * @since 1.0
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @param string $none_text optional text to return if there is no availability datetime set
+ * @return string the formatted availability date
+ */
+ public static function get_localized_availability_date( $product, $none_text = '' ) {
+ if ( '' === $none_text ) {
+ $none_text = __( 'at a future date', 'woocommerce-pre-orders' );
+ }
+
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return '';
+ }
+ }
+
+ $timestamp = self::get_localized_availability_datetime_timestamp( $product );
+
+ if ( ! $timestamp ) {
+ return $none_text;
+ }
+
+ return apply_filters( 'wc_pre_orders_localized_availability_date', date_i18n( wc_date_format(), $timestamp ), $product, $none_text );
+ }
+
+ /**
+ * Gets the availability time of the product formatted according to the site's time format and timezone
+ *
+ * @since 1.0
+ * @param object|int $product preferably the product object, or product ID if object is inconvenient to provide
+ * @return string the formatted availability time
+ */
+ public static function get_localized_availability_time( $product ) {
+ $timestamp = self::get_localized_availability_datetime_timestamp( $product );
+
+ $localized_time = date( get_option( 'time_format' ), $timestamp );
+
+ return apply_filters( 'wc_pre_orders_localized_availability_time', $localized_time, $timestamp );
+ }
+
+ /**
+ * Gets the availability timestamp of the product localized to the configured
+ * timezone
+ *
+ * @param WC_Product|int $product the product object or post identifier
+ * @return int the timestamp, localized to the current timezone
+ */
+ public static function get_localized_availability_datetime_timestamp( $product ) {
+ if ( ! is_object( $product ) ) {
+ $product = wc_get_product( $product );
+
+ if ( ! is_object( $product ) ) {
+ return 0;
+ }
+ }
+
+ if ( ! $product || ! $timestamp = get_post_meta( $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(), '_wc_pre_orders_availability_datetime', true ) ) {
+ return 0;
+ }
+
+ try {
+ // Get datetime object from unix timestamp
+ $datetime = new DateTime( "@{$timestamp}", new DateTimeZone( 'UTC' ) );
+
+ // Set the timezone to the site timezone
+ $datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
+
+ // Return the unix timestamp adjusted to reflect the site's timezone
+ return $timestamp + $datetime->getOffset();
+
+ } catch ( Exception $e ) {
+ global $wc_pre_orders;
+
+ // Log error
+ $wc_pre_orders->log( $e->getMessage() );
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the timezone string for a site, even if it's set to a UTC offset
+ *
+ * Adapted from http://www.php.net/manual/en/function.timezone-name-from-abbr.php#89155
+ *
+ * @since 1.0
+ * @return string valid PHP timezone string
+ */
+ public static function get_wp_timezone_string() {
+ _deprecated_function( 'WC_Pre_Orders_Product::get_wp_timezone_string', '1.5.29', 'wc_timezone_string' );
+ return wc_timezone_string();
+ }
+
+ /**
+ * Maybe cancel pre order when product is trashed
+ *
+ * @param int $product_id Product ID
+ * @return void
+ */
+ public function maybe_cancel_pre_order_product_trashed( $product_id ) {
+ global $wpdb;
+
+ $orders = $wpdb->get_results(
+ $wpdb->prepare(
+ "
+ SELECT order_items.order_id
+ FROM {$wpdb->prefix}woocommerce_order_items AS order_items
+ LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_itemmeta
+ ON order_itemmeta.order_item_id = order_items.order_item_id
+ WHERE order_itemmeta.meta_key = '_product_id'
+ AND order_itemmeta.meta_value = %d
+ ",
+ $product_id
+ )
+ );
+
+ if ( is_array( $orders ) ) {
+ foreach ( $orders as $order_data ) {
+ $order = wc_get_order( $order_data->order_id );
+ if ( ! $order ) {
+ continue;
+ }
+
+ if ( WC_Pre_Orders_Order::order_contains_pre_order( $order ) && WC_Pre_Orders_Manager::can_pre_order_be_changed_to( 'cancelled', $order ) ) {
+ WC_Pre_Orders_Order::update_pre_order_status( $order, 'cancelled' );
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the list of products with an availability date in the past.
+ *
+ * @return array An array of products IDs which have passed their scheduled availability date.
+ */
+ public static function get_products_passed_release_date() {
+ $time_now_in_utc = time();
+
+ // Get all products that are currently an active pre order product still
+ return get_posts(
+ array(
+ 'fields' => 'ids',
+ 'nopaging' => true,
+ 'post_status' => 'publish',
+ 'post_type' => 'product',
+ 'meta_query' => array(
+ 'relation' => 'AND',
+ array(
+ 'key' => '_wc_pre_orders_enabled',
+ 'value' => 'yes',
+ ),
+ array(
+ 'key' => '_wc_pre_orders_availability_datetime',
+ 'value' => $time_now_in_utc,
+ 'compare' => '<',
+ ),
+ ),
+ )
+ );
+ }
+}
diff --git a/includes/class-wc-pre-orders.php b/includes/class-wc-pre-orders.php
new file mode 100644
index 0000000..e547092
--- /dev/null
+++ b/includes/class-wc-pre-orders.php
@@ -0,0 +1,443 @@
+base_file = $base_file;
+
+ // load core classes
+ $this->load_classes();
+
+ // load classes that require WC to be loaded
+ add_action( 'woocommerce_init', array( $this, 'init' ) );
+
+ // add pre-order notification emails
+ add_filter( 'woocommerce_email_classes', array( $this, 'add_email_classes' ) );
+
+ // add 'pay later' payment gateway
+ add_filter( 'woocommerce_payment_gateways', array( $this, 'add_pay_later_gateway' ) );
+
+ // Declare compatibility with various Woo features.
+ add_action( 'before_woocommerce_init', array( $this, 'declare_feature_compatibility' ) );
+
+ // Hook up emails
+ $emails = array(
+ 'wc_pre_order_status_new_to_active',
+ 'wc_pre_order_status_completed',
+ 'wc_pre_order_status_active_to_cancelled',
+ 'wc_pre_orders_pre_order_date_changed',
+ 'wc_pre_orders_pre_ordered',
+ 'wc_pre_orders_pre_order_available',
+ );
+ foreach ( $emails as $action ) {
+ add_action( $action, array( $this, 'send_transactional_email' ), 10, 2 );
+ add_action(
+ 'woocommerce_order_action_send_email_' . $action,
+ function ( $order ) use ( $action ) {
+ return $this->sendmail( $action, $order );
+ }
+ );
+ }
+
+ // Un-schedule events on plugin deactivation
+ register_deactivation_hook( $this->base_file, array( $this, 'deactivate' ) );
+ }
+
+ /**
+ * Main Instance.
+ *
+ * Ensures only one instance is loaded or can be loaded.
+ *
+ * @return WC_Pre_Orders
+ * @since 1.5.25
+ */
+ public static function instance() {
+ if ( is_null( self::$_instance ) ) {
+ self::$_instance = new self();
+ }
+
+ return self::$_instance;
+ }
+
+ /**
+ * This function will send email based on action name.
+ *
+ * @param string $email Action name
+ * @param WC_Order $order
+ */
+ public function sendmail( $email, $order ) {
+ // Convert action name to class name
+ $email = implode( '_', array_map( 'ucfirst', explode( '_', $email ) ) );
+ $email = str_replace( 'Wc_Pre_Orders_', 'WC_Pre_Orders_Email_', $email );
+
+ $emails = WC()->mailer->emails;
+
+ if ( ! isset( $emails[ $email ] ) ) {
+ return;
+ }
+
+ $mail = $emails[ $email ];
+
+ $mail->trigger( $order->get_id() );
+
+ /* translators: %s: email title */
+ $order->add_order_note( sprintf( __( '%s email notification manually sent.', 'woocommerce-pre-orders' ), $mail->title ), false, true );
+ }
+
+ /**
+ * Load core classes
+ *
+ * @since 1.0
+ */
+ public function load_classes() {
+ if( is_admin() ){
+ // Load admin filters.
+ require 'admin/filters.php';
+ }
+
+ // load wp-cron hooks for scheduled events
+ require 'class-wc-pre-orders-cron.php';
+ $this->cron = new WC_Pre_Orders_Cron();
+
+ // load manager class to process pre-order actions
+ require 'class-wc-pre-orders-manager.php';
+ $this->manager = new WC_Pre_Orders_Manager();
+
+ // load product customizations / tweaks
+ require 'class-wc-pre-orders-product.php';
+ $this->product = new WC_Pre_Orders_Product();
+
+ // Load cart customizations / overrides
+ require 'class-wc-pre-orders-cart.php';
+ $this->cart = new WC_Pre_Orders_Cart();
+
+ // Load checkout customizations / overrides
+ require 'class-wc-pre-orders-checkout.php';
+ $this->checkout = new WC_Pre_Orders_Checkout();
+
+ // Load order hooks
+ require 'class-wc-pre-orders-order.php';
+ $this->order = new WC_Pre_Orders_Order();
+
+ include_once 'class-wc-pre-orders-my-pre-orders.php';
+ }
+
+ /**
+ * Loads the classes for the integration with WooCommerce Blocks.
+ */
+ public static function load_block_classes() {
+
+ if ( WC_PRE_ORDERS_GUTENBERG_EXISTS ) {
+ require_once __DIR__ . '/blocks/class-wc-pre-orders-blocks-integration.php';
+ require_once __DIR__ . '/blocks/class-wc-pre-orders-extend-store-api.php';
+ new WooCommerce\Pre_Orders\Blocks\WC_Pre_Orders_Blocks_Integration();
+ }
+ }
+
+ /**
+ * Load actions and filters that require WC to be loaded
+ *
+ * @since 1.0
+ */
+ public function init() {
+
+ if ( is_admin() ) {
+ // Load admin.
+ if ( defined( 'DOING_AJAX' ) ) {
+ require 'admin/class-wc-pre-orders-admin-ajax.php';
+ } else {
+ require 'admin/class-wc-pre-orders-admin.php';
+ }
+
+ // add a 'Configure' link to the plugin action links
+ add_filter(
+ 'plugin_action_links_' . plugin_basename( $this->base_file ),
+ array(
+ $this,
+ 'plugin_action_links',
+ )
+ );
+ } else {
+
+ // Watch for cancel URL action
+ add_action( 'init', array( $this->manager, 'check_cancel_pre_order' ) );
+
+ // add countdown shortcode
+ $this->add_countdown_shortcode();
+ }
+ }
+
+ /**
+ * Add the 'pay later' gateway, which replaces gateways that do not support pre-orders when the pre-order is charged
+ * upon release
+ *
+ * @since 1.0
+ */
+ public function add_pay_later_gateway( $gateways ) {
+ require_once 'gateways/class-wc-pre-orders-gateway-pay-later.php';
+
+ $gateways[] = 'WC_Pre_Orders_Gateway_Pay_Later';
+
+ return $gateways;
+ }
+
+ /**
+ * Adds the countdown shortcode.
+ *
+ * @return void
+ */
+ private function add_countdown_shortcode() {
+ require_once 'shortcodes/class-wc-pre-orders-shortcode-countdown.php';
+ add_shortcode( 'woocommerce_pre_order_countdown', array( 'WC_Pre_Orders_Shortcode_Countdown', 'get_pre_order_countdown_shortcode_content' ) );
+ }
+
+ /**
+ * Adds Pre-Order email classes
+ *
+ * @since 1.0
+ */
+ public function add_email_classes( $email_classes ) {
+
+ foreach (
+ array(
+ 'new-pre-order',
+ 'pre-order-available',
+ 'pre-order-cancelled',
+ 'admin-pre-order-cancelled',
+ 'pre-order-date-changed',
+ 'pre-ordered',
+ ) as $class_file_name
+ ) {
+ require_once "emails/class-wc-pre-orders-email-{$class_file_name}.php";
+ }
+
+ $email_classes['WC_Pre_Orders_Email_New_Pre_Order'] = new WC_Pre_Orders_Email_New_Pre_Order();
+ $email_classes['WC_Pre_Orders_Email_Pre_Ordered'] = new WC_Pre_Orders_Email_Pre_Ordered();
+ $email_classes['WC_Pre_Orders_Email_Pre_Order_Date_Changed'] = new WC_Pre_Orders_Email_Pre_Order_Date_Changed();
+ $email_classes['WC_Pre_Orders_Email_Pre_Order_Cancelled'] = new WC_Pre_Orders_Email_Pre_Order_Cancelled();
+ $email_classes['WC_Pre_Orders_Email_Admin_Pre_Order_Cancelled'] = new WC_Pre_Orders_Email_Admin_Pre_Order_Cancelled();
+ $email_classes['WC_Pre_Orders_Email_Pre_Order_Available'] = new WC_Pre_Orders_Email_Pre_Order_Available();
+
+ return $email_classes;
+ }
+
+ /**
+ * Sends transactional email by hooking into pre-order status changes
+ *
+ * @since 1.0
+ */
+ public function send_transactional_email( $args = array(), $message = '' ) {
+ global $woocommerce;
+
+ $woocommerce->mailer();
+
+ do_action( current_filter() . '_notification', $args, $message );
+ }
+
+ /**
+ * Remove terms and scheduled events on plugin deactivation
+ *
+ * @since 1.0
+ */
+ public function deactivate() {
+
+ // Remove scheduling function before removing scheduled hook, or else it will get re-added
+ remove_action( 'init', array( $this->cron, 'add_scheduled_events' ) );
+
+ // clear pre-order completion check event
+ wp_clear_scheduled_hook( 'wc_pre_orders_completion_check' );
+ }
+
+ /**
+ * Return the plugin action links.
+ *
+ * @param array $actions Associative array of action names to anchor tags.
+ *
+ * @return array Associative array of plugin action links.
+ */
+ public function plugin_action_links( $actions ) {
+ $plugin_actions = array(
+ 'settings' => sprintf( '%s ', esc_url( admin_url( 'admin.php?page=wc-settings&tab=pre_orders' ) ), __( 'Settings', 'woocommerce-pre-orders' ) ),
+ 'manage' => sprintf( '%s ', esc_url( admin_url( 'admin.php?page=wc_pre_orders' ) ), __( 'Manage pre-orders', 'woocommerce-pre-orders' ) ),
+ 'support' => '' . __( 'Support', 'woocommerce-pre-orders' ) . ' ',
+ 'docs' => '' . __( 'Docs', 'woocommerce-pre-orders' ) . ' ',
+ );
+
+ return array_merge( $plugin_actions, $actions );
+ }
+
+ /**
+ * Returns the plugin's path without a trailing slash
+ *
+ * @return string the plugin path
+ * @since 1.0
+ *
+ */
+ public function get_plugin_path() {
+ if ( $this->plugin_path ) {
+ return $this->plugin_path;
+ }
+
+ $this->plugin_path = untrailingslashit( plugin_dir_path( $this->base_file ) );
+
+ return $this->plugin_path;
+ }
+
+
+ /**
+ * Returns the plugin's url without a trailing slash
+ *
+ * @return string the plugin url
+ * @since 1.0
+ *
+ */
+ public function get_plugin_url() {
+ if ( $this->plugin_url ) {
+ return $this->plugin_url;
+ }
+
+ $this->plugin_url = plugins_url( basename( plugin_dir_path( $this->base_file ) ), basename( $this->base_file ) );
+
+ return $this->plugin_url;
+ }
+
+ /**
+ * Log errors to WooCommerce log
+ *
+ * @param string $message message to log
+ *
+ * @since 1.0
+ *
+ */
+ public function log( $message ) {
+ global $woocommerce;
+
+ if ( ! is_object( $this->logger ) ) {
+ if ( class_exists( 'WC_Logger' ) ) {
+ $this->logger = new WC_Logger();
+ } else {
+ $this->logger = $woocommerce->logger();
+ }
+ }
+
+ $this->logger->add( 'pre-orders', $message );
+ }
+
+ /**
+ * Get supported product types.
+ *
+ * @return array
+ */
+ public static function get_supported_product_types() {
+ $product_types = array(
+ 'simple',
+ 'variable',
+ 'composite',
+ 'bundle',
+ 'booking',
+ 'mix-and-match',
+ );
+
+ return apply_filters( 'wc_pre_orders_supported_product_types', $product_types );
+ }
+
+ /**
+ * Declare compatibility with various Woo features.
+ *
+ * @since 1.9.0
+ */
+ public function declare_feature_compatibility() {
+ if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
+ \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', $this->base_file, true );
+
+ require_once 'admin/class-wc-pre-orders-product-editor-compatibility.php';
+ \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'product_block_editor', $this->base_file, true );
+ }
+ }
+
+ /**
+ * Check if High-performance Order Storage ("HPOS") enable
+ *
+ * @return bool Whether enabled or not
+ */
+ public static function is_hpos_enabled() {
+ if ( class_exists( 'Automattic\WooCommerce\Utilities\OrderUtil' ) ) {
+ return Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();
+ }
+ return false;
+ }
+}
diff --git a/includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php b/includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php
new file mode 100644
index 0000000..18591cc
--- /dev/null
+++ b/includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php
@@ -0,0 +1,130 @@
+id = 'wc_pre_orders_admin_pre_order_cancelled';
+ $this->title = __( 'Pre-order Cancelled (Admin)', 'woocommerce-pre-orders' );
+ $this->description = __( 'This is an order notification sent to the admin after a pre-order is cancelled.', 'woocommerce-pre-orders' );
+
+ $this->heading = __( 'Pre-order Cancelled', 'woocommerce-pre-orders' );
+ $this->subject = __( '[{site_title}] pre-order from {order_date} has been cancelled', 'woocommerce-pre-orders' );
+
+ $this->template_base = $wc_pre_orders->get_plugin_path() . '/templates/';
+ $this->template_html = 'emails/admin-pre-order-cancelled.php';
+ $this->template_plain = 'emails/plain/admin-pre-order-cancelled.php';
+
+ // Triggers for this email
+ add_action( 'wc_pre_order_status_active_to_cancelled_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor
+ parent::__construct();
+ }
+
+
+ /**
+ * Dispatch the email
+ */
+ public function trigger( $order_id, $message ) {
+ if ( $order_id ) {
+ $this->object = new WC_Order( $order_id );
+ $this->recipient = get_option( 'admin_email' );
+ $this->message = $message;
+
+ $this->placeholders = array_merge(
+ array(
+ '{order_date}' => date_i18n(
+ wc_date_format(),
+ strtotime(
+ $this->object->get_date_created()
+ ? gmdate( 'Y-m-d H:i:s', $this->object->get_date_created()->getOffsetTimestamp() )
+ : ''
+ )
+ ),
+ '{release_date}' => WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ) ),
+ '{order_number}' => $this->object->get_order_number()
+ ),
+ $this->placeholders
+ );
+ }
+
+ if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
+ return;
+ }
+
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+
+ /**
+ * Gets the email HTML content
+ *
+ * @return string the email HTML content
+ */
+ public function get_content_html() {
+ ob_start();
+ wc_get_template(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'plain_text' => false,
+ 'email' => $this,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Gets the email plain content
+ *
+ * @return string the email plain content
+ */
+ public function get_content_plain() {
+ ob_start();
+ wc_get_template(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'plain_text' => true,
+ 'email' => $this,
+ 'sent_to_admin' => true,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+}
diff --git a/includes/emails/class-wc-pre-orders-email-new-pre-order.php b/includes/emails/class-wc-pre-orders-email-new-pre-order.php
new file mode 100644
index 0000000..7778517
--- /dev/null
+++ b/includes/emails/class-wc-pre-orders-email-new-pre-order.php
@@ -0,0 +1,188 @@
+id = 'wc_pre_orders_new_pre_order';
+ $this->title = __( 'New pre-order', 'woocommerce-pre-orders' );
+ $this->description = __( 'New pre-order emails are sent when a pre-order is received.', 'woocommerce-pre-orders' );
+
+ $this->heading = __( 'New pre-order: #{order_number}', 'woocommerce-pre-orders' );
+ $this->subject = __( '[{site_title}] New customer pre-order ({order_number}) - {order_date}', 'woocommerce-pre-orders' );
+
+ $this->template_base = $wc_pre_orders->get_plugin_path() . '/templates/';
+ $this->template_html = 'emails/admin-new-pre-order.php';
+ $this->template_plain = 'emails/plain/admin-new-pre-order.php';
+
+ // Triggers for this email
+ add_action( 'wc_pre_order_status_new_to_active_notification', array( $this, 'trigger' ) );
+
+ // Call parent constructor
+ parent::__construct();
+
+ // Other settings
+ $this->recipient = $this->get_option( 'recipient' );
+
+ if ( ! $this->recipient ) {
+ $this->recipient = get_option( 'admin_email' );
+ }
+ }
+
+
+ /**
+ * Dispatch the email
+ *
+ * @since 1.0
+ */
+ public function trigger( $order_id ) {
+ if ( $order_id ) {
+ $this->object = new WC_Order( $order_id );
+
+ $this->placeholders = array_merge(
+ array(
+ '{order_date}' => date_i18n(
+ wc_date_format(),
+ strtotime( (
+ $this->object->get_date_created()
+ ? gmdate( 'Y-m-d H:i:s', $this->object->get_date_created()->getOffsetTimestamp() )
+ : ''
+ ) )
+ ),
+ '{order_number}' => $this->object->get_order_number()
+ ),
+ $this->placeholders
+ );
+ }
+
+ if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
+ return;
+ }
+
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+
+ /**
+ * Gets the email HTML content
+ *
+ * @since 1.0
+ * @return string the email HTML content
+ */
+ public function get_content_html() {
+ global $wc_pre_orders;
+ ob_start();
+ wc_get_template(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'plain_text' => false,
+ 'email' => $this,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Gets the email plain content
+ *
+ * @since 1.0
+ * @return string the email plain content
+ */
+ public function get_content_plain() {
+ global $wc_pre_orders;
+ ob_start();
+ wc_get_template(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'plain_text' => true,
+ 'sent_to_admin' => true,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Initialise Settings Form Fields
+ *
+ * @since 1.0
+ */
+ public function init_form_fields() {
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce-pre-orders' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable this email notification', 'woocommerce-pre-orders' ),
+ 'default' => 'yes',
+ ),
+ 'recipient' => array(
+ 'title' => __( 'Recipient(s)', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ /* translators: %s: admin email address */
+ 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to %s
.', 'woocommerce-pre-orders' ), esc_attr( get_option( 'admin_email' ) ) ),
+ 'placeholder' => '',
+ 'default' => '',
+ ),
+ 'subject' => array(
+ 'title' => __( 'Subject', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ /* translators: %s: email subject */
+ 'description' => sprintf( __( 'This controls the email subject line. Leave blank to use the default subject: %s
.', 'woocommerce-pre-orders' ), $this->subject ),
+ 'placeholder' => '',
+ 'default' => '',
+ ),
+ 'heading' => array(
+ 'title' => __( 'Email heading', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ /* translators: %s: email heading */
+ 'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: %s
.', 'woocommerce-pre-orders' ), $this->heading ),
+ 'placeholder' => '',
+ 'default' => '',
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce-pre-orders' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce-pre-orders' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => array(
+ 'plain' => __( 'Plain text', 'woocommerce-pre-orders' ),
+ 'html' => __( 'HTML', 'woocommerce-pre-orders' ),
+ 'multipart' => __( 'Multipart', 'woocommerce-pre-orders' ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/includes/emails/class-wc-pre-orders-email-pre-order-available.php b/includes/emails/class-wc-pre-orders-email-pre-order-available.php
new file mode 100644
index 0000000..890943a
--- /dev/null
+++ b/includes/emails/class-wc-pre-orders-email-pre-order-available.php
@@ -0,0 +1,140 @@
+id = 'wc_pre_orders_pre_order_available';
+ $this->title = __( 'Pre-order available', 'woocommerce-pre-orders' );
+ $this->description = __( 'This is an order notification sent to the customer once a pre-order is complete.', 'woocommerce-pre-orders' );
+
+ $this->heading = __( 'Pre-order available', 'woocommerce-pre-orders' );
+ $this->subject = __( 'Your {site_title} pre-order from {order_date} is now available', 'woocommerce-pre-orders' );
+
+ $this->template_base = $wc_pre_orders->get_plugin_path() . '/templates/';
+ $this->template_html = 'emails/customer-pre-order-available.php';
+ $this->template_plain = 'emails/plain/customer-pre-order-available.php';
+
+ // Triggers for this email
+ add_action( 'wc_pre_order_status_completed_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor
+ parent::__construct();
+ }
+
+
+ /**
+ * Dispatch the email
+ *
+ * @since 1.0
+ */
+ public function trigger( $order_id, $message = '' ) {
+ if ( $order_id ) {
+ $this->object = new WC_Order( $order_id );
+ $this->recipient = $this->object->get_billing_email();
+ $this->message = $message;
+
+ $this->placeholders = array_merge(
+ array(
+ '{order_date}' => date_i18n(
+ wc_date_format(),
+ strtotime( (
+ $this->object->get_date_created() ?
+ gmdate( 'Y-m-d H:i:s', $this->object->get_date_created()->getOffsetTimestamp() )
+ : ''
+ ) )
+ ),
+ '{release_date}' => WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ) ),
+ '{order_number}' => $this->object->get_order_number()
+ ),
+ $this->placeholders
+ );
+ }
+
+ if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
+ return;
+ }
+
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+
+ /**
+ * Gets the email HTML content
+ *
+ * @since 1.0
+ * @return string the email HTML content
+ */
+ public function get_content_html() {
+ ob_start();
+ wc_get_template(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'plain_text' => false,
+ 'email' => $this,
+ 'sent_to_admin' => false,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Gets the email plain content
+ *
+ * @since 1.0
+ * @return string the email plain content
+ */
+ public function get_content_plain() {
+ ob_start();
+ wc_get_template(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'plain_text' => true,
+ 'email' => $this,
+ 'sent_to_admin' => false,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+}
diff --git a/includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php b/includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php
new file mode 100644
index 0000000..e30437a
--- /dev/null
+++ b/includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php
@@ -0,0 +1,138 @@
+id = 'wc_pre_orders_pre_order_cancelled';
+ $this->title = __( 'Pre-order cancelled', 'woocommerce-pre-orders' );
+ $this->description = __( 'This is an order notification sent to the customer after a pre-order is cancelled.', 'woocommerce-pre-orders' );
+
+ $this->heading = __( 'Pre-order cancelled', 'woocommerce-pre-orders' );
+ $this->subject = __( 'Your {site_title} pre-order from {order_date} has been cancelled', 'woocommerce-pre-orders' );
+
+ $this->template_base = $wc_pre_orders->get_plugin_path() . '/templates/';
+ $this->template_html = 'emails/customer-pre-order-cancelled.php';
+ $this->template_plain = 'emails/plain/customer-pre-order-cancelled.php';
+
+ // Triggers for this email
+ add_action( 'wc_pre_order_status_active_to_cancelled_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor
+ parent::__construct();
+ }
+
+
+ /**
+ * Dispatch the email
+ *
+ * @since 1.0
+ */
+ public function trigger( $order_id, $message ) {
+ if ( $order_id ) {
+ $this->object = new WC_Order( $order_id );
+ $this->recipient = $this->object->get_billing_email();
+ $this->message = $message;
+
+ $this->placeholders = array_merge(
+ array(
+ '{order_date}' => date_i18n(
+ wc_date_format(),
+ strtotime( (
+ $this->object->get_date_created() ?
+ gmdate( 'Y-m-d H:i:s', $this->object->get_date_created()->getOffsetTimestamp() )
+ : ''
+ ) )
+ ),
+ '{release_date}' => WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ) ),
+ '{order_number}' => $this->object->get_order_number()
+ ),
+ $this->placeholders
+ );
+ }
+
+ if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
+ return;
+ }
+
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+
+ /**
+ * Gets the email HTML content
+ *
+ * @since 1.0
+ * @return string the email HTML content
+ */
+ public function get_content_html() {
+ ob_start();
+ wc_get_template(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'plain_text' => false,
+ 'email' => $this,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Gets the email plain content
+ *
+ * @since 1.0
+ * @return string the email plain content
+ */
+ public function get_content_plain() {
+ ob_start();
+ wc_get_template(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'plain_text' => true,
+ 'email' => $this,
+ 'sent_to_admin' => false,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+}
diff --git a/includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php b/includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php
new file mode 100644
index 0000000..23373b6
--- /dev/null
+++ b/includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php
@@ -0,0 +1,157 @@
+id = 'wc_pre_orders_pre_order_date_changed';
+ $this->title = __( 'Pre-order release date changed', 'woocommerce-pre-orders' );
+ $this->description = __( 'This is an order notification sent to the customer after a pre-order release date is changed.', 'woocommerce-pre-orders' );
+
+ $this->heading = __( 'Pre-order release date changed', 'woocommerce-pre-orders' );
+ $this->subject = __( 'The release date for your {site_title} pre-order from {order_date} has been changed', 'woocommerce-pre-orders' );
+
+ $this->template_base = $wc_pre_orders->get_plugin_path() . '/templates/';
+ $this->template_html = 'emails/customer-pre-order-date-changed.php';
+ $this->template_plain = 'emails/plain/customer-pre-order-date-changed.php';
+
+ // Triggers for this email
+ add_action( 'wc_pre_orders_pre_order_date_changed_notification', array( $this, 'trigger' ), 10 );
+
+ // Call parent constructor
+ parent::__construct();
+ }
+
+
+ /**
+ * Dispatch the email
+ *
+ * @since 2.0.7 Update logic to handle function first argument as array.
+ * First argument is same as for wc_pre_orders_pre_order_date_changed action hook.
+ * @since 1.0
+ */
+ public function trigger( array $args ) {
+ if (
+ ! array_key_exists( 'order', $args )
+ || ! array_key_exists( 'message', $args )
+ || ! $this->is_enabled()
+ ) {
+ return;
+ }
+
+ $this->object = $args['order'];
+ $this->recipient = $this->object->get_billing_email();
+ $this->message = $args['message'];
+ $this->availability_date = WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ) );
+
+ $this->placeholders = array_merge(
+ array(
+ '{order_date}' => date_i18n(
+ wc_date_format(),
+ strtotime(
+ $this->object->get_date_created()
+ ? gmdate( 'Y-m-d H:i:s', $this->object->get_date_created()->getOffsetTimestamp() )
+ : ''
+ )
+ ),
+ '{release_date}' => WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ) ),
+ '{order_number}' => $this->object->get_order_number(),
+ ),
+ $this->placeholders
+ );
+
+ if ( $this->get_recipient() ) {
+ $this->send(
+ $this->get_recipient(),
+ $this->get_subject(),
+ $this->get_content(),
+ $this->get_headers(),
+ $this->get_attachments()
+ );
+ }
+ }
+
+
+ /**
+ * Gets the email HTML content
+ *
+ * @since 1.0
+ * @return string the email HTML content
+ */
+ public function get_content_html() {
+ ob_start();
+ wc_get_template(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'availability_date' => $this->availability_date,
+ 'plain_text' => false,
+ 'email' => $this,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Gets the email plain content
+ *
+ * @since 1.0
+ * @return string the email plain content
+ */
+ public function get_content_plain() {
+ ob_start();
+ wc_get_template(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'message' => $this->message,
+ 'availability_date' => $this->availability_date,
+ 'plain_text' => true,
+ 'email' => $this,
+ 'sent_to_admin' => false,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+}
diff --git a/includes/emails/class-wc-pre-orders-email-pre-ordered.php b/includes/emails/class-wc-pre-orders-email-pre-ordered.php
new file mode 100644
index 0000000..c610df6
--- /dev/null
+++ b/includes/emails/class-wc-pre-orders-email-pre-ordered.php
@@ -0,0 +1,141 @@
+id = 'wc_pre_orders_pre_ordered';
+ $this->title = __( 'Pre-ordered', 'woocommerce-pre-orders' );
+ $this->description = __( 'This is an order notification sent to the customer after placing a pre-order and containing order details.', 'woocommerce-pre-orders' );
+
+ $this->heading = __( 'Thank you for your pre-order', 'woocommerce-pre-orders' );
+ $this->subject = __( 'Your {site_title} pre-order confirmation from {order_date}', 'woocommerce-pre-orders' );
+
+ $this->template_base = $wc_pre_orders->get_plugin_path() . '/templates/';
+ $this->template_html = 'emails/customer-pre-ordered.php';
+ $this->template_plain = 'emails/plain/customer-pre-ordered.php';
+
+ // Triggers for this email
+ add_action( 'wc_pre_order_status_new_to_active_notification', array( $this, 'trigger' ) );
+
+ // Call parent constructor
+ parent::__construct();
+ }
+
+
+ /**
+ * Dispatch the email
+ *
+ * @since 1.0
+ */
+ public function trigger( $order_id ) {
+ if ( $order_id ) {
+ $this->object = new WC_Order( $order_id );
+ $this->recipient = $this->object->get_billing_email();
+ $this->availability_date = WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ),
+ __( 'a future date', 'woocommerce-pre-orders' ) );
+
+ $this->placeholders = array_merge(
+ array(
+ '{order_date}' => date_i18n(
+ wc_date_format(),
+ strtotime( (
+ $this->object->get_date_created() ?
+ gmdate( 'Y-m-d H:i:s', $this->object->get_date_created()->getOffsetTimestamp() )
+ : ''
+ ) )
+ ),
+ '{release_date}' => WC_Pre_Orders_Product::get_localized_availability_date( WC_Pre_Orders_Order::get_pre_order_product( $this->object ) ),
+ '{order_number}' => $this->object->get_order_number()
+ ),
+ $this->placeholders
+ );
+ }
+
+ if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
+ return;
+ }
+
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+
+ /**
+ * Gets the email HTML content
+ *
+ * @since 1.0
+ * @return string the email HTML content
+ */
+ public function get_content_html() {
+ ob_start();
+ wc_get_template(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'availability_date' => $this->availability_date,
+ 'plain_text' => false,
+ 'email' => $this,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Gets the email plain content
+ *
+ * @since 1.0
+ * @return string the email plain content
+ */
+ public function get_content_plain() {
+ ob_start();
+ wc_get_template(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'availability_date' => $this->availability_date,
+ 'plain_text' => true,
+ 'email' => $this,
+ 'sent_to_admin' => false,
+ ),
+ '',
+ $this->template_base
+ );
+ return ob_get_clean();
+ }
+}
diff --git a/includes/gateways/class-wc-pre-orders-gateway-pay-later.php b/includes/gateways/class-wc-pre-orders-gateway-pay-later.php
new file mode 100644
index 0000000..ed57d06
--- /dev/null
+++ b/includes/gateways/class-wc-pre-orders-gateway-pay-later.php
@@ -0,0 +1,175 @@
+id = 'pre_orders_pay_later';
+ $this->method_title = __( 'pay later', 'woocommerce-pre-orders' );
+ $this->method_description = __( 'This payment method replaces all other methods that do not support pre-orders when the pre-order is charged upon release.', 'woocommerce-pre-orders' );
+ $this->icon = apply_filters( 'wc_pre_orders_pay_later_icon', '' );
+ $this->has_fields = false;
+
+ // Load the settings
+ $this->init_form_fields();
+ $this->init_settings();
+
+ $this->enabled = $this->get_option( 'enabled', 'yes' );
+ $this->title = $this->get_option( 'title' );
+ $this->description = $this->get_option( 'description' );
+
+ // Support pre-orders
+ $this->supports = array( 'products', 'pre-orders' );
+
+ // Save settings
+ if ( is_admin() ) {
+ add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ // pay page fallback
+ add_action( 'woocommerce_receipt_' . $this->id, array( $this, 'receipt_page' ) );
+ }
+
+
+ /**
+ * Disables the gateway under any of these conditions:
+ * 1) If the cart does not contain a pre-order
+ * 2) If the pre-order amount is charged upfront
+ * 3) On the pay page
+ *
+ * @since 1.0
+ * @return bool
+ */
+ public function is_available() {
+
+ $is_available = true;
+
+ // Backwards compatibility checking for payment page
+ if ( function_exists( 'is_checkout_pay_page' ) ) {
+ $pay_page = is_checkout_pay_page();
+ } else {
+ $pay_page = is_page( wc_get_page_id( 'pay' ) );
+ }
+
+ // On checkout page
+ if ( ! $pay_page || ( defined( 'WOOCOMMERCE_CHECKOUT' ) && WOOCOMMERCE_CHECKOUT ) ) {
+
+ // Not available if the cart does not contain a pre-order
+ if ( WC_Pre_Orders_Cart::cart_contains_pre_order() ) {
+
+ // Not available when the pre-order amount is charged upfront
+ if ( WC_Pre_Orders_Product::product_is_charged_upfront( WC_Pre_Orders_Cart::get_pre_order_product() ) ) {
+ $is_available = false;
+ }
+ } else {
+
+ $is_available = false;
+ }
+ } else {
+
+ // Not available on the pay page (for now)
+ $is_available = false;
+ }
+
+ return $is_available;
+ }
+
+
+ /**
+ * Setup gateway form fields
+ *
+ * @since 1.0
+ */
+ public function init_form_fields() {
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce-pre-orders' ),
+ 'label' => __( 'Enable pay later', 'woocommerce-pre-orders' ),
+ 'type' => 'checkbox',
+ 'description' => '',
+ 'default' => 'yes',
+ ),
+ 'title' => array(
+ 'title' => __( 'Title', 'woocommerce-pre-orders' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-pre-orders' ),
+ 'default' => __( 'Pay later', 'woocommerce-pre-orders' ),
+ 'desc_tip' => true,
+ ),
+ 'description' => array(
+ 'title' => __( 'Customer message', 'woocommerce-pre-orders' ),
+ 'type' => 'textarea',
+ 'description' => __( 'Let the customer know how they will be able to pay for their pre-order.', 'woocommerce-pre-orders' ),
+ 'default' => __( 'You will receive an email when the pre-order is available along with instructions on how to complete your order.', 'woocommerce-pre-orders' ),
+ ),
+ );
+ }
+
+
+ /**
+ * Process the payment and return the result
+ *
+ * @since 1.0
+ *
+ * @param int $order_id
+ *
+ * @return array
+ */
+ public function process_payment( $order_id ) {
+ $order = new WC_Order( $order_id );
+
+ // Remove cart
+ WC()->cart->empty_cart();
+
+ // Update status
+ $order->update_status( 'pre-ordered' );
+
+ // Add a flag the order used pay later.
+ $order->update_meta_data( '_wc_pre_orders_is_pay_later', 'yes' );
+ $order->save();
+
+ WC_Pre_Orders_Manager::reduce_stock_level( $order );
+
+ // Redirect to thank you page
+ return array(
+ 'result' => 'success',
+ 'redirect' => $this->get_return_url( $order ),
+ );
+ }
+
+ /**
+ * Receipt page.
+ *
+ * @param WC_Order $order
+ *
+ * @return string
+ */
+ public function receipt_page( $order ) {
+ echo '' . esc_html__( 'Thank you for your order.', 'woocommerce-pre-orders' ) . '
';
+ }
+
+} // end \WC_Pre_Orders_Gateway_Pay_Later class
diff --git a/includes/shortcodes/class-wc-pre-orders-shortcode-countdown.php b/includes/shortcodes/class-wc-pre-orders-shortcode-countdown.php
new file mode 100644
index 0000000..16e2b2f
--- /dev/null
+++ b/includes/shortcodes/class-wc-pre-orders-shortcode-countdown.php
@@ -0,0 +1,229 @@
+shortcode_wrapper( array( __CLASS__, 'output' ), $atts, array( 'class' => 'woocommerce-pre-orders' ) );
+ }
+
+ /**
+ * Sanitize the layout content.
+ *
+ * @param string $content Layout content
+ * @return string
+ */
+ private static function sanitize_layout( $content ) {
+ $content = wp_kses_no_null( $content, array( 'slash_zero' => 'keep' ) );
+ $content = wp_kses_normalize_entities( $content );
+ $content = preg_replace_callback( '%(|$))|(<(?!})[^>]*(>|$))%', array( __CLASS__, 'sanitize_layout_callback' ), $content );
+
+ // This sanitization comes from the `esc_js` function in WordPress.
+ // The same sanitization is used except for `_wp_specialchars` which removes characters needed for HTML.
+ // https://core.trac.wordpress.org/browser/tags/6.2/src/wp-includes/formatting.php#L4548
+ $content = wp_check_invalid_utf8( $content );
+ $content = preg_replace( '/(x)?0*(?(1)27|39);?/i', "'", stripslashes( $content ) );
+ $content = str_replace( "\r", '', $content );
+ return str_replace( "\n", '\\n', addslashes( $content ) );
+ }
+
+ /**
+ * Callback for `sanitize_layout()`.
+ *
+ * @param array $matches preg_replace regexp matches
+ * @return string
+ */
+ public static function sanitize_layout_callback( $matches ) {
+ $allowed_html = wp_kses_allowed_html( 'post' );
+ $allowed_protocols = wp_allowed_protocols();
+
+ return wp_kses_split2( $matches[0], $allowed_html, $allowed_protocols );
+ }
+
+ /**
+ * Output the countdown timer. This defaults to the following format, where
+ * elments in [ ] are not shown if zero:
+ *
+ * [y Years] [o Months] [d Days] h Hours m Minutes s Seconds
+ *
+ * The following shortcode arguments are optional:
+ *
+ * * product_id/product_sku - id or sku of pre-order product to countdown to.
+ * Defaults to current product, if any
+ * * until - date/time to count down to, overrides product release date
+ * if set. Example values: "15 March 2015", "+1 month".
+ * More examples: http://php.net/manual/en/function.strtotime.php
+ * * before - text to show before the countdown. Only available if 'layout' is not ''
+ * * after - text to show after the countdown. Only available if 'layout' is not ''
+ * * layout - The countdown layout, defaults to y Years o Months d Days h Hours m Minutes s Seconds
+ * See http://keith-wood.name/countdownRef.html#layout for all possible options
+ * * format - The format for the countdown display. Example: 'yodhms'
+ * to display the year, month, day and time. See http://keith-wood.name/countdownRef.html#format for all options
+ * * compact - If 'true' displays the date/time labels in compact form, ie
+ * 'd' rather than 'days'. Defaults to 'false'
+ *
+ * When the countdown date/time is reached the page will refresh.
+ *
+ * To test different time periods you can create shortcodes like the following samples:
+ *
+ * [woocommerce_pre_order_countdown until="+10 year"]
+ * [woocommerce_pre_order_countdown until="+10 month"]
+ * [woocommerce_pre_order_countdown until="+10 day"]
+ * [woocommerce_pre_order_countdown until="+10 second"]
+ *
+ * @param array $atts associative array of shortcode parameters
+ */
+ public static function get_pre_order_countdown_shortcode_content( $atts ) {
+ global $woocommerce, $product, $wpdb;
+
+ $shortcode_atts = shortcode_atts(
+ array(
+ 'product_id' => '',
+ 'product_sku' => '',
+ 'until' => '',
+ 'before' => '',
+ 'after' => '',
+ 'layout' => '{y<}{yn} {yl}{y>} {o<}{on} {ol}{o>} {d<}{dn} {dl}{d>} {h<}{hn} {hl}{h>} {m<}{mn} {ml}{m>} {s<}{sn} {sl}{s>}',
+ 'format' => 'yodHMS',
+ 'compact' => 'false',
+ ),
+ $atts
+ );
+
+ $product_id = $shortcode_atts['product_id'];
+
+ // product by sku?
+ if ( $shortcode_atts['product_sku'] ) {
+ $product_id = wc_get_product_id_by_sku( $shortcode_atts['product_sku'] );
+ }
+
+ // product by id?
+ if ( $product_id ) {
+ $product = wc_get_product( $product_id );
+ }
+
+ // no product, or product is in the trash? Bail.
+ if ( ! $product instanceof WC_Product || 'trash' === $product->get_status() ) {
+ return;
+ }
+
+ // date override (convert from string unless someone was savvy enough to provide a timestamp)
+ $until = $shortcode_atts['until'];
+ if ( $until && ! is_numeric( $until ) ) {
+ $until = strtotime( $until );
+ }
+
+ // no date override, get the datetime from the product.
+ if ( ! $until ) {
+ $until = get_post_meta( $product->get_id(), '_wc_pre_orders_availability_datetime', true );
+ }
+
+ // can't do anything without an 'until' date
+ if ( ! $until ) {
+ return;
+ }
+
+ // if a layout is being used, prepend/append the before/after text
+ $layout = $shortcode_atts['layout'];
+ if ( $layout ) {
+ $layout = esc_js( $shortcode_atts['before'] );
+ $layout .= self::sanitize_layout( $shortcode_atts['layout'] );
+ $layout .= esc_js( $shortcode_atts['after'] );
+ }
+
+ // enqueue the required javascripts
+ self::enqueue_scripts();
+
+ // countdown javascript
+ ob_start();
+ ?>
+ $('#woocommerce-pre-orders-countdown-').countdown({
+ until: new Date(),
+ layout: '',
+ format: '',
+ compact: ,
+ expiryUrl: location.href,
+ });
+ add_inline_js( $javascript );
+ }
+
+ ob_start();
+ ?>
+
+ get_plugin_url() . '/assets/js/jquery.countdown/jquery.countdown' . $suffix . '.js', array( 'jquery' ), '1.6.1' );
+
+ if ( defined( 'WPLANG' ) && WPLANG ) {
+ // countdown includes some localization files, in the form: jquery.countdown-es.js and jquery.countdown-pt-BR.js
+ // convert our WPLANG constant to that format and see whether we have a localization file to include
+ @list( $lang, $dialect ) = explode( '_', WPLANG );
+ if ( 0 === strcasecmp( $lang, $dialect ) ) {
+ $dialect = null;
+ }
+ $localization = $lang;
+ if ( $dialect ) {
+ $localization .= '-' . $dialect;
+ }
+
+ if ( ! is_readable( $wc_pre_orders->get_plugin_path() . '/assets/js/jquery.countdown/jquery.countdown-' . $localization . '.js' ) ) {
+ $localization = $lang;
+ if ( ! is_readable( $wc_pre_orders->get_plugin_path() . '/assets/js/jquery.countdown/jquery.countdown-' . $localization . '.js' ) ) { // try falling back to base language if dialect is not found
+ $localization = null;
+ }
+ }
+
+ if ( $localization ) {
+ wp_enqueue_script( 'jquery-countdown-' . $localization, $wc_pre_orders->get_plugin_url() . '/assets/js/jquery.countdown/jquery.countdown-' . $localization . $suffix . '.js', array( 'jquery-countdown' ), '1.6.1' );
+ }
+ }
+ }
+}
diff --git a/languages/woocommerce-pre-orders.pot b/languages/woocommerce-pre-orders.pot
new file mode 100644
index 0000000..215a1bb
--- /dev/null
+++ b/languages/woocommerce-pre-orders.pot
@@ -0,0 +1,1152 @@
+# Copyright (C) 2024 WooCommerce
+# This file is distributed under the GNU General Public License v3.0.
+msgid ""
+msgstr ""
+"Project-Id-Version: WooCommerce Pre-Orders 2.1.0\n"
+"Report-Msgid-Bugs-To: "
+"https://wordpress.org/support/plugin/woocommerce-pre-orders\n"
+"POT-Creation-Date: 2024-03-04 16:23:34+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2024-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"X-Generator: node-wp-i18n 1.2.7\n"
+
+#: includes/admin/class-wc-pre-orders-admin-ajax.php:52
+msgid ""
+"You can't add multiple products on a pre-order. Change the quantity of the "
+"item instead of adding more items."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-ajax.php:57
+msgid "You can't add multiple products on a pre-order"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-orders.php:69
+#. translators: %s: email title
+msgid "Resend %s"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-orders.php:203
+msgid "All orders types"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:53
+msgid "Manage"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:54
+msgid "Actions"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:65
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:66
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:146
+#: includes/admin/class-wc-pre-orders-admin-products.php:78
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:140
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:149
+#: includes/class-wc-pre-orders-list-table.php:47
+#: includes/class-wc-pre-orders-my-pre-orders.php:74
+#: includes/class-wc-pre-orders-my-pre-orders.php:111
+#: includes/class-wc-pre-orders-privacy.php:12
+msgid "Pre-orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:106
+msgid "Pre-order customers emailed successfully"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:110
+msgid "Pre-order date changed"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:114
+msgid "Pre-orders completed"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:118
+msgid "Pre-orders cancelled"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:170
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:200
+msgid "Action failed. Please refresh the page and retry."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:175
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:205
+msgid "You do not have the correct permissions to do this."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:182
+#. translators: %s = order id
+msgid "Pre-order #%s cancelled."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:349
+#. translators: %d = success count
+msgid "%d pre-order cancelled."
+msgid_plural "%d pre-orders cancelled."
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:353
+#. translators: %d = error count
+msgid "%d pre-order could not be cancelled."
+msgid_plural "%d pre-orders could not be cancelled."
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:360
+#. translators: %d = success count
+msgid "%d pre-order completed."
+msgid_plural "%d pre-orders completed."
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:364
+#. translators: %d = error count
+msgid "%d pre-order could not be completed."
+msgid_plural "%d pre-orders could not be completed."
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:370
+#. translators: %d = The count of emails dispatched
+msgid "%d email dispatched."
+msgid_plural "%d emails dispatched."
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:427
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:516
+#: includes/class-wc-pre-orders-list-table.php:64
+#: includes/class-wc-pre-orders-list-table.php:270
+#: includes/class-wc-pre-orders-my-pre-orders.php:168
+msgid "Cancel"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:428
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:515
+#: includes/class-wc-pre-orders-list-table.php:65
+msgid "Complete"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:429
+#: includes/class-wc-pre-orders-list-table.php:66
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:124
+msgid "Customer message"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:501
+msgid ""
+"There is no pre-order product currently. List of pre-order products will "
+"appear in the drop-down Product below."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:513
+msgid "Email"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:514
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:682
+msgid "Change release date"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:542
+#: includes/class-wc-pre-orders.php:335
+msgid "Manage pre-orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:546
+#. translators: %s = The search query
+msgid "Search results for \"%s\""
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:555
+msgid "Search pre-orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:580
+msgid "Select a product"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:591
+msgid "Email pre-order customers"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:593
+#. translators: %1$s = Opening anchor tag for WooCommerce email customer note,
+#. %2$s = Closing anchor tag
+msgid ""
+"You may send an email message to all customers who have pre-ordered a "
+"specific product. This will use the default template specified for the "
+"%1$sCustomer Note%2$s Email."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:599
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:640
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:697
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:742
+#: includes/class-wc-pre-orders-list-table.php:202
+#: templates/myaccount/my-pre-orders.php:18
+#: templates/myaccount/my-pre-orders.php:44
+msgid "Product"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:600
+msgid "Select which product to email all pre-ordered customers."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:612
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:672
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:718
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:763
+msgid "Message"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:613
+msgid ""
+"Enter a message to include in the email notification to customer. Limited "
+"HTML allowed."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:625
+msgid "Send emails"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:633
+msgid "Change the pre-order release date"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:634
+msgid ""
+"You may change the release date for all pre-orders of a specific product. "
+"This will send an email notification to each customer informing them that "
+"the pre-order release date was changed, along with the new release date."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:641
+msgid "Select which product to change the release date for."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:653
+msgid "New availability date"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:654
+msgid ""
+"The new availability date for the product. This must be later than the "
+"current availability date."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:664
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:710
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:755
+msgid "Send email notification"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:665
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:711
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:756
+msgid "Uncheck this to prevent email notifications from being sent to customers."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:673
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:719
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:764
+msgid "Enter a message to include in the email notification to customer."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:690
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:728
+msgid "Complete pre-orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:691
+msgid ""
+"You may complete all pre-orders for a specific product. This will charge "
+"the customer's card the pre-ordered amount, change their order status to "
+"completed, and send them an email notification."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:698
+msgid "Select which product to complete all pre-orders for."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:735
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:773
+msgid "Cancel pre-orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:736
+msgid ""
+"You may cancel all pre-orders for a specific product. This will mark the "
+"order as cancelled and send the customer an email notification. If "
+"pre-orders were charged upfront, you must manually refund the orders."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-pre-orders.php:743
+msgid "Select which product to cancel all pre-orders for."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:46
+msgid "Pre-Orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:76
+msgid "Button text"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:81
+msgid "Add to cart button text"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:82
+msgid ""
+"This controls the add to cart button text on single product pages for "
+"products that have pre-orders enabled."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:85
+msgid "Pre-order now"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:90
+msgid "Place Order Button Text"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:91
+msgid ""
+"This controls the place order button text on the checkout when an order "
+"contains a pre-orders."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:94
+#: includes/blocks/class-wc-pre-orders-blocks-gateway.php:135
+msgid "Place pre-order now"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:101
+msgid "Product message"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:103
+#. translators: %1$s: Availability Time %2$s: Availability Date
+msgid ""
+"Adjust the message by using %1$s{availability_date}%2$s and "
+"%1$s{availability_time}%2$s to represent the product's availability date "
+"and time."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:108
+msgid "Single product page message"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:109
+msgid ""
+"Add an optional message to the single product page below the price. Use "
+"this to announce when the pre-order will be available by using "
+"{availability_date} and {availability_time}. Limited HTML is allowed. Leave "
+"blank to disable."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:113
+#. translators: %s: Availability Date
+msgid "This item will be released %s."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:118
+msgid "Shop loop product message"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:119
+msgid ""
+"Add an optional message to each pre-order enabled product on the shop loop "
+"page below the product title. Use this to announce when the pre-order will "
+"be available by using {availability_date} and {availability_time}. Limited "
+"HTML is allowed. Leave blank to disable."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:123
+#. translators: %s: Availability Date
+msgid "Available %s."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:130
+msgid "Cart / Checkout display text"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:132
+#. translators: %1$s: Order Total %2$s: Availability Date
+msgid ""
+"Adjust the display of the order total by using %1$s{order_total}%2$s to "
+"represent the order total and %1$s{availability_date}%2$s to represent the "
+"product's availability date."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:137
+msgid "Availability date title text"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:138
+msgid ""
+"This controls the title of the availability date section on the "
+"cart/checkout page. Leave blank to disable display of the availability date "
+"in the cart."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:141
+msgid "Available"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:146
+msgid "Charged upon release order total format"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:147
+msgid ""
+"This controls the order total format when the cart contains a pre-order "
+"charged upon release. Use this to indicate when the customer will be "
+"charged for their pre-order by using {availability_date} and {order_total}."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:151
+#. translators: %1$s: Order Total %2$s: Availability Date
+msgid "%1$s charged %2$s"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:157
+msgid "Charged upfront order total format"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:158
+msgid ""
+"This controls the order total format when the cart contains a pre-order "
+"charged upfront. Use this to indicate how the customer is charged for their "
+"pre-order by using {availability_date} and {order_total}."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:162
+#. translators: %s: Order Total
+msgid "%s charged upfront"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:170
+msgid "Out of stock"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:174
+msgid "Enable pre-orders for products that get out of stock"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:175
+msgid ""
+"When a product becomes out of stock customers will be able to pre-order it. "
+"Variable products need to have all variations out of stock."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:184
+msgid "Staging/Test"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:189
+msgid "Disable automated pre-order processing."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-settings.php:190
+msgid ""
+"This is used for when you're on a staging/testing site and don't want any "
+"pre orders to be processed automatically."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:161
+#. translators: %s Actions menu page URL
+msgid ""
+"There are active pre-orders for this product. To change the release date, "
+"use the Actions menu ."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:183
+#. translators: %s Pre orders admin page URL
+msgid ""
+"To change other settings, please complete or cancel the "
+"active pre-orders first."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:203
+#: includes/admin/views/html-product-tab-options.php:29
+msgid "Enable pre-orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:205
+#: includes/admin/views/html-product-tab-options.php:30
+msgid "Enable pre-orders for this product."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:224
+#: includes/admin/views/html-product-tab-options.php:48
+msgid "Pre-order Fee"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:225
+#: includes/admin/views/html-product-tab-options.php:49
+msgid ""
+"Set a fee to be charged when a pre-order is placed. Leave blank to not "
+"charge a pre-order fee."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:241
+#: includes/admin/views/html-product-tab-options.php:38
+msgid "Availability date/time"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:242
+#: includes/admin/views/html-product-tab-options.php:40
+msgid ""
+"Set the date & time that this pre-order will be available. The product will "
+"behave as a normal product when this date/time is reached."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:258
+#: includes/admin/views/html-product-tab-options.php:58
+msgid "When to Charge"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:259
+#: includes/admin/views/html-product-tab-options.php:59
+msgid ""
+"Select \"Upon Release\" to charge the entire pre-order amount (the product "
+"price + pre-order fee if applicable) when the pre-order becomes available. "
+"Select \"Upfront\" to charge the pre-order amount during the initial "
+"checkout."
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:263
+#: includes/admin/views/html-product-tab-options.php:64
+msgid "Upfront"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-product-editor-compatibility.php:267
+msgid "Upon Release"
+msgstr ""
+
+#: includes/admin/views/html-product-tab-options.php:17
+msgid ""
+"There are active pre-orders for this product. To change the release date, "
+"%1$suse the Actions menu%2$s."
+msgstr ""
+
+#: includes/admin/views/html-product-tab-options.php:20
+msgid ""
+"To change other settings, please %1$scomplete or cancel the active "
+"pre-orders%2$s first."
+msgstr ""
+
+#: includes/admin/views/html-product-tab-options.php:63
+msgid "Upon release"
+msgstr ""
+
+#: includes/blocks/class-wc-pre-orders-blocks-gateway.php:133
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:120
+msgid "Pay later"
+msgstr ""
+
+#: includes/blocks/class-wc-pre-orders-blocks-gateway.php:134
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:127
+msgid ""
+"You will receive an email when the pre-order is available along with "
+"instructions on how to complete your order."
+msgstr ""
+
+#: includes/blocks/class-wc-pre-orders-extend-store-api.php:88
+msgid "Availability date for product."
+msgstr ""
+
+#: includes/blocks/class-wc-pre-orders-extend-store-api.php:94
+msgid "Indicates if customer is going to be charged only when product is released."
+msgstr ""
+
+#: includes/blocks/class-wc-pre-orders-extend-store-api.php:100
+msgid "Indicates if customer is going to be charged upfront."
+msgstr ""
+
+#: includes/class-wc-pre-orders-cart.php:133
+msgid ""
+"Your previous cart was emptied because pre-orders must be purchased "
+"separately."
+msgstr ""
+
+#: includes/class-wc-pre-orders-cart.php:155
+#: includes/class-wc-pre-orders-cart.php:158
+msgid ""
+"This product cannot be added to your cart because it already contains a "
+"pre-order, which must be purchased separately."
+msgstr ""
+
+#: includes/class-wc-pre-orders-cart.php:215
+msgid "Pre-order fee"
+msgstr ""
+
+#: includes/class-wc-pre-orders-checkout.php:86
+#: templates/emails/customer-pre-ordered.php:23
+#: templates/emails/plain/customer-pre-ordered.php:23
+#. translators: %s: availability date
+msgid " on %s."
+msgstr ""
+
+#: includes/class-wc-pre-orders-checkout.php:89
+#: templates/emails/customer-pre-ordered.php:34
+#: templates/emails/plain/customer-pre-ordered.php:31
+#. translators: 1: availability date
+#. translators: %s: availability date
+msgid ""
+"Your pre-order has been received. You will be prompted for payment for your "
+"order when your pre-order is released%s Your order details are shown below "
+"for your reference."
+msgstr ""
+
+#: includes/class-wc-pre-orders-checkout.php:93
+#: templates/emails/customer-pre-ordered.php:31
+#: templates/emails/plain/customer-pre-ordered.php:29
+#. translators: 1: availability date
+#. translators: %s: availability date
+msgid ""
+"Your pre-order has been received. You will be automatically charged for "
+"your order via your selected payment method when your pre-order is "
+"released%s Your order details are shown below for your reference."
+msgstr ""
+
+#: includes/class-wc-pre-orders-cron.php:55
+msgid "Every %d minutes"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:46
+msgid "Pre-order"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:200
+#: templates/myaccount/my-pre-orders.php:19
+#: templates/myaccount/my-pre-orders.php:49
+msgid "Status"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:201
+msgid "Customer"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:203
+#: templates/myaccount/my-pre-orders.php:17
+#: templates/myaccount/my-pre-orders.php:33
+msgid "Order"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:204
+msgid "Order status"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:205
+msgid "Order date"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:206
+msgid "Availability date"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:305
+#. translators: %s: order number
+msgid "Order %s"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:691
+msgid "No pre-orders found"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:693
+msgid ""
+"Pre-orders will appear here for you to view and manage once purchased by a "
+"customer."
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:697
+#. translators: %1$s = Opening anchor tag for WooCommerce Pre-Orders
+#. documentation on WooCommerce.com, %2$s = closing anchor tag
+msgid "%1$sLearn more about managing pre-orders%2$s"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:703
+#. translators: %1$s = Opening anchor tag for adding new product, %2$s =
+#. closing anchor tag
+msgid "%1$sSetup a product to allow pre-orders%2$s"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:741
+msgid "Search for a customer…"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:749
+msgid "Search for a product…"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:760
+msgid "Filter"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:765
+#: includes/class-wc-pre-orders-list-table.php:800
+msgid "Optional message to include in the email to the customer"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:786
+msgid "Are you sure you want to cancel this pre-order?"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:833
+msgid "Show all availability dates"
+msgstr ""
+
+#: includes/class-wc-pre-orders-list-table.php:848
+#. translators: %1$s month, %2$d year
+msgid "%1$s %2$d"
+msgstr ""
+
+#: includes/class-wc-pre-orders-manager.php:631
+#. translators: %s: Availability date
+msgid "Pre-order release date changed to %s"
+msgstr ""
+
+#: includes/class-wc-pre-orders-manager.php:631
+msgid "N/A"
+msgstr ""
+
+#: includes/class-wc-pre-orders-manager.php:836
+#: includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php:35
+#: includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php:38
+msgid "Pre-order cancelled"
+msgstr ""
+
+#: includes/class-wc-pre-orders-manager.php:954
+msgid "Your pre-order has been cancelled."
+msgstr ""
+
+#: includes/class-wc-pre-orders-order.php:77
+#. translators: %s: number of pre-orders
+msgid "Pre-ordered (%s) "
+msgid_plural "Pre-ordered (%s) "
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/class-wc-pre-orders-order.php:333
+msgid "Active"
+msgstr ""
+
+#: includes/class-wc-pre-orders-order.php:336
+msgid "Completed"
+msgstr ""
+
+#: includes/class-wc-pre-orders-order.php:339
+msgid "Cancelled"
+msgstr ""
+
+#: includes/class-wc-pre-orders-order.php:433
+#. translators: %1$s: old pre-order status %2$s: new pre-order status
+msgid "Pre-order status changed from %1$s to %2$s."
+msgstr ""
+
+#: includes/class-wc-pre-orders-privacy.php:20
+msgid ""
+"By using this extension, you may be storing personal data or sharing data "
+"with an external service. Learn more about "
+"how this works, including what you may want to include in your privacy "
+"policy. "
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:186
+#: includes/class-wc-pre-orders-product.php:197
+#: includes/class-wc-pre-orders-product.php:216
+msgid "Available for pre-ordering"
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:191
+#. translators: 1: product total stock
+msgid "Only %s left available for pre-ordering"
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:194
+#: includes/class-wc-pre-orders-product.php:206
+msgid "(can be backordered)"
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:203
+#. translators: 1: product total stock
+msgid "%s available for pre-ordering"
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:213
+msgid "Available on backorder"
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:219
+#: includes/class-wc-pre-orders-product.php:223
+msgid "No longer available for pre-ordering"
+msgstr ""
+
+#: includes/class-wc-pre-orders-product.php:435
+msgid "at a future date"
+msgstr ""
+
+#: includes/class-wc-pre-orders.php:158
+#. translators: %s: email title
+msgid "%s email notification manually sent."
+msgstr ""
+
+#: includes/class-wc-pre-orders.php:334
+msgid "Settings"
+msgstr ""
+
+#: includes/class-wc-pre-orders.php:336
+msgid "Support"
+msgstr ""
+
+#: includes/class-wc-pre-orders.php:337
+msgid "Docs"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php:31
+msgid "Pre-order Cancelled (Admin)"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php:32
+msgid ""
+"This is an order notification sent to the admin after a pre-order is "
+"cancelled."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php:34
+msgid "Pre-order Cancelled"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-admin-pre-order-cancelled.php:35
+msgid "[{site_title}] pre-order from {order_date} has been cancelled"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:31
+msgid "New pre-order"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:32
+msgid "New pre-order emails are sent when a pre-order is received."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:34
+msgid "New pre-order: #{order_number}"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:35
+msgid "[{site_title}] New customer pre-order ({order_number}) - {order_date}"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:145
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:110
+msgid "Enable/Disable"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:147
+msgid "Enable this email notification"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:151
+msgid "Recipient(s)"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:154
+#. translators: %s: admin email address
+msgid ""
+"Enter recipients (comma separated) for this email. Defaults to "
+"%s
."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:159
+msgid "Subject"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:162
+#. translators: %s: email subject
+msgid ""
+"This controls the email subject line. Leave blank to use the default "
+"subject: %s
."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:167
+msgid "Email heading"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:170
+#. translators: %s: email heading
+msgid ""
+"This controls the main heading contained within the email notification. "
+"Leave blank to use the default heading: %s
."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:175
+msgid "Email type"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:177
+msgid "Choose which format of email to send."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:181
+msgid "Plain text"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:182
+msgid "HTML"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-new-pre-order.php:183
+msgid "Multipart"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-available.php:36
+#: includes/emails/class-wc-pre-orders-email-pre-order-available.php:39
+msgid "Pre-order available"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-available.php:37
+msgid ""
+"This is an order notification sent to the customer once a pre-order is "
+"complete."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-available.php:40
+msgid "Your {site_title} pre-order from {order_date} is now available"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php:36
+msgid ""
+"This is an order notification sent to the customer after a pre-order is "
+"cancelled."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-cancelled.php:39
+msgid "Your {site_title} pre-order from {order_date} has been cancelled"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php:39
+#: includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php:42
+msgid "Pre-order release date changed"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php:40
+msgid ""
+"This is an order notification sent to the customer after a pre-order "
+"release date is changed."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-order-date-changed.php:43
+msgid ""
+"The release date for your {site_title} pre-order from {order_date} has been "
+"changed"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-ordered.php:37
+msgid "Pre-ordered"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-ordered.php:38
+msgid ""
+"This is an order notification sent to the customer after placing a "
+"pre-order and containing order details."
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-ordered.php:40
+msgid "Thank you for your pre-order"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-ordered.php:41
+msgid "Your {site_title} pre-order confirmation from {order_date}"
+msgstr ""
+
+#: includes/emails/class-wc-pre-orders-email-pre-ordered.php:65
+msgid "a future date"
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:32
+msgid "pay later"
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:33
+msgid ""
+"This payment method replaces all other methods that do not support "
+"pre-orders when the pre-order is charged upon release."
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:111
+msgid "Enable pay later"
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:117
+msgid "Title"
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:119
+msgid "This controls the title which the user sees during checkout."
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:126
+msgid "Let the customer know how they will be able to pay for their pre-order."
+msgstr ""
+
+#: includes/gateways/class-wc-pre-orders-gateway-pay-later.php:172
+msgid "Thank you for your order."
+msgstr ""
+
+#: templates/emails/admin-new-pre-order.php:25
+#: templates/emails/plain/admin-new-pre-order.php:24
+#. translators: %s: billing first name and last name
+#. translators: %s: first name and last name
+msgid "You have received a pre-order from %s. Their pre-order is as follows:"
+msgstr ""
+
+#: templates/emails/admin-pre-order-cancelled.php:31
+#: templates/emails/plain/admin-pre-order-cancelled.php:21
+#. Translators: %s Full name of the customer
+msgid ""
+"A pre-order from %s has been cancelled. The order details are shown below "
+"for your reference."
+msgstr ""
+
+#: templates/emails/customer-pre-order-available.php:29
+#. translators: %1$s: href link for checkout payment url %2$s: closing href
+#. link
+msgid ""
+"Your pre-order is now available, but requires payment. %1$sPlease pay for "
+"your pre-order now.%2$s"
+msgstr ""
+
+#: templates/emails/customer-pre-order-available.php:36
+#: templates/emails/plain/customer-pre-order-available.php:29
+msgid ""
+"Your pre-order is now available, but is waiting for the payment to be "
+"confirmed. Please wait until it's confirmed. Optionally, make sure the "
+"related payment has been sent to avoid delays on your order."
+msgstr ""
+
+#: templates/emails/customer-pre-order-available.php:44
+#. translators: %1$s: href link for checkout payment url %2$s: closing href
+#. link
+msgid ""
+"Your pre-order is now available, but automatic payment failed. %1$sPlease "
+"update your payment information now.%2$s"
+msgstr ""
+
+#: templates/emails/customer-pre-order-available.php:50
+#: templates/emails/plain/customer-pre-order-available.php:37
+msgid ""
+"Your pre-order is now available. Your order details are shown below for "
+"your reference."
+msgstr ""
+
+#: templates/emails/customer-pre-order-available.php:91
+#: templates/emails/plain/customer-pre-order-available.php:78
+msgid "Thanks for shopping with us."
+msgstr ""
+
+#: templates/emails/customer-pre-order-cancelled.php:24
+#: templates/emails/plain/customer-pre-order-cancelled.php:22
+msgid ""
+"Your pre-order has been cancelled. Your order details are shown below for "
+"your reference."
+msgstr ""
+
+#: templates/emails/customer-pre-order-date-changed.php:27
+#: templates/emails/plain/customer-pre-order-date-changed.php:24
+#. translators: %s: availability date
+msgid ""
+"Your pre-order release date has been changed. The new release date is %s. "
+"Your order details are shown below for your reference."
+msgstr ""
+
+#: templates/emails/customer-pre-order-date-changed.php:32
+#: templates/emails/plain/customer-pre-order-date-changed.php:26
+msgid ""
+"Your pre-order release date has been changed. Your order details are shown "
+"below for your reference."
+msgstr ""
+
+#: templates/emails/customer-pre-ordered.php:42
+#: templates/emails/plain/customer-pre-ordered.php:36
+#. translators: %s: availability date
+msgid ""
+"Your pre-order has been received. You will be notified when your pre-order "
+"is released%s Your order details are shown below for your reference."
+msgstr ""
+
+#: templates/emails/plain/customer-pre-order-available.php:25
+msgid ""
+"Your pre-order is now available, but requires payment. Please pay for your "
+"pre-order now: "
+msgstr ""
+
+#: templates/emails/plain/customer-pre-order-available.php:33
+msgid ""
+"Your pre-order is now available, but automatic payment failed. Please "
+"update your payment information now : "
+msgstr ""
+
+#: templates/myaccount/my-pre-orders.php:20
+#: templates/myaccount/my-pre-orders.php:56
+msgid "Release date"
+msgstr ""
+
+#: templates/myaccount/my-pre-orders.php:76
+msgid "You have no pre-orders."
+msgstr ""
+
+#: woocommerce-pre-orders.php:39
+#. translators: %s WC download URL link.
+msgid ""
+"Pre-orders require WooCommerce to be installed and active. You can download "
+"%s here."
+msgstr ""
+
+#. Plugin Name of the plugin/theme
+msgid "WooCommerce Pre-Orders"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "https://woocommerce.com/products/woocommerce-pre-orders/"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid "Sell pre-orders for products in your WooCommerce store."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "WooCommerce"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "https://woocommerce.com"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-orders.php:206
+#: includes/admin/class-wc-pre-orders-admin-orders.php:231
+msgctxt "An order type"
+msgid "Non Pre-Orders"
+msgstr ""
+
+#: includes/admin/class-wc-pre-orders-admin-orders.php:207
+#: includes/admin/class-wc-pre-orders-admin-orders.php:232
+msgctxt "An order type"
+msgid "Pre-Orders Only"
+msgstr ""
+
+#: includes/class-wc-pre-orders-order.php:71
+#: includes/class-wc-pre-orders-order.php:89
+msgctxt "Order status"
+msgid "Pre-ordered"
+msgstr ""
\ No newline at end of file
diff --git a/src/admin/blocks/date-time-picker/block.json b/src/admin/blocks/date-time-picker/block.json
new file mode 100644
index 0000000..537c0e0
--- /dev/null
+++ b/src/admin/blocks/date-time-picker/block.json
@@ -0,0 +1,34 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "woocommerce-pre-orders/date-time-picker",
+ "version": "0.1.0",
+ "title": "Date-time picker",
+ "category": "widgets",
+ "icon": "flag",
+ "description": "A block to select the date-time",
+ "attributes": {
+ "property": {
+ "type": "string",
+ "default": ""
+ },
+ "title": {
+ "type": "string",
+ "default": ""
+ },
+ "help": {
+ "type": "string",
+ "default": ""
+ },
+ "date": {
+ "type": "object",
+ "default": null
+ }
+ },
+ "supports": {
+ "html": false,
+ "inserter": false
+ },
+ "textdomain": "woocommerce-pre-orders",
+ "editorScript": "file:./index.js"
+}
diff --git a/src/admin/blocks/date-time-picker/edit.tsx b/src/admin/blocks/date-time-picker/edit.tsx
new file mode 100644
index 0000000..ae293cb
--- /dev/null
+++ b/src/admin/blocks/date-time-picker/edit.tsx
@@ -0,0 +1,98 @@
+/**
+ * External dependencies
+ */
+import { useWooBlockProps } from '@woocommerce/block-templates';
+import {
+ TextControl,
+ DateTimePicker,
+ Popover,
+ Card,
+ CardBody,
+ Button,
+ Flex,
+ FlexItem,
+ BaseControl,
+} from '@wordpress/components';
+import { useState } from '@wordpress/element';
+import {
+ __experimentalUseProductEntityProp as useProductEntityProp,
+} from '@woocommerce/product-editor';
+import { __ } from '@wordpress/i18n';
+
+export function Edit({ attributes, context: { postType } } ) {
+ const blockProps = useWooBlockProps( attributes );
+ const {
+ title,
+ property,
+ help,
+ date,
+ disabled,
+ } = attributes;
+
+ const [ value, setValue ] = useProductEntityProp( property, { postType } );
+ const [ isPickerVisible, setIsPickerVisible ] = useState( false );
+
+ function formatDateTime( date: string ) {
+ const dateTime = new Date( date );
+
+ if ( isNaN( dateTime ) ) {
+ return '';
+ }
+
+ // Get the components of the date and time
+ const year = dateTime.getFullYear();
+ const month = String(dateTime.getMonth() + 1).padStart(2, '0'); // Months are zero-based
+ const day = String(dateTime.getDate()).padStart(2, '0');
+ const hours = String(dateTime.getHours()).padStart(2, '0');
+ const minutes = String(dateTime.getMinutes()).padStart(2, '0');
+
+ // Format the date and time as "YYYY-MM-DD HH:MM"
+ return `${year}-${month}-${day} ${hours}:${minutes}`;
+ }
+
+ return (
+
+
+
+
+ setIsPickerVisible( true ) }
+ autoComplete="off"
+ placeholder='YYYY-MM-DD HH:MM'
+ value={ formatDateTime( value ) || '' }
+ disabled={ disabled }
+ />
+
+
+ setValue( '' ) }
+ >
+ { __( 'Clear', 'woocommerce-pre-orders' ) }
+
+
+
+
+ { isPickerVisible && (
+
setIsPickerVisible( false ) }
+ >
+
+
+ {
+ setValue( formatDateTime( date ) );
+ } }
+ />
+
+
+ )
+ }
+
+ );
+}
diff --git a/src/admin/blocks/date-time-picker/index.ts b/src/admin/blocks/date-time-picker/index.ts
new file mode 100644
index 0000000..6a4e0a5
--- /dev/null
+++ b/src/admin/blocks/date-time-picker/index.ts
@@ -0,0 +1,30 @@
+/**
+ * External dependencies
+ */
+import { registerProductEditorBlockType } from '@woocommerce/product-editor';
+
+/**
+ * Internal dependencies
+ */
+import { Edit } from './edit';
+import blockConfiguration from './block.json';
+
+const { name, ...metadata } = blockConfiguration;
+const settings = {
+ example: {},
+ edit: Edit,
+};
+
+
+/**
+ * Every block starts by registering a new block type definition.
+ *
+ * @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block
+ */
+registerProductEditorBlockType(
+ {
+ name,
+ metadata: metadata as never,
+ settings: settings as never,
+ }
+);
diff --git a/src/admin/blocks/message-control/block.json b/src/admin/blocks/message-control/block.json
new file mode 100644
index 0000000..289e98f
--- /dev/null
+++ b/src/admin/blocks/message-control/block.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "woocommerce-pre-orders/message-control-block",
+ "version": "0.1.0",
+ "title": "Message Block",
+ "category": "widgets",
+ "icon": "flag",
+ "description": "A block to display messages in plain-text or HTML.",
+ "attributes": {
+ "content": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ "supports": {
+ "html": true,
+ "inserter": false
+ },
+ "textdomain": "woocommerce-pre-orders",
+ "editorScript": "file:./index.js"
+}
diff --git a/src/admin/blocks/message-control/edit.tsx b/src/admin/blocks/message-control/edit.tsx
new file mode 100644
index 0000000..21f1754
--- /dev/null
+++ b/src/admin/blocks/message-control/edit.tsx
@@ -0,0 +1,27 @@
+/**
+ * External dependencies
+ */
+import { useWooBlockProps } from '@woocommerce/block-templates';
+import { useEntityProp } from '@wordpress/core-data';
+import parse from 'html-react-parser';
+
+export function Edit({ attributes, context: { postType } } ) {
+ const blockProps = useWooBlockProps( attributes );
+ let {
+ content,
+ } = attributes;
+
+ const [ productId ] = useEntityProp< number >(
+ 'postType',
+ 'product',
+ 'id'
+ );
+
+ content = content.replace( 'postIdPlaceholder', productId.toString() );
+
+ return (
+
+ );
+}
diff --git a/src/admin/blocks/message-control/index.ts b/src/admin/blocks/message-control/index.ts
new file mode 100644
index 0000000..6a4e0a5
--- /dev/null
+++ b/src/admin/blocks/message-control/index.ts
@@ -0,0 +1,30 @@
+/**
+ * External dependencies
+ */
+import { registerProductEditorBlockType } from '@woocommerce/product-editor';
+
+/**
+ * Internal dependencies
+ */
+import { Edit } from './edit';
+import blockConfiguration from './block.json';
+
+const { name, ...metadata } = blockConfiguration;
+const settings = {
+ example: {},
+ edit: Edit,
+};
+
+
+/**
+ * Every block starts by registering a new block type definition.
+ *
+ * @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block
+ */
+registerProductEditorBlockType(
+ {
+ name,
+ metadata: metadata as never,
+ settings: settings as never,
+ }
+);
diff --git a/src/admin/blocks/select-control/block.json b/src/admin/blocks/select-control/block.json
new file mode 100644
index 0000000..a79d872
--- /dev/null
+++ b/src/admin/blocks/select-control/block.json
@@ -0,0 +1,38 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "woocommerce-pre-orders/select-control-block",
+ "version": "0.1.0",
+ "title": "Select Control",
+ "category": "widgets",
+ "icon": "flag",
+ "description": "A block to display a select control.",
+ "attributes": {
+ "property": {
+ "type": "string",
+ "default": ""
+ },
+ "title": {
+ "type": "string",
+ "default": ""
+ },
+ "help": {
+ "type": "string",
+ "default": ""
+ },
+ "options": {
+ "type": "array",
+ "default": []
+ },
+ "multiple": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "supports": {
+ "html": false,
+ "inserter": false
+ },
+ "textdomain": "woocommerce-pre-orders",
+ "editorScript": "file:./index.js"
+}
diff --git a/src/admin/blocks/select-control/edit.tsx b/src/admin/blocks/select-control/edit.tsx
new file mode 100644
index 0000000..4901a0a
--- /dev/null
+++ b/src/admin/blocks/select-control/edit.tsx
@@ -0,0 +1,47 @@
+/**
+ * External dependencies
+ */
+import { useWooBlockProps } from '@woocommerce/block-templates';
+import { SelectControl } from '@wordpress/components';
+import { MultiSelectControl } from '@codeamp/block-components';
+import parse from 'html-react-parser';
+import {
+ __experimentalUseProductEntityProp as useProductEntityProp,
+} from '@woocommerce/product-editor';
+
+export function Edit({ attributes, context: { postType } } ) {
+ const blockProps = useWooBlockProps( attributes );
+ const {
+ title,
+ property,
+ options,
+ help,
+ multiple,
+ disabled,
+ } = attributes;
+
+ const [ value, setValue ] = useProductEntityProp( property, { postType } );
+
+ function setData( selected: string | string[] | number[] ) {
+ if ( Array.isArray( selected ) && selected.every( item => ! isNaN( item ) ) ) {
+ setValue( selected.map( Number ) );
+ } else {
+ setValue( selected );
+ }
+ }
+
+ const CustomSelectControl = multiple ? MultiSelectControl : SelectControl;
+
+ return (
+
+
+
+ );
+}
diff --git a/src/admin/blocks/select-control/index.ts b/src/admin/blocks/select-control/index.ts
new file mode 100644
index 0000000..6a4e0a5
--- /dev/null
+++ b/src/admin/blocks/select-control/index.ts
@@ -0,0 +1,30 @@
+/**
+ * External dependencies
+ */
+import { registerProductEditorBlockType } from '@woocommerce/product-editor';
+
+/**
+ * Internal dependencies
+ */
+import { Edit } from './edit';
+import blockConfiguration from './block.json';
+
+const { name, ...metadata } = blockConfiguration;
+const settings = {
+ example: {},
+ edit: Edit,
+};
+
+
+/**
+ * Every block starts by registering a new block type definition.
+ *
+ * @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block
+ */
+registerProductEditorBlockType(
+ {
+ name,
+ metadata: metadata as never,
+ settings: settings as never,
+ }
+);
diff --git a/src/preorder-gateway/gateway.js b/src/preorder-gateway/gateway.js
new file mode 100644
index 0000000..1d857e7
--- /dev/null
+++ b/src/preorder-gateway/gateway.js
@@ -0,0 +1,45 @@
+/**
+ * External dependencies
+ */
+import { getSetting } from '@woocommerce/settings';
+import { decodeEntities } from '@wordpress/html-entities';
+
+const PAYMENT_METHOD_NAME = 'pre_orders_pay_later';
+const settings = getSetting( 'pre_orders_pay_later_data', {} );
+const label = decodeEntities( settings.title );
+const orderButtonText = decodeEntities( settings.order_button_text );
+
+/**
+ * Content component
+ */
+const Content = () => {
+ return decodeEntities( settings.description || '' );
+};
+
+/**
+ * Label component
+ *
+ * @param {*} props Props from payment API.
+ */
+const Label = ( props ) => {
+ const { PaymentMethodLabel } = props.components;
+ return ;
+};
+
+/**
+ * Pre-Orders payment method config object.
+ */
+const preOrdersPaymentMethod = {
+ name: PAYMENT_METHOD_NAME,
+ content: ,
+ label: ,
+ edit: ,
+ canMakePayment: () => true,
+ ariaLabel: label,
+ supports: {
+ features: settings.supports,
+ },
+ placeOrderButtonLabel: orderButtonText,
+};
+
+export default preOrdersPaymentMethod;
diff --git a/src/preorder-gateway/index.js b/src/preorder-gateway/index.js
new file mode 100644
index 0000000..17adb04
--- /dev/null
+++ b/src/preorder-gateway/index.js
@@ -0,0 +1,95 @@
+/**
+ * External dependencies
+ */
+import { registerPaymentMethod } from '@woocommerce/blocks-registry';
+import { __experimentalRegisterCheckoutFilters } from '@woocommerce/blocks-checkout';
+import { __, _x, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import preorderPaymentMethod from './gateway';
+import './index.scss';
+
+/**
+ * Inspects the cart payload and the cart item `extension` property for
+ * additional information regarding if it is a preorder cart item type.
+ *
+ * @param {*} cart
+ * @return {boolean} A boolean indicating the presence of a pre-order product in cart.
+ */
+const cartContainsPreorders = ( cart ) => {
+ if ( cart.cartItemsCount > 0 ) {
+ return (
+ cart.cartItems[ 0 ].extensions?.preorders?.charged_upfront ||
+ cart.cartItems[ 0 ].extensions?.preorders?.charged_upon_release
+ );
+ }
+ return false;
+};
+
+/**
+ * Looks for the availability information (date) at the the
+ * cart item `extension` property.
+ *
+ * @param {*} cart
+ * @return {string} Returns the date in string format to be displayed.
+ */
+const getPreorderDate = ( cart ) => {
+ if ( cart.cartItemsCount > 0 ) {
+ return cart.cartItems[ 0 ].extensions?.preorders?.availability;
+ }
+};
+
+/**
+ * Prepares the information that is going to be added to the
+ * total label on both cart and checkout blocks.
+ *
+ * @param {*} cart
+ * @return {string} Returns the sentence to be used with the total label.
+ */
+const getPreorderAdditionalInformation = ( cart ) => {
+ const chargedUpfront =
+ cart.cartItems[ 0 ].extensions?.preorders?.charged_upfront;
+ const chargedUponRelease =
+ cart.cartItems[ 0 ].extensions?.preorders?.charged_upon_release;
+ if ( chargedUpfront ) {
+ return __( 'charged upfront.', 'woocommerce-pre-orders' );
+ } else if ( chargedUponRelease ) {
+ const preorderDate = getPreorderDate( cart );
+ return sprintf(
+ /* translators: 1:Pre-order product date */
+ __( 'charged %1$s', 'woocommerce-pre-orders' ),
+ preorderDate
+ );
+ }
+ return '';
+};
+
+/*
+ * Register the new payment gateway.
+ */
+registerPaymentMethod( preorderPaymentMethod );
+
+/**
+ * Deals with manipulating the total label to add information if needed.
+ */
+__experimentalRegisterCheckoutFilters( 'woocommerce-pre-order', {
+ totalLabel: ( label, extensions, { cart } ) => {
+ if ( cartContainsPreorders( cart ) ) {
+ const additionalInformation =
+ getPreorderAdditionalInformation( cart );
+ return sprintf(
+ /* translators: 1: Label, 2: Additional information */
+ _x(
+ '%1$s %2$s',
+ 'label and additional info',
+ 'woocommerce-pre-orders'
+ ),
+ label,
+ additionalInformation
+ );
+ }
+ return label;
+ },
+} );
diff --git a/src/preorder-gateway/index.scss b/src/preorder-gateway/index.scss
new file mode 100644
index 0000000..2f7494a
--- /dev/null
+++ b/src/preorder-gateway/index.scss
@@ -0,0 +1 @@
+// In case it is to be used in future versions.
diff --git a/templates/emails/admin-new-pre-order.php b/templates/emails/admin-new-pre-order.php
new file mode 100644
index 0000000..9bc97f0
--- /dev/null
+++ b/templates/emails/admin-new-pre-order.php
@@ -0,0 +1,35 @@
+
+
+
+
+
+get_billing_first_name() . ' ' . $order->get_billing_last_name();
+/* translators: %s: billing first name and last name */
+printf( esc_html__( 'You have received a pre-order from %s. Their pre-order is as follows:', 'woocommerce-pre-orders' ), $full_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+?>
+
+
+
+
+
+
+
+
+
diff --git a/templates/emails/admin-pre-order-cancelled.php b/templates/emails/admin-pre-order-cancelled.php
new file mode 100644
index 0000000..941529f
--- /dev/null
+++ b/templates/emails/admin-pre-order-cancelled.php
@@ -0,0 +1,76 @@
+
+
+
+
+
+get_billing_first_name() . ' ' . $order->get_billing_last_name();
+
+/* Translators: %s Full name of the customer */
+printf( esc_html__( 'A pre-order from %s has been cancelled. The order details are shown below for your reference.', 'woocommerce-pre-orders' ), esc_html( $full_name ) );
+?>
+
+
+
+
+
+
+
+
+
diff --git a/templates/emails/customer-pre-order-available.php b/templates/emails/customer-pre-order-available.php
new file mode 100644
index 0000000..eec8bfb
--- /dev/null
+++ b/templates/emails/customer-pre-order-available.php
@@ -0,0 +1,102 @@
+
+
+
+
+get_status() && ! WC_Pre_Orders_Manager::is_zero_cost_order( $order ) ) :
+ ?>
+
+
+ get_checkout_payment_url() ) . '">', '' );
+ ?>
+
+
+get_status() && ! WC_Pre_Orders_Manager::is_zero_cost_order( $order ) ) : ?>
+
+
+
+
+
+get_status() ) : ?>
+
+
+ get_checkout_payment_url() ) . '">', '' );
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/emails/customer-pre-order-date-changed.php b/templates/emails/customer-pre-order-date-changed.php
new file mode 100644
index 0000000..36d5a0c
--- /dev/null
+++ b/templates/emails/customer-pre-order-date-changed.php
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/emails/customer-pre-ordered.php b/templates/emails/customer-pre-ordered.php
new file mode 100644
index 0000000..8afb0e4
--- /dev/null
+++ b/templates/emails/customer-pre-ordered.php
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+ ' . sprintf( esc_html__( 'Your pre-order has been received. You will be automatically charged for your order via your selected payment method when your pre-order is released%s Your order details are shown below for your reference.', 'woocommerce-pre-orders' ), $availability_date_text ) . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ } else {
+ /* translators: %s: availability date */
+ echo '' . sprintf( esc_html__( 'Your pre-order has been received. You will be prompted for payment for your order when your pre-order is released%s Your order details are shown below for your reference.', 'woocommerce-pre-orders' ), $availability_date_text ) . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/emails/plain/admin-new-pre-order.php b/templates/emails/plain/admin-new-pre-order.php
new file mode 100644
index 0000000..fe9360c
--- /dev/null
+++ b/templates/emails/plain/admin-new-pre-order.php
@@ -0,0 +1,57 @@
+get_billing_first_name() . ' ' . $order->get_billing_last_name();
+/* translators: %s: first name and last name */
+echo sprintf( esc_html__( 'You have received a pre-order from %s. Their pre-order is as follows:', 'woocommerce-pre-orders' ), esc_html( $full_name ) ) . "\n\n";
+
+/*
+ * @hooked WC_Emails::order_details() Shows the order details table.
+ * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
+ * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
+ * @since 2.5.0
+ */
+do_action( 'woocommerce_email_order_details', $order, $sent_to_admin, $plain_text, $email );
+
+echo "\n----------------------------------------\n\n";
+
+/*
+ * @hooked WC_Emails::order_meta() Shows order meta data.
+ */
+do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
+
+/*
+ * @hooked WC_Emails::customer_details() Shows customer details
+ * @hooked WC_Emails::email_address() Shows email address
+ */
+do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
+
+echo "\n\n----------------------------------------\n\n";
+
+/**
+ * Show user-defined additional content - this is set in each email's settings.
+ */
+if ( $additional_content ) {
+ echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) );
+ echo "\n\n----------------------------------------\n\n";
+}
+
+echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) );
diff --git a/templates/emails/plain/admin-pre-order-cancelled.php b/templates/emails/plain/admin-pre-order-cancelled.php
new file mode 100644
index 0000000..8c00fd1
--- /dev/null
+++ b/templates/emails/plain/admin-pre-order-cancelled.php
@@ -0,0 +1,70 @@
+get_billing_first_name() . ' ' . $order->get_billing_last_name();
+/* Translators: %s Full name of the customer */
+printf( esc_html__( 'A pre-order from %s has been cancelled. The order details are shown below for your reference.', 'woocommerce-pre-orders' ), esc_html( $full_name ) ) . "\n\n";
+
+if ( $message ) :
+
+ echo "----------\n\n";
+ echo esc_html( wp_strip_all_tags( wptexturize( $message ) ) ) . "\n\n";
+ echo "----------\n\n";
+
+endif;
+
+/**
+ * @hooked WC_Emails::order_details() Shows the order details table.
+ * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
+ * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
+ * @since 2.5.0
+ */
+do_action( 'woocommerce_email_order_details', $order, $sent_to_admin, $plain_text, $email );
+
+echo "\n----------------------------------------\n\n";
+
+/**
+ * @hooked WC_Emails::order_meta() Shows order meta data.
+ *
+ * @since 1.7.3
+ */
+do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
+
+/**
+ * @hooked WC_Emails::customer_details() Shows customer details
+ * @hooked WC_Emails::email_address() Shows email address
+ * @since 1.7.3
+ */
+do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
+
+echo "\n\n----------------------------------------\n\n";
+
+/**
+ * Show user-defined additional content - this is set in each email's settings.
+ */
+if ( $additional_content ) {
+ echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) );
+ echo "\n\n----------------------------------------\n\n";
+}
+
+/**
+ * @hooked woocommerce_email_footer_text modifies the footer text of the email
+ *
+ * @since 1.7.3
+ */
+echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) );
diff --git a/templates/emails/plain/customer-pre-order-available.php b/templates/emails/plain/customer-pre-order-available.php
new file mode 100644
index 0000000..9e8f546
--- /dev/null
+++ b/templates/emails/plain/customer-pre-order-available.php
@@ -0,0 +1,81 @@
+get_status() && ! WC_Pre_Orders_Manager::is_zero_cost_order( $order ) ) :
+
+ esc_html_e( 'Your pre-order is now available, but requires payment. Please pay for your pre-order now: ', 'woocommerce-pre-orders' ) . esc_url( $order->get_checkout_payment_url() ) . "\n\n";
+
+elseif ( 'on-hold' === $order->get_status() && ! WC_Pre_Orders_Manager::is_zero_cost_order( $order ) ) :
+
+ esc_html_e( "Your pre-order is now available, but is waiting for the payment to be confirmed. Please wait until it's confirmed. Optionally, make sure the related payment has been sent to avoid delays on your order.", 'woocommerce-pre-orders' ) . "\n\n";
+
+elseif ( 'failed' === $order->get_status() ) :
+
+ esc_html_e( 'Your pre-order is now available, but automatic payment failed. Please update your payment information now : ', 'woocommerce-pre-orders' ) . esc_url( $order->get_checkout_payment_url() ) . "\n\n";
+
+else :
+
+ esc_html_e( 'Your pre-order is now available. Your order details are shown below for your reference.', 'woocommerce-pre-orders' ) . "\n\n";
+
+endif;
+
+if ( $message ) :
+
+ echo "----------\n\n";
+ echo esc_html( wp_strip_all_tags( wptexturize( $message ) ) ) . "\n\n";
+ echo "----------\n\n";
+
+endif;
+
+/*
+ * @hooked WC_Emails::order_details() Shows the order details table.
+ * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
+ * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
+ * @since 2.5.0
+ */
+do_action( 'woocommerce_email_order_details', $order, $sent_to_admin, $plain_text, $email );
+
+echo "\n----------------------------------------\n\n";
+
+/*
+ * @hooked WC_Emails::order_meta() Shows order meta data.
+ */
+do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
+
+/*
+ * @hooked WC_Emails::customer_details() Shows customer details
+ * @hooked WC_Emails::email_address() Shows email address
+ */
+do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
+
+echo "\n\n----------------------------------------\n\n";
+
+/**
+ * Show user-defined additional content - this is set in each email's settings.
+ */
+if ( $additional_content ) {
+ echo esc_html( wp_strip_all_tags( wptexturize( $additional_content ) ) );
+} else {
+ echo esc_html__( 'Thanks for shopping with us.', 'woocommerce-pre-orders' );
+}
+
+echo wp_kses_post( apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) ) );
diff --git a/templates/emails/plain/customer-pre-order-cancelled.php b/templates/emails/plain/customer-pre-order-cancelled.php
new file mode 100644
index 0000000..1d8fd43
--- /dev/null
+++ b/templates/emails/plain/customer-pre-order-cancelled.php
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+ ' . sprintf( esc_html__( 'Pre-orders require WooCommerce to be installed and active. You can download %s here.', 'woocommerce-pre-orders' ), 'WooCommerce ' ) . '
';
+}
+
+// When plugin is activated.
+register_activation_hook( __FILE__, 'woocommerce_pre_orders_activate' );
+
+/**
+ * Actions to perform when plugin is activated.
+ *
+ * @since 1.4.7
+ */
+function woocommerce_pre_orders_activate() {
+ add_rewrite_endpoint( 'pre-orders', EP_ROOT | EP_PAGES );
+ flush_rewrite_rules();
+}
+
+if ( ! class_exists( 'WC_Pre_Orders' ) ) :
+ define( 'WC_PRE_ORDERS_VERSION', '2.1.0' ); // WRCS: DEFINED_VERSION.
+ define( 'WC_PRE_ORDERS_PLUGIN_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
+ define( 'WC_PRE_ORDERS_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ), basename( __FILE__ ) ) ) ) );
+ define( 'WC_PRE_ORDERS_GUTENBERG_EXISTS', function_exists( 'register_block_type' ) ? true : false );
+ require 'includes/class-wc-pre-orders.php';
+endif;
+
+add_action( 'plugins_loaded', 'woocommerce_pre_orders_init' );
+
+/**
+ * Initializes the extension.
+ *
+ * @return Object Instance of the extension.
+ * @since 1.5.25
+ */
+function woocommerce_pre_orders_init() {
+ load_plugin_textdomain( 'woocommerce-pre-orders', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
+
+ if ( ! class_exists( 'WooCommerce' ) ) {
+ add_action( 'admin_notices', 'woocommerce_pre_orders_missing_wc_notice' );
+
+ return;
+ }
+
+ $GLOBALS['wc_pre_orders'] = new WC_Pre_Orders( __FILE__ );
+}
+
+add_action( 'plugins_loaded', 'woocommerce_pre_orders_init' );
+
+add_filter( 'woocommerce_translations_updates_for_' . basename( __FILE__, '.php' ), '__return_true' );
+
+/**
+ * Loads the classes for the integration with WooCommerce Blocks.
+ */
+function woocommerce_pre_orders_load_block_classes() {
+ if ( class_exists( 'Automattic\WooCommerce\Blocks\Package' ) && version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '6.5.0', '>' ) ) {
+ \WC_Pre_Orders::load_block_classes();
+ }
+}
+
+add_action( 'woocommerce_blocks_loaded', 'woocommerce_pre_orders_load_block_classes' );