diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/404.html b/404.html new file mode 100644 index 000000000..e54bec665 --- /dev/null +++ b/404.html @@ -0,0 +1,2852 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ +

404 - Not found

+ +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..cdcfdff63 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +wpbrowser.wptestkit.dev diff --git a/DispatcherAPI/index.html b/DispatcherAPI/index.html new file mode 100644 index 000000000..7fd3aff7a --- /dev/null +++ b/DispatcherAPI/index.html @@ -0,0 +1,3673 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dispatcher API - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+ +
+ + + + + + + + +

Dispatcher API

+ +

An API to dispatch and subscribe to events fired during tests execution.

+

Events dispatched by Codeception

+

You can subscribe to the following events dispatched by Codeception in either the global bootstrap file +(usually tests/_bootstrap.php), or in a suite bootstrap file (usually tests/<suite>/_bootstrap.php) using the +Event Dispatcher Bridge extension:

+
    +
  • Codeception\Events::SUITE_BEFORE
  • +
  • Codeception\Events::SUITE_AFTER
  • +
  • CodeceptionventsEvents::TEST_START
  • +
  • CodeceptionventsEvents::TEST_BEFORE
  • +
  • CodeceptionventsEvents::STEP_BEFORE
  • +
  • CodeceptionventsEvents::STEP_AFTER
  • +
  • CodeceptionventsEvents::TEST_FAIL
  • +
  • CodeceptionventsEvents::TEST_ERROR
  • +
  • CodeceptionventsEvents::TEST_PARSED
  • +
  • CodeceptionventsEvents::TEST_INCOMPLETE
  • +
  • CodeceptionventsEvents::TEST_SKIPPED
  • +
  • CodeceptionventsEvents::TEST_WARNING
  • +
  • CodeceptionventsEvents::TEST_USELESS
  • +
  • CodeceptionventsEvents::TEST_SUCCESS
  • +
  • CodeceptionventsEvents::TEST_AFTER
  • +
  • CodeceptionventsEvents::TEST_END
  • +
  • CodeceptionventsEvents::TEST_FAIL_PRINT
  • +
  • CodeceptionventsEvents::RESULT_PRINT_AFTER
  • +
+

In the global bootstrap file (usually tests/_bootstrap.php), or the suite bootstrap file (usually +tests/<suite>/_bootstrap.php), subscribe to the Codeception events by providing a callback function that will accept +different parameters depending on the event being dispatched:

+
<?php
+
+use Codeception\Events;
+use Codeception\Event\SuiteEvent
+use Codeception\Event\TestEvent;
+use Codeception\Event\StepEvent;
+use Codeception\Event\PrintResultEvent;
+use lucatume\WPBrowser\Events\Dispatcher;
+
+Dispatcher::addListener(Events::SUITE_BEFORE, function (SuiteEvent $suiteEvent) {
+    codecept_debug('Running on SUITE BEFORE');
+});
+
+Dispatcher::addListener(Events::SUITE_AFTER, function (SuiteEvent $suiteEvent) {
+    codecept_debug('Running on SUITE AFTER');
+});
+
+Dispatcher::addListener(Events::TEST_START, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST START');
+});
+
+Dispatcher::addListener(Events::TEST_BEFORE, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST BEFORE');
+});
+
+Dispatcher::addListener(Events::STEP_BEFORE, function (StepEvent $stepEvent) {
+    codecept_debug('Running on STEP BEFORE');
+});
+
+Dispatcher::addListener(Events::STEP_AFTER, function (StepEvent $stepEvent) {
+    codecept_debug('Running on STEP AFTER');
+});
+
+Dispatcher::addListener(Events::TEST_FAIL, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST FAIL');
+});
+
+Dispatcher::addListener(Events::TEST_ERROR, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST ERROR');
+});
+
+Dispatcher::addListener(Events::TEST_PARSED, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST PARSED');
+});
+
+Dispatcher::addListener(Events::TEST_INCOMPLETE, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST INCOMPLETE');
+});
+
+Dispatcher::addListener(Events::TEST_SKIPPED, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST SKIPPED');
+});
+
+Dispatcher::addListener(Events::TEST_WARNING, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST WARNING');
+});
+
+Dispatcher::addListener(Events::TEST_USELESS, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST USELESS');
+});
+
+Dispatcher::addListener(Events::TEST_SUCCESS, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST SUCCESS');
+});
+
+Dispatcher::addListener(Events::TEST_AFTER, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST AFTER');
+});
+
+Dispatcher::addListener(Events::TEST_END, function (TestEvent $testEvent) {
+    codecept_debug('Running on TEST END');
+});
+
+Dispatcher::addListener(Events::TEST_FAIL_PRINT, function (PrintResultEvent $printResultEvent) {
+    codecept_debug('Running on TEST FAIL PRINT');
+});
+
+Dispatcher::addListener(Events::RESULT_PRINT_AFTER, function (PrintResultEvent $printResultEvent) {
+    codecept_debug('Running on RESULT PRINT AFTER');
+});
+
+

Events dispatched by wp-browser

+

The project dispatches its own events, allowing you to subscribe to them to control the test state and execution.
+To subscribe to the events dispatched by wp-browser, you do not need to use the +Event Dispatcher Bridge extension.

+

WPLoader Module Events

+

The WPLoader module will dispatch events during its initialization.

+
EVENT_BEFORE_LOADONLY
+

This event fires before WordPress is loaded by the WPLoader module when loadOnly is set to true.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

WordPress is not loaded yet, so you cannot use functions or classes defined by WordPress, themes or plugins here.
+You can interact with the WordPress installation and use the lucatume\WPBrowser\WordPress\PreloadFilters class to +hook on actions and filters that will be fired by WordPress once loaded.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPLoader;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPLoader::EVENT_BEFORE_LOADONLY, function (Event $event) {
+    /** @var WPLoader $wpLoader */
+    $wpLoader = $event->getOrigin();
+
+    codecept_debug('Running on EVENT_BEFORE_LOADONLY');
+
+    // Interact with the WordPress installation, its filesystem and database.
+    $installation = $wpLoader->getInstallation();
+    $pluginsDir = $installation->getPluginsDir();
+    $db = $installation->getDb();
+    $db->import(codecept_data_dir('some-dump.sql'));
+
+    // Use the PreloadFilters class to hook on WordPress actions and filters.
+    PreloadFilters::addFilter('init', fn() => update_option('some_option', 'some_value'));
+    PreloadFilters::addFilter('pre_option_some_option', fn() => 'some_value');
+});
+
+
EVENT_AFTER_LOADONLY
+

This event fires after WordPress is loaded by the WPLoader module when loadOnly is set to true.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

At this point, WordPress has been loaded. +You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPLoader;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPLoader::EVENT_AFTER_LOADONLY, function (Event $event) {
+    /** @var WPLoader $wpLoader */
+    $wpLoader = $event->getOrigin();
+
+    codecept_debug('Running on EVENT_AFTER_LOADONLY');
+
+    // Interact with the WordPress installation, its filesystem and database.    
+    $installation = $wpLoader->getInstallation();
+    $pluginsDir = $installation->getPluginsDir();
+    $db = $installation->getDb();
+    $db->import(codecept_data_dir('some-dump.sql'));
+
+    // Use WordPress functions and classes.
+    update_option('some_option', 'some_value');
+});
+
+
EVENT_BEFORE_INSTALL
+

This event fires before WordPress is installed by the WPLoader module when loadOnly is set to false.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

WordPress is not loaded yet, so you cannot use functions or classes defined by WordPress, themes or plugins here.
+You can interact with the WordPress installation and use the lucatume\WPBrowser\WordPress\PreloadFilters class to +hook on actions and filters that will be fired by WordPress once loaded.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPLoader;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPLoader::EVENT_BEFORE_INSTALL, function (Event $event) {
+    /** @var WPLoader $wpLoader */
+    $wpLoader = $event->getOrigin();
+
+    codecept_debug('Running on EVENT_BEFORE_INSTALL');
+
+    // Interact with the WordPress installation, its filesystem and database.
+    $installation = $wpLoader->getInstallation();
+    $pluginsDir = $installation->getPluginsDir();
+    $db = $installation->getDb();
+    $db->import(codecept_data_dir('some-dump.sql'));
+
+    // Use the PreloadFilters class to hook on WordPress actions and filters.
+    PreloadFilters::addFilter('init', fn() => update_option('some_option', 'some_value'));
+    PreloadFilters::addFilter('pre_option_some_option', fn() => 'some_value');
+});
+
+
EVENT_AFTER_INSTALL
+

This event fires after WordPress is installed by the WPLoader module when loadOnly is set to false.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

At this point, WordPress has been installed and loaded. +You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins. +This event fires before dump files specified in the dump configuration parameter of the WPLoader module are +imported.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPLoader;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPLoader::EVENT_AFTER_INSTALL, function (Event $event) {
+    /** @var WPLoader $wpLoader */
+    $wpLoader = $event->getOrigin();
+
+    codecept_debug('Running on EVENT_AFTER_INSTALL');
+
+    // Interact with the WordPress installation, its filesystem and database.    
+    $installation = $wpLoader->getInstallation();
+    $pluginsDir = $installation->getPluginsDir();
+    $db = $installation->getDb();
+    $db->import(codecept_data_dir('some-dump.sql'));
+
+    // Use WordPress functions and classes.    
+    update_option('some_option', 'some_value');
+});
+
+
EVENT_AFTER_INSTALL
+

This event fires after WordPress is installed by the WPLoader module when loadOnly is set to false.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

At this point, WordPress has been installed and loaded. +You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPLoader;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPLoader::EVENT_AFTER_INSTALL, function (Event $event) {
+    /** @var WPLoader $wpLoader */
+    $wpLoader = $event->getOrigin();
+
+    codecept_debug('Running on EVENT_AFTER_INSTALL');
+
+    // Interact with the WordPress installation, its filesystem and database.    
+    $installation = $wpLoader->getInstallation();
+    $pluginsDir = $installation->getPluginsDir();
+    $db = $installation->getDb();
+    $db->import(codecept_data_dir('some-dump.sql'));
+
+    // Use WordPress functions and classes.
+    update_option('some_option', 'some_value');
+});
+
+
EVENT_AFTER_BOOTSTRAP
+

This event fires after the WPLoader module has finished bootstrapping the WordPress installation and dump files +specified in the dump configuration parameter of the WPLoader module are imported.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPLoader;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPLoader::EVENT_AFTER_BOOTSTRAP, function (Event $event) {
+    /** @var WPLoader $wpLoader */
+    $wpLoader = $event->getOrigin();
+
+    codecept_debug('Running on EVENT_AFTER_BOOTSTRAP');
+
+    // Interact with the WordPress installation, its filesystem and database.    
+    $installation = $wpLoader->getInstallation();
+    $pluginsDir = $installation->getPluginsDir();
+    $db = $installation->getDb();
+    $db->import(codecept_data_dir('some-dump.sql'));
+
+    // Use WordPress functions and classes.
+    update_option('some_option', 'some_value');
+});
+
+

WPDb Module Events

+
EVENT_BEFORE_SUITE
+

This event fires after the WPDb module has run its _beforeSuite method.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+

At this point the module has connected to the database, cleaned up and populated the database with the dump files.

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPDb;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPDb::EVENT_BEFORE_SUITE, function (Event $event) {
+    /** @var WPDb $wpDb */
+    $wpDb = $event->getOrigin();    
+
+    codecept_debug('Running on EVENT_BEFORE_SUIT
+    E');
+});
+
+
EVENT_BEFORE_INITIALIZE
+

This event fires before the WPDb module initializes.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Module\WPDb;
+use lucatume\WPBrowser\Events\Event;
+
+Dispatcher::addListener(WPDb::EVENT_BEFORE_INITIALIZE, function (Event $event) {
+    /** @var WPDb $wpDb */
+    $wpDb = $event->getOrigin();    
+
+    codecept_debug('Running on EVENT_BEFORE_INITIALIZE');
+});
+
+
EVENT_AFTER_INITIALIZE
+

This event fires after the WPDb module has initialized.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;  
+use lucatume\WPBrowser\Module\WPDb;  
+use lucatume\WPBrowser\Events\Event;  
+
+Dispatcher::addListener(WPDb::EVENT_AFTER_INITIALIZE, function (Event $event) {
+    /** @var WPDb $wpDb */
+    $wpDb = $event->getOrigin();    
+
+    codecept_debug('Running on EVENT_AFTER_INITIALIZE');
+});
+
+
EVENT_AFTER_DB_PREPARE
+

This event fires after the WPDb module has prepared the database setting up some default values for +quality-of-life improvements.

+

Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;  
+use lucatume\WPBrowser\Module\WPDb;  
+use lucatume\WPBrowser\Events\Event;  
+
+Dispatcher::addListener(WPDb::EVENT_AFTER_DB_PREPARE, function (Event $event) {
+    /** @var WPDb $wpDb */
+    $wpDb = $event->getOrigin();    
+
+    codecept_debug('Running on EVENT_AFTER_DB_PREPARE');
+});
+
+

Dispatching custom events

+

You can use the Dispatcher::dispatch method to dispatch and subscribe to custom events:

+
<?php
+
+use lucatume\WPBrowser\Events\Dispatcher;
+use lucatume\WPBrowser\Events\Event;  
+
+Dispatcher::dispatch('my-event', 'my-origin', ['foo' => 'bar']);
+
+// Some other code...
+Dispatcher::addListener('my-event', function (Event $event) {
+    $origin = $event->getOrigin();
+    $foo = $event->get('foo');
+    codecept_debug('Running on my custom event');
+});
+
+ + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/assets/external/fonts.googleapis.com/css.49ea35f2.css b/assets/external/fonts.googleapis.com/css.49ea35f2.css new file mode 100644 index 000000000..14eb3ad40 --- /dev/null +++ b/assets/external/fonts.googleapis.com/css.49ea35f2.css @@ -0,0 +1,594 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2) format('woff2'); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2 new file mode 100644 index 000000000..d88dd2b86 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2 new file mode 100644 index 000000000..0f8ca12a6 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2 new file mode 100644 index 000000000..317f651ef Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2 new file mode 100644 index 000000000..0e37f9873 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2 new file mode 100644 index 000000000..e0934d94e Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2 new file mode 100644 index 000000000..d95067a4d Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2 new file mode 100644 index 000000000..83874b7b8 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2 new file mode 100644 index 000000000..50a280591 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2 new file mode 100644 index 000000000..efbe79a29 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2 new file mode 100644 index 000000000..ea329ab82 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2 new file mode 100644 index 000000000..993b327ca Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2 new file mode 100644 index 000000000..d3cb894a2 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2 new file mode 100644 index 000000000..1283c45d7 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2 new file mode 100644 index 000000000..851fedb92 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2 new file mode 100644 index 000000000..8f20a2cc1 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2 new file mode 100644 index 000000000..bed870800 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2 new file mode 100644 index 000000000..e1f558cd3 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2 new file mode 100644 index 000000000..688c713dc Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2 new file mode 100644 index 000000000..9dc0be836 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2 new file mode 100644 index 000000000..3e5facb89 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2 new file mode 100644 index 000000000..1125cc012 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 new file mode 100644 index 000000000..a57fbdc26 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 new file mode 100644 index 000000000..72226f5df Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 new file mode 100644 index 000000000..b61eed30c Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 new file mode 100644 index 000000000..a26ba157a Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 new file mode 100644 index 000000000..a69131b3a Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 new file mode 100644 index 000000000..14af54ae6 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 new file mode 100644 index 000000000..a7026d4c3 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 new file mode 100644 index 000000000..41637e58c Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 new file mode 100644 index 000000000..22f6f53cd Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 new file mode 100644 index 000000000..19fc4b1ba Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 new file mode 100644 index 000000000..98f53f744 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 new file mode 100644 index 000000000..660850eed Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 new file mode 100644 index 000000000..327eb6644 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 new file mode 100644 index 000000000..c17545332 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 new file mode 100644 index 000000000..a7f32b6f0 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2 new file mode 100644 index 000000000..2d7b21513 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 new file mode 100644 index 000000000..a4962e9b4 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2 new file mode 100644 index 000000000..e3d708f35 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 new file mode 100644 index 000000000..20c87e676 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 new file mode 100644 index 000000000..cfd043dba Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 new file mode 100644 index 000000000..47ce460fa Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2 new file mode 100644 index 000000000..022274d4c Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2 new file mode 100644 index 000000000..48edd1b09 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2 new file mode 100644 index 000000000..cb41535eb Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2 new file mode 100644 index 000000000..1d988a3f4 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2 new file mode 100644 index 000000000..11e6a46a4 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2 new file mode 100644 index 000000000..50fb8e711 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2 new file mode 100644 index 000000000..1f1c97fec Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2 new file mode 100644 index 000000000..162300519 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2 new file mode 100644 index 000000000..6f232c38a Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2 new file mode 100644 index 000000000..a3e5aef7c Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2 new file mode 100644 index 000000000..f73f27d6e Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2 new file mode 100644 index 000000000..135d06e00 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2 differ diff --git a/assets/external/unpkg.com/mermaid@11/dist/mermaid.min.js b/assets/external/unpkg.com/mermaid@11/dist/mermaid.min.js new file mode 100644 index 000000000..9f2882748 --- /dev/null +++ b/assets/external/unpkg.com/mermaid@11/dist/mermaid.min.js @@ -0,0 +1,2186 @@ +"use strict";var __esbuild_esm_mermaid=(()=>{var Pve=Object.create;var G1=Object.defineProperty;var Bve=Object.getOwnPropertyDescriptor;var Fve=Object.getOwnPropertyNames;var zve=Object.getPrototypeOf,Gve=Object.prototype.hasOwnProperty;var o=(t,e)=>G1(t,"name",{value:e,configurable:!0});var R=(t,e)=>()=>(t&&(e=t(t=0)),e);var gi=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),hr=(t,e)=>{for(var r in e)G1(t,r,{get:e[r],enumerable:!0})},Rb=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Fve(e))!Gve.call(t,i)&&i!==r&&G1(t,i,{get:()=>e[i],enumerable:!(n=Bve(e,i))||n.enumerable});return t},dr=(t,e,r)=>(Rb(t,e,"default"),r&&Rb(r,e,"default")),Xi=(t,e,r)=>(r=t!=null?Pve(zve(t)):{},Rb(e||!t||!t.__esModule?G1(r,"default",{value:t,enumerable:!0}):r,t)),$ve=t=>Rb(G1({},"__esModule",{value:!0}),t);var Nb=gi((AC,_C)=>{"use strict";(function(t,e){typeof AC=="object"&&typeof _C<"u"?_C.exports=e():typeof define=="function"&&define.amd?define(e):(t=typeof globalThis<"u"?globalThis:t||self).dayjs=e()})(AC,function(){"use strict";var t=1e3,e=6e4,r=36e5,n="millisecond",i="second",a="minute",s="hour",l="day",u="week",h="month",f="quarter",d="year",p="date",m="Invalid Date",g=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,v={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:o(function(k){var I=["th","st","nd","rd"],C=k%100;return"["+k+(I[(C-20)%10]||I[C]||I[0])+"]"},"ordinal")},x=o(function(k,I,C){var O=String(k);return!O||O.length>=I?k:""+Array(I+1-O.length).join(C)+k},"m"),b={s:x,z:o(function(k){var I=-k.utcOffset(),C=Math.abs(I),O=Math.floor(C/60),D=C%60;return(I<=0?"+":"-")+x(O,2,"0")+":"+x(D,2,"0")},"z"),m:o(function k(I,C){if(I.date()1)return k(F[0])}else{var B=I.name;S[B]=I,D=B}return!O&&D&&(w=D),D||!O&&w},"t"),A=o(function(k,I){if(E(k))return k.clone();var C=typeof I=="object"?I:{};return C.date=k,C.args=arguments,new M(C)},"O"),L=b;L.l=_,L.i=E,L.w=function(k,I){return A(k,{locale:I.$L,utc:I.$u,x:I.$x,$offset:I.$offset})};var M=function(){function k(C){this.$L=_(C.locale,null,!0),this.parse(C),this.$x=this.$x||C.x||{},this[T]=!0}o(k,"M");var I=k.prototype;return I.parse=function(C){this.$d=function(O){var D=O.date,P=O.utc;if(D===null)return new Date(NaN);if(L.u(D))return new Date;if(D instanceof Date)return new Date(D);if(typeof D=="string"&&!/Z$/i.test(D)){var F=D.match(g);if(F){var B=F[2]-1||0,$=(F[7]||"0").substring(0,3);return P?new Date(Date.UTC(F[1],B,F[3]||1,F[4]||0,F[5]||0,F[6]||0,$)):new Date(F[1],B,F[3]||1,F[4]||0,F[5]||0,F[6]||0,$)}}return new Date(D)}(C),this.init()},I.init=function(){var C=this.$d;this.$y=C.getFullYear(),this.$M=C.getMonth(),this.$D=C.getDate(),this.$W=C.getDay(),this.$H=C.getHours(),this.$m=C.getMinutes(),this.$s=C.getSeconds(),this.$ms=C.getMilliseconds()},I.$utils=function(){return L},I.isValid=function(){return this.$d.toString()!==m},I.isSame=function(C,O){var D=A(C);return this.startOf(O)<=D&&D<=this.endOf(O)},I.isAfter=function(C,O){return A(C){"use strict";LF=Xi(Nb(),1),Zc={trace:0,debug:1,info:2,warn:3,error:4,fatal:5},V={trace:o((...t)=>{},"trace"),debug:o((...t)=>{},"debug"),info:o((...t)=>{},"info"),warn:o((...t)=>{},"warn"),error:o((...t)=>{},"error"),fatal:o((...t)=>{},"fatal")},$1=o(function(t="fatal"){let e=Zc.fatal;typeof t=="string"?t.toLowerCase()in Zc&&(e=Zc[t]):typeof t=="number"&&(e=t),V.trace=()=>{},V.debug=()=>{},V.info=()=>{},V.warn=()=>{},V.error=()=>{},V.fatal=()=>{},e<=Zc.fatal&&(V.fatal=console.error?console.error.bind(console,Eo("FATAL"),"color: orange"):console.log.bind(console,"\x1B[35m",Eo("FATAL"))),e<=Zc.error&&(V.error=console.error?console.error.bind(console,Eo("ERROR"),"color: orange"):console.log.bind(console,"\x1B[31m",Eo("ERROR"))),e<=Zc.warn&&(V.warn=console.warn?console.warn.bind(console,Eo("WARN"),"color: orange"):console.log.bind(console,"\x1B[33m",Eo("WARN"))),e<=Zc.info&&(V.info=console.info?console.info.bind(console,Eo("INFO"),"color: lightblue"):console.log.bind(console,"\x1B[34m",Eo("INFO"))),e<=Zc.debug&&(V.debug=console.debug?console.debug.bind(console,Eo("DEBUG"),"color: lightgreen"):console.log.bind(console,"\x1B[32m",Eo("DEBUG"))),e<=Zc.trace&&(V.trace=console.debug?console.debug.bind(console,Eo("TRACE"),"color: lightgreen"):console.log.bind(console,"\x1B[32m",Eo("TRACE")))},"setLogLevel"),Eo=o(t=>`%c${(0,LF.default)().format("ss.SSS")} : ${t} : `,"format")});var Vve,np,LC,DF,Mb=R(()=>{"use strict";Vve=Object.freeze({left:0,top:0,width:16,height:16}),np=Object.freeze({rotate:0,vFlip:!1,hFlip:!1}),LC=Object.freeze({...Vve,...np}),DF=Object.freeze({...LC,body:"",hidden:!1})});var Uve,RF,NF=R(()=>{"use strict";Mb();Uve=Object.freeze({width:null,height:null}),RF=Object.freeze({...Uve,...np})});var Ib,DC,Ob,MF=R(()=>{"use strict";Ib=/^[a-z0-9]+(-[a-z0-9]+)*$/,DC=o((t,e,r,n="")=>{let i=t.split(":");if(t.slice(0,1)==="@"){if(i.length<2||i.length>3)return null;n=i.shift().slice(1)}if(i.length>3||!i.length)return null;if(i.length>1){let l=i.pop(),u=i.pop(),h={provider:i.length>0?i[0]:n,prefix:u,name:l};return e&&!Ob(h)?null:h}let a=i[0],s=a.split("-");if(s.length>1){let l={provider:n,prefix:s.shift(),name:s.join("-")};return e&&!Ob(l)?null:l}if(r&&n===""){let l={provider:n,prefix:"",name:a};return e&&!Ob(l,r)?null:l}return null},"stringToIcon"),Ob=o((t,e)=>t?!!((t.provider===""||t.provider.match(Ib))&&(e&&t.prefix===""||t.prefix.match(Ib))&&t.name.match(Ib)):!1,"validateIconName")});function IF(t,e){let r={};!t.hFlip!=!e.hFlip&&(r.hFlip=!0),!t.vFlip!=!e.vFlip&&(r.vFlip=!0);let n=((t.rotate||0)+(e.rotate||0))%4;return n&&(r.rotate=n),r}var OF=R(()=>{"use strict";o(IF,"mergeIconTransformations")});function RC(t,e){let r=IF(t,e);for(let n in DF)n in np?n in t&&!(n in r)&&(r[n]=np[n]):n in e?r[n]=e[n]:n in t&&(r[n]=t[n]);return r}var PF=R(()=>{"use strict";Mb();OF();o(RC,"mergeIconData")});function BF(t,e){let r=t.icons,n=t.aliases||Object.create(null),i=Object.create(null);function a(s){if(r[s])return i[s]=[];if(!(s in i)){i[s]=null;let l=n[s]&&n[s].parent,u=l&&a(l);u&&(i[s]=[l].concat(u))}return i[s]}return o(a,"resolve"),(e||Object.keys(r).concat(Object.keys(n))).forEach(a),i}var FF=R(()=>{"use strict";o(BF,"getIconsTree")});function zF(t,e,r){let n=t.icons,i=t.aliases||Object.create(null),a={};function s(l){a=RC(n[l]||i[l],a)}return o(s,"parse"),s(e),r.forEach(s),RC(t,a)}function NC(t,e){if(t.icons[e])return zF(t,e,[]);let r=BF(t,[e])[e];return r?zF(t,e,r):null}var GF=R(()=>{"use strict";PF();FF();o(zF,"internalGetIconData");o(NC,"getIconData")});function MC(t,e,r){if(e===1)return t;if(r=r||100,typeof t=="number")return Math.ceil(t*e*r)/r;if(typeof t!="string")return t;let n=t.split(Hve);if(n===null||!n.length)return t;let i=[],a=n.shift(),s=Yve.test(a);for(;;){if(s){let l=parseFloat(a);isNaN(l)?i.push(a):i.push(Math.ceil(l*e*r)/r)}else i.push(a);if(a=n.shift(),a===void 0)return i.join("");s=!s}}var Hve,Yve,$F=R(()=>{"use strict";Hve=/(-?[0-9.]*[0-9]+[0-9.]*)/g,Yve=/^-?[0-9.]*[0-9]+[0-9.]*$/g;o(MC,"calculateSize")});function Wve(t,e="defs"){let r="",n=t.indexOf("<"+e);for(;n>=0;){let i=t.indexOf(">",n),a=t.indexOf("",a);if(s===-1)break;r+=t.slice(i+1,a).trim(),t=t.slice(0,n).trim()+t.slice(s+1)}return{defs:r,content:t}}function qve(t,e){return t?""+t+""+e:e}function VF(t,e,r){let n=Wve(t);return qve(n.defs,e+n.content+r)}var UF=R(()=>{"use strict";o(Wve,"splitSVGDefs");o(qve,"mergeDefsAndContent");o(VF,"wrapSVGContent")});function IC(t,e){let r={...LC,...t},n={...RF,...e},i={left:r.left,top:r.top,width:r.width,height:r.height},a=r.body;[r,n].forEach(y=>{let v=[],x=y.hFlip,b=y.vFlip,w=y.rotate;x?b?w+=2:(v.push("translate("+(i.width+i.left).toString()+" "+(0-i.top).toString()+")"),v.push("scale(-1 1)"),i.top=i.left=0):b&&(v.push("translate("+(0-i.left).toString()+" "+(i.height+i.top).toString()+")"),v.push("scale(1 -1)"),i.top=i.left=0);let S;switch(w<0&&(w-=Math.floor(w/4)*4),w=w%4,w){case 1:S=i.height/2+i.top,v.unshift("rotate(90 "+S.toString()+" "+S.toString()+")");break;case 2:v.unshift("rotate(180 "+(i.width/2+i.left).toString()+" "+(i.height/2+i.top).toString()+")");break;case 3:S=i.width/2+i.left,v.unshift("rotate(-90 "+S.toString()+" "+S.toString()+")");break}w%2===1&&(i.left!==i.top&&(S=i.left,i.left=i.top,i.top=S),i.width!==i.height&&(S=i.width,i.width=i.height,i.height=S)),v.length&&(a=VF(a,'',""))});let s=n.width,l=n.height,u=i.width,h=i.height,f,d;s===null?(d=l===null?"1em":l==="auto"?h:l,f=MC(d,u/h)):(f=s==="auto"?u:s,d=l===null?MC(f,h/u):l==="auto"?h:l);let p={},m=o((y,v)=>{Xve(v)||(p[y]=v.toString())},"setAttr");m("width",f),m("height",d);let g=[i.left,i.top,u,h];return p.viewBox=g.join(" "),{attributes:p,viewBox:g,body:a}}var Xve,HF=R(()=>{"use strict";Mb();NF();$F();UF();Xve=o(t=>t==="unset"||t==="undefined"||t==="none","isUnsetKeyword");o(IC,"iconToSVG")});function OC(t,e=Kve){let r=[],n;for(;n=jve.exec(t);)r.push(n[1]);if(!r.length)return t;let i="suffix"+(Math.random()*16777216|Date.now()).toString(16);return r.forEach(a=>{let s=typeof e=="function"?e(a):e+(Qve++).toString(),l=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");t=t.replace(new RegExp('([#;"])('+l+')([")]|\\.[a-z])',"g"),"$1"+s+i+"$3")}),t=t.replace(new RegExp(i,"g"),""),t}var jve,Kve,Qve,YF=R(()=>{"use strict";jve=/\sid="(\S+)"/g,Kve="IconifyId"+Date.now().toString(16)+(Math.random()*16777216|0).toString(16),Qve=0;o(OC,"replaceIDs")});function PC(t,e){let r=t.indexOf("xlink:")===-1?"":' xmlns:xlink="http://www.w3.org/1999/xlink"';for(let n in e)r+=" "+n+'="'+e[n]+'"';return'"+t+""}var WF=R(()=>{"use strict";o(PC,"iconToHTML")});var XF=gi((ait,qF)=>{"use strict";var ip=1e3,ap=ip*60,sp=ap*60,$f=sp*24,Zve=$f*7,Jve=$f*365.25;qF.exports=function(t,e){e=e||{};var r=typeof t;if(r==="string"&&t.length>0)return e2e(t);if(r==="number"&&isFinite(t))return e.long?r2e(t):t2e(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))};function e2e(t){if(t=String(t),!(t.length>100)){var e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(t);if(e){var r=parseFloat(e[1]),n=(e[2]||"ms").toLowerCase();switch(n){case"years":case"year":case"yrs":case"yr":case"y":return r*Jve;case"weeks":case"week":case"w":return r*Zve;case"days":case"day":case"d":return r*$f;case"hours":case"hour":case"hrs":case"hr":case"h":return r*sp;case"minutes":case"minute":case"mins":case"min":case"m":return r*ap;case"seconds":case"second":case"secs":case"sec":case"s":return r*ip;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}o(e2e,"parse");function t2e(t){var e=Math.abs(t);return e>=$f?Math.round(t/$f)+"d":e>=sp?Math.round(t/sp)+"h":e>=ap?Math.round(t/ap)+"m":e>=ip?Math.round(t/ip)+"s":t+"ms"}o(t2e,"fmtShort");function r2e(t){var e=Math.abs(t);return e>=$f?Pb(t,e,$f,"day"):e>=sp?Pb(t,e,sp,"hour"):e>=ap?Pb(t,e,ap,"minute"):e>=ip?Pb(t,e,ip,"second"):t+" ms"}o(r2e,"fmtLong");function Pb(t,e,r,n){var i=e>=r*1.5;return Math.round(t/r)+" "+n+(i?"s":"")}o(Pb,"plural")});var KF=gi((oit,jF)=>{"use strict";function n2e(t){r.debug=r,r.default=r,r.coerce=u,r.disable=a,r.enable=i,r.enabled=s,r.humanize=XF(),r.destroy=h,Object.keys(t).forEach(f=>{r[f]=t[f]}),r.names=[],r.skips=[],r.formatters={};function e(f){let d=0;for(let p=0;p{if(E==="%%")return"%";S++;let A=r.formatters[_];if(typeof A=="function"){let L=v[S];E=A.call(x,L),v.splice(S,1),S--}return E}),r.formatArgs.call(x,v),(x.log||r.log).apply(x,v)}return o(y,"debug"),y.namespace=f,y.useColors=r.useColors(),y.color=r.selectColor(f),y.extend=n,y.destroy=r.destroy,Object.defineProperty(y,"enabled",{enumerable:!0,configurable:!1,get:o(()=>p!==null?p:(m!==r.namespaces&&(m=r.namespaces,g=r.enabled(f)),g),"get"),set:o(v=>{p=v},"set")}),typeof r.init=="function"&&r.init(y),y}o(r,"createDebug");function n(f,d){let p=r(this.namespace+(typeof d>"u"?":":d)+f);return p.log=this.log,p}o(n,"extend");function i(f){r.save(f),r.namespaces=f,r.names=[],r.skips=[];let d,p=(typeof f=="string"?f:"").split(/[\s,]+/),m=p.length;for(d=0;d"-"+d)].join(",");return r.enable(""),f}o(a,"disable");function s(f){if(f[f.length-1]==="*")return!0;let d,p;for(d=0,p=r.skips.length;d{"use strict";Ys.formatArgs=a2e;Ys.save=s2e;Ys.load=o2e;Ys.useColors=i2e;Ys.storage=l2e();Ys.destroy=(()=>{let t=!1;return()=>{t||(t=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();Ys.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function i2e(){if(typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs))return!0;if(typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let t;return typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&(t=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(t[1],10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}o(i2e,"useColors");function a2e(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+Bb.exports.humanize(this.diff),!this.useColors)return;let e="color: "+this.color;t.splice(1,0,e,"color: inherit");let r=0,n=0;t[0].replace(/%[a-zA-Z%]/g,i=>{i!=="%%"&&(r++,i==="%c"&&(n=r))}),t.splice(n,0,e)}o(a2e,"formatArgs");Ys.log=console.debug||console.log||(()=>{});function s2e(t){try{t?Ys.storage.setItem("debug",t):Ys.storage.removeItem("debug")}catch{}}o(s2e,"save");function o2e(){let t;try{t=Ys.storage.getItem("debug")}catch{}return!t&&typeof process<"u"&&"env"in process&&(t=process.env.DEBUG),t}o(o2e,"load");function l2e(){try{return localStorage}catch{}}o(l2e,"localstorage");Bb.exports=KF()(Ys);var{formatters:c2e}=Bb.exports;c2e.j=function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}});var uit,ZF=R(()=>{"use strict";MF();GF();HF();YF();WF();uit=Xi(QF(),1)});var FC,BC,JF,Fb,u2e,zb,V1=R(()=>{"use strict";ut();ZF();FC={body:'?',height:80,width:80},BC=new Map,JF=new Map,Fb=o(t=>{for(let e of t){if(!e.name)throw new Error('Invalid icon loader. Must have a "name" property with non-empty string value.');if(V.debug("Registering icon pack:",e.name),"loader"in e)JF.set(e.name,e.loader);else if("icons"in e)BC.set(e.name,e.icons);else throw V.error("Invalid icon loader:",e),new Error('Invalid icon loader. Must have either "icons" or "loader" property.')}},"registerIconPacks"),u2e=o(async(t,e)=>{let r=DC(t,!0,e!==void 0);if(!r)throw new Error(`Invalid icon name: ${t}`);let n=r.prefix||e;if(!n)throw new Error(`Icon name must contain a prefix: ${t}`);let i=BC.get(n);if(!i){let s=JF.get(n);if(!s)throw new Error(`Icon set not found: ${r.prefix}`);try{i={...await s(),prefix:n},BC.set(n,i)}catch(l){throw V.error(l),new Error(`Failed to load icon set: ${r.prefix}`)}}let a=NC(i,r.name);if(!a)throw new Error(`Icon not found: ${t}`);return a},"getRegisteredIconData"),zb=o(async(t,e)=>{let r;try{r=await u2e(t,e?.fallbackPrefix)}catch(a){V.error(a),r=FC}let n=IC(r,e);return PC(OC(n.body),n.attributes)},"getIconSVG")});function Gb(t){for(var e=[],r=1;r{"use strict";o(Gb,"dedent")});var $b,Vf,ez,Vb=R(()=>{"use strict";$b=/^-{3}\s*[\n\r](.*?)[\n\r]-{3}\s*[\n\r]+/s,Vf=/%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi,ez=/\s*%%.*\n/gm});var op,GC=R(()=>{"use strict";op=class extends Error{static{o(this,"UnknownDiagramError")}constructor(e){super(e),this.name="UnknownDiagramError"}}});var Uf,lp,Ub,$C,tz,Hf=R(()=>{"use strict";ut();Vb();GC();Uf={},lp=o(function(t,e){t=t.replace($b,"").replace(Vf,"").replace(ez,` +`);for(let[r,{detector:n}]of Object.entries(Uf))if(n(t,e))return r;throw new op(`No diagram type detected matching given configuration for text: ${t}`)},"detectType"),Ub=o((...t)=>{for(let{id:e,detector:r,loader:n}of t)$C(e,r,n)},"registerLazyLoadedDiagrams"),$C=o((t,e,r)=>{Uf[t]&&V.warn(`Detector with key ${t} already exists. Overwriting.`),Uf[t]={detector:e,loader:r},V.debug(`Detector with key ${t} added${r?" with loader":""}`)},"addDetector"),tz=o(t=>Uf[t].loader,"getDiagramLoader")});var U1,rz,VC=R(()=>{"use strict";U1=function(){var t=o(function(_e,me,W,fe){for(W=W||{},fe=_e.length;fe--;W[_e[fe]]=me);return W},"o"),e=[1,24],r=[1,25],n=[1,26],i=[1,27],a=[1,28],s=[1,63],l=[1,64],u=[1,65],h=[1,66],f=[1,67],d=[1,68],p=[1,69],m=[1,29],g=[1,30],y=[1,31],v=[1,32],x=[1,33],b=[1,34],w=[1,35],S=[1,36],T=[1,37],E=[1,38],_=[1,39],A=[1,40],L=[1,41],M=[1,42],N=[1,43],k=[1,44],I=[1,45],C=[1,46],O=[1,47],D=[1,48],P=[1,50],F=[1,51],B=[1,52],$=[1,53],z=[1,54],Y=[1,55],Q=[1,56],X=[1,57],ie=[1,58],j=[1,59],J=[1,60],Z=[14,42],H=[14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],q=[12,14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],K=[1,82],se=[1,83],ce=[1,84],ue=[1,85],te=[12,14,42],De=[12,14,33,42],oe=[12,14,33,42,76,77,79,80],ke=[12,33],Ie=[34,36,37,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],Se={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,direction_tb:6,direction_bt:7,direction_rl:8,direction_lr:9,graphConfig:10,C4_CONTEXT:11,NEWLINE:12,statements:13,EOF:14,C4_CONTAINER:15,C4_COMPONENT:16,C4_DYNAMIC:17,C4_DEPLOYMENT:18,otherStatements:19,diagramStatements:20,otherStatement:21,title:22,accDescription:23,acc_title:24,acc_title_value:25,acc_descr:26,acc_descr_value:27,acc_descr_multiline_value:28,boundaryStatement:29,boundaryStartStatement:30,boundaryStopStatement:31,boundaryStart:32,LBRACE:33,ENTERPRISE_BOUNDARY:34,attributes:35,SYSTEM_BOUNDARY:36,BOUNDARY:37,CONTAINER_BOUNDARY:38,NODE:39,NODE_L:40,NODE_R:41,RBRACE:42,diagramStatement:43,PERSON:44,PERSON_EXT:45,SYSTEM:46,SYSTEM_DB:47,SYSTEM_QUEUE:48,SYSTEM_EXT:49,SYSTEM_EXT_DB:50,SYSTEM_EXT_QUEUE:51,CONTAINER:52,CONTAINER_DB:53,CONTAINER_QUEUE:54,CONTAINER_EXT:55,CONTAINER_EXT_DB:56,CONTAINER_EXT_QUEUE:57,COMPONENT:58,COMPONENT_DB:59,COMPONENT_QUEUE:60,COMPONENT_EXT:61,COMPONENT_EXT_DB:62,COMPONENT_EXT_QUEUE:63,REL:64,BIREL:65,REL_U:66,REL_D:67,REL_L:68,REL_R:69,REL_B:70,REL_INDEX:71,UPDATE_EL_STYLE:72,UPDATE_REL_STYLE:73,UPDATE_LAYOUT_CONFIG:74,attribute:75,STR:76,STR_KEY:77,STR_VALUE:78,ATTRIBUTE:79,ATTRIBUTE_EMPTY:80,$accept:0,$end:1},terminals_:{2:"error",6:"direction_tb",7:"direction_bt",8:"direction_rl",9:"direction_lr",11:"C4_CONTEXT",12:"NEWLINE",14:"EOF",15:"C4_CONTAINER",16:"C4_COMPONENT",17:"C4_DYNAMIC",18:"C4_DEPLOYMENT",22:"title",23:"accDescription",24:"acc_title",25:"acc_title_value",26:"acc_descr",27:"acc_descr_value",28:"acc_descr_multiline_value",33:"LBRACE",34:"ENTERPRISE_BOUNDARY",36:"SYSTEM_BOUNDARY",37:"BOUNDARY",38:"CONTAINER_BOUNDARY",39:"NODE",40:"NODE_L",41:"NODE_R",42:"RBRACE",44:"PERSON",45:"PERSON_EXT",46:"SYSTEM",47:"SYSTEM_DB",48:"SYSTEM_QUEUE",49:"SYSTEM_EXT",50:"SYSTEM_EXT_DB",51:"SYSTEM_EXT_QUEUE",52:"CONTAINER",53:"CONTAINER_DB",54:"CONTAINER_QUEUE",55:"CONTAINER_EXT",56:"CONTAINER_EXT_DB",57:"CONTAINER_EXT_QUEUE",58:"COMPONENT",59:"COMPONENT_DB",60:"COMPONENT_QUEUE",61:"COMPONENT_EXT",62:"COMPONENT_EXT_DB",63:"COMPONENT_EXT_QUEUE",64:"REL",65:"BIREL",66:"REL_U",67:"REL_D",68:"REL_L",69:"REL_R",70:"REL_B",71:"REL_INDEX",72:"UPDATE_EL_STYLE",73:"UPDATE_REL_STYLE",74:"UPDATE_LAYOUT_CONFIG",76:"STR",77:"STR_KEY",78:"STR_VALUE",79:"ATTRIBUTE",80:"ATTRIBUTE_EMPTY"},productions_:[0,[3,1],[3,1],[5,1],[5,1],[5,1],[5,1],[4,1],[10,4],[10,4],[10,4],[10,4],[10,4],[13,1],[13,1],[13,2],[19,1],[19,2],[19,3],[21,1],[21,1],[21,2],[21,2],[21,1],[29,3],[30,3],[30,3],[30,4],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[31,1],[20,1],[20,2],[20,3],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,1],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[35,1],[35,2],[75,1],[75,2],[75,1],[75,1]],performAction:o(function(me,W,fe,ge,re,he,ne){var ae=he.length-1;switch(re){case 3:ge.setDirection("TB");break;case 4:ge.setDirection("BT");break;case 5:ge.setDirection("RL");break;case 6:ge.setDirection("LR");break;case 8:case 9:case 10:case 11:case 12:ge.setC4Type(he[ae-3]);break;case 19:ge.setTitle(he[ae].substring(6)),this.$=he[ae].substring(6);break;case 20:ge.setAccDescription(he[ae].substring(15)),this.$=he[ae].substring(15);break;case 21:this.$=he[ae].trim(),ge.setTitle(this.$);break;case 22:case 23:this.$=he[ae].trim(),ge.setAccDescription(this.$);break;case 28:he[ae].splice(2,0,"ENTERPRISE"),ge.addPersonOrSystemBoundary(...he[ae]),this.$=he[ae];break;case 29:he[ae].splice(2,0,"SYSTEM"),ge.addPersonOrSystemBoundary(...he[ae]),this.$=he[ae];break;case 30:ge.addPersonOrSystemBoundary(...he[ae]),this.$=he[ae];break;case 31:he[ae].splice(2,0,"CONTAINER"),ge.addContainerBoundary(...he[ae]),this.$=he[ae];break;case 32:ge.addDeploymentNode("node",...he[ae]),this.$=he[ae];break;case 33:ge.addDeploymentNode("nodeL",...he[ae]),this.$=he[ae];break;case 34:ge.addDeploymentNode("nodeR",...he[ae]),this.$=he[ae];break;case 35:ge.popBoundaryParseStack();break;case 39:ge.addPersonOrSystem("person",...he[ae]),this.$=he[ae];break;case 40:ge.addPersonOrSystem("external_person",...he[ae]),this.$=he[ae];break;case 41:ge.addPersonOrSystem("system",...he[ae]),this.$=he[ae];break;case 42:ge.addPersonOrSystem("system_db",...he[ae]),this.$=he[ae];break;case 43:ge.addPersonOrSystem("system_queue",...he[ae]),this.$=he[ae];break;case 44:ge.addPersonOrSystem("external_system",...he[ae]),this.$=he[ae];break;case 45:ge.addPersonOrSystem("external_system_db",...he[ae]),this.$=he[ae];break;case 46:ge.addPersonOrSystem("external_system_queue",...he[ae]),this.$=he[ae];break;case 47:ge.addContainer("container",...he[ae]),this.$=he[ae];break;case 48:ge.addContainer("container_db",...he[ae]),this.$=he[ae];break;case 49:ge.addContainer("container_queue",...he[ae]),this.$=he[ae];break;case 50:ge.addContainer("external_container",...he[ae]),this.$=he[ae];break;case 51:ge.addContainer("external_container_db",...he[ae]),this.$=he[ae];break;case 52:ge.addContainer("external_container_queue",...he[ae]),this.$=he[ae];break;case 53:ge.addComponent("component",...he[ae]),this.$=he[ae];break;case 54:ge.addComponent("component_db",...he[ae]),this.$=he[ae];break;case 55:ge.addComponent("component_queue",...he[ae]),this.$=he[ae];break;case 56:ge.addComponent("external_component",...he[ae]),this.$=he[ae];break;case 57:ge.addComponent("external_component_db",...he[ae]),this.$=he[ae];break;case 58:ge.addComponent("external_component_queue",...he[ae]),this.$=he[ae];break;case 60:ge.addRel("rel",...he[ae]),this.$=he[ae];break;case 61:ge.addRel("birel",...he[ae]),this.$=he[ae];break;case 62:ge.addRel("rel_u",...he[ae]),this.$=he[ae];break;case 63:ge.addRel("rel_d",...he[ae]),this.$=he[ae];break;case 64:ge.addRel("rel_l",...he[ae]),this.$=he[ae];break;case 65:ge.addRel("rel_r",...he[ae]),this.$=he[ae];break;case 66:ge.addRel("rel_b",...he[ae]),this.$=he[ae];break;case 67:he[ae].splice(0,1),ge.addRel("rel",...he[ae]),this.$=he[ae];break;case 68:ge.updateElStyle("update_el_style",...he[ae]),this.$=he[ae];break;case 69:ge.updateRelStyle("update_rel_style",...he[ae]),this.$=he[ae];break;case 70:ge.updateLayoutConfig("update_layout_config",...he[ae]),this.$=he[ae];break;case 71:this.$=[he[ae]];break;case 72:he[ae].unshift(he[ae-1]),this.$=he[ae];break;case 73:case 75:this.$=he[ae].trim();break;case 74:let we={};we[he[ae-1].trim()]=he[ae].trim(),this.$=we;break;case 76:this.$="";break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],7:[1,6],8:[1,7],9:[1,8],10:4,11:[1,9],15:[1,10],16:[1,11],17:[1,12],18:[1,13]},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,7]},{1:[2,3]},{1:[2,4]},{1:[2,5]},{1:[2,6]},{12:[1,14]},{12:[1,15]},{12:[1,16]},{12:[1,17]},{12:[1,18]},{13:19,19:20,20:21,21:22,22:e,23:r,24:n,26:i,28:a,29:49,30:61,32:62,34:s,36:l,37:u,38:h,39:f,40:d,41:p,43:23,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J},{13:70,19:20,20:21,21:22,22:e,23:r,24:n,26:i,28:a,29:49,30:61,32:62,34:s,36:l,37:u,38:h,39:f,40:d,41:p,43:23,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J},{13:71,19:20,20:21,21:22,22:e,23:r,24:n,26:i,28:a,29:49,30:61,32:62,34:s,36:l,37:u,38:h,39:f,40:d,41:p,43:23,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J},{13:72,19:20,20:21,21:22,22:e,23:r,24:n,26:i,28:a,29:49,30:61,32:62,34:s,36:l,37:u,38:h,39:f,40:d,41:p,43:23,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J},{13:73,19:20,20:21,21:22,22:e,23:r,24:n,26:i,28:a,29:49,30:61,32:62,34:s,36:l,37:u,38:h,39:f,40:d,41:p,43:23,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J},{14:[1,74]},t(Z,[2,13],{43:23,29:49,30:61,32:62,20:75,34:s,36:l,37:u,38:h,39:f,40:d,41:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J}),t(Z,[2,14]),t(H,[2,16],{12:[1,76]}),t(Z,[2,36],{12:[1,77]}),t(q,[2,19]),t(q,[2,20]),{25:[1,78]},{27:[1,79]},t(q,[2,23]),{35:80,75:81,76:K,77:se,79:ce,80:ue},{35:86,75:81,76:K,77:se,79:ce,80:ue},{35:87,75:81,76:K,77:se,79:ce,80:ue},{35:88,75:81,76:K,77:se,79:ce,80:ue},{35:89,75:81,76:K,77:se,79:ce,80:ue},{35:90,75:81,76:K,77:se,79:ce,80:ue},{35:91,75:81,76:K,77:se,79:ce,80:ue},{35:92,75:81,76:K,77:se,79:ce,80:ue},{35:93,75:81,76:K,77:se,79:ce,80:ue},{35:94,75:81,76:K,77:se,79:ce,80:ue},{35:95,75:81,76:K,77:se,79:ce,80:ue},{35:96,75:81,76:K,77:se,79:ce,80:ue},{35:97,75:81,76:K,77:se,79:ce,80:ue},{35:98,75:81,76:K,77:se,79:ce,80:ue},{35:99,75:81,76:K,77:se,79:ce,80:ue},{35:100,75:81,76:K,77:se,79:ce,80:ue},{35:101,75:81,76:K,77:se,79:ce,80:ue},{35:102,75:81,76:K,77:se,79:ce,80:ue},{35:103,75:81,76:K,77:se,79:ce,80:ue},{35:104,75:81,76:K,77:se,79:ce,80:ue},t(te,[2,59]),{35:105,75:81,76:K,77:se,79:ce,80:ue},{35:106,75:81,76:K,77:se,79:ce,80:ue},{35:107,75:81,76:K,77:se,79:ce,80:ue},{35:108,75:81,76:K,77:se,79:ce,80:ue},{35:109,75:81,76:K,77:se,79:ce,80:ue},{35:110,75:81,76:K,77:se,79:ce,80:ue},{35:111,75:81,76:K,77:se,79:ce,80:ue},{35:112,75:81,76:K,77:se,79:ce,80:ue},{35:113,75:81,76:K,77:se,79:ce,80:ue},{35:114,75:81,76:K,77:se,79:ce,80:ue},{35:115,75:81,76:K,77:se,79:ce,80:ue},{20:116,29:49,30:61,32:62,34:s,36:l,37:u,38:h,39:f,40:d,41:p,43:23,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J},{12:[1,118],33:[1,117]},{35:119,75:81,76:K,77:se,79:ce,80:ue},{35:120,75:81,76:K,77:se,79:ce,80:ue},{35:121,75:81,76:K,77:se,79:ce,80:ue},{35:122,75:81,76:K,77:se,79:ce,80:ue},{35:123,75:81,76:K,77:se,79:ce,80:ue},{35:124,75:81,76:K,77:se,79:ce,80:ue},{35:125,75:81,76:K,77:se,79:ce,80:ue},{14:[1,126]},{14:[1,127]},{14:[1,128]},{14:[1,129]},{1:[2,8]},t(Z,[2,15]),t(H,[2,17],{21:22,19:130,22:e,23:r,24:n,26:i,28:a}),t(Z,[2,37],{19:20,20:21,21:22,43:23,29:49,30:61,32:62,13:131,22:e,23:r,24:n,26:i,28:a,34:s,36:l,37:u,38:h,39:f,40:d,41:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w,51:S,52:T,53:E,54:_,55:A,56:L,57:M,58:N,59:k,60:I,61:C,62:O,63:D,64:P,65:F,66:B,67:$,68:z,69:Y,70:Q,71:X,72:ie,73:j,74:J}),t(q,[2,21]),t(q,[2,22]),t(te,[2,39]),t(De,[2,71],{75:81,35:132,76:K,77:se,79:ce,80:ue}),t(oe,[2,73]),{78:[1,133]},t(oe,[2,75]),t(oe,[2,76]),t(te,[2,40]),t(te,[2,41]),t(te,[2,42]),t(te,[2,43]),t(te,[2,44]),t(te,[2,45]),t(te,[2,46]),t(te,[2,47]),t(te,[2,48]),t(te,[2,49]),t(te,[2,50]),t(te,[2,51]),t(te,[2,52]),t(te,[2,53]),t(te,[2,54]),t(te,[2,55]),t(te,[2,56]),t(te,[2,57]),t(te,[2,58]),t(te,[2,60]),t(te,[2,61]),t(te,[2,62]),t(te,[2,63]),t(te,[2,64]),t(te,[2,65]),t(te,[2,66]),t(te,[2,67]),t(te,[2,68]),t(te,[2,69]),t(te,[2,70]),{31:134,42:[1,135]},{12:[1,136]},{33:[1,137]},t(ke,[2,28]),t(ke,[2,29]),t(ke,[2,30]),t(ke,[2,31]),t(ke,[2,32]),t(ke,[2,33]),t(ke,[2,34]),{1:[2,9]},{1:[2,10]},{1:[2,11]},{1:[2,12]},t(H,[2,18]),t(Z,[2,38]),t(De,[2,72]),t(oe,[2,74]),t(te,[2,24]),t(te,[2,35]),t(Ie,[2,25]),t(Ie,[2,26],{12:[1,138]}),t(Ie,[2,27])],defaultActions:{2:[2,1],3:[2,2],4:[2,7],5:[2,3],6:[2,4],7:[2,5],8:[2,6],74:[2,8],126:[2,9],127:[2,10],128:[2,11],129:[2,12]},parseError:o(function(me,W){if(W.recoverable)this.trace(me);else{var fe=new Error(me);throw fe.hash=W,fe}},"parseError"),parse:o(function(me){var W=this,fe=[0],ge=[],re=[null],he=[],ne=this.table,ae="",we=0,Te=0,Ce=0,Ae=2,Ge=1,Me=he.slice.call(arguments,1),ye=Object.create(this.lexer),He={yy:{}};for(var ze in this.yy)Object.prototype.hasOwnProperty.call(this.yy,ze)&&(He.yy[ze]=this.yy[ze]);ye.setInput(me,He.yy),He.yy.lexer=ye,He.yy.parser=this,typeof ye.yylloc>"u"&&(ye.yylloc={});var Ze=ye.yylloc;he.push(Ze);var gt=ye.options&&ye.options.ranges;typeof He.yy.parseError=="function"?this.parseError=He.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function yt(St){fe.length=fe.length-2*St,re.length=re.length-St,he.length=he.length-St}o(yt,"popStack");function tt(){var St;return St=ge.pop()||ye.lex()||Ge,typeof St!="number"&&(St instanceof Array&&(ge=St,St=ge.pop()),St=W.symbols_[St]||St),St}o(tt,"lex");for(var Ye,Je,Ve,je,kt,at,xt={},it,dt,lt,It;;){if(Ve=fe[fe.length-1],this.defaultActions[Ve]?je=this.defaultActions[Ve]:((Ye===null||typeof Ye>"u")&&(Ye=tt()),je=ne[Ve]&&ne[Ve][Ye]),typeof je>"u"||!je.length||!je[0]){var mt="";It=[];for(it in ne[Ve])this.terminals_[it]&&it>Ae&&It.push("'"+this.terminals_[it]+"'");ye.showPosition?mt="Parse error on line "+(we+1)+`: +`+ye.showPosition()+` +Expecting `+It.join(", ")+", got '"+(this.terminals_[Ye]||Ye)+"'":mt="Parse error on line "+(we+1)+": Unexpected "+(Ye==Ge?"end of input":"'"+(this.terminals_[Ye]||Ye)+"'"),this.parseError(mt,{text:ye.match,token:this.terminals_[Ye]||Ye,line:ye.yylineno,loc:Ze,expected:It})}if(je[0]instanceof Array&&je.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Ve+", token: "+Ye);switch(je[0]){case 1:fe.push(Ye),re.push(ye.yytext),he.push(ye.yylloc),fe.push(je[1]),Ye=null,Je?(Ye=Je,Je=null):(Te=ye.yyleng,ae=ye.yytext,we=ye.yylineno,Ze=ye.yylloc,Ce>0&&Ce--);break;case 2:if(dt=this.productions_[je[1]][1],xt.$=re[re.length-dt],xt._$={first_line:he[he.length-(dt||1)].first_line,last_line:he[he.length-1].last_line,first_column:he[he.length-(dt||1)].first_column,last_column:he[he.length-1].last_column},gt&&(xt._$.range=[he[he.length-(dt||1)].range[0],he[he.length-1].range[1]]),at=this.performAction.apply(xt,[ae,Te,we,He.yy,je[1],re,he].concat(Me)),typeof at<"u")return at;dt&&(fe=fe.slice(0,-1*dt*2),re=re.slice(0,-1*dt),he=he.slice(0,-1*dt)),fe.push(this.productions_[je[1]][0]),re.push(xt.$),he.push(xt._$),lt=ne[fe[fe.length-2]][fe[fe.length-1]],fe.push(lt);break;case 3:return!0}}return!0},"parse")},Ue=function(){var _e={EOF:1,parseError:o(function(W,fe){if(this.yy.parser)this.yy.parser.parseError(W,fe);else throw new Error(W)},"parseError"),setInput:o(function(me,W){return this.yy=W||this.yy||{},this._input=me,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var me=this._input[0];this.yytext+=me,this.yyleng++,this.offset++,this.match+=me,this.matched+=me;var W=me.match(/(?:\r\n?|\n).*/g);return W?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),me},"input"),unput:o(function(me){var W=me.length,fe=me.split(/(?:\r\n?|\n)/g);this._input=me+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-W),this.offset-=W;var ge=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),fe.length-1&&(this.yylineno-=fe.length-1);var re=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:fe?(fe.length===ge.length?this.yylloc.first_column:0)+ge[ge.length-fe.length].length-fe[0].length:this.yylloc.first_column-W},this.options.ranges&&(this.yylloc.range=[re[0],re[0]+this.yyleng-W]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(me){this.unput(this.match.slice(me))},"less"),pastInput:o(function(){var me=this.matched.substr(0,this.matched.length-this.match.length);return(me.length>20?"...":"")+me.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var me=this.match;return me.length<20&&(me+=this._input.substr(0,20-me.length)),(me.substr(0,20)+(me.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var me=this.pastInput(),W=new Array(me.length+1).join("-");return me+this.upcomingInput()+` +`+W+"^"},"showPosition"),test_match:o(function(me,W){var fe,ge,re;if(this.options.backtrack_lexer&&(re={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(re.yylloc.range=this.yylloc.range.slice(0))),ge=me[0].match(/(?:\r\n?|\n).*/g),ge&&(this.yylineno+=ge.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:ge?ge[ge.length-1].length-ge[ge.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+me[0].length},this.yytext+=me[0],this.match+=me[0],this.matches=me,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(me[0].length),this.matched+=me[0],fe=this.performAction.call(this,this.yy,this,W,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),fe)return fe;if(this._backtrack){for(var he in re)this[he]=re[he];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var me,W,fe,ge;this._more||(this.yytext="",this.match="");for(var re=this._currentRules(),he=0;heW[0].length)){if(W=fe,ge=he,this.options.backtrack_lexer){if(me=this.test_match(fe,re[he]),me!==!1)return me;if(this._backtrack){W=!1;continue}else return!1}else if(!this.options.flex)break}return W?(me=this.test_match(W,re[ge]),me!==!1?me:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var W=this.next();return W||this.lex()},"lex"),begin:o(function(W){this.conditionStack.push(W)},"begin"),popState:o(function(){var W=this.conditionStack.length-1;return W>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(W){return W=this.conditionStack.length-1-Math.abs(W||0),W>=0?this.conditionStack[W]:"INITIAL"},"topState"),pushState:o(function(W){this.begin(W)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:o(function(W,fe,ge,re){var he=re;switch(ge){case 0:return 6;case 1:return 7;case 2:return 8;case 3:return 9;case 4:return 22;case 5:return 23;case 6:return this.begin("acc_title"),24;break;case 7:return this.popState(),"acc_title_value";break;case 8:return this.begin("acc_descr"),26;break;case 9:return this.popState(),"acc_descr_value";break;case 10:this.begin("acc_descr_multiline");break;case 11:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:break;case 14:c;break;case 15:return 12;case 16:break;case 17:return 11;case 18:return 15;case 19:return 16;case 20:return 17;case 21:return 18;case 22:return this.begin("person_ext"),45;break;case 23:return this.begin("person"),44;break;case 24:return this.begin("system_ext_queue"),51;break;case 25:return this.begin("system_ext_db"),50;break;case 26:return this.begin("system_ext"),49;break;case 27:return this.begin("system_queue"),48;break;case 28:return this.begin("system_db"),47;break;case 29:return this.begin("system"),46;break;case 30:return this.begin("boundary"),37;break;case 31:return this.begin("enterprise_boundary"),34;break;case 32:return this.begin("system_boundary"),36;break;case 33:return this.begin("container_ext_queue"),57;break;case 34:return this.begin("container_ext_db"),56;break;case 35:return this.begin("container_ext"),55;break;case 36:return this.begin("container_queue"),54;break;case 37:return this.begin("container_db"),53;break;case 38:return this.begin("container"),52;break;case 39:return this.begin("container_boundary"),38;break;case 40:return this.begin("component_ext_queue"),63;break;case 41:return this.begin("component_ext_db"),62;break;case 42:return this.begin("component_ext"),61;break;case 43:return this.begin("component_queue"),60;break;case 44:return this.begin("component_db"),59;break;case 45:return this.begin("component"),58;break;case 46:return this.begin("node"),39;break;case 47:return this.begin("node"),39;break;case 48:return this.begin("node_l"),40;break;case 49:return this.begin("node_r"),41;break;case 50:return this.begin("rel"),64;break;case 51:return this.begin("birel"),65;break;case 52:return this.begin("rel_u"),66;break;case 53:return this.begin("rel_u"),66;break;case 54:return this.begin("rel_d"),67;break;case 55:return this.begin("rel_d"),67;break;case 56:return this.begin("rel_l"),68;break;case 57:return this.begin("rel_l"),68;break;case 58:return this.begin("rel_r"),69;break;case 59:return this.begin("rel_r"),69;break;case 60:return this.begin("rel_b"),70;break;case 61:return this.begin("rel_index"),71;break;case 62:return this.begin("update_el_style"),72;break;case 63:return this.begin("update_rel_style"),73;break;case 64:return this.begin("update_layout_config"),74;break;case 65:return"EOF_IN_STRUCT";case 66:return this.begin("attribute"),"ATTRIBUTE_EMPTY";break;case 67:this.begin("attribute");break;case 68:this.popState(),this.popState();break;case 69:return 80;case 70:break;case 71:return 80;case 72:this.begin("string");break;case 73:this.popState();break;case 74:return"STR";case 75:this.begin("string_kv");break;case 76:return this.begin("string_kv_key"),"STR_KEY";break;case 77:this.popState(),this.begin("string_kv_value");break;case 78:return"STR_VALUE";case 79:this.popState(),this.popState();break;case 80:return"STR";case 81:return"LBRACE";case 82:return"RBRACE";case 83:return"SPACE";case 84:return"EOL";case 85:return 14}},"anonymous"),rules:[/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:title\s[^#\n;]+)/,/^(?:accDescription\s[^#\n;]+)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:C4Context\b)/,/^(?:C4Container\b)/,/^(?:C4Component\b)/,/^(?:C4Dynamic\b)/,/^(?:C4Deployment\b)/,/^(?:Person_Ext\b)/,/^(?:Person\b)/,/^(?:SystemQueue_Ext\b)/,/^(?:SystemDb_Ext\b)/,/^(?:System_Ext\b)/,/^(?:SystemQueue\b)/,/^(?:SystemDb\b)/,/^(?:System\b)/,/^(?:Boundary\b)/,/^(?:Enterprise_Boundary\b)/,/^(?:System_Boundary\b)/,/^(?:ContainerQueue_Ext\b)/,/^(?:ContainerDb_Ext\b)/,/^(?:Container_Ext\b)/,/^(?:ContainerQueue\b)/,/^(?:ContainerDb\b)/,/^(?:Container\b)/,/^(?:Container_Boundary\b)/,/^(?:ComponentQueue_Ext\b)/,/^(?:ComponentDb_Ext\b)/,/^(?:Component_Ext\b)/,/^(?:ComponentQueue\b)/,/^(?:ComponentDb\b)/,/^(?:Component\b)/,/^(?:Deployment_Node\b)/,/^(?:Node\b)/,/^(?:Node_L\b)/,/^(?:Node_R\b)/,/^(?:Rel\b)/,/^(?:BiRel\b)/,/^(?:Rel_Up\b)/,/^(?:Rel_U\b)/,/^(?:Rel_Down\b)/,/^(?:Rel_D\b)/,/^(?:Rel_Left\b)/,/^(?:Rel_L\b)/,/^(?:Rel_Right\b)/,/^(?:Rel_R\b)/,/^(?:Rel_Back\b)/,/^(?:RelIndex\b)/,/^(?:UpdateElementStyle\b)/,/^(?:UpdateRelStyle\b)/,/^(?:UpdateLayoutConfig\b)/,/^(?:$)/,/^(?:[(][ ]*[,])/,/^(?:[(])/,/^(?:[)])/,/^(?:,,)/,/^(?:,)/,/^(?:[ ]*["]["])/,/^(?:[ ]*["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:[ ]*[\$])/,/^(?:[^=]*)/,/^(?:[=][ ]*["])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:[^,]+)/,/^(?:\{)/,/^(?:\})/,/^(?:[\s]+)/,/^(?:[\n\r]+)/,/^(?:$)/],conditions:{acc_descr_multiline:{rules:[11,12],inclusive:!1},acc_descr:{rules:[9],inclusive:!1},acc_title:{rules:[7],inclusive:!1},string_kv_value:{rules:[78,79],inclusive:!1},string_kv_key:{rules:[77],inclusive:!1},string_kv:{rules:[76],inclusive:!1},string:{rules:[73,74],inclusive:!1},attribute:{rules:[68,69,70,71,72,75,80],inclusive:!1},update_layout_config:{rules:[65,66,67,68],inclusive:!1},update_rel_style:{rules:[65,66,67,68],inclusive:!1},update_el_style:{rules:[65,66,67,68],inclusive:!1},rel_b:{rules:[65,66,67,68],inclusive:!1},rel_r:{rules:[65,66,67,68],inclusive:!1},rel_l:{rules:[65,66,67,68],inclusive:!1},rel_d:{rules:[65,66,67,68],inclusive:!1},rel_u:{rules:[65,66,67,68],inclusive:!1},rel_bi:{rules:[],inclusive:!1},rel:{rules:[65,66,67,68],inclusive:!1},node_r:{rules:[65,66,67,68],inclusive:!1},node_l:{rules:[65,66,67,68],inclusive:!1},node:{rules:[65,66,67,68],inclusive:!1},index:{rules:[],inclusive:!1},rel_index:{rules:[65,66,67,68],inclusive:!1},component_ext_queue:{rules:[],inclusive:!1},component_ext_db:{rules:[65,66,67,68],inclusive:!1},component_ext:{rules:[65,66,67,68],inclusive:!1},component_queue:{rules:[65,66,67,68],inclusive:!1},component_db:{rules:[65,66,67,68],inclusive:!1},component:{rules:[65,66,67,68],inclusive:!1},container_boundary:{rules:[65,66,67,68],inclusive:!1},container_ext_queue:{rules:[65,66,67,68],inclusive:!1},container_ext_db:{rules:[65,66,67,68],inclusive:!1},container_ext:{rules:[65,66,67,68],inclusive:!1},container_queue:{rules:[65,66,67,68],inclusive:!1},container_db:{rules:[65,66,67,68],inclusive:!1},container:{rules:[65,66,67,68],inclusive:!1},birel:{rules:[65,66,67,68],inclusive:!1},system_boundary:{rules:[65,66,67,68],inclusive:!1},enterprise_boundary:{rules:[65,66,67,68],inclusive:!1},boundary:{rules:[65,66,67,68],inclusive:!1},system_ext_queue:{rules:[65,66,67,68],inclusive:!1},system_ext_db:{rules:[65,66,67,68],inclusive:!1},system_ext:{rules:[65,66,67,68],inclusive:!1},system_queue:{rules:[65,66,67,68],inclusive:!1},system_db:{rules:[65,66,67,68],inclusive:!1},system:{rules:[65,66,67,68],inclusive:!1},person_ext:{rules:[65,66,67,68],inclusive:!1},person:{rules:[65,66,67,68],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,8,10,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,81,82,83,84,85],inclusive:!0}}};return _e}();Se.lexer=Ue;function Pe(){this.yy={}}return o(Pe,"Parser"),Pe.prototype=Se,Se.Parser=Pe,new Pe}();U1.parser=U1;rz=U1});var UC,On,cp=R(()=>{"use strict";UC=o((t,e,{depth:r=2,clobber:n=!1}={})=>{let i={depth:r,clobber:n};return Array.isArray(e)&&!Array.isArray(t)?(e.forEach(a=>UC(t,a,i)),t):Array.isArray(e)&&Array.isArray(t)?(e.forEach(a=>{t.includes(a)||t.push(a)}),t):t===void 0||r<=0?t!=null&&typeof t=="object"&&typeof e=="object"?Object.assign(t,e):e:(e!==void 0&&typeof t=="object"&&typeof e=="object"&&Object.keys(e).forEach(a=>{typeof e[a]=="object"&&(t[a]===void 0||typeof t[a]=="object")?(t[a]===void 0&&(t[a]=Array.isArray(e[a])?[]:{}),t[a]=UC(t[a],e[a],{depth:r-1,clobber:n})):(n||typeof t[a]!="object"&&typeof e[a]!="object")&&(t[a]=e[a])}),t)},"assignWithDepth"),On=UC});var Hb,nz,iz=R(()=>{"use strict";Hb={min:{r:0,g:0,b:0,s:0,l:0,a:0},max:{r:255,g:255,b:255,h:360,s:100,l:100,a:1},clamp:{r:o(t=>t>=255?255:t<0?0:t,"r"),g:o(t=>t>=255?255:t<0?0:t,"g"),b:o(t=>t>=255?255:t<0?0:t,"b"),h:o(t=>t%360,"h"),s:o(t=>t>=100?100:t<0?0:t,"s"),l:o(t=>t>=100?100:t<0?0:t,"l"),a:o(t=>t>=1?1:t<0?0:t,"a")},toLinear:o(t=>{let e=t/255;return t>.03928?Math.pow((e+.055)/1.055,2.4):e/12.92},"toLinear"),hue2rgb:o((t,e,r)=>(r<0&&(r+=1),r>1&&(r-=1),r<.16666666666666666?t+(e-t)*6*r:r<.5?e:r<.6666666666666666?t+(e-t)*(.6666666666666666-r)*6:t),"hue2rgb"),hsl2rgb:o(({h:t,s:e,l:r},n)=>{if(!e)return r*2.55;t/=360,e/=100,r/=100;let i=r<.5?r*(1+e):r+e-r*e,a=2*r-i;switch(n){case"r":return Hb.hue2rgb(a,i,t+.3333333333333333)*255;case"g":return Hb.hue2rgb(a,i,t)*255;case"b":return Hb.hue2rgb(a,i,t-.3333333333333333)*255}},"hsl2rgb"),rgb2hsl:o(({r:t,g:e,b:r},n)=>{t/=255,e/=255,r/=255;let i=Math.max(t,e,r),a=Math.min(t,e,r),s=(i+a)/2;if(n==="l")return s*100;if(i===a)return 0;let l=i-a,u=s>.5?l/(2-i-a):l/(i+a);if(n==="s")return u*100;switch(i){case t:return((e-r)/l+(e{"use strict";h2e={clamp:o((t,e,r)=>e>r?Math.min(e,Math.max(r,t)):Math.min(r,Math.max(e,t)),"clamp"),round:o(t=>Math.round(t*1e10)/1e10,"round")},az=h2e});var f2e,oz,lz=R(()=>{"use strict";f2e={dec2hex:o(t=>{let e=Math.round(t).toString(16);return e.length>1?e:`0${e}`},"dec2hex")},oz=f2e});var d2e,Bt,jl=R(()=>{"use strict";iz();sz();lz();d2e={channel:nz,lang:az,unit:oz},Bt=d2e});var Jc,Li,H1=R(()=>{"use strict";jl();Jc={};for(let t=0;t<=255;t++)Jc[t]=Bt.unit.dec2hex(t);Li={ALL:0,RGB:1,HSL:2}});var HC,cz,uz=R(()=>{"use strict";H1();HC=class{static{o(this,"Type")}constructor(){this.type=Li.ALL}get(){return this.type}set(e){if(this.type&&this.type!==e)throw new Error("Cannot change both RGB and HSL channels at the same time");this.type=e}reset(){this.type=Li.ALL}is(e){return this.type===e}},cz=HC});var YC,hz,fz=R(()=>{"use strict";jl();uz();H1();YC=class{static{o(this,"Channels")}constructor(e,r){this.color=r,this.changed=!1,this.data=e,this.type=new cz}set(e,r){return this.color=r,this.changed=!1,this.data=e,this.type.type=Li.ALL,this}_ensureHSL(){let e=this.data,{h:r,s:n,l:i}=e;r===void 0&&(e.h=Bt.channel.rgb2hsl(e,"h")),n===void 0&&(e.s=Bt.channel.rgb2hsl(e,"s")),i===void 0&&(e.l=Bt.channel.rgb2hsl(e,"l"))}_ensureRGB(){let e=this.data,{r,g:n,b:i}=e;r===void 0&&(e.r=Bt.channel.hsl2rgb(e,"r")),n===void 0&&(e.g=Bt.channel.hsl2rgb(e,"g")),i===void 0&&(e.b=Bt.channel.hsl2rgb(e,"b"))}get r(){let e=this.data,r=e.r;return!this.type.is(Li.HSL)&&r!==void 0?r:(this._ensureHSL(),Bt.channel.hsl2rgb(e,"r"))}get g(){let e=this.data,r=e.g;return!this.type.is(Li.HSL)&&r!==void 0?r:(this._ensureHSL(),Bt.channel.hsl2rgb(e,"g"))}get b(){let e=this.data,r=e.b;return!this.type.is(Li.HSL)&&r!==void 0?r:(this._ensureHSL(),Bt.channel.hsl2rgb(e,"b"))}get h(){let e=this.data,r=e.h;return!this.type.is(Li.RGB)&&r!==void 0?r:(this._ensureRGB(),Bt.channel.rgb2hsl(e,"h"))}get s(){let e=this.data,r=e.s;return!this.type.is(Li.RGB)&&r!==void 0?r:(this._ensureRGB(),Bt.channel.rgb2hsl(e,"s"))}get l(){let e=this.data,r=e.l;return!this.type.is(Li.RGB)&&r!==void 0?r:(this._ensureRGB(),Bt.channel.rgb2hsl(e,"l"))}get a(){return this.data.a}set r(e){this.type.set(Li.RGB),this.changed=!0,this.data.r=e}set g(e){this.type.set(Li.RGB),this.changed=!0,this.data.g=e}set b(e){this.type.set(Li.RGB),this.changed=!0,this.data.b=e}set h(e){this.type.set(Li.HSL),this.changed=!0,this.data.h=e}set s(e){this.type.set(Li.HSL),this.changed=!0,this.data.s=e}set l(e){this.type.set(Li.HSL),this.changed=!0,this.data.l=e}set a(e){this.changed=!0,this.data.a=e}},hz=YC});var p2e,oh,Y1=R(()=>{"use strict";fz();p2e=new hz({r:0,g:0,b:0,a:0},"transparent"),oh=p2e});var dz,Yf,WC=R(()=>{"use strict";Y1();H1();dz={re:/^#((?:[a-f0-9]{2}){2,4}|[a-f0-9]{3})$/i,parse:o(t=>{if(t.charCodeAt(0)!==35)return;let e=t.match(dz.re);if(!e)return;let r=e[1],n=parseInt(r,16),i=r.length,a=i%4===0,s=i>4,l=s?1:17,u=s?8:4,h=a?0:-1,f=s?255:15;return oh.set({r:(n>>u*(h+3)&f)*l,g:(n>>u*(h+2)&f)*l,b:(n>>u*(h+1)&f)*l,a:a?(n&f)*l/255:1},t)},"parse"),stringify:o(t=>{let{r:e,g:r,b:n,a:i}=t;return i<1?`#${Jc[Math.round(e)]}${Jc[Math.round(r)]}${Jc[Math.round(n)]}${Jc[Math.round(i*255)]}`:`#${Jc[Math.round(e)]}${Jc[Math.round(r)]}${Jc[Math.round(n)]}`},"stringify")},Yf=dz});var Yb,W1,pz=R(()=>{"use strict";jl();Y1();Yb={re:/^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,hueRe:/^(.+?)(deg|grad|rad|turn)$/i,_hue2deg:o(t=>{let e=t.match(Yb.hueRe);if(e){let[,r,n]=e;switch(n){case"grad":return Bt.channel.clamp.h(parseFloat(r)*.9);case"rad":return Bt.channel.clamp.h(parseFloat(r)*180/Math.PI);case"turn":return Bt.channel.clamp.h(parseFloat(r)*360)}}return Bt.channel.clamp.h(parseFloat(t))},"_hue2deg"),parse:o(t=>{let e=t.charCodeAt(0);if(e!==104&&e!==72)return;let r=t.match(Yb.re);if(!r)return;let[,n,i,a,s,l]=r;return oh.set({h:Yb._hue2deg(n),s:Bt.channel.clamp.s(parseFloat(i)),l:Bt.channel.clamp.l(parseFloat(a)),a:s?Bt.channel.clamp.a(l?parseFloat(s)/100:parseFloat(s)):1},t)},"parse"),stringify:o(t=>{let{h:e,s:r,l:n,a:i}=t;return i<1?`hsla(${Bt.lang.round(e)}, ${Bt.lang.round(r)}%, ${Bt.lang.round(n)}%, ${i})`:`hsl(${Bt.lang.round(e)}, ${Bt.lang.round(r)}%, ${Bt.lang.round(n)}%)`},"stringify")},W1=Yb});var Wb,qC,mz=R(()=>{"use strict";WC();Wb={colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyanaqua:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",transparent:"#00000000",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},parse:o(t=>{t=t.toLowerCase();let e=Wb.colors[t];if(e)return Yf.parse(e)},"parse"),stringify:o(t=>{let e=Yf.stringify(t);for(let r in Wb.colors)if(Wb.colors[r]===e)return r},"stringify")},qC=Wb});var gz,q1,yz=R(()=>{"use strict";jl();Y1();gz={re:/^rgba?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?)))?\s*?\)$/i,parse:o(t=>{let e=t.charCodeAt(0);if(e!==114&&e!==82)return;let r=t.match(gz.re);if(!r)return;let[,n,i,a,s,l,u,h,f]=r;return oh.set({r:Bt.channel.clamp.r(i?parseFloat(n)*2.55:parseFloat(n)),g:Bt.channel.clamp.g(s?parseFloat(a)*2.55:parseFloat(a)),b:Bt.channel.clamp.b(u?parseFloat(l)*2.55:parseFloat(l)),a:h?Bt.channel.clamp.a(f?parseFloat(h)/100:parseFloat(h)):1},t)},"parse"),stringify:o(t=>{let{r:e,g:r,b:n,a:i}=t;return i<1?`rgba(${Bt.lang.round(e)}, ${Bt.lang.round(r)}, ${Bt.lang.round(n)}, ${Bt.lang.round(i)})`:`rgb(${Bt.lang.round(e)}, ${Bt.lang.round(r)}, ${Bt.lang.round(n)})`},"stringify")},q1=gz});var m2e,Di,eu=R(()=>{"use strict";WC();pz();mz();yz();H1();m2e={format:{keyword:qC,hex:Yf,rgb:q1,rgba:q1,hsl:W1,hsla:W1},parse:o(t=>{if(typeof t!="string")return t;let e=Yf.parse(t)||q1.parse(t)||W1.parse(t)||qC.parse(t);if(e)return e;throw new Error(`Unsupported color format: "${t}"`)},"parse"),stringify:o(t=>!t.changed&&t.color?t.color:t.type.is(Li.HSL)||t.data.r===void 0?W1.stringify(t):t.a<1||!Number.isInteger(t.r)||!Number.isInteger(t.g)||!Number.isInteger(t.b)?q1.stringify(t):Yf.stringify(t),"stringify")},Di=m2e});var g2e,qb,XC=R(()=>{"use strict";jl();eu();g2e=o((t,e)=>{let r=Di.parse(t);for(let n in e)r[n]=Bt.channel.clamp[n](e[n]);return Di.stringify(r)},"change"),qb=g2e});var y2e,Ws,jC=R(()=>{"use strict";jl();Y1();eu();XC();y2e=o((t,e,r=0,n=1)=>{if(typeof t!="number")return qb(t,{a:e});let i=oh.set({r:Bt.channel.clamp.r(t),g:Bt.channel.clamp.g(e),b:Bt.channel.clamp.b(r),a:Bt.channel.clamp.a(n)});return Di.stringify(i)},"rgba"),Ws=y2e});var v2e,X1,vz=R(()=>{"use strict";jl();eu();v2e=o((t,e)=>Bt.lang.round(Di.parse(t)[e]),"channel"),X1=v2e});var x2e,xz,bz=R(()=>{"use strict";jl();eu();x2e=o(t=>{let{r:e,g:r,b:n}=Di.parse(t),i=.2126*Bt.channel.toLinear(e)+.7152*Bt.channel.toLinear(r)+.0722*Bt.channel.toLinear(n);return Bt.lang.round(i)},"luminance"),xz=x2e});var b2e,wz,Tz=R(()=>{"use strict";bz();b2e=o(t=>xz(t)>=.5,"isLight"),wz=b2e});var w2e,Wa,kz=R(()=>{"use strict";Tz();w2e=o(t=>!wz(t),"isDark"),Wa=w2e});var T2e,Xb,KC=R(()=>{"use strict";jl();eu();T2e=o((t,e,r)=>{let n=Di.parse(t),i=n[e],a=Bt.channel.clamp[e](i+r);return i!==a&&(n[e]=a),Di.stringify(n)},"adjustChannel"),Xb=T2e});var k2e,Et,Ez=R(()=>{"use strict";KC();k2e=o((t,e)=>Xb(t,"l",e),"lighten"),Et=k2e});var E2e,Dt,Cz=R(()=>{"use strict";KC();E2e=o((t,e)=>Xb(t,"l",-e),"darken"),Dt=E2e});var C2e,Oe,Sz=R(()=>{"use strict";eu();XC();C2e=o((t,e)=>{let r=Di.parse(t),n={};for(let i in e)e[i]&&(n[i]=r[i]+e[i]);return qb(t,n)},"adjust"),Oe=C2e});var S2e,Az,_z=R(()=>{"use strict";eu();jC();S2e=o((t,e,r=50)=>{let{r:n,g:i,b:a,a:s}=Di.parse(t),{r:l,g:u,b:h,a:f}=Di.parse(e),d=r/100,p=d*2-1,m=s-f,y=((p*m===-1?p:(p+m)/(1+p*m))+1)/2,v=1-y,x=n*y+l*v,b=i*y+u*v,w=a*y+h*v,S=s*d+f*(1-d);return Ws(x,b,w,S)},"mix"),Az=S2e});var A2e,ot,Lz=R(()=>{"use strict";eu();_z();A2e=o((t,e=100)=>{let r=Di.parse(t);return r.r=255-r.r,r.g=255-r.g,r.b=255-r.b,Az(r,t,e)},"invert"),ot=A2e});var Dz=R(()=>{"use strict";jC();vz();kz();Ez();Cz();Sz();Lz()});var al=R(()=>{"use strict";Dz()});var lh,ch,j1=R(()=>{"use strict";lh="#ffffff",ch="#f2f2f2"});var yi,up=R(()=>{"use strict";al();yi=o((t,e)=>e?Oe(t,{s:-40,l:10}):Oe(t,{s:-40,l:-10}),"mkBorder")});var QC,Nz,Mz=R(()=>{"use strict";al();j1();up();QC=class{static{o(this,"Theme")}constructor(){this.background="#f4f4f4",this.primaryColor="#fff4dd",this.noteBkgColor="#fff5ad",this.noteTextColor="#333",this.THEME_COLOR_LIMIT=12,this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px"}updateColors(){if(this.primaryTextColor=this.primaryTextColor||(this.darkMode?"#eee":"#333"),this.secondaryColor=this.secondaryColor||Oe(this.primaryColor,{h:-120}),this.tertiaryColor=this.tertiaryColor||Oe(this.primaryColor,{h:180,l:5}),this.primaryBorderColor=this.primaryBorderColor||yi(this.primaryColor,this.darkMode),this.secondaryBorderColor=this.secondaryBorderColor||yi(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=this.tertiaryBorderColor||yi(this.tertiaryColor,this.darkMode),this.noteBorderColor=this.noteBorderColor||yi(this.noteBkgColor,this.darkMode),this.noteBkgColor=this.noteBkgColor||"#fff5ad",this.noteTextColor=this.noteTextColor||"#333",this.secondaryTextColor=this.secondaryTextColor||ot(this.secondaryColor),this.tertiaryTextColor=this.tertiaryTextColor||ot(this.tertiaryColor),this.lineColor=this.lineColor||ot(this.background),this.arrowheadColor=this.arrowheadColor||ot(this.background),this.textColor=this.textColor||this.primaryTextColor,this.border2=this.border2||this.tertiaryBorderColor,this.nodeBkg=this.nodeBkg||this.primaryColor,this.mainBkg=this.mainBkg||this.primaryColor,this.nodeBorder=this.nodeBorder||this.primaryBorderColor,this.clusterBkg=this.clusterBkg||this.tertiaryColor,this.clusterBorder=this.clusterBorder||this.tertiaryBorderColor,this.defaultLinkColor=this.defaultLinkColor||this.lineColor,this.titleColor=this.titleColor||this.tertiaryTextColor,this.edgeLabelBackground=this.edgeLabelBackground||(this.darkMode?Dt(this.secondaryColor,30):this.secondaryColor),this.nodeTextColor=this.nodeTextColor||this.primaryTextColor,this.actorBorder=this.actorBorder||this.primaryBorderColor,this.actorBkg=this.actorBkg||this.mainBkg,this.actorTextColor=this.actorTextColor||this.primaryTextColor,this.actorLineColor=this.actorLineColor||this.actorBorder,this.labelBoxBkgColor=this.labelBoxBkgColor||this.actorBkg,this.signalColor=this.signalColor||this.textColor,this.signalTextColor=this.signalTextColor||this.textColor,this.labelBoxBorderColor=this.labelBoxBorderColor||this.actorBorder,this.labelTextColor=this.labelTextColor||this.actorTextColor,this.loopTextColor=this.loopTextColor||this.actorTextColor,this.activationBorderColor=this.activationBorderColor||Dt(this.secondaryColor,10),this.activationBkgColor=this.activationBkgColor||this.secondaryColor,this.sequenceNumberColor=this.sequenceNumberColor||ot(this.lineColor),this.sectionBkgColor=this.sectionBkgColor||this.tertiaryColor,this.altSectionBkgColor=this.altSectionBkgColor||"white",this.sectionBkgColor=this.sectionBkgColor||this.secondaryColor,this.sectionBkgColor2=this.sectionBkgColor2||this.primaryColor,this.excludeBkgColor=this.excludeBkgColor||"#eeeeee",this.taskBorderColor=this.taskBorderColor||this.primaryBorderColor,this.taskBkgColor=this.taskBkgColor||this.primaryColor,this.activeTaskBorderColor=this.activeTaskBorderColor||this.primaryColor,this.activeTaskBkgColor=this.activeTaskBkgColor||Et(this.primaryColor,23),this.gridColor=this.gridColor||"lightgrey",this.doneTaskBkgColor=this.doneTaskBkgColor||"lightgrey",this.doneTaskBorderColor=this.doneTaskBorderColor||"grey",this.critBorderColor=this.critBorderColor||"#ff8888",this.critBkgColor=this.critBkgColor||"red",this.todayLineColor=this.todayLineColor||"red",this.taskTextColor=this.taskTextColor||this.textColor,this.taskTextOutsideColor=this.taskTextOutsideColor||this.textColor,this.taskTextLightColor=this.taskTextLightColor||this.textColor,this.taskTextColor=this.taskTextColor||this.primaryTextColor,this.taskTextDarkColor=this.taskTextDarkColor||this.textColor,this.taskTextClickableColor=this.taskTextClickableColor||"#003163",this.personBorder=this.personBorder||this.primaryBorderColor,this.personBkg=this.personBkg||this.mainBkg,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||this.tertiaryColor,this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.nodeBorder,this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.transitionColor=this.transitionColor||this.lineColor,this.specialStateColor=this.lineColor,this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||Oe(this.primaryColor,{h:30}),this.cScale4=this.cScale4||Oe(this.primaryColor,{h:60}),this.cScale5=this.cScale5||Oe(this.primaryColor,{h:90}),this.cScale6=this.cScale6||Oe(this.primaryColor,{h:120}),this.cScale7=this.cScale7||Oe(this.primaryColor,{h:150}),this.cScale8=this.cScale8||Oe(this.primaryColor,{h:210,l:150}),this.cScale9=this.cScale9||Oe(this.primaryColor,{h:270}),this.cScale10=this.cScale10||Oe(this.primaryColor,{h:300}),this.cScale11=this.cScale11||Oe(this.primaryColor,{h:330}),this.darkMode)for(let r=0;r{this[n]=e[n]}),this.updateColors(),r.forEach(n=>{this[n]=e[n]})}},Nz=o(t=>{let e=new QC;return e.calculate(t),e},"getThemeVariables")});var ZC,Iz,Oz=R(()=>{"use strict";al();up();ZC=class{static{o(this,"Theme")}constructor(){this.background="#333",this.primaryColor="#1f2020",this.secondaryColor=Et(this.primaryColor,16),this.tertiaryColor=Oe(this.primaryColor,{h:-160}),this.primaryBorderColor=ot(this.background),this.secondaryBorderColor=yi(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=yi(this.tertiaryColor,this.darkMode),this.primaryTextColor=ot(this.primaryColor),this.secondaryTextColor=ot(this.secondaryColor),this.tertiaryTextColor=ot(this.tertiaryColor),this.lineColor=ot(this.background),this.textColor=ot(this.background),this.mainBkg="#1f2020",this.secondBkg="calculated",this.mainContrastColor="lightgrey",this.darkTextColor=Et(ot("#323D47"),10),this.lineColor="calculated",this.border1="#ccc",this.border2=Ws(255,255,255,.25),this.arrowheadColor="calculated",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.labelBackground="#181818",this.textColor="#ccc",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="#F9FFFE",this.edgeLabelBackground="calculated",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="calculated",this.actorLineColor="calculated",this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="calculated",this.activationBkgColor="calculated",this.sequenceNumberColor="black",this.sectionBkgColor=Dt("#EAE8D9",30),this.altSectionBkgColor="calculated",this.sectionBkgColor2="#EAE8D9",this.excludeBkgColor=Dt(this.sectionBkgColor,10),this.taskBorderColor=Ws(255,255,255,70),this.taskBkgColor="calculated",this.taskTextColor="calculated",this.taskTextLightColor="calculated",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor=Ws(255,255,255,50),this.activeTaskBkgColor="#81B1DB",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="grey",this.critBorderColor="#E83737",this.critBkgColor="#E83737",this.taskTextDarkColor="calculated",this.todayLineColor="#DB5757",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="calculated",this.errorBkgColor="#a44141",this.errorTextColor="#ddd"}updateColors(){this.secondBkg=Et(this.mainBkg,16),this.lineColor=this.mainContrastColor,this.arrowheadColor=this.mainContrastColor,this.nodeBkg=this.mainBkg,this.nodeBorder=this.border1,this.clusterBkg=this.secondBkg,this.clusterBorder=this.border2,this.defaultLinkColor=this.lineColor,this.edgeLabelBackground=Et(this.labelBackground,25),this.actorBorder=this.border1,this.actorBkg=this.mainBkg,this.actorTextColor=this.mainContrastColor,this.actorLineColor=this.actorBorder,this.signalColor=this.mainContrastColor,this.signalTextColor=this.mainContrastColor,this.labelBoxBkgColor=this.actorBkg,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.mainContrastColor,this.loopTextColor=this.mainContrastColor,this.noteBorderColor=this.secondaryBorderColor,this.noteBkgColor=this.secondBkg,this.noteTextColor=this.secondaryTextColor,this.activationBorderColor=this.border1,this.activationBkgColor=this.secondBkg,this.altSectionBkgColor=this.background,this.taskBkgColor=Et(this.mainBkg,23),this.taskTextColor=this.darkTextColor,this.taskTextLightColor=this.mainContrastColor,this.taskTextOutsideColor=this.taskTextLightColor,this.gridColor=this.mainContrastColor,this.doneTaskBkgColor=this.mainContrastColor,this.taskTextDarkColor=this.darkTextColor,this.archEdgeColor=this.lineColor,this.archEdgeArrowColor=this.lineColor,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||"#555",this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.primaryBorderColor,this.specialStateColor="#f4f4f4",this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.fillType0=this.primaryColor,this.fillType1=this.secondaryColor,this.fillType2=Oe(this.primaryColor,{h:64}),this.fillType3=Oe(this.secondaryColor,{h:64}),this.fillType4=Oe(this.primaryColor,{h:-64}),this.fillType5=Oe(this.secondaryColor,{h:-64}),this.fillType6=Oe(this.primaryColor,{h:128}),this.fillType7=Oe(this.secondaryColor,{h:128}),this.cScale1=this.cScale1||"#0b0000",this.cScale2=this.cScale2||"#4d1037",this.cScale3=this.cScale3||"#3f5258",this.cScale4=this.cScale4||"#4f2f1b",this.cScale5=this.cScale5||"#6e0a0a",this.cScale6=this.cScale6||"#3b0048",this.cScale7=this.cScale7||"#995a01",this.cScale8=this.cScale8||"#154706",this.cScale9=this.cScale9||"#161722",this.cScale10=this.cScale10||"#00296f",this.cScale11=this.cScale11||"#01629c",this.cScale12=this.cScale12||"#010029",this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||Oe(this.primaryColor,{h:30}),this.cScale4=this.cScale4||Oe(this.primaryColor,{h:60}),this.cScale5=this.cScale5||Oe(this.primaryColor,{h:90}),this.cScale6=this.cScale6||Oe(this.primaryColor,{h:120}),this.cScale7=this.cScale7||Oe(this.primaryColor,{h:150}),this.cScale8=this.cScale8||Oe(this.primaryColor,{h:210}),this.cScale9=this.cScale9||Oe(this.primaryColor,{h:270}),this.cScale10=this.cScale10||Oe(this.primaryColor,{h:300}),this.cScale11=this.cScale11||Oe(this.primaryColor,{h:330});for(let e=0;e{this[n]=e[n]}),this.updateColors(),r.forEach(n=>{this[n]=e[n]})}},Iz=o(t=>{let e=new ZC;return e.calculate(t),e},"getThemeVariables")});var JC,hp,jb=R(()=>{"use strict";al();up();j1();JC=class{static{o(this,"Theme")}constructor(){this.background="#f4f4f4",this.primaryColor="#ECECFF",this.secondaryColor=Oe(this.primaryColor,{h:120}),this.secondaryColor="#ffffde",this.tertiaryColor=Oe(this.primaryColor,{h:-160}),this.primaryBorderColor=yi(this.primaryColor,this.darkMode),this.secondaryBorderColor=yi(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=yi(this.tertiaryColor,this.darkMode),this.primaryTextColor=ot(this.primaryColor),this.secondaryTextColor=ot(this.secondaryColor),this.tertiaryTextColor=ot(this.tertiaryColor),this.lineColor=ot(this.background),this.textColor=ot(this.background),this.background="white",this.mainBkg="#ECECFF",this.secondBkg="#ffffde",this.lineColor="#333333",this.border1="#9370DB",this.border2="#aaaa33",this.arrowheadColor="#333333",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.labelBackground="rgba(232,232,232, 0.8)",this.textColor="#333",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="calculated",this.edgeLabelBackground="calculated",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="black",this.actorLineColor="calculated",this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="calculated",this.altSectionBkgColor="calculated",this.sectionBkgColor2="calculated",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="calculated",this.taskTextLightColor="calculated",this.taskTextColor=this.taskTextLightColor,this.taskTextDarkColor="calculated",this.taskTextOutsideColor=this.taskTextDarkColor,this.taskTextClickableColor="calculated",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="calculated",this.critBorderColor="calculated",this.critBkgColor="calculated",this.todayLineColor="calculated",this.sectionBkgColor=Ws(102,102,255,.49),this.altSectionBkgColor="white",this.sectionBkgColor2="#fff400",this.taskBorderColor="#534fbc",this.taskBkgColor="#8a90dd",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="black",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="#534fbc",this.activeTaskBkgColor="#bfc7ff",this.gridColor="lightgrey",this.doneTaskBkgColor="lightgrey",this.doneTaskBorderColor="grey",this.critBorderColor="#ff8888",this.critBkgColor="red",this.todayLineColor="red",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222",this.updateColors()}updateColors(){this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||Oe(this.primaryColor,{h:30}),this.cScale4=this.cScale4||Oe(this.primaryColor,{h:60}),this.cScale5=this.cScale5||Oe(this.primaryColor,{h:90}),this.cScale6=this.cScale6||Oe(this.primaryColor,{h:120}),this.cScale7=this.cScale7||Oe(this.primaryColor,{h:150}),this.cScale8=this.cScale8||Oe(this.primaryColor,{h:210}),this.cScale9=this.cScale9||Oe(this.primaryColor,{h:270}),this.cScale10=this.cScale10||Oe(this.primaryColor,{h:300}),this.cScale11=this.cScale11||Oe(this.primaryColor,{h:330}),this.cScalePeer1=this.cScalePeer1||Dt(this.secondaryColor,45),this.cScalePeer2=this.cScalePeer2||Dt(this.tertiaryColor,40);for(let e=0;e{this[n]=e[n]}),this.updateColors(),r.forEach(n=>{this[n]=e[n]})}},hp=o(t=>{let e=new JC;return e.calculate(t),e},"getThemeVariables")});var e7,Pz,Bz=R(()=>{"use strict";al();j1();up();e7=class{static{o(this,"Theme")}constructor(){this.background="#f4f4f4",this.primaryColor="#cde498",this.secondaryColor="#cdffb2",this.background="white",this.mainBkg="#cde498",this.secondBkg="#cdffb2",this.lineColor="green",this.border1="#13540c",this.border2="#6eaa49",this.arrowheadColor="green",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.tertiaryColor=Et("#cde498",10),this.primaryBorderColor=yi(this.primaryColor,this.darkMode),this.secondaryBorderColor=yi(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=yi(this.tertiaryColor,this.darkMode),this.primaryTextColor=ot(this.primaryColor),this.secondaryTextColor=ot(this.secondaryColor),this.tertiaryTextColor=ot(this.primaryColor),this.lineColor=ot(this.background),this.textColor=ot(this.background),this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="#333",this.edgeLabelBackground="#e8e8e8",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="black",this.actorLineColor="calculated",this.signalColor="#333",this.signalTextColor="#333",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="#326932",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="#6eaa49",this.altSectionBkgColor="white",this.sectionBkgColor2="#6eaa49",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="#487e3a",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="black",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="lightgrey",this.doneTaskBkgColor="lightgrey",this.doneTaskBorderColor="grey",this.critBorderColor="#ff8888",this.critBkgColor="red",this.todayLineColor="red",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222"}updateColors(){this.actorBorder=Dt(this.mainBkg,20),this.actorBkg=this.mainBkg,this.labelBoxBkgColor=this.actorBkg,this.labelTextColor=this.actorTextColor,this.loopTextColor=this.actorTextColor,this.noteBorderColor=this.border2,this.noteTextColor=this.actorTextColor,this.actorLineColor=this.actorBorder,this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||Oe(this.primaryColor,{h:30}),this.cScale4=this.cScale4||Oe(this.primaryColor,{h:60}),this.cScale5=this.cScale5||Oe(this.primaryColor,{h:90}),this.cScale6=this.cScale6||Oe(this.primaryColor,{h:120}),this.cScale7=this.cScale7||Oe(this.primaryColor,{h:150}),this.cScale8=this.cScale8||Oe(this.primaryColor,{h:210}),this.cScale9=this.cScale9||Oe(this.primaryColor,{h:270}),this.cScale10=this.cScale10||Oe(this.primaryColor,{h:300}),this.cScale11=this.cScale11||Oe(this.primaryColor,{h:330}),this.cScalePeer1=this.cScalePeer1||Dt(this.secondaryColor,45),this.cScalePeer2=this.cScalePeer2||Dt(this.tertiaryColor,40);for(let e=0;e{this[n]=e[n]}),this.updateColors(),r.forEach(n=>{this[n]=e[n]})}},Pz=o(t=>{let e=new e7;return e.calculate(t),e},"getThemeVariables")});var t7,Fz,zz=R(()=>{"use strict";al();up();j1();t7=class{static{o(this,"Theme")}constructor(){this.primaryColor="#eee",this.contrast="#707070",this.secondaryColor=Et(this.contrast,55),this.background="#ffffff",this.tertiaryColor=Oe(this.primaryColor,{h:-160}),this.primaryBorderColor=yi(this.primaryColor,this.darkMode),this.secondaryBorderColor=yi(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=yi(this.tertiaryColor,this.darkMode),this.primaryTextColor=ot(this.primaryColor),this.secondaryTextColor=ot(this.secondaryColor),this.tertiaryTextColor=ot(this.tertiaryColor),this.lineColor=ot(this.background),this.textColor=ot(this.background),this.mainBkg="#eee",this.secondBkg="calculated",this.lineColor="#666",this.border1="#999",this.border2="calculated",this.note="#ffa",this.text="#333",this.critical="#d42",this.done="#bbb",this.arrowheadColor="#333333",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="calculated",this.edgeLabelBackground="white",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="calculated",this.actorLineColor=this.actorBorder,this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="calculated",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="calculated",this.altSectionBkgColor="white",this.sectionBkgColor2="calculated",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="calculated",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="calculated",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="calculated",this.critBkgColor="calculated",this.critBorderColor="calculated",this.todayLineColor="calculated",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222"}updateColors(){this.secondBkg=Et(this.contrast,55),this.border2=this.contrast,this.actorBorder=Et(this.border1,23),this.actorBkg=this.mainBkg,this.actorTextColor=this.text,this.actorLineColor=this.actorBorder,this.signalColor=this.text,this.signalTextColor=this.text,this.labelBoxBkgColor=this.actorBkg,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.text,this.loopTextColor=this.text,this.noteBorderColor="#999",this.noteBkgColor="#666",this.noteTextColor="#fff",this.cScale0=this.cScale0||"#555",this.cScale1=this.cScale1||"#F4F4F4",this.cScale2=this.cScale2||"#555",this.cScale3=this.cScale3||"#BBB",this.cScale4=this.cScale4||"#777",this.cScale5=this.cScale5||"#999",this.cScale6=this.cScale6||"#DDD",this.cScale7=this.cScale7||"#FFF",this.cScale8=this.cScale8||"#DDD",this.cScale9=this.cScale9||"#BBB",this.cScale10=this.cScale10||"#999",this.cScale11=this.cScale11||"#777";for(let e=0;e{this[n]=e[n]}),this.updateColors(),r.forEach(n=>{this[n]=e[n]})}},Fz=o(t=>{let e=new t7;return e.calculate(t),e},"getThemeVariables")});var Co,Kb=R(()=>{"use strict";Mz();Oz();jb();Bz();zz();Co={base:{getThemeVariables:Nz},dark:{getThemeVariables:Iz},default:{getThemeVariables:hp},forest:{getThemeVariables:Pz},neutral:{getThemeVariables:Fz}}});var tu,Gz=R(()=>{"use strict";tu={flowchart:{useMaxWidth:!0,titleTopMargin:25,subGraphTitleMargin:{top:0,bottom:0},diagramPadding:8,htmlLabels:!0,nodeSpacing:50,rankSpacing:50,curve:"basis",padding:15,defaultRenderer:"dagre-wrapper",wrappingWidth:200},sequence:{useMaxWidth:!0,hideUnusedParticipants:!1,activationWidth:10,diagramMarginX:50,diagramMarginY:10,actorMargin:50,width:150,height:65,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",mirrorActors:!0,forceMenus:!1,bottomMarginAdj:1,rightAngles:!1,showSequenceNumbers:!1,actorFontSize:14,actorFontFamily:'"Open Sans", sans-serif',actorFontWeight:400,noteFontSize:14,noteFontFamily:'"trebuchet ms", verdana, arial, sans-serif',noteFontWeight:400,noteAlign:"center",messageFontSize:16,messageFontFamily:'"trebuchet ms", verdana, arial, sans-serif',messageFontWeight:400,wrap:!1,wrapPadding:10,labelBoxWidth:50,labelBoxHeight:20},gantt:{useMaxWidth:!0,titleTopMargin:25,barHeight:20,barGap:4,topPadding:50,rightPadding:75,leftPadding:75,gridLineStartPadding:35,fontSize:11,sectionFontSize:11,numberSectionStyles:4,axisFormat:"%Y-%m-%d",topAxis:!1,displayMode:"",weekday:"sunday"},journey:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,leftMargin:150,width:150,height:50,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,rightAngles:!1,taskFontSize:14,taskFontFamily:'"Open Sans", sans-serif',taskMargin:50,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"]},class:{useMaxWidth:!0,titleTopMargin:25,arrowMarkerAbsolute:!1,dividerMargin:10,padding:5,textHeight:10,defaultRenderer:"dagre-wrapper",htmlLabels:!1},state:{useMaxWidth:!0,titleTopMargin:25,dividerMargin:10,sizeUnit:5,padding:8,textHeight:10,titleShift:-15,noteMargin:10,forkWidth:70,forkHeight:7,miniPadding:2,fontSizeFactor:5.02,fontSize:24,labelHeight:16,edgeLengthFactor:"20",compositTitleSize:35,radius:5,defaultRenderer:"dagre-wrapper"},er:{useMaxWidth:!0,titleTopMargin:25,diagramPadding:20,layoutDirection:"TB",minEntityWidth:100,minEntityHeight:75,entityPadding:15,stroke:"gray",fill:"honeydew",fontSize:12},pie:{useMaxWidth:!0,textPosition:.75},quadrantChart:{useMaxWidth:!0,chartWidth:500,chartHeight:500,titleFontSize:20,titlePadding:10,quadrantPadding:5,xAxisLabelPadding:5,yAxisLabelPadding:5,xAxisLabelFontSize:16,yAxisLabelFontSize:16,quadrantLabelFontSize:16,quadrantTextTopPadding:5,pointTextPadding:5,pointLabelFontSize:12,pointRadius:5,xAxisPosition:"top",yAxisPosition:"left",quadrantInternalBorderStrokeWidth:1,quadrantExternalBorderStrokeWidth:2},xyChart:{useMaxWidth:!0,width:700,height:500,titleFontSize:20,titlePadding:10,showTitle:!0,xAxis:{$ref:"#/$defs/XYChartAxisConfig",showLabel:!0,labelFontSize:14,labelPadding:5,showTitle:!0,titleFontSize:16,titlePadding:5,showTick:!0,tickLength:5,tickWidth:2,showAxisLine:!0,axisLineWidth:2},yAxis:{$ref:"#/$defs/XYChartAxisConfig",showLabel:!0,labelFontSize:14,labelPadding:5,showTitle:!0,titleFontSize:16,titlePadding:5,showTick:!0,tickLength:5,tickWidth:2,showAxisLine:!0,axisLineWidth:2},chartOrientation:"vertical",plotReservedSpacePercent:50},requirement:{useMaxWidth:!0,rect_fill:"#f9f9f9",text_color:"#333",rect_border_size:"0.5px",rect_border_color:"#bbb",rect_min_width:200,rect_min_height:200,fontSize:14,rect_padding:10,line_height:20},mindmap:{useMaxWidth:!0,padding:10,maxNodeWidth:200},timeline:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,leftMargin:150,width:150,height:50,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,rightAngles:!1,taskFontSize:14,taskFontFamily:'"Open Sans", sans-serif',taskMargin:50,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"],disableMulticolor:!1},gitGraph:{useMaxWidth:!0,titleTopMargin:25,diagramPadding:8,nodeLabel:{width:75,height:100,x:-25,y:0},mainBranchName:"main",mainBranchOrder:0,showCommitLabel:!0,showBranches:!0,rotateCommitLabel:!0,parallelCommits:!1,arrowMarkerAbsolute:!1},c4:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,c4ShapeMargin:50,c4ShapePadding:20,width:216,height:60,boxMargin:10,c4ShapeInRow:4,nextLinePaddingX:0,c4BoundaryInRow:2,personFontSize:14,personFontFamily:'"Open Sans", sans-serif',personFontWeight:"normal",external_personFontSize:14,external_personFontFamily:'"Open Sans", sans-serif',external_personFontWeight:"normal",systemFontSize:14,systemFontFamily:'"Open Sans", sans-serif',systemFontWeight:"normal",external_systemFontSize:14,external_systemFontFamily:'"Open Sans", sans-serif',external_systemFontWeight:"normal",system_dbFontSize:14,system_dbFontFamily:'"Open Sans", sans-serif',system_dbFontWeight:"normal",external_system_dbFontSize:14,external_system_dbFontFamily:'"Open Sans", sans-serif',external_system_dbFontWeight:"normal",system_queueFontSize:14,system_queueFontFamily:'"Open Sans", sans-serif',system_queueFontWeight:"normal",external_system_queueFontSize:14,external_system_queueFontFamily:'"Open Sans", sans-serif',external_system_queueFontWeight:"normal",boundaryFontSize:14,boundaryFontFamily:'"Open Sans", sans-serif',boundaryFontWeight:"normal",messageFontSize:12,messageFontFamily:'"Open Sans", sans-serif',messageFontWeight:"normal",containerFontSize:14,containerFontFamily:'"Open Sans", sans-serif',containerFontWeight:"normal",external_containerFontSize:14,external_containerFontFamily:'"Open Sans", sans-serif',external_containerFontWeight:"normal",container_dbFontSize:14,container_dbFontFamily:'"Open Sans", sans-serif',container_dbFontWeight:"normal",external_container_dbFontSize:14,external_container_dbFontFamily:'"Open Sans", sans-serif',external_container_dbFontWeight:"normal",container_queueFontSize:14,container_queueFontFamily:'"Open Sans", sans-serif',container_queueFontWeight:"normal",external_container_queueFontSize:14,external_container_queueFontFamily:'"Open Sans", sans-serif',external_container_queueFontWeight:"normal",componentFontSize:14,componentFontFamily:'"Open Sans", sans-serif',componentFontWeight:"normal",external_componentFontSize:14,external_componentFontFamily:'"Open Sans", sans-serif',external_componentFontWeight:"normal",component_dbFontSize:14,component_dbFontFamily:'"Open Sans", sans-serif',component_dbFontWeight:"normal",external_component_dbFontSize:14,external_component_dbFontFamily:'"Open Sans", sans-serif',external_component_dbFontWeight:"normal",component_queueFontSize:14,component_queueFontFamily:'"Open Sans", sans-serif',component_queueFontWeight:"normal",external_component_queueFontSize:14,external_component_queueFontFamily:'"Open Sans", sans-serif',external_component_queueFontWeight:"normal",wrap:!0,wrapPadding:10,person_bg_color:"#08427B",person_border_color:"#073B6F",external_person_bg_color:"#686868",external_person_border_color:"#8A8A8A",system_bg_color:"#1168BD",system_border_color:"#3C7FC0",system_db_bg_color:"#1168BD",system_db_border_color:"#3C7FC0",system_queue_bg_color:"#1168BD",system_queue_border_color:"#3C7FC0",external_system_bg_color:"#999999",external_system_border_color:"#8A8A8A",external_system_db_bg_color:"#999999",external_system_db_border_color:"#8A8A8A",external_system_queue_bg_color:"#999999",external_system_queue_border_color:"#8A8A8A",container_bg_color:"#438DD5",container_border_color:"#3C7FC0",container_db_bg_color:"#438DD5",container_db_border_color:"#3C7FC0",container_queue_bg_color:"#438DD5",container_queue_border_color:"#3C7FC0",external_container_bg_color:"#B3B3B3",external_container_border_color:"#A6A6A6",external_container_db_bg_color:"#B3B3B3",external_container_db_border_color:"#A6A6A6",external_container_queue_bg_color:"#B3B3B3",external_container_queue_border_color:"#A6A6A6",component_bg_color:"#85BBF0",component_border_color:"#78A8D8",component_db_bg_color:"#85BBF0",component_db_border_color:"#78A8D8",component_queue_bg_color:"#85BBF0",component_queue_border_color:"#78A8D8",external_component_bg_color:"#CCCCCC",external_component_border_color:"#BFBFBF",external_component_db_bg_color:"#CCCCCC",external_component_db_border_color:"#BFBFBF",external_component_queue_bg_color:"#CCCCCC",external_component_queue_border_color:"#BFBFBF"},sankey:{useMaxWidth:!0,width:600,height:400,linkColor:"gradient",nodeAlignment:"justify",showValues:!0,prefix:"",suffix:""},block:{useMaxWidth:!0,padding:8},packet:{useMaxWidth:!0,rowHeight:32,bitWidth:32,bitsPerRow:32,showBits:!0,paddingX:5,paddingY:5},architecture:{useMaxWidth:!0,padding:40,iconSize:80,fontSize:16},theme:"default",look:"classic",handDrawnSeed:0,layout:"dagre",maxTextSize:5e4,maxEdges:500,darkMode:!1,fontFamily:'"trebuchet ms", verdana, arial, sans-serif;',logLevel:5,securityLevel:"strict",startOnLoad:!0,arrowMarkerAbsolute:!1,secure:["secure","securityLevel","startOnLoad","maxTextSize","suppressErrorRendering","maxEdges"],legacyMathML:!1,forceLegacyMathML:!1,deterministicIds:!1,fontSize:16,markdownAutoWrap:!0,suppressErrorRendering:!1}});var $z,Vz,Uz,mr,sl=R(()=>{"use strict";Kb();Gz();$z={...tu,deterministicIDSeed:void 0,elk:{mergeEdges:!1,nodePlacementStrategy:"SIMPLE"},themeCSS:void 0,themeVariables:Co.default.getThemeVariables(),sequence:{...tu.sequence,messageFont:o(function(){return{fontFamily:this.messageFontFamily,fontSize:this.messageFontSize,fontWeight:this.messageFontWeight}},"messageFont"),noteFont:o(function(){return{fontFamily:this.noteFontFamily,fontSize:this.noteFontSize,fontWeight:this.noteFontWeight}},"noteFont"),actorFont:o(function(){return{fontFamily:this.actorFontFamily,fontSize:this.actorFontSize,fontWeight:this.actorFontWeight}},"actorFont")},gantt:{...tu.gantt,tickInterval:void 0,useWidth:void 0},c4:{...tu.c4,useWidth:void 0,personFont:o(function(){return{fontFamily:this.personFontFamily,fontSize:this.personFontSize,fontWeight:this.personFontWeight}},"personFont"),external_personFont:o(function(){return{fontFamily:this.external_personFontFamily,fontSize:this.external_personFontSize,fontWeight:this.external_personFontWeight}},"external_personFont"),systemFont:o(function(){return{fontFamily:this.systemFontFamily,fontSize:this.systemFontSize,fontWeight:this.systemFontWeight}},"systemFont"),external_systemFont:o(function(){return{fontFamily:this.external_systemFontFamily,fontSize:this.external_systemFontSize,fontWeight:this.external_systemFontWeight}},"external_systemFont"),system_dbFont:o(function(){return{fontFamily:this.system_dbFontFamily,fontSize:this.system_dbFontSize,fontWeight:this.system_dbFontWeight}},"system_dbFont"),external_system_dbFont:o(function(){return{fontFamily:this.external_system_dbFontFamily,fontSize:this.external_system_dbFontSize,fontWeight:this.external_system_dbFontWeight}},"external_system_dbFont"),system_queueFont:o(function(){return{fontFamily:this.system_queueFontFamily,fontSize:this.system_queueFontSize,fontWeight:this.system_queueFontWeight}},"system_queueFont"),external_system_queueFont:o(function(){return{fontFamily:this.external_system_queueFontFamily,fontSize:this.external_system_queueFontSize,fontWeight:this.external_system_queueFontWeight}},"external_system_queueFont"),containerFont:o(function(){return{fontFamily:this.containerFontFamily,fontSize:this.containerFontSize,fontWeight:this.containerFontWeight}},"containerFont"),external_containerFont:o(function(){return{fontFamily:this.external_containerFontFamily,fontSize:this.external_containerFontSize,fontWeight:this.external_containerFontWeight}},"external_containerFont"),container_dbFont:o(function(){return{fontFamily:this.container_dbFontFamily,fontSize:this.container_dbFontSize,fontWeight:this.container_dbFontWeight}},"container_dbFont"),external_container_dbFont:o(function(){return{fontFamily:this.external_container_dbFontFamily,fontSize:this.external_container_dbFontSize,fontWeight:this.external_container_dbFontWeight}},"external_container_dbFont"),container_queueFont:o(function(){return{fontFamily:this.container_queueFontFamily,fontSize:this.container_queueFontSize,fontWeight:this.container_queueFontWeight}},"container_queueFont"),external_container_queueFont:o(function(){return{fontFamily:this.external_container_queueFontFamily,fontSize:this.external_container_queueFontSize,fontWeight:this.external_container_queueFontWeight}},"external_container_queueFont"),componentFont:o(function(){return{fontFamily:this.componentFontFamily,fontSize:this.componentFontSize,fontWeight:this.componentFontWeight}},"componentFont"),external_componentFont:o(function(){return{fontFamily:this.external_componentFontFamily,fontSize:this.external_componentFontSize,fontWeight:this.external_componentFontWeight}},"external_componentFont"),component_dbFont:o(function(){return{fontFamily:this.component_dbFontFamily,fontSize:this.component_dbFontSize,fontWeight:this.component_dbFontWeight}},"component_dbFont"),external_component_dbFont:o(function(){return{fontFamily:this.external_component_dbFontFamily,fontSize:this.external_component_dbFontSize,fontWeight:this.external_component_dbFontWeight}},"external_component_dbFont"),component_queueFont:o(function(){return{fontFamily:this.component_queueFontFamily,fontSize:this.component_queueFontSize,fontWeight:this.component_queueFontWeight}},"component_queueFont"),external_component_queueFont:o(function(){return{fontFamily:this.external_component_queueFontFamily,fontSize:this.external_component_queueFontSize,fontWeight:this.external_component_queueFontWeight}},"external_component_queueFont"),boundaryFont:o(function(){return{fontFamily:this.boundaryFontFamily,fontSize:this.boundaryFontSize,fontWeight:this.boundaryFontWeight}},"boundaryFont"),messageFont:o(function(){return{fontFamily:this.messageFontFamily,fontSize:this.messageFontSize,fontWeight:this.messageFontWeight}},"messageFont")},pie:{...tu.pie,useWidth:984},xyChart:{...tu.xyChart,useWidth:void 0},requirement:{...tu.requirement,useWidth:void 0},packet:{...tu.packet}},Vz=o((t,e="")=>Object.keys(t).reduce((r,n)=>Array.isArray(t[n])?r:typeof t[n]=="object"&&t[n]!==null?[...r,e+n,...Vz(t[n],"")]:[...r,e+n],[]),"keyify"),Uz=new Set(Vz($z,"")),mr=$z});var fp,_2e,r7=R(()=>{"use strict";sl();ut();fp=o(t=>{if(V.debug("sanitizeDirective called with",t),!(typeof t!="object"||t==null)){if(Array.isArray(t)){t.forEach(e=>fp(e));return}for(let e of Object.keys(t)){if(V.debug("Checking key",e),e.startsWith("__")||e.includes("proto")||e.includes("constr")||!Uz.has(e)||t[e]==null){V.debug("sanitize deleting key: ",e),delete t[e];continue}if(typeof t[e]=="object"){V.debug("sanitizing object",e),fp(t[e]);continue}let r=["themeCSS","fontFamily","altFontFamily"];for(let n of r)e.includes(n)&&(V.debug("sanitizing css option",e),t[e]=_2e(t[e]))}if(t.themeVariables)for(let e of Object.keys(t.themeVariables)){let r=t.themeVariables[e];r?.match&&!r.match(/^[\d "#%(),.;A-Za-z]+$/)&&(t.themeVariables[e]="")}V.debug("After sanitization",t)}},"sanitizeDirective"),_2e=o(t=>{let e=0,r=0;for(let n of t){if(e{"use strict";cp();ut();Kb();sl();r7();uh=Object.freeze(mr),fs=On({},uh),dp=[],K1=On({},uh),Qb=o((t,e)=>{let r=On({},t),n={};for(let i of e)Xz(i),n=On(n,i);if(r=On(r,n),n.theme&&n.theme in Co){let i=On({},Yz),a=On(i.themeVariables||{},n.themeVariables);r.theme&&r.theme in Co&&(r.themeVariables=Co[r.theme].getThemeVariables(a))}return K1=r,Kz(K1),K1},"updateCurrentConfig"),n7=o(t=>(fs=On({},uh),fs=On(fs,t),t.theme&&Co[t.theme]&&(fs.themeVariables=Co[t.theme].getThemeVariables(t.themeVariables)),Qb(fs,dp),fs),"setSiteConfig"),Wz=o(t=>{Yz=On({},t)},"saveConfigFromInitialize"),qz=o(t=>(fs=On(fs,t),Qb(fs,dp),fs),"updateSiteConfig"),i7=o(()=>On({},fs),"getSiteConfig"),Zb=o(t=>(Kz(t),On(K1,t),Or()),"setConfig"),Or=o(()=>On({},K1),"getConfig"),Xz=o(t=>{t&&(["secure",...fs.secure??[]].forEach(e=>{Object.hasOwn(t,e)&&(V.debug(`Denied attempt to modify a secure key ${e}`,t[e]),delete t[e])}),Object.keys(t).forEach(e=>{e.startsWith("__")&&delete t[e]}),Object.keys(t).forEach(e=>{typeof t[e]=="string"&&(t[e].includes("<")||t[e].includes(">")||t[e].includes("url(data:"))&&delete t[e],typeof t[e]=="object"&&Xz(t[e])}))},"sanitize"),jz=o(t=>{fp(t),t.fontFamily&&!t.themeVariables?.fontFamily&&(t.themeVariables={...t.themeVariables,fontFamily:t.fontFamily}),dp.push(t),Qb(fs,dp)},"addDirective"),Q1=o((t=fs)=>{dp=[],Qb(t,dp)},"reset"),L2e={LAZY_LOAD_DEPRECATED:"The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead."},Hz={},D2e=o(t=>{Hz[t]||(V.warn(L2e[t]),Hz[t]=!0)},"issueWarning"),Kz=o(t=>{t&&(t.lazyLoadedDiagrams||t.loadExternalDiagramsAtStartup)&&D2e("LAZY_LOAD_DEPRECATED")},"checkConfig")});var o7=gi((a7,s7)=>{"use strict";(function(t,e){typeof a7=="object"&&typeof s7<"u"?s7.exports=e():typeof define=="function"&&define.amd?define(e):(t=typeof globalThis<"u"?globalThis:t||self,t.DOMPurify=e())})(a7,function(){"use strict";let{entries:t,setPrototypeOf:e,isFrozen:r,getPrototypeOf:n,getOwnPropertyDescriptor:i}=Object,{freeze:a,seal:s,create:l}=Object,{apply:u,construct:h}=typeof Reflect<"u"&&Reflect;a||(a=o(function(Se){return Se},"freeze")),s||(s=o(function(Se){return Se},"seal")),u||(u=o(function(Se,Ue,Pe){return Se.apply(Ue,Pe)},"apply")),h||(h=o(function(Se,Ue){return new Se(...Ue)},"construct"));let f=E(Array.prototype.forEach),d=E(Array.prototype.pop),p=E(Array.prototype.push),m=E(String.prototype.toLowerCase),g=E(String.prototype.toString),y=E(String.prototype.match),v=E(String.prototype.replace),x=E(String.prototype.indexOf),b=E(String.prototype.trim),w=E(Object.prototype.hasOwnProperty),S=E(RegExp.prototype.test),T=_(TypeError);function E(Ie){return function(Se){for(var Ue=arguments.length,Pe=new Array(Ue>1?Ue-1:0),_e=1;_e2&&arguments[2]!==void 0?arguments[2]:m;e&&e(Ie,null);let Pe=Se.length;for(;Pe--;){let _e=Se[Pe];if(typeof _e=="string"){let me=Ue(_e);me!==_e&&(r(Se)||(Se[Pe]=me),_e=me)}Ie[_e]=!0}return Ie}o(A,"addToSet");function L(Ie){for(let Se=0;Se/gm),ie=s(/\${[\w\W]*}/gm),j=s(/^data-[\-\w.\u00B7-\uFFFF]/),J=s(/^aria-[\-\w]+$/),Z=s(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),H=s(/^(?:\w+script|data):/i),q=s(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),K=s(/^html$/i),se=s(/^[a-z][.\w]*(-[.\w]+)+$/i);var ce=Object.freeze({__proto__:null,MUSTACHE_EXPR:Q,ERB_EXPR:X,TMPLIT_EXPR:ie,DATA_ATTR:j,ARIA_ATTR:J,IS_ALLOWED_URI:Z,IS_SCRIPT_OR_DATA:H,ATTR_WHITESPACE:q,DOCTYPE_NAME:K,CUSTOM_ELEMENT:se});let ue={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},te=o(function(){return typeof window>"u"?null:window},"getGlobal"),De=o(function(Se,Ue){if(typeof Se!="object"||typeof Se.createPolicy!="function")return null;let Pe=null,_e="data-tt-policy-suffix";Ue&&Ue.hasAttribute(_e)&&(Pe=Ue.getAttribute(_e));let me="dompurify"+(Pe?"#"+Pe:"");try{return Se.createPolicy(me,{createHTML(W){return W},createScriptURL(W){return W}})}catch{return console.warn("TrustedTypes policy "+me+" could not be created."),null}},"_createTrustedTypesPolicy");function oe(){let Ie=arguments.length>0&&arguments[0]!==void 0?arguments[0]:te(),Se=o(Ft=>oe(Ft),"DOMPurify");if(Se.version="3.1.6",Se.removed=[],!Ie||!Ie.document||Ie.document.nodeType!==ue.document)return Se.isSupported=!1,Se;let{document:Ue}=Ie,Pe=Ue,_e=Pe.currentScript,{DocumentFragment:me,HTMLTemplateElement:W,Node:fe,Element:ge,NodeFilter:re,NamedNodeMap:he=Ie.NamedNodeMap||Ie.MozNamedAttrMap,HTMLFormElement:ne,DOMParser:ae,trustedTypes:we}=Ie,Te=ge.prototype,Ce=N(Te,"cloneNode"),Ae=N(Te,"remove"),Ge=N(Te,"nextSibling"),Me=N(Te,"childNodes"),ye=N(Te,"parentNode");if(typeof W=="function"){let Ft=Ue.createElement("template");Ft.content&&Ft.content.ownerDocument&&(Ue=Ft.content.ownerDocument)}let He,ze="",{implementation:Ze,createNodeIterator:gt,createDocumentFragment:yt,getElementsByTagName:tt}=Ue,{importNode:Ye}=Pe,Je={};Se.isSupported=typeof t=="function"&&typeof ye=="function"&&Ze&&Ze.createHTMLDocument!==void 0;let{MUSTACHE_EXPR:Ve,ERB_EXPR:je,TMPLIT_EXPR:kt,DATA_ATTR:at,ARIA_ATTR:xt,IS_SCRIPT_OR_DATA:it,ATTR_WHITESPACE:dt,CUSTOM_ELEMENT:lt}=ce,{IS_ALLOWED_URI:It}=ce,mt=null,St=A({},[...k,...I,...C,...D,...F]),gr=null,xn=A({},[...B,...$,...z,...Y]),jt=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),rn=null,Er=null,Kn=!0,hn=!0,Qn=!1,on=!0,Rn=!1,Ha=!0,_a=!1,To=!1,qi=!1,ht=!1,At=!1,$t=!1,rt=!0,Ot=!1,pe="user-content-",ur=!0,be=!1,Ir={},Xc=null,M1=A({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),_b=null,I1=A({},["audio","video","img","source","image","track"]),O1=null,ci=A({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ko="http://www.w3.org/1998/Math/MathML",ih="http://www.w3.org/2000/svg",Us="http://www.w3.org/1999/xhtml",ah=Us,Lb=!1,P1=null,sa=A({},[ko,ih,Us],g),jc=null,Kc=["application/xhtml+xml","text/html"],us="text/html",_i=null,Wl=null,sh=Ue.createElement("form"),zf=o(function(Re){return Re instanceof RegExp||Re instanceof Function},"isRegexOrFunction"),Hs=o(function(){let Re=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!(Wl&&Wl===Re)){if((!Re||typeof Re!="object")&&(Re={}),Re=M(Re),jc=Kc.indexOf(Re.PARSER_MEDIA_TYPE)===-1?us:Re.PARSER_MEDIA_TYPE,_i=jc==="application/xhtml+xml"?g:m,mt=w(Re,"ALLOWED_TAGS")?A({},Re.ALLOWED_TAGS,_i):St,gr=w(Re,"ALLOWED_ATTR")?A({},Re.ALLOWED_ATTR,_i):xn,P1=w(Re,"ALLOWED_NAMESPACES")?A({},Re.ALLOWED_NAMESPACES,g):sa,O1=w(Re,"ADD_URI_SAFE_ATTR")?A(M(ci),Re.ADD_URI_SAFE_ATTR,_i):ci,_b=w(Re,"ADD_DATA_URI_TAGS")?A(M(I1),Re.ADD_DATA_URI_TAGS,_i):I1,Xc=w(Re,"FORBID_CONTENTS")?A({},Re.FORBID_CONTENTS,_i):M1,rn=w(Re,"FORBID_TAGS")?A({},Re.FORBID_TAGS,_i):{},Er=w(Re,"FORBID_ATTR")?A({},Re.FORBID_ATTR,_i):{},Ir=w(Re,"USE_PROFILES")?Re.USE_PROFILES:!1,Kn=Re.ALLOW_ARIA_ATTR!==!1,hn=Re.ALLOW_DATA_ATTR!==!1,Qn=Re.ALLOW_UNKNOWN_PROTOCOLS||!1,on=Re.ALLOW_SELF_CLOSE_IN_ATTR!==!1,Rn=Re.SAFE_FOR_TEMPLATES||!1,Ha=Re.SAFE_FOR_XML!==!1,_a=Re.WHOLE_DOCUMENT||!1,ht=Re.RETURN_DOM||!1,At=Re.RETURN_DOM_FRAGMENT||!1,$t=Re.RETURN_TRUSTED_TYPE||!1,qi=Re.FORCE_BODY||!1,rt=Re.SANITIZE_DOM!==!1,Ot=Re.SANITIZE_NAMED_PROPS||!1,ur=Re.KEEP_CONTENT!==!1,be=Re.IN_PLACE||!1,It=Re.ALLOWED_URI_REGEXP||Z,ah=Re.NAMESPACE||Us,jt=Re.CUSTOM_ELEMENT_HANDLING||{},Re.CUSTOM_ELEMENT_HANDLING&&zf(Re.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(jt.tagNameCheck=Re.CUSTOM_ELEMENT_HANDLING.tagNameCheck),Re.CUSTOM_ELEMENT_HANDLING&&zf(Re.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(jt.attributeNameCheck=Re.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),Re.CUSTOM_ELEMENT_HANDLING&&typeof Re.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(jt.allowCustomizedBuiltInElements=Re.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Rn&&(hn=!1),At&&(ht=!0),Ir&&(mt=A({},F),gr=[],Ir.html===!0&&(A(mt,k),A(gr,B)),Ir.svg===!0&&(A(mt,I),A(gr,$),A(gr,Y)),Ir.svgFilters===!0&&(A(mt,C),A(gr,$),A(gr,Y)),Ir.mathMl===!0&&(A(mt,D),A(gr,z),A(gr,Y))),Re.ADD_TAGS&&(mt===St&&(mt=M(mt)),A(mt,Re.ADD_TAGS,_i)),Re.ADD_ATTR&&(gr===xn&&(gr=M(gr)),A(gr,Re.ADD_ATTR,_i)),Re.ADD_URI_SAFE_ATTR&&A(O1,Re.ADD_URI_SAFE_ATTR,_i),Re.FORBID_CONTENTS&&(Xc===M1&&(Xc=M(Xc)),A(Xc,Re.FORBID_CONTENTS,_i)),ur&&(mt["#text"]=!0),_a&&A(mt,["html","head","body"]),mt.table&&(A(mt,["tbody"]),delete rn.tbody),Re.TRUSTED_TYPES_POLICY){if(typeof Re.TRUSTED_TYPES_POLICY.createHTML!="function")throw T('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if(typeof Re.TRUSTED_TYPES_POLICY.createScriptURL!="function")throw T('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');He=Re.TRUSTED_TYPES_POLICY,ze=He.createHTML("")}else He===void 0&&(He=De(we,_e)),He!==null&&typeof ze=="string"&&(ze=He.createHTML(""));a&&a(Re),Wl=Re}},"_parseConfig"),B1=A({},["mi","mo","mn","ms","mtext"]),Gf=A({},["foreignobject","annotation-xml"]),F1=A({},["title","style","font","a","script"]),La=A({},[...I,...C,...O]),vF=A({},[...D,...P]),Ive=o(function(Re){let st=ye(Re);(!st||!st.tagName)&&(st={namespaceURI:ah,tagName:"template"});let Rt=m(Re.tagName),bn=m(st.tagName);return P1[Re.namespaceURI]?Re.namespaceURI===ih?st.namespaceURI===Us?Rt==="svg":st.namespaceURI===ko?Rt==="svg"&&(bn==="annotation-xml"||B1[bn]):!!La[Rt]:Re.namespaceURI===ko?st.namespaceURI===Us?Rt==="math":st.namespaceURI===ih?Rt==="math"&&Gf[bn]:!!vF[Rt]:Re.namespaceURI===Us?st.namespaceURI===ih&&!Gf[bn]||st.namespaceURI===ko&&!B1[bn]?!1:!vF[Rt]&&(F1[Rt]||!La[Rt]):!!(jc==="application/xhtml+xml"&&P1[Re.namespaceURI]):!1},"_checkValidNamespace"),ql=o(function(Re){p(Se.removed,{element:Re});try{ye(Re).removeChild(Re)}catch{Ae(Re)}},"_forceRemove"),Db=o(function(Re,st){try{p(Se.removed,{attribute:st.getAttributeNode(Re),from:st})}catch{p(Se.removed,{attribute:null,from:st})}if(st.removeAttribute(Re),Re==="is"&&!gr[Re])if(ht||At)try{ql(st)}catch{}else try{st.setAttribute(Re,"")}catch{}},"_removeAttribute"),xF=o(function(Re){let st=null,Rt=null;if(qi)Re=""+Re;else{let oa=y(Re,/^[\r\n\t ]+/);Rt=oa&&oa[0]}jc==="application/xhtml+xml"&&ah===Us&&(Re=''+Re+"");let bn=He?He.createHTML(Re):Re;if(ah===Us)try{st=new ae().parseFromString(bn,jc)}catch{}if(!st||!st.documentElement){st=Ze.createDocument(ah,"template",null);try{st.documentElement.innerHTML=Lb?ze:bn}catch{}}let Da=st.body||st.documentElement;return Re&&Rt&&Da.insertBefore(Ue.createTextNode(Rt),Da.childNodes[0]||null),ah===Us?tt.call(st,_a?"html":"body")[0]:_a?st.documentElement:Da},"_initDocument"),bF=o(function(Re){return gt.call(Re.ownerDocument||Re,Re,re.SHOW_ELEMENT|re.SHOW_COMMENT|re.SHOW_TEXT|re.SHOW_PROCESSING_INSTRUCTION|re.SHOW_CDATA_SECTION,null)},"_createNodeIterator"),wF=o(function(Re){return Re instanceof ne&&(typeof Re.nodeName!="string"||typeof Re.textContent!="string"||typeof Re.removeChild!="function"||!(Re.attributes instanceof he)||typeof Re.removeAttribute!="function"||typeof Re.setAttribute!="function"||typeof Re.namespaceURI!="string"||typeof Re.insertBefore!="function"||typeof Re.hasChildNodes!="function")},"_isClobbered"),TF=o(function(Re){return typeof fe=="function"&&Re instanceof fe},"_isNode"),Qc=o(function(Re,st,Rt){Je[Re]&&f(Je[Re],bn=>{bn.call(Se,st,Rt,Wl)})},"_executeHook"),kF=o(function(Re){let st=null;if(Qc("beforeSanitizeElements",Re,null),wF(Re))return ql(Re),!0;let Rt=_i(Re.nodeName);if(Qc("uponSanitizeElement",Re,{tagName:Rt,allowedTags:mt}),Re.hasChildNodes()&&!TF(Re.firstElementChild)&&S(/<[/\w]/g,Re.innerHTML)&&S(/<[/\w]/g,Re.textContent)||Re.nodeType===ue.progressingInstruction||Ha&&Re.nodeType===ue.comment&&S(/<[/\w]/g,Re.data))return ql(Re),!0;if(!mt[Rt]||rn[Rt]){if(!rn[Rt]&&CF(Rt)&&(jt.tagNameCheck instanceof RegExp&&S(jt.tagNameCheck,Rt)||jt.tagNameCheck instanceof Function&&jt.tagNameCheck(Rt)))return!1;if(ur&&!Xc[Rt]){let bn=ye(Re)||Re.parentNode,Da=Me(Re)||Re.childNodes;if(Da&&bn){let oa=Da.length;for(let hs=oa-1;hs>=0;--hs){let Xl=Ce(Da[hs],!0);Xl.__removalCount=(Re.__removalCount||0)+1,bn.insertBefore(Xl,Ge(Re))}}}return ql(Re),!0}return Re instanceof ge&&!Ive(Re)||(Rt==="noscript"||Rt==="noembed"||Rt==="noframes")&&S(/<\/no(script|embed|frames)/i,Re.innerHTML)?(ql(Re),!0):(Rn&&Re.nodeType===ue.text&&(st=Re.textContent,f([Ve,je,kt],bn=>{st=v(st,bn," ")}),Re.textContent!==st&&(p(Se.removed,{element:Re.cloneNode()}),Re.textContent=st)),Qc("afterSanitizeElements",Re,null),!1)},"_sanitizeElements"),EF=o(function(Re,st,Rt){if(rt&&(st==="id"||st==="name")&&(Rt in Ue||Rt in sh))return!1;if(!(hn&&!Er[st]&&S(at,st))){if(!(Kn&&S(xt,st))){if(!gr[st]||Er[st]){if(!(CF(Re)&&(jt.tagNameCheck instanceof RegExp&&S(jt.tagNameCheck,Re)||jt.tagNameCheck instanceof Function&&jt.tagNameCheck(Re))&&(jt.attributeNameCheck instanceof RegExp&&S(jt.attributeNameCheck,st)||jt.attributeNameCheck instanceof Function&&jt.attributeNameCheck(st))||st==="is"&&jt.allowCustomizedBuiltInElements&&(jt.tagNameCheck instanceof RegExp&&S(jt.tagNameCheck,Rt)||jt.tagNameCheck instanceof Function&&jt.tagNameCheck(Rt))))return!1}else if(!O1[st]){if(!S(It,v(Rt,dt,""))){if(!((st==="src"||st==="xlink:href"||st==="href")&&Re!=="script"&&x(Rt,"data:")===0&&_b[Re])){if(!(Qn&&!S(it,v(Rt,dt,"")))){if(Rt)return!1}}}}}}return!0},"_isValidAttribute"),CF=o(function(Re){return Re!=="annotation-xml"&&y(Re,lt)},"_isBasicCustomElement"),SF=o(function(Re){Qc("beforeSanitizeAttributes",Re,null);let{attributes:st}=Re;if(!st)return;let Rt={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:gr},bn=st.length;for(;bn--;){let Da=st[bn],{name:oa,namespaceURI:hs,value:Xl}=Da,z1=_i(oa),Ya=oa==="value"?Xl:b(Xl);if(Rt.attrName=z1,Rt.attrValue=Ya,Rt.keepAttr=!0,Rt.forceKeepAttr=void 0,Qc("uponSanitizeAttribute",Re,Rt),Ya=Rt.attrValue,Ha&&S(/((--!?|])>)|<\/(style|title)/i,Ya)){Db(oa,Re);continue}if(Rt.forceKeepAttr||(Db(oa,Re),!Rt.keepAttr))continue;if(!on&&S(/\/>/i,Ya)){Db(oa,Re);continue}Rn&&f([Ve,je,kt],_F=>{Ya=v(Ya,_F," ")});let AF=_i(Re.nodeName);if(EF(AF,z1,Ya)){if(Ot&&(z1==="id"||z1==="name")&&(Db(oa,Re),Ya=pe+Ya),He&&typeof we=="object"&&typeof we.getAttributeType=="function"&&!hs)switch(we.getAttributeType(AF,z1)){case"TrustedHTML":{Ya=He.createHTML(Ya);break}case"TrustedScriptURL":{Ya=He.createScriptURL(Ya);break}}try{hs?Re.setAttributeNS(hs,oa,Ya):Re.setAttribute(oa,Ya),wF(Re)?ql(Re):d(Se.removed)}catch{}}}Qc("afterSanitizeAttributes",Re,null)},"_sanitizeAttributes"),Ove=o(function Ft(Re){let st=null,Rt=bF(Re);for(Qc("beforeSanitizeShadowDOM",Re,null);st=Rt.nextNode();)Qc("uponSanitizeShadowNode",st,null),!kF(st)&&(st.content instanceof me&&Ft(st.content),SF(st));Qc("afterSanitizeShadowDOM",Re,null)},"_sanitizeShadowDOM");return Se.sanitize=function(Ft){let Re=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},st=null,Rt=null,bn=null,Da=null;if(Lb=!Ft,Lb&&(Ft=""),typeof Ft!="string"&&!TF(Ft))if(typeof Ft.toString=="function"){if(Ft=Ft.toString(),typeof Ft!="string")throw T("dirty is not a string, aborting")}else throw T("toString is not a function");if(!Se.isSupported)return Ft;if(To||Hs(Re),Se.removed=[],typeof Ft=="string"&&(be=!1),be){if(Ft.nodeName){let Xl=_i(Ft.nodeName);if(!mt[Xl]||rn[Xl])throw T("root node is forbidden and cannot be sanitized in-place")}}else if(Ft instanceof fe)st=xF(""),Rt=st.ownerDocument.importNode(Ft,!0),Rt.nodeType===ue.element&&Rt.nodeName==="BODY"||Rt.nodeName==="HTML"?st=Rt:st.appendChild(Rt);else{if(!ht&&!Rn&&!_a&&Ft.indexOf("<")===-1)return He&&$t?He.createHTML(Ft):Ft;if(st=xF(Ft),!st)return ht?null:$t?ze:""}st&&qi&&ql(st.firstChild);let oa=bF(be?Ft:st);for(;bn=oa.nextNode();)kF(bn)||(bn.content instanceof me&&Ove(bn.content),SF(bn));if(be)return Ft;if(ht){if(At)for(Da=yt.call(st.ownerDocument);st.firstChild;)Da.appendChild(st.firstChild);else Da=st;return(gr.shadowroot||gr.shadowrootmode)&&(Da=Ye.call(Pe,Da,!0)),Da}let hs=_a?st.outerHTML:st.innerHTML;return _a&&mt["!doctype"]&&st.ownerDocument&&st.ownerDocument.doctype&&st.ownerDocument.doctype.name&&S(K,st.ownerDocument.doctype.name)&&(hs=" +`+hs),Rn&&f([Ve,je,kt],Xl=>{hs=v(hs,Xl," ")}),He&&$t?He.createHTML(hs):hs},Se.setConfig=function(){let Ft=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};Hs(Ft),To=!0},Se.clearConfig=function(){Wl=null,To=!1},Se.isValidAttribute=function(Ft,Re,st){Wl||Hs({});let Rt=_i(Ft),bn=_i(Re);return EF(Rt,bn,st)},Se.addHook=function(Ft,Re){typeof Re=="function"&&(Je[Ft]=Je[Ft]||[],p(Je[Ft],Re))},Se.removeHook=function(Ft){if(Je[Ft])return d(Je[Ft])},Se.removeHooks=function(Ft){Je[Ft]&&(Je[Ft]=[])},Se.removeAllHooks=function(){Je={}},Se}o(oe,"createDOMPurify");var ke=oe();return ke})});var k$={};hr(k$,{default:()=>Ebe});function B2e(t){return String(t).replace(P2e,e=>O2e[e])}function $2e(t){if(t.default)return t.default;var e=t.type,r=Array.isArray(e)?e[0]:e;if(typeof r!="string")return r.enum[0];switch(r){case"boolean":return!1;case"string":return"";case"number":return 0;case"object":return{}}}function X2e(t){for(var e=0;e=i[0]&&t<=i[1])return r.name}return null}function LG(t){for(var e=0;e=h4[e]&&t<=h4[e+1])return!0;return!1}function axe(t,e){Zl[t]=e}function M7(t,e,r){if(!Zl[e])throw new Error("Font metrics not found for font: "+e+".");var n=t.charCodeAt(0),i=Zl[e][n];if(!i&&t[0]in Zz&&(n=Zz[t[0]].charCodeAt(0),i=Zl[e][n]),!i&&r==="text"&&LG(n)&&(i=Zl[e][77]),i)return{depth:i[0],height:i[1],italic:i[2],skew:i[3],width:i[4]}}function sxe(t){var e;if(t>=5?e=0:t>=3?e=1:e=2,!l7[e]){var r=l7[e]={cssEmPerMu:Jb.quad[e]/18};for(var n in Jb)Jb.hasOwnProperty(n)&&(r[n]=Jb[n][e])}return l7[e]}function tG(t){if(t instanceof ms)return t;throw new Error("Expected symbolNode but got "+String(t)+".")}function uxe(t){if(t instanceof jf)return t;throw new Error("Expected span but got "+String(t)+".")}function G(t,e,r,n,i,a){wn[t][i]={font:e,group:r,replace:n},a&&n&&(wn[t][n]=wn[t][i])}function vt(t){for(var{type:e,names:r,props:n,handler:i,htmlBuilder:a,mathmlBuilder:s}=t,l={type:e,numArgs:n.numArgs,argTypes:n.argTypes,allowedInArgument:!!n.allowedInArgument,allowedInText:!!n.allowedInText,allowedInMath:n.allowedInMath===void 0?!0:n.allowedInMath,numOptionalArgs:n.numOptionalArgs||0,infix:!!n.infix,primitive:!!n.primitive,handler:i},u=0;u0&&(a.push(s4(s,e)),s=[]),a.push(n[l]));s.length>0&&a.push(s4(s,e));var h;r?(h=s4(Ri(r,e,!0)),h.classes=["tag"],a.push(h)):i&&a.push(i);var f=su(["katex-html"],a);if(f.setAttribute("aria-hidden","true"),h){var d=h.children[0];d.style.height=ct(f.height+f.depth),f.depth&&(d.style.verticalAlign=ct(-f.depth))}return f}function $G(t){return new Xf(t)}function sG(t,e,r,n,i){var a=gs(t,r),s;a.length===1&&a[0]instanceof ps&&Vt.contains(["mrow","mtable"],a[0].type)?s=a[0]:s=new et.MathNode("mrow",a);var l=new et.MathNode("annotation",[new et.TextNode(e)]);l.setAttribute("encoding","application/x-tex");var u=new et.MathNode("semantics",[s,l]),h=new et.MathNode("math",[u]);h.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),n&&h.setAttribute("display","block");var f=i?"katex":"katex-mathml";return Be.makeSpan([f],[h])}function ir(t,e){if(!t||t.type!==e)throw new Error("Expected node of type "+e+", but got "+(t?"node of type "+t.type:String(t)));return t}function B7(t){var e=T4(t);if(!e)throw new Error("Expected node of symbol group type, but got "+(t?"node of type "+t.type:String(t)));return e}function T4(t){return t&&(t.type==="atom"||fxe.hasOwnProperty(t.type))?t:null}function YG(t,e){var r=Ri(t.body,e,!0);return Vxe([t.mclass],r,e)}function WG(t,e){var r,n=gs(t.body,e);return t.mclass==="minner"?r=new et.MathNode("mpadded",n):t.mclass==="mord"?t.isCharacterBox?(r=n[0],r.type="mi"):r=new et.MathNode("mi",n):(t.isCharacterBox?(r=n[0],r.type="mo"):r=new et.MathNode("mo",n),t.mclass==="mbin"?(r.attributes.lspace="0.22em",r.attributes.rspace="0.22em"):t.mclass==="mpunct"?(r.attributes.lspace="0em",r.attributes.rspace="0.17em"):t.mclass==="mopen"||t.mclass==="mclose"?(r.attributes.lspace="0em",r.attributes.rspace="0em"):t.mclass==="minner"&&(r.attributes.lspace="0.0556em",r.attributes.width="+0.1111em")),r}function Yxe(t,e,r){var n=Uxe[t];switch(n){case"\\\\cdrightarrow":case"\\\\cdleftarrow":return r.callFunction(n,[e[0]],[e[1]]);case"\\uparrow":case"\\downarrow":{var i=r.callFunction("\\\\cdleft",[e[0]],[]),a={type:"atom",text:n,mode:"math",family:"rel"},s=r.callFunction("\\Big",[a],[]),l=r.callFunction("\\\\cdright",[e[1]],[]),u={type:"ordgroup",mode:"math",body:[i,s,l]};return r.callFunction("\\\\cdparent",[u],[])}case"\\\\cdlongequal":return r.callFunction("\\\\cdlongequal",[],[]);case"\\Vert":{var h={type:"textord",text:"\\Vert",mode:"math"};return r.callFunction("\\Big",[h],[])}default:return{type:"textord",text:" ",mode:"math"}}}function Wxe(t){var e=[];for(t.gullet.beginGroup(),t.gullet.macros.set("\\cr","\\\\\\relax"),t.gullet.beginGroup();;){e.push(t.parseExpression(!1,"\\\\")),t.gullet.endGroup(),t.gullet.beginGroup();var r=t.fetch().text;if(r==="&"||r==="\\\\")t.consume();else if(r==="\\end"){e[e.length-1].length===0&&e.pop();break}else throw new nt("Expected \\\\ or \\cr or \\end",t.nextToken)}for(var n=[],i=[n],a=0;a-1))if("<>AV".indexOf(h)>-1)for(var d=0;d<2;d++){for(var p=!0,m=u+1;mAV=|." after @',s[u]);var g=Yxe(h,f,t),y={type:"styling",body:[g],mode:"math",style:"display"};n.push(y),l=oG()}a%2===0?n.push(l):n.shift(),n=[],i.push(n)}t.gullet.endGroup(),t.gullet.endGroup();var v=new Array(i[0].length).fill({type:"align",align:"c",pregap:.25,postgap:.25});return{type:"array",mode:"math",body:i,arraystretch:1,addJot:!0,rowGaps:[null],cols:v,colSeparationType:"CD",hLinesBeforeRow:new Array(i.length+1).fill([])}}function E4(t,e){var r=T4(t);if(r&&Vt.contains(abe,r.text))return r;throw r?new nt("Invalid delimiter '"+r.text+"' after '"+e.funcName+"'",t):new nt("Invalid delimiter type '"+t.type+"'",t)}function uG(t){if(!t.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}function ec(t){for(var{type:e,names:r,props:n,handler:i,htmlBuilder:a,mathmlBuilder:s}=t,l={type:e,numArgs:n.numArgs||0,allowedInText:!1,numOptionalArgs:0,handler:i},u=0;u1||!f)&&y.pop(),x.length{"use strict";Xs=class t{static{o(this,"SourceLocation")}constructor(e,r,n){this.lexer=void 0,this.start=void 0,this.end=void 0,this.lexer=e,this.start=r,this.end=n}static range(e,r){return r?!e||!e.loc||!r.loc||e.loc.lexer!==r.loc.lexer?null:new t(e.loc.lexer,e.loc.start,r.loc.end):e&&e.loc}},Ao=class t{static{o(this,"Token")}constructor(e,r){this.text=void 0,this.loc=void 0,this.noexpand=void 0,this.treatAsRelax=void 0,this.text=e,this.loc=r}range(e,r){return new t(r,Xs.range(this,e))}},nt=class t{static{o(this,"ParseError")}constructor(e,r){this.name=void 0,this.position=void 0,this.length=void 0,this.rawMessage=void 0;var n="KaTeX parse error: "+e,i,a,s=r&&r.loc;if(s&&s.start<=s.end){var l=s.lexer.input;i=s.start,a=s.end,i===l.length?n+=" at end of input: ":n+=" at position "+(i+1)+": ";var u=l.slice(i,a).replace(/[^]/g,"$&\u0332"),h;i>15?h="\u2026"+l.slice(i-15,i):h=l.slice(0,i);var f;a+15":">","<":"<",'"':""","'":"'"},P2e=/[&><"']/g;o(B2e,"escape");_G=o(function t(e){return e.type==="ordgroup"||e.type==="color"?e.body.length===1?t(e.body[0]):e:e.type==="font"?t(e.body):e},"getBaseElem"),F2e=o(function(e){var r=_G(e);return r.type==="mathord"||r.type==="textord"||r.type==="atom"},"isCharacterBox"),z2e=o(function(e){if(!e)throw new Error("Expected non-null, but got "+String(e));return e},"assert"),G2e=o(function(e){var r=/^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(e);return r?r[2]!==":"||!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(r[1])?null:r[1].toLowerCase():"_relative"},"protocolFromUrl"),Vt={contains:R2e,deflt:N2e,escape:B2e,hyphenate:I2e,getBaseElem:_G,isCharacterBox:F2e,protocolFromUrl:G2e},u4={displayMode:{type:"boolean",description:"Render math in display mode, which puts the math in display style (so \\int and \\sum are large, for example), and centers the math on the page on its own line.",cli:"-d, --display-mode"},output:{type:{enum:["htmlAndMathml","html","mathml"]},description:"Determines the markup language of the output.",cli:"-F, --format "},leqno:{type:"boolean",description:"Render display math in leqno style (left-justified tags)."},fleqn:{type:"boolean",description:"Render display math flush left."},throwOnError:{type:"boolean",default:!0,cli:"-t, --no-throw-on-error",cliDescription:"Render errors (in the color given by --error-color) instead of throwing a ParseError exception when encountering an error."},errorColor:{type:"string",default:"#cc0000",cli:"-c, --error-color ",cliDescription:"A color string given in the format 'rgb' or 'rrggbb' (no #). This option determines the color of errors rendered by the -t option.",cliProcessor:o(t=>"#"+t,"cliProcessor")},macros:{type:"object",cli:"-m, --macro ",cliDescription:"Define custom macro of the form '\\foo:expansion' (use multiple -m arguments for multiple macros).",cliDefault:[],cliProcessor:o((t,e)=>(e.push(t),e),"cliProcessor")},minRuleThickness:{type:"number",description:"Specifies a minimum thickness, in ems, for fraction lines, `\\sqrt` top lines, `{array}` vertical lines, `\\hline`, `\\hdashline`, `\\underline`, `\\overline`, and the borders of `\\fbox`, `\\boxed`, and `\\fcolorbox`.",processor:o(t=>Math.max(0,t),"processor"),cli:"--min-rule-thickness ",cliProcessor:parseFloat},colorIsTextColor:{type:"boolean",description:"Makes \\color behave like LaTeX's 2-argument \\textcolor, instead of LaTeX's one-argument \\color mode change.",cli:"-b, --color-is-text-color"},strict:{type:[{enum:["warn","ignore","error"]},"boolean","function"],description:"Turn on strict / LaTeX faithfulness mode, which throws an error if the input uses features that are not supported by LaTeX.",cli:"-S, --strict",cliDefault:!1},trust:{type:["boolean","function"],description:"Trust the input, enabling all HTML features such as \\url.",cli:"-T, --trust"},maxSize:{type:"number",default:1/0,description:"If non-zero, all user-specified sizes, e.g. in \\rule{500em}{500em}, will be capped to maxSize ems. Otherwise, elements and spaces can be arbitrarily large",processor:o(t=>Math.max(0,t),"processor"),cli:"-s, --max-size ",cliProcessor:parseInt},maxExpand:{type:"number",default:1e3,description:"Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to Infinity, the macro expander will try to fully expand as in LaTeX.",processor:o(t=>Math.max(0,t),"processor"),cli:"-e, --max-expand ",cliProcessor:o(t=>t==="Infinity"?1/0:parseInt(t),"cliProcessor")},globalGroup:{type:"boolean",cli:!1}};o($2e,"getDefaultValue");ry=class{static{o(this,"Settings")}constructor(e){this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,this.globalGroup=void 0,e=e||{};for(var r in u4)if(u4.hasOwnProperty(r)){var n=u4[r];this[r]=e[r]!==void 0?n.processor?n.processor(e[r]):e[r]:$2e(n)}}reportNonstrict(e,r,n){var i=this.strict;if(typeof i=="function"&&(i=i(e,r,n)),!(!i||i==="ignore")){if(i===!0||i==="error")throw new nt("LaTeX-incompatible input and strict mode is set to 'error': "+(r+" ["+e+"]"),n);i==="warn"?typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+(r+" ["+e+"]")):typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to "+("unrecognized '"+i+"': "+r+" ["+e+"]"))}}useStrictBehavior(e,r,n){var i=this.strict;if(typeof i=="function")try{i=i(e,r,n)}catch{i="error"}return!i||i==="ignore"?!1:i===!0||i==="error"?!0:i==="warn"?(typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+(r+" ["+e+"]")),!1):(typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to "+("unrecognized '"+i+"': "+r+" ["+e+"]")),!1)}isTrusted(e){if(e.url&&!e.protocol){var r=Vt.protocolFromUrl(e.url);if(r==null)return!1;e.protocol=r}var n=typeof this.trust=="function"?this.trust(e):this.trust;return!!n}},Kl=class{static{o(this,"Style")}constructor(e,r,n){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=e,this.size=r,this.cramped=n}sup(){return Ql[V2e[this.id]]}sub(){return Ql[U2e[this.id]]}fracNum(){return Ql[H2e[this.id]]}fracDen(){return Ql[Y2e[this.id]]}cramp(){return Ql[W2e[this.id]]}text(){return Ql[q2e[this.id]]}isTight(){return this.size>=2}},N7=0,f4=1,gp=2,iu=3,ny=4,So=5,yp=6,qa=7,Ql=[new Kl(N7,0,!1),new Kl(f4,0,!0),new Kl(gp,1,!1),new Kl(iu,1,!0),new Kl(ny,2,!1),new Kl(So,2,!0),new Kl(yp,3,!1),new Kl(qa,3,!0)],V2e=[ny,So,ny,So,yp,qa,yp,qa],U2e=[So,So,So,So,qa,qa,qa,qa],H2e=[gp,iu,ny,So,yp,qa,yp,qa],Y2e=[iu,iu,So,So,qa,qa,qa,qa],W2e=[f4,f4,iu,iu,So,So,qa,qa],q2e=[N7,f4,gp,iu,gp,iu,gp,iu],Ht={DISPLAY:Ql[N7],TEXT:Ql[gp],SCRIPT:Ql[ny],SCRIPTSCRIPT:Ql[yp]},b7=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"armenian",blocks:[[1328,1423]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}];o(X2e,"scriptFromCodepoint");h4=[];b7.forEach(t=>t.blocks.forEach(e=>h4.push(...e)));o(LG,"supportedCodepoint");mp=80,j2e=o(function(e,r){return"M95,"+(622+e+r)+` +c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14 +c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54 +c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10 +s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429 +c69,-144,104.5,-217.7,106.5,-221 +l`+e/2.075+" -"+e+` +c5.3,-9.3,12,-14,20,-14 +H400000v`+(40+e)+`H845.2724 +s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7 +c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z +M`+(834+e)+" "+r+"h400000v"+(40+e)+"h-400000z"},"sqrtMain"),K2e=o(function(e,r){return"M263,"+(601+e+r)+`c0.7,0,18,39.7,52,119 +c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120 +c340,-704.7,510.7,-1060.3,512,-1067 +l`+e/2.084+" -"+e+` +c4.7,-7.3,11,-11,19,-11 +H40000v`+(40+e)+`H1012.3 +s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232 +c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1 +s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26 +c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z +M`+(1001+e)+" "+r+"h400000v"+(40+e)+"h-400000z"},"sqrtSize1"),Q2e=o(function(e,r){return"M983 "+(10+e+r)+` +l`+e/3.13+" -"+e+` +c4,-6.7,10,-10,18,-10 H400000v`+(40+e)+` +H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7 +s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744 +c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30 +c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722 +c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5 +c53.7,-170.3,84.5,-266.8,92.5,-289.5z +M`+(1001+e)+" "+r+"h400000v"+(40+e)+"h-400000z"},"sqrtSize2"),Z2e=o(function(e,r){return"M424,"+(2398+e+r)+` +c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514 +c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20 +s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121 +s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081 +l`+e/4.223+" -"+e+`c4,-6.7,10,-10,18,-10 H400000 +v`+(40+e)+`H1014.6 +s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185 +c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2z M`+(1001+e)+" "+r+` +h400000v`+(40+e)+"h-400000z"},"sqrtSize3"),J2e=o(function(e,r){return"M473,"+(2713+e+r)+` +c339.3,-1799.3,509.3,-2700,510,-2702 l`+e/5.298+" -"+e+` +c3.3,-7.3,9.3,-11,18,-11 H400000v`+(40+e)+`H1017.7 +s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200 +c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26 +s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104, +606zM`+(1001+e)+" "+r+"h400000v"+(40+e)+"H1017.7z"},"sqrtSize4"),exe=o(function(e){var r=e/2;return"M400000 "+e+" H0 L"+r+" 0 l65 45 L145 "+(e-80)+" H400000z"},"phasePath"),txe=o(function(e,r,n){var i=n-54-r-e;return"M702 "+(e+r)+"H400000"+(40+e)+` +H742v`+i+`l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1 +h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170 +c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667 +219 661 l218 661zM702 `+r+"H400000v"+(40+e)+"H742z"},"sqrtTall"),rxe=o(function(e,r,n){r=1e3*r;var i="";switch(e){case"sqrtMain":i=j2e(r,mp);break;case"sqrtSize1":i=K2e(r,mp);break;case"sqrtSize2":i=Q2e(r,mp);break;case"sqrtSize3":i=Z2e(r,mp);break;case"sqrtSize4":i=J2e(r,mp);break;case"sqrtTall":i=txe(r,mp,n)}return i},"sqrtPath"),nxe=o(function(e,r){switch(e){case"\u239C":return"M291 0 H417 V"+r+" H291z M291 0 H417 V"+r+" H291z";case"\u2223":return"M145 0 H188 V"+r+" H145z M145 0 H188 V"+r+" H145z";case"\u2225":return"M145 0 H188 V"+r+" H145z M145 0 H188 V"+r+" H145z"+("M367 0 H410 V"+r+" H367z M367 0 H410 V"+r+" H367z");case"\u239F":return"M457 0 H583 V"+r+" H457z M457 0 H583 V"+r+" H457z";case"\u23A2":return"M319 0 H403 V"+r+" H319z M319 0 H403 V"+r+" H319z";case"\u23A5":return"M263 0 H347 V"+r+" H263z M263 0 H347 V"+r+" H263z";case"\u23AA":return"M384 0 H504 V"+r+" H384z M384 0 H504 V"+r+" H384z";case"\u23D0":return"M312 0 H355 V"+r+" H312z M312 0 H355 V"+r+" H312z";case"\u2016":return"M257 0 H300 V"+r+" H257z M257 0 H300 V"+r+" H257z"+("M478 0 H521 V"+r+" H478z M478 0 H521 V"+r+" H478z");default:return""}},"innerPath"),Qz={doubleleftarrow:`M262 157 +l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3 + 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28 + 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5 +c2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5 + 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87 +-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7 +-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z +m8 0v40h399730v-40zm0 194v40h399730v-40z`,doublerightarrow:`M399738 392l +-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5 + 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88 +-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68 +-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18 +-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782 +c-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3 +-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z`,leftarrow:`M400000 241H110l3-3c68.7-52.7 113.7-120 + 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8 +-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247 +c-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208 + 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3 + 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202 + l-3-3h399890zM100 241v40h399900v-40z`,leftbrace:`M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117 +-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7 + 5-6 9-10 13-.7 1-7.3 1-20 1H6z`,leftbraceunder:`M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13 + 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688 + 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7 +-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z`,leftgroup:`M400000 80 +H435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0 + 435 0h399565z`,leftgroupunder:`M400000 262 +H435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219 + 435 219h399565z`,leftharpoon:`M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3 +-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5 +-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7 +-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z`,leftharpoonplus:`M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5 + 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3 +-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7 +-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z +m0 0v40h400000v-40z`,leftharpoondown:`M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333 + 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5 + 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667 +-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z`,leftharpoondownplus:`M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12 + 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7 +-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0 +v40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z`,lefthook:`M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5 +-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3 +-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21 + 71.5 23h399859zM103 281v-40h399897v40z`,leftlinesegment:`M40 281 V428 H0 V94 H40 V241 H400000 v40z +M40 281 V428 H0 V94 H40 V241 H400000 v40z`,leftmapsto:`M40 281 V448H0V74H40V241H400000v40z +M40 281 V448H0V74H40V241H400000v40z`,leftToFrom:`M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23 +-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8 +c28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3 + 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z`,longequal:`M0 50 h400000 v40H0z m0 194h40000v40H0z +M0 50 h400000 v40H0z m0 194h40000v40H0z`,midbrace:`M200428 334 +c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14 +-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7 + 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11 + 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z`,midbraceunder:`M199572 214 +c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14 + 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3 + 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0 +-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z`,oiintSize1:`M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6 +-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z +m368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8 +60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z`,oiintSize2:`M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8 +-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z +m502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2 +c0 110 84 276 504 276s502.4-166 502.4-276z`,oiiintSize1:`M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6 +-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z +m525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0 +85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z`,oiiintSize2:`M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8 +-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z +m770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1 +c0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z`,rightarrow:`M0 241v40h399891c-47.3 35.3-84 78-110 128 +-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 + 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 + 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85 +-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 + 151.7 139 205zm0 0v40h399900v-40z`,rightbrace:`M400000 542l +-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5 +s-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1 +c124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z`,rightbraceunder:`M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3 + 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237 +-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z`,rightgroup:`M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0 + 3-1 3-3v-38c-76-158-257-219-435-219H0z`,rightgroupunder:`M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18 + 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z`,rightharpoon:`M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3 +-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2 +-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 + 69.2 92 94.5zm0 0v40h399900v-40z`,rightharpoonplus:`M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11 +-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7 + 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z +m0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z`,rightharpoondown:`M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8 + 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5 +-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95 +-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z`,rightharpoondownplus:`M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8 + 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 + 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3 +-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z +m0-194v40h400000v-40zm0 0v40h400000v-40z`,righthook:`M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3 + 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0 +-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21 + 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z`,rightlinesegment:`M399960 241 V94 h40 V428 h-40 V281 H0 v-40z +M399960 241 V94 h40 V428 h-40 V281 H0 v-40z`,rightToFrom:`M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23 + 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32 +-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142 +-167z M100 147v40h399900v-40zM0 341v40h399900v-40z`,twoheadleftarrow:`M0 167c68 40 + 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69 +-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3 +-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19 +-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101 + 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z`,twoheadrightarrow:`M400000 167 +c-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3 + 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42 + 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333 +-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70 + 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z`,tilde1:`M200 55.538c-77 0-168 73.953-177 73.953-3 0-7 +-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0 + 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0 + 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128 +-68.267.847-113-73.952-191-73.952z`,tilde2:`M344 55.266c-142 0-300.638 81.316-311.5 86.418 +-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9 + 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114 +c1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751 + 181.476 676 181.476c-149 0-189-126.21-332-126.21z`,tilde3:`M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457 +-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0 + 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697 + 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696 + -338 0-409-156.573-744-156.573z`,tilde4:`M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345 +-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409 + 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9 + 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409 + -175.236-744-175.236z`,vec:`M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5 +3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11 +10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63 +-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1 +-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59 +H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359 +c-16-25.333-24-45-24-59z`,widehat1:`M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22 +c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z`,widehat2:`M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widehat3:`M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widehat4:`M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widecheck1:`M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1, +-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z`,widecheck2:`M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,widecheck3:`M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,widecheck4:`M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,baraboveleftarrow:`M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202 +c4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5 +c-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130 +s-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47 +121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6 +s2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11 +c0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z +M100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z`,rightarrowabovebar:`M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32 +-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0 +13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39 +-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5 +-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 +151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z`,baraboveshortleftharpoon:`M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 +c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 +c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 +c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z +M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`,rightharpoonaboveshortbar:`M0,241 l0,40c399126,0,399993,0,399993,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`,shortbaraboveleftharpoon:`M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, +1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, +-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z +M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`,shortrightharpoonabovebar:`M53,241l0,40c398570,0,399437,0,399437,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`},ixe=o(function(e,r){switch(e){case"lbrack":return"M403 1759 V84 H666 V0 H319 V1759 v"+r+` v1759 h347 v-84 +H403z M403 1759 V0 H319 V1759 v`+r+" v1759 h84z";case"rbrack":return"M347 1759 V0 H0 V84 H263 V1759 v"+r+` v1759 H0 v84 H347z +M347 1759 V0 H263 V1759 v`+r+" v1759 h84z";case"vert":return"M145 15 v585 v"+r+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-r+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v`+r+" v585 h43z";case"doublevert":return"M145 15 v585 v"+r+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-r+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v`+r+` v585 h43z +M367 15 v585 v`+r+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-r+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M410 15 H367 v585 v`+r+" v585 h43z";case"lfloor":return"M319 602 V0 H403 V602 v"+r+` v1715 h263 v84 H319z +MM319 602 V0 H403 V602 v`+r+" v1715 H319z";case"rfloor":return"M319 602 V0 H403 V602 v"+r+` v1799 H0 v-84 H319z +MM319 602 V0 H403 V602 v`+r+" v1715 H319z";case"lceil":return"M403 1759 V84 H666 V0 H319 V1759 v"+r+` v602 h84z +M403 1759 V0 H319 V1759 v`+r+" v602 h84z";case"rceil":return"M347 1759 V0 H0 V84 H263 V1759 v"+r+` v602 h84z +M347 1759 V0 h-84 V1759 v`+r+" v602 h84z";case"lparen":return`M863,9c0,-2,-2,-5,-6,-9c0,0,-17,0,-17,0c-12.7,0,-19.3,0.3,-20,1 +c-5.3,5.3,-10.3,11,-15,17c-242.7,294.7,-395.3,682,-458,1162c-21.3,163.3,-33.3,349, +-36,557 l0,`+(r+84)+`c0.2,6,0,26,0,60c2,159.3,10,310.7,24,454c53.3,528,210, +949.7,470,1265c4.7,6,9.7,11.7,15,17c0.7,0.7,7,1,19,1c0,0,18,0,18,0c4,-4,6,-7,6,-9 +c0,-2.7,-3.3,-8.7,-10,-18c-135.3,-192.7,-235.5,-414.3,-300.5,-665c-65,-250.7,-102.5, +-544.7,-112.5,-882c-2,-104,-3,-167,-3,-189 +l0,-`+(r+92)+`c0,-162.7,5.7,-314,17,-454c20.7,-272,63.7,-513,129,-723c65.3, +-210,155.3,-396.3,270,-559c6.7,-9.3,10,-15.3,10,-18z`;case"rparen":return`M76,0c-16.7,0,-25,3,-25,9c0,2,2,6.3,6,13c21.3,28.7,42.3,60.3, +63,95c96.7,156.7,172.8,332.5,228.5,527.5c55.7,195,92.8,416.5,111.5,664.5 +c11.3,139.3,17,290.7,17,454c0,28,1.7,43,3.3,45l0,`+(r+9)+` +c-3,4,-3.3,16.7,-3.3,38c0,162,-5.7,313.7,-17,455c-18.7,248,-55.8,469.3,-111.5,664 +c-55.7,194.7,-131.8,370.3,-228.5,527c-20.7,34.7,-41.7,66.3,-63,95c-2,3.3,-4,7,-6,11 +c0,7.3,5.7,11,17,11c0,0,11,0,11,0c9.3,0,14.3,-0.3,15,-1c5.3,-5.3,10.3,-11,15,-17 +c242.7,-294.7,395.3,-681.7,458,-1161c21.3,-164.7,33.3,-350.7,36,-558 +l0,-`+(r+144)+`c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7, +-470,-1265c-4.7,-6,-9.7,-11.7,-15,-17c-0.7,-0.7,-6.7,-1,-18,-1z`;default:throw new Error("Unknown stretchy delimiter.")}},"tallDelim"),Xf=class{static{o(this,"DocumentFragment")}constructor(e){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=e,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}hasClass(e){return Vt.contains(this.classes,e)}toNode(){for(var e=document.createDocumentFragment(),r=0;rr.toText(),"toText");return this.children.map(e).join("")}},Zl={"AMS-Regular":{32:[0,0,0,0,.25],65:[0,.68889,0,0,.72222],66:[0,.68889,0,0,.66667],67:[0,.68889,0,0,.72222],68:[0,.68889,0,0,.72222],69:[0,.68889,0,0,.66667],70:[0,.68889,0,0,.61111],71:[0,.68889,0,0,.77778],72:[0,.68889,0,0,.77778],73:[0,.68889,0,0,.38889],74:[.16667,.68889,0,0,.5],75:[0,.68889,0,0,.77778],76:[0,.68889,0,0,.66667],77:[0,.68889,0,0,.94445],78:[0,.68889,0,0,.72222],79:[.16667,.68889,0,0,.77778],80:[0,.68889,0,0,.61111],81:[.16667,.68889,0,0,.77778],82:[0,.68889,0,0,.72222],83:[0,.68889,0,0,.55556],84:[0,.68889,0,0,.66667],85:[0,.68889,0,0,.72222],86:[0,.68889,0,0,.72222],87:[0,.68889,0,0,1],88:[0,.68889,0,0,.72222],89:[0,.68889,0,0,.72222],90:[0,.68889,0,0,.66667],107:[0,.68889,0,0,.55556],160:[0,0,0,0,.25],165:[0,.675,.025,0,.75],174:[.15559,.69224,0,0,.94666],240:[0,.68889,0,0,.55556],295:[0,.68889,0,0,.54028],710:[0,.825,0,0,2.33334],732:[0,.9,0,0,2.33334],770:[0,.825,0,0,2.33334],771:[0,.9,0,0,2.33334],989:[.08167,.58167,0,0,.77778],1008:[0,.43056,.04028,0,.66667],8245:[0,.54986,0,0,.275],8463:[0,.68889,0,0,.54028],8487:[0,.68889,0,0,.72222],8498:[0,.68889,0,0,.55556],8502:[0,.68889,0,0,.66667],8503:[0,.68889,0,0,.44445],8504:[0,.68889,0,0,.66667],8513:[0,.68889,0,0,.63889],8592:[-.03598,.46402,0,0,.5],8594:[-.03598,.46402,0,0,.5],8602:[-.13313,.36687,0,0,1],8603:[-.13313,.36687,0,0,1],8606:[.01354,.52239,0,0,1],8608:[.01354,.52239,0,0,1],8610:[.01354,.52239,0,0,1.11111],8611:[.01354,.52239,0,0,1.11111],8619:[0,.54986,0,0,1],8620:[0,.54986,0,0,1],8621:[-.13313,.37788,0,0,1.38889],8622:[-.13313,.36687,0,0,1],8624:[0,.69224,0,0,.5],8625:[0,.69224,0,0,.5],8630:[0,.43056,0,0,1],8631:[0,.43056,0,0,1],8634:[.08198,.58198,0,0,.77778],8635:[.08198,.58198,0,0,.77778],8638:[.19444,.69224,0,0,.41667],8639:[.19444,.69224,0,0,.41667],8642:[.19444,.69224,0,0,.41667],8643:[.19444,.69224,0,0,.41667],8644:[.1808,.675,0,0,1],8646:[.1808,.675,0,0,1],8647:[.1808,.675,0,0,1],8648:[.19444,.69224,0,0,.83334],8649:[.1808,.675,0,0,1],8650:[.19444,.69224,0,0,.83334],8651:[.01354,.52239,0,0,1],8652:[.01354,.52239,0,0,1],8653:[-.13313,.36687,0,0,1],8654:[-.13313,.36687,0,0,1],8655:[-.13313,.36687,0,0,1],8666:[.13667,.63667,0,0,1],8667:[.13667,.63667,0,0,1],8669:[-.13313,.37788,0,0,1],8672:[-.064,.437,0,0,1.334],8674:[-.064,.437,0,0,1.334],8705:[0,.825,0,0,.5],8708:[0,.68889,0,0,.55556],8709:[.08167,.58167,0,0,.77778],8717:[0,.43056,0,0,.42917],8722:[-.03598,.46402,0,0,.5],8724:[.08198,.69224,0,0,.77778],8726:[.08167,.58167,0,0,.77778],8733:[0,.69224,0,0,.77778],8736:[0,.69224,0,0,.72222],8737:[0,.69224,0,0,.72222],8738:[.03517,.52239,0,0,.72222],8739:[.08167,.58167,0,0,.22222],8740:[.25142,.74111,0,0,.27778],8741:[.08167,.58167,0,0,.38889],8742:[.25142,.74111,0,0,.5],8756:[0,.69224,0,0,.66667],8757:[0,.69224,0,0,.66667],8764:[-.13313,.36687,0,0,.77778],8765:[-.13313,.37788,0,0,.77778],8769:[-.13313,.36687,0,0,.77778],8770:[-.03625,.46375,0,0,.77778],8774:[.30274,.79383,0,0,.77778],8776:[-.01688,.48312,0,0,.77778],8778:[.08167,.58167,0,0,.77778],8782:[.06062,.54986,0,0,.77778],8783:[.06062,.54986,0,0,.77778],8785:[.08198,.58198,0,0,.77778],8786:[.08198,.58198,0,0,.77778],8787:[.08198,.58198,0,0,.77778],8790:[0,.69224,0,0,.77778],8791:[.22958,.72958,0,0,.77778],8796:[.08198,.91667,0,0,.77778],8806:[.25583,.75583,0,0,.77778],8807:[.25583,.75583,0,0,.77778],8808:[.25142,.75726,0,0,.77778],8809:[.25142,.75726,0,0,.77778],8812:[.25583,.75583,0,0,.5],8814:[.20576,.70576,0,0,.77778],8815:[.20576,.70576,0,0,.77778],8816:[.30274,.79383,0,0,.77778],8817:[.30274,.79383,0,0,.77778],8818:[.22958,.72958,0,0,.77778],8819:[.22958,.72958,0,0,.77778],8822:[.1808,.675,0,0,.77778],8823:[.1808,.675,0,0,.77778],8828:[.13667,.63667,0,0,.77778],8829:[.13667,.63667,0,0,.77778],8830:[.22958,.72958,0,0,.77778],8831:[.22958,.72958,0,0,.77778],8832:[.20576,.70576,0,0,.77778],8833:[.20576,.70576,0,0,.77778],8840:[.30274,.79383,0,0,.77778],8841:[.30274,.79383,0,0,.77778],8842:[.13597,.63597,0,0,.77778],8843:[.13597,.63597,0,0,.77778],8847:[.03517,.54986,0,0,.77778],8848:[.03517,.54986,0,0,.77778],8858:[.08198,.58198,0,0,.77778],8859:[.08198,.58198,0,0,.77778],8861:[.08198,.58198,0,0,.77778],8862:[0,.675,0,0,.77778],8863:[0,.675,0,0,.77778],8864:[0,.675,0,0,.77778],8865:[0,.675,0,0,.77778],8872:[0,.69224,0,0,.61111],8873:[0,.69224,0,0,.72222],8874:[0,.69224,0,0,.88889],8876:[0,.68889,0,0,.61111],8877:[0,.68889,0,0,.61111],8878:[0,.68889,0,0,.72222],8879:[0,.68889,0,0,.72222],8882:[.03517,.54986,0,0,.77778],8883:[.03517,.54986,0,0,.77778],8884:[.13667,.63667,0,0,.77778],8885:[.13667,.63667,0,0,.77778],8888:[0,.54986,0,0,1.11111],8890:[.19444,.43056,0,0,.55556],8891:[.19444,.69224,0,0,.61111],8892:[.19444,.69224,0,0,.61111],8901:[0,.54986,0,0,.27778],8903:[.08167,.58167,0,0,.77778],8905:[.08167,.58167,0,0,.77778],8906:[.08167,.58167,0,0,.77778],8907:[0,.69224,0,0,.77778],8908:[0,.69224,0,0,.77778],8909:[-.03598,.46402,0,0,.77778],8910:[0,.54986,0,0,.76042],8911:[0,.54986,0,0,.76042],8912:[.03517,.54986,0,0,.77778],8913:[.03517,.54986,0,0,.77778],8914:[0,.54986,0,0,.66667],8915:[0,.54986,0,0,.66667],8916:[0,.69224,0,0,.66667],8918:[.0391,.5391,0,0,.77778],8919:[.0391,.5391,0,0,.77778],8920:[.03517,.54986,0,0,1.33334],8921:[.03517,.54986,0,0,1.33334],8922:[.38569,.88569,0,0,.77778],8923:[.38569,.88569,0,0,.77778],8926:[.13667,.63667,0,0,.77778],8927:[.13667,.63667,0,0,.77778],8928:[.30274,.79383,0,0,.77778],8929:[.30274,.79383,0,0,.77778],8934:[.23222,.74111,0,0,.77778],8935:[.23222,.74111,0,0,.77778],8936:[.23222,.74111,0,0,.77778],8937:[.23222,.74111,0,0,.77778],8938:[.20576,.70576,0,0,.77778],8939:[.20576,.70576,0,0,.77778],8940:[.30274,.79383,0,0,.77778],8941:[.30274,.79383,0,0,.77778],8994:[.19444,.69224,0,0,.77778],8995:[.19444,.69224,0,0,.77778],9416:[.15559,.69224,0,0,.90222],9484:[0,.69224,0,0,.5],9488:[0,.69224,0,0,.5],9492:[0,.37788,0,0,.5],9496:[0,.37788,0,0,.5],9585:[.19444,.68889,0,0,.88889],9586:[.19444,.74111,0,0,.88889],9632:[0,.675,0,0,.77778],9633:[0,.675,0,0,.77778],9650:[0,.54986,0,0,.72222],9651:[0,.54986,0,0,.72222],9654:[.03517,.54986,0,0,.77778],9660:[0,.54986,0,0,.72222],9661:[0,.54986,0,0,.72222],9664:[.03517,.54986,0,0,.77778],9674:[.11111,.69224,0,0,.66667],9733:[.19444,.69224,0,0,.94445],10003:[0,.69224,0,0,.83334],10016:[0,.69224,0,0,.83334],10731:[.11111,.69224,0,0,.66667],10846:[.19444,.75583,0,0,.61111],10877:[.13667,.63667,0,0,.77778],10878:[.13667,.63667,0,0,.77778],10885:[.25583,.75583,0,0,.77778],10886:[.25583,.75583,0,0,.77778],10887:[.13597,.63597,0,0,.77778],10888:[.13597,.63597,0,0,.77778],10889:[.26167,.75726,0,0,.77778],10890:[.26167,.75726,0,0,.77778],10891:[.48256,.98256,0,0,.77778],10892:[.48256,.98256,0,0,.77778],10901:[.13667,.63667,0,0,.77778],10902:[.13667,.63667,0,0,.77778],10933:[.25142,.75726,0,0,.77778],10934:[.25142,.75726,0,0,.77778],10935:[.26167,.75726,0,0,.77778],10936:[.26167,.75726,0,0,.77778],10937:[.26167,.75726,0,0,.77778],10938:[.26167,.75726,0,0,.77778],10949:[.25583,.75583,0,0,.77778],10950:[.25583,.75583,0,0,.77778],10955:[.28481,.79383,0,0,.77778],10956:[.28481,.79383,0,0,.77778],57350:[.08167,.58167,0,0,.22222],57351:[.08167,.58167,0,0,.38889],57352:[.08167,.58167,0,0,.77778],57353:[0,.43056,.04028,0,.66667],57356:[.25142,.75726,0,0,.77778],57357:[.25142,.75726,0,0,.77778],57358:[.41951,.91951,0,0,.77778],57359:[.30274,.79383,0,0,.77778],57360:[.30274,.79383,0,0,.77778],57361:[.41951,.91951,0,0,.77778],57366:[.25142,.75726,0,0,.77778],57367:[.25142,.75726,0,0,.77778],57368:[.25142,.75726,0,0,.77778],57369:[.25142,.75726,0,0,.77778],57370:[.13597,.63597,0,0,.77778],57371:[.13597,.63597,0,0,.77778]},"Caligraphic-Regular":{32:[0,0,0,0,.25],65:[0,.68333,0,.19445,.79847],66:[0,.68333,.03041,.13889,.65681],67:[0,.68333,.05834,.13889,.52653],68:[0,.68333,.02778,.08334,.77139],69:[0,.68333,.08944,.11111,.52778],70:[0,.68333,.09931,.11111,.71875],71:[.09722,.68333,.0593,.11111,.59487],72:[0,.68333,.00965,.11111,.84452],73:[0,.68333,.07382,0,.54452],74:[.09722,.68333,.18472,.16667,.67778],75:[0,.68333,.01445,.05556,.76195],76:[0,.68333,0,.13889,.68972],77:[0,.68333,0,.13889,1.2009],78:[0,.68333,.14736,.08334,.82049],79:[0,.68333,.02778,.11111,.79611],80:[0,.68333,.08222,.08334,.69556],81:[.09722,.68333,0,.11111,.81667],82:[0,.68333,0,.08334,.8475],83:[0,.68333,.075,.13889,.60556],84:[0,.68333,.25417,0,.54464],85:[0,.68333,.09931,.08334,.62583],86:[0,.68333,.08222,0,.61278],87:[0,.68333,.08222,.08334,.98778],88:[0,.68333,.14643,.13889,.7133],89:[.09722,.68333,.08222,.08334,.66834],90:[0,.68333,.07944,.13889,.72473],160:[0,0,0,0,.25]},"Fraktur-Regular":{32:[0,0,0,0,.25],33:[0,.69141,0,0,.29574],34:[0,.69141,0,0,.21471],38:[0,.69141,0,0,.73786],39:[0,.69141,0,0,.21201],40:[.24982,.74947,0,0,.38865],41:[.24982,.74947,0,0,.38865],42:[0,.62119,0,0,.27764],43:[.08319,.58283,0,0,.75623],44:[0,.10803,0,0,.27764],45:[.08319,.58283,0,0,.75623],46:[0,.10803,0,0,.27764],47:[.24982,.74947,0,0,.50181],48:[0,.47534,0,0,.50181],49:[0,.47534,0,0,.50181],50:[0,.47534,0,0,.50181],51:[.18906,.47534,0,0,.50181],52:[.18906,.47534,0,0,.50181],53:[.18906,.47534,0,0,.50181],54:[0,.69141,0,0,.50181],55:[.18906,.47534,0,0,.50181],56:[0,.69141,0,0,.50181],57:[.18906,.47534,0,0,.50181],58:[0,.47534,0,0,.21606],59:[.12604,.47534,0,0,.21606],61:[-.13099,.36866,0,0,.75623],63:[0,.69141,0,0,.36245],65:[0,.69141,0,0,.7176],66:[0,.69141,0,0,.88397],67:[0,.69141,0,0,.61254],68:[0,.69141,0,0,.83158],69:[0,.69141,0,0,.66278],70:[.12604,.69141,0,0,.61119],71:[0,.69141,0,0,.78539],72:[.06302,.69141,0,0,.7203],73:[0,.69141,0,0,.55448],74:[.12604,.69141,0,0,.55231],75:[0,.69141,0,0,.66845],76:[0,.69141,0,0,.66602],77:[0,.69141,0,0,1.04953],78:[0,.69141,0,0,.83212],79:[0,.69141,0,0,.82699],80:[.18906,.69141,0,0,.82753],81:[.03781,.69141,0,0,.82699],82:[0,.69141,0,0,.82807],83:[0,.69141,0,0,.82861],84:[0,.69141,0,0,.66899],85:[0,.69141,0,0,.64576],86:[0,.69141,0,0,.83131],87:[0,.69141,0,0,1.04602],88:[0,.69141,0,0,.71922],89:[.18906,.69141,0,0,.83293],90:[.12604,.69141,0,0,.60201],91:[.24982,.74947,0,0,.27764],93:[.24982,.74947,0,0,.27764],94:[0,.69141,0,0,.49965],97:[0,.47534,0,0,.50046],98:[0,.69141,0,0,.51315],99:[0,.47534,0,0,.38946],100:[0,.62119,0,0,.49857],101:[0,.47534,0,0,.40053],102:[.18906,.69141,0,0,.32626],103:[.18906,.47534,0,0,.5037],104:[.18906,.69141,0,0,.52126],105:[0,.69141,0,0,.27899],106:[0,.69141,0,0,.28088],107:[0,.69141,0,0,.38946],108:[0,.69141,0,0,.27953],109:[0,.47534,0,0,.76676],110:[0,.47534,0,0,.52666],111:[0,.47534,0,0,.48885],112:[.18906,.52396,0,0,.50046],113:[.18906,.47534,0,0,.48912],114:[0,.47534,0,0,.38919],115:[0,.47534,0,0,.44266],116:[0,.62119,0,0,.33301],117:[0,.47534,0,0,.5172],118:[0,.52396,0,0,.5118],119:[0,.52396,0,0,.77351],120:[.18906,.47534,0,0,.38865],121:[.18906,.47534,0,0,.49884],122:[.18906,.47534,0,0,.39054],160:[0,0,0,0,.25],8216:[0,.69141,0,0,.21471],8217:[0,.69141,0,0,.21471],58112:[0,.62119,0,0,.49749],58113:[0,.62119,0,0,.4983],58114:[.18906,.69141,0,0,.33328],58115:[.18906,.69141,0,0,.32923],58116:[.18906,.47534,0,0,.50343],58117:[0,.69141,0,0,.33301],58118:[0,.62119,0,0,.33409],58119:[0,.47534,0,0,.50073]},"Main-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.35],34:[0,.69444,0,0,.60278],35:[.19444,.69444,0,0,.95833],36:[.05556,.75,0,0,.575],37:[.05556,.75,0,0,.95833],38:[0,.69444,0,0,.89444],39:[0,.69444,0,0,.31944],40:[.25,.75,0,0,.44722],41:[.25,.75,0,0,.44722],42:[0,.75,0,0,.575],43:[.13333,.63333,0,0,.89444],44:[.19444,.15556,0,0,.31944],45:[0,.44444,0,0,.38333],46:[0,.15556,0,0,.31944],47:[.25,.75,0,0,.575],48:[0,.64444,0,0,.575],49:[0,.64444,0,0,.575],50:[0,.64444,0,0,.575],51:[0,.64444,0,0,.575],52:[0,.64444,0,0,.575],53:[0,.64444,0,0,.575],54:[0,.64444,0,0,.575],55:[0,.64444,0,0,.575],56:[0,.64444,0,0,.575],57:[0,.64444,0,0,.575],58:[0,.44444,0,0,.31944],59:[.19444,.44444,0,0,.31944],60:[.08556,.58556,0,0,.89444],61:[-.10889,.39111,0,0,.89444],62:[.08556,.58556,0,0,.89444],63:[0,.69444,0,0,.54305],64:[0,.69444,0,0,.89444],65:[0,.68611,0,0,.86944],66:[0,.68611,0,0,.81805],67:[0,.68611,0,0,.83055],68:[0,.68611,0,0,.88194],69:[0,.68611,0,0,.75555],70:[0,.68611,0,0,.72361],71:[0,.68611,0,0,.90416],72:[0,.68611,0,0,.9],73:[0,.68611,0,0,.43611],74:[0,.68611,0,0,.59444],75:[0,.68611,0,0,.90138],76:[0,.68611,0,0,.69166],77:[0,.68611,0,0,1.09166],78:[0,.68611,0,0,.9],79:[0,.68611,0,0,.86388],80:[0,.68611,0,0,.78611],81:[.19444,.68611,0,0,.86388],82:[0,.68611,0,0,.8625],83:[0,.68611,0,0,.63889],84:[0,.68611,0,0,.8],85:[0,.68611,0,0,.88472],86:[0,.68611,.01597,0,.86944],87:[0,.68611,.01597,0,1.18888],88:[0,.68611,0,0,.86944],89:[0,.68611,.02875,0,.86944],90:[0,.68611,0,0,.70277],91:[.25,.75,0,0,.31944],92:[.25,.75,0,0,.575],93:[.25,.75,0,0,.31944],94:[0,.69444,0,0,.575],95:[.31,.13444,.03194,0,.575],97:[0,.44444,0,0,.55902],98:[0,.69444,0,0,.63889],99:[0,.44444,0,0,.51111],100:[0,.69444,0,0,.63889],101:[0,.44444,0,0,.52708],102:[0,.69444,.10903,0,.35139],103:[.19444,.44444,.01597,0,.575],104:[0,.69444,0,0,.63889],105:[0,.69444,0,0,.31944],106:[.19444,.69444,0,0,.35139],107:[0,.69444,0,0,.60694],108:[0,.69444,0,0,.31944],109:[0,.44444,0,0,.95833],110:[0,.44444,0,0,.63889],111:[0,.44444,0,0,.575],112:[.19444,.44444,0,0,.63889],113:[.19444,.44444,0,0,.60694],114:[0,.44444,0,0,.47361],115:[0,.44444,0,0,.45361],116:[0,.63492,0,0,.44722],117:[0,.44444,0,0,.63889],118:[0,.44444,.01597,0,.60694],119:[0,.44444,.01597,0,.83055],120:[0,.44444,0,0,.60694],121:[.19444,.44444,.01597,0,.60694],122:[0,.44444,0,0,.51111],123:[.25,.75,0,0,.575],124:[.25,.75,0,0,.31944],125:[.25,.75,0,0,.575],126:[.35,.34444,0,0,.575],160:[0,0,0,0,.25],163:[0,.69444,0,0,.86853],168:[0,.69444,0,0,.575],172:[0,.44444,0,0,.76666],176:[0,.69444,0,0,.86944],177:[.13333,.63333,0,0,.89444],184:[.17014,0,0,0,.51111],198:[0,.68611,0,0,1.04166],215:[.13333,.63333,0,0,.89444],216:[.04861,.73472,0,0,.89444],223:[0,.69444,0,0,.59722],230:[0,.44444,0,0,.83055],247:[.13333,.63333,0,0,.89444],248:[.09722,.54167,0,0,.575],305:[0,.44444,0,0,.31944],338:[0,.68611,0,0,1.16944],339:[0,.44444,0,0,.89444],567:[.19444,.44444,0,0,.35139],710:[0,.69444,0,0,.575],711:[0,.63194,0,0,.575],713:[0,.59611,0,0,.575],714:[0,.69444,0,0,.575],715:[0,.69444,0,0,.575],728:[0,.69444,0,0,.575],729:[0,.69444,0,0,.31944],730:[0,.69444,0,0,.86944],732:[0,.69444,0,0,.575],733:[0,.69444,0,0,.575],915:[0,.68611,0,0,.69166],916:[0,.68611,0,0,.95833],920:[0,.68611,0,0,.89444],923:[0,.68611,0,0,.80555],926:[0,.68611,0,0,.76666],928:[0,.68611,0,0,.9],931:[0,.68611,0,0,.83055],933:[0,.68611,0,0,.89444],934:[0,.68611,0,0,.83055],936:[0,.68611,0,0,.89444],937:[0,.68611,0,0,.83055],8211:[0,.44444,.03194,0,.575],8212:[0,.44444,.03194,0,1.14999],8216:[0,.69444,0,0,.31944],8217:[0,.69444,0,0,.31944],8220:[0,.69444,0,0,.60278],8221:[0,.69444,0,0,.60278],8224:[.19444,.69444,0,0,.51111],8225:[.19444,.69444,0,0,.51111],8242:[0,.55556,0,0,.34444],8407:[0,.72444,.15486,0,.575],8463:[0,.69444,0,0,.66759],8465:[0,.69444,0,0,.83055],8467:[0,.69444,0,0,.47361],8472:[.19444,.44444,0,0,.74027],8476:[0,.69444,0,0,.83055],8501:[0,.69444,0,0,.70277],8592:[-.10889,.39111,0,0,1.14999],8593:[.19444,.69444,0,0,.575],8594:[-.10889,.39111,0,0,1.14999],8595:[.19444,.69444,0,0,.575],8596:[-.10889,.39111,0,0,1.14999],8597:[.25,.75,0,0,.575],8598:[.19444,.69444,0,0,1.14999],8599:[.19444,.69444,0,0,1.14999],8600:[.19444,.69444,0,0,1.14999],8601:[.19444,.69444,0,0,1.14999],8636:[-.10889,.39111,0,0,1.14999],8637:[-.10889,.39111,0,0,1.14999],8640:[-.10889,.39111,0,0,1.14999],8641:[-.10889,.39111,0,0,1.14999],8656:[-.10889,.39111,0,0,1.14999],8657:[.19444,.69444,0,0,.70277],8658:[-.10889,.39111,0,0,1.14999],8659:[.19444,.69444,0,0,.70277],8660:[-.10889,.39111,0,0,1.14999],8661:[.25,.75,0,0,.70277],8704:[0,.69444,0,0,.63889],8706:[0,.69444,.06389,0,.62847],8707:[0,.69444,0,0,.63889],8709:[.05556,.75,0,0,.575],8711:[0,.68611,0,0,.95833],8712:[.08556,.58556,0,0,.76666],8715:[.08556,.58556,0,0,.76666],8722:[.13333,.63333,0,0,.89444],8723:[.13333,.63333,0,0,.89444],8725:[.25,.75,0,0,.575],8726:[.25,.75,0,0,.575],8727:[-.02778,.47222,0,0,.575],8728:[-.02639,.47361,0,0,.575],8729:[-.02639,.47361,0,0,.575],8730:[.18,.82,0,0,.95833],8733:[0,.44444,0,0,.89444],8734:[0,.44444,0,0,1.14999],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.31944],8741:[.25,.75,0,0,.575],8743:[0,.55556,0,0,.76666],8744:[0,.55556,0,0,.76666],8745:[0,.55556,0,0,.76666],8746:[0,.55556,0,0,.76666],8747:[.19444,.69444,.12778,0,.56875],8764:[-.10889,.39111,0,0,.89444],8768:[.19444,.69444,0,0,.31944],8771:[.00222,.50222,0,0,.89444],8773:[.027,.638,0,0,.894],8776:[.02444,.52444,0,0,.89444],8781:[.00222,.50222,0,0,.89444],8801:[.00222,.50222,0,0,.89444],8804:[.19667,.69667,0,0,.89444],8805:[.19667,.69667,0,0,.89444],8810:[.08556,.58556,0,0,1.14999],8811:[.08556,.58556,0,0,1.14999],8826:[.08556,.58556,0,0,.89444],8827:[.08556,.58556,0,0,.89444],8834:[.08556,.58556,0,0,.89444],8835:[.08556,.58556,0,0,.89444],8838:[.19667,.69667,0,0,.89444],8839:[.19667,.69667,0,0,.89444],8846:[0,.55556,0,0,.76666],8849:[.19667,.69667,0,0,.89444],8850:[.19667,.69667,0,0,.89444],8851:[0,.55556,0,0,.76666],8852:[0,.55556,0,0,.76666],8853:[.13333,.63333,0,0,.89444],8854:[.13333,.63333,0,0,.89444],8855:[.13333,.63333,0,0,.89444],8856:[.13333,.63333,0,0,.89444],8857:[.13333,.63333,0,0,.89444],8866:[0,.69444,0,0,.70277],8867:[0,.69444,0,0,.70277],8868:[0,.69444,0,0,.89444],8869:[0,.69444,0,0,.89444],8900:[-.02639,.47361,0,0,.575],8901:[-.02639,.47361,0,0,.31944],8902:[-.02778,.47222,0,0,.575],8968:[.25,.75,0,0,.51111],8969:[.25,.75,0,0,.51111],8970:[.25,.75,0,0,.51111],8971:[.25,.75,0,0,.51111],8994:[-.13889,.36111,0,0,1.14999],8995:[-.13889,.36111,0,0,1.14999],9651:[.19444,.69444,0,0,1.02222],9657:[-.02778,.47222,0,0,.575],9661:[.19444,.69444,0,0,1.02222],9667:[-.02778,.47222,0,0,.575],9711:[.19444,.69444,0,0,1.14999],9824:[.12963,.69444,0,0,.89444],9825:[.12963,.69444,0,0,.89444],9826:[.12963,.69444,0,0,.89444],9827:[.12963,.69444,0,0,.89444],9837:[0,.75,0,0,.44722],9838:[.19444,.69444,0,0,.44722],9839:[.19444,.69444,0,0,.44722],10216:[.25,.75,0,0,.44722],10217:[.25,.75,0,0,.44722],10815:[0,.68611,0,0,.9],10927:[.19667,.69667,0,0,.89444],10928:[.19667,.69667,0,0,.89444],57376:[.19444,.69444,0,0,0]},"Main-BoldItalic":{32:[0,0,0,0,.25],33:[0,.69444,.11417,0,.38611],34:[0,.69444,.07939,0,.62055],35:[.19444,.69444,.06833,0,.94444],37:[.05556,.75,.12861,0,.94444],38:[0,.69444,.08528,0,.88555],39:[0,.69444,.12945,0,.35555],40:[.25,.75,.15806,0,.47333],41:[.25,.75,.03306,0,.47333],42:[0,.75,.14333,0,.59111],43:[.10333,.60333,.03306,0,.88555],44:[.19444,.14722,0,0,.35555],45:[0,.44444,.02611,0,.41444],46:[0,.14722,0,0,.35555],47:[.25,.75,.15806,0,.59111],48:[0,.64444,.13167,0,.59111],49:[0,.64444,.13167,0,.59111],50:[0,.64444,.13167,0,.59111],51:[0,.64444,.13167,0,.59111],52:[.19444,.64444,.13167,0,.59111],53:[0,.64444,.13167,0,.59111],54:[0,.64444,.13167,0,.59111],55:[.19444,.64444,.13167,0,.59111],56:[0,.64444,.13167,0,.59111],57:[0,.64444,.13167,0,.59111],58:[0,.44444,.06695,0,.35555],59:[.19444,.44444,.06695,0,.35555],61:[-.10889,.39111,.06833,0,.88555],63:[0,.69444,.11472,0,.59111],64:[0,.69444,.09208,0,.88555],65:[0,.68611,0,0,.86555],66:[0,.68611,.0992,0,.81666],67:[0,.68611,.14208,0,.82666],68:[0,.68611,.09062,0,.87555],69:[0,.68611,.11431,0,.75666],70:[0,.68611,.12903,0,.72722],71:[0,.68611,.07347,0,.89527],72:[0,.68611,.17208,0,.8961],73:[0,.68611,.15681,0,.47166],74:[0,.68611,.145,0,.61055],75:[0,.68611,.14208,0,.89499],76:[0,.68611,0,0,.69777],77:[0,.68611,.17208,0,1.07277],78:[0,.68611,.17208,0,.8961],79:[0,.68611,.09062,0,.85499],80:[0,.68611,.0992,0,.78721],81:[.19444,.68611,.09062,0,.85499],82:[0,.68611,.02559,0,.85944],83:[0,.68611,.11264,0,.64999],84:[0,.68611,.12903,0,.7961],85:[0,.68611,.17208,0,.88083],86:[0,.68611,.18625,0,.86555],87:[0,.68611,.18625,0,1.15999],88:[0,.68611,.15681,0,.86555],89:[0,.68611,.19803,0,.86555],90:[0,.68611,.14208,0,.70888],91:[.25,.75,.1875,0,.35611],93:[.25,.75,.09972,0,.35611],94:[0,.69444,.06709,0,.59111],95:[.31,.13444,.09811,0,.59111],97:[0,.44444,.09426,0,.59111],98:[0,.69444,.07861,0,.53222],99:[0,.44444,.05222,0,.53222],100:[0,.69444,.10861,0,.59111],101:[0,.44444,.085,0,.53222],102:[.19444,.69444,.21778,0,.4],103:[.19444,.44444,.105,0,.53222],104:[0,.69444,.09426,0,.59111],105:[0,.69326,.11387,0,.35555],106:[.19444,.69326,.1672,0,.35555],107:[0,.69444,.11111,0,.53222],108:[0,.69444,.10861,0,.29666],109:[0,.44444,.09426,0,.94444],110:[0,.44444,.09426,0,.64999],111:[0,.44444,.07861,0,.59111],112:[.19444,.44444,.07861,0,.59111],113:[.19444,.44444,.105,0,.53222],114:[0,.44444,.11111,0,.50167],115:[0,.44444,.08167,0,.48694],116:[0,.63492,.09639,0,.385],117:[0,.44444,.09426,0,.62055],118:[0,.44444,.11111,0,.53222],119:[0,.44444,.11111,0,.76777],120:[0,.44444,.12583,0,.56055],121:[.19444,.44444,.105,0,.56166],122:[0,.44444,.13889,0,.49055],126:[.35,.34444,.11472,0,.59111],160:[0,0,0,0,.25],168:[0,.69444,.11473,0,.59111],176:[0,.69444,0,0,.94888],184:[.17014,0,0,0,.53222],198:[0,.68611,.11431,0,1.02277],216:[.04861,.73472,.09062,0,.88555],223:[.19444,.69444,.09736,0,.665],230:[0,.44444,.085,0,.82666],248:[.09722,.54167,.09458,0,.59111],305:[0,.44444,.09426,0,.35555],338:[0,.68611,.11431,0,1.14054],339:[0,.44444,.085,0,.82666],567:[.19444,.44444,.04611,0,.385],710:[0,.69444,.06709,0,.59111],711:[0,.63194,.08271,0,.59111],713:[0,.59444,.10444,0,.59111],714:[0,.69444,.08528,0,.59111],715:[0,.69444,0,0,.59111],728:[0,.69444,.10333,0,.59111],729:[0,.69444,.12945,0,.35555],730:[0,.69444,0,0,.94888],732:[0,.69444,.11472,0,.59111],733:[0,.69444,.11472,0,.59111],915:[0,.68611,.12903,0,.69777],916:[0,.68611,0,0,.94444],920:[0,.68611,.09062,0,.88555],923:[0,.68611,0,0,.80666],926:[0,.68611,.15092,0,.76777],928:[0,.68611,.17208,0,.8961],931:[0,.68611,.11431,0,.82666],933:[0,.68611,.10778,0,.88555],934:[0,.68611,.05632,0,.82666],936:[0,.68611,.10778,0,.88555],937:[0,.68611,.0992,0,.82666],8211:[0,.44444,.09811,0,.59111],8212:[0,.44444,.09811,0,1.18221],8216:[0,.69444,.12945,0,.35555],8217:[0,.69444,.12945,0,.35555],8220:[0,.69444,.16772,0,.62055],8221:[0,.69444,.07939,0,.62055]},"Main-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.12417,0,.30667],34:[0,.69444,.06961,0,.51444],35:[.19444,.69444,.06616,0,.81777],37:[.05556,.75,.13639,0,.81777],38:[0,.69444,.09694,0,.76666],39:[0,.69444,.12417,0,.30667],40:[.25,.75,.16194,0,.40889],41:[.25,.75,.03694,0,.40889],42:[0,.75,.14917,0,.51111],43:[.05667,.56167,.03694,0,.76666],44:[.19444,.10556,0,0,.30667],45:[0,.43056,.02826,0,.35778],46:[0,.10556,0,0,.30667],47:[.25,.75,.16194,0,.51111],48:[0,.64444,.13556,0,.51111],49:[0,.64444,.13556,0,.51111],50:[0,.64444,.13556,0,.51111],51:[0,.64444,.13556,0,.51111],52:[.19444,.64444,.13556,0,.51111],53:[0,.64444,.13556,0,.51111],54:[0,.64444,.13556,0,.51111],55:[.19444,.64444,.13556,0,.51111],56:[0,.64444,.13556,0,.51111],57:[0,.64444,.13556,0,.51111],58:[0,.43056,.0582,0,.30667],59:[.19444,.43056,.0582,0,.30667],61:[-.13313,.36687,.06616,0,.76666],63:[0,.69444,.1225,0,.51111],64:[0,.69444,.09597,0,.76666],65:[0,.68333,0,0,.74333],66:[0,.68333,.10257,0,.70389],67:[0,.68333,.14528,0,.71555],68:[0,.68333,.09403,0,.755],69:[0,.68333,.12028,0,.67833],70:[0,.68333,.13305,0,.65277],71:[0,.68333,.08722,0,.77361],72:[0,.68333,.16389,0,.74333],73:[0,.68333,.15806,0,.38555],74:[0,.68333,.14028,0,.525],75:[0,.68333,.14528,0,.76888],76:[0,.68333,0,0,.62722],77:[0,.68333,.16389,0,.89666],78:[0,.68333,.16389,0,.74333],79:[0,.68333,.09403,0,.76666],80:[0,.68333,.10257,0,.67833],81:[.19444,.68333,.09403,0,.76666],82:[0,.68333,.03868,0,.72944],83:[0,.68333,.11972,0,.56222],84:[0,.68333,.13305,0,.71555],85:[0,.68333,.16389,0,.74333],86:[0,.68333,.18361,0,.74333],87:[0,.68333,.18361,0,.99888],88:[0,.68333,.15806,0,.74333],89:[0,.68333,.19383,0,.74333],90:[0,.68333,.14528,0,.61333],91:[.25,.75,.1875,0,.30667],93:[.25,.75,.10528,0,.30667],94:[0,.69444,.06646,0,.51111],95:[.31,.12056,.09208,0,.51111],97:[0,.43056,.07671,0,.51111],98:[0,.69444,.06312,0,.46],99:[0,.43056,.05653,0,.46],100:[0,.69444,.10333,0,.51111],101:[0,.43056,.07514,0,.46],102:[.19444,.69444,.21194,0,.30667],103:[.19444,.43056,.08847,0,.46],104:[0,.69444,.07671,0,.51111],105:[0,.65536,.1019,0,.30667],106:[.19444,.65536,.14467,0,.30667],107:[0,.69444,.10764,0,.46],108:[0,.69444,.10333,0,.25555],109:[0,.43056,.07671,0,.81777],110:[0,.43056,.07671,0,.56222],111:[0,.43056,.06312,0,.51111],112:[.19444,.43056,.06312,0,.51111],113:[.19444,.43056,.08847,0,.46],114:[0,.43056,.10764,0,.42166],115:[0,.43056,.08208,0,.40889],116:[0,.61508,.09486,0,.33222],117:[0,.43056,.07671,0,.53666],118:[0,.43056,.10764,0,.46],119:[0,.43056,.10764,0,.66444],120:[0,.43056,.12042,0,.46389],121:[.19444,.43056,.08847,0,.48555],122:[0,.43056,.12292,0,.40889],126:[.35,.31786,.11585,0,.51111],160:[0,0,0,0,.25],168:[0,.66786,.10474,0,.51111],176:[0,.69444,0,0,.83129],184:[.17014,0,0,0,.46],198:[0,.68333,.12028,0,.88277],216:[.04861,.73194,.09403,0,.76666],223:[.19444,.69444,.10514,0,.53666],230:[0,.43056,.07514,0,.71555],248:[.09722,.52778,.09194,0,.51111],338:[0,.68333,.12028,0,.98499],339:[0,.43056,.07514,0,.71555],710:[0,.69444,.06646,0,.51111],711:[0,.62847,.08295,0,.51111],713:[0,.56167,.10333,0,.51111],714:[0,.69444,.09694,0,.51111],715:[0,.69444,0,0,.51111],728:[0,.69444,.10806,0,.51111],729:[0,.66786,.11752,0,.30667],730:[0,.69444,0,0,.83129],732:[0,.66786,.11585,0,.51111],733:[0,.69444,.1225,0,.51111],915:[0,.68333,.13305,0,.62722],916:[0,.68333,0,0,.81777],920:[0,.68333,.09403,0,.76666],923:[0,.68333,0,0,.69222],926:[0,.68333,.15294,0,.66444],928:[0,.68333,.16389,0,.74333],931:[0,.68333,.12028,0,.71555],933:[0,.68333,.11111,0,.76666],934:[0,.68333,.05986,0,.71555],936:[0,.68333,.11111,0,.76666],937:[0,.68333,.10257,0,.71555],8211:[0,.43056,.09208,0,.51111],8212:[0,.43056,.09208,0,1.02222],8216:[0,.69444,.12417,0,.30667],8217:[0,.69444,.12417,0,.30667],8220:[0,.69444,.1685,0,.51444],8221:[0,.69444,.06961,0,.51444],8463:[0,.68889,0,0,.54028]},"Main-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.27778],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.77778],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.19444,.10556,0,0,.27778],45:[0,.43056,0,0,.33333],46:[0,.10556,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.64444,0,0,.5],49:[0,.64444,0,0,.5],50:[0,.64444,0,0,.5],51:[0,.64444,0,0,.5],52:[0,.64444,0,0,.5],53:[0,.64444,0,0,.5],54:[0,.64444,0,0,.5],55:[0,.64444,0,0,.5],56:[0,.64444,0,0,.5],57:[0,.64444,0,0,.5],58:[0,.43056,0,0,.27778],59:[.19444,.43056,0,0,.27778],60:[.0391,.5391,0,0,.77778],61:[-.13313,.36687,0,0,.77778],62:[.0391,.5391,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.77778],65:[0,.68333,0,0,.75],66:[0,.68333,0,0,.70834],67:[0,.68333,0,0,.72222],68:[0,.68333,0,0,.76389],69:[0,.68333,0,0,.68056],70:[0,.68333,0,0,.65278],71:[0,.68333,0,0,.78472],72:[0,.68333,0,0,.75],73:[0,.68333,0,0,.36111],74:[0,.68333,0,0,.51389],75:[0,.68333,0,0,.77778],76:[0,.68333,0,0,.625],77:[0,.68333,0,0,.91667],78:[0,.68333,0,0,.75],79:[0,.68333,0,0,.77778],80:[0,.68333,0,0,.68056],81:[.19444,.68333,0,0,.77778],82:[0,.68333,0,0,.73611],83:[0,.68333,0,0,.55556],84:[0,.68333,0,0,.72222],85:[0,.68333,0,0,.75],86:[0,.68333,.01389,0,.75],87:[0,.68333,.01389,0,1.02778],88:[0,.68333,0,0,.75],89:[0,.68333,.025,0,.75],90:[0,.68333,0,0,.61111],91:[.25,.75,0,0,.27778],92:[.25,.75,0,0,.5],93:[.25,.75,0,0,.27778],94:[0,.69444,0,0,.5],95:[.31,.12056,.02778,0,.5],97:[0,.43056,0,0,.5],98:[0,.69444,0,0,.55556],99:[0,.43056,0,0,.44445],100:[0,.69444,0,0,.55556],101:[0,.43056,0,0,.44445],102:[0,.69444,.07778,0,.30556],103:[.19444,.43056,.01389,0,.5],104:[0,.69444,0,0,.55556],105:[0,.66786,0,0,.27778],106:[.19444,.66786,0,0,.30556],107:[0,.69444,0,0,.52778],108:[0,.69444,0,0,.27778],109:[0,.43056,0,0,.83334],110:[0,.43056,0,0,.55556],111:[0,.43056,0,0,.5],112:[.19444,.43056,0,0,.55556],113:[.19444,.43056,0,0,.52778],114:[0,.43056,0,0,.39167],115:[0,.43056,0,0,.39445],116:[0,.61508,0,0,.38889],117:[0,.43056,0,0,.55556],118:[0,.43056,.01389,0,.52778],119:[0,.43056,.01389,0,.72222],120:[0,.43056,0,0,.52778],121:[.19444,.43056,.01389,0,.52778],122:[0,.43056,0,0,.44445],123:[.25,.75,0,0,.5],124:[.25,.75,0,0,.27778],125:[.25,.75,0,0,.5],126:[.35,.31786,0,0,.5],160:[0,0,0,0,.25],163:[0,.69444,0,0,.76909],167:[.19444,.69444,0,0,.44445],168:[0,.66786,0,0,.5],172:[0,.43056,0,0,.66667],176:[0,.69444,0,0,.75],177:[.08333,.58333,0,0,.77778],182:[.19444,.69444,0,0,.61111],184:[.17014,0,0,0,.44445],198:[0,.68333,0,0,.90278],215:[.08333,.58333,0,0,.77778],216:[.04861,.73194,0,0,.77778],223:[0,.69444,0,0,.5],230:[0,.43056,0,0,.72222],247:[.08333,.58333,0,0,.77778],248:[.09722,.52778,0,0,.5],305:[0,.43056,0,0,.27778],338:[0,.68333,0,0,1.01389],339:[0,.43056,0,0,.77778],567:[.19444,.43056,0,0,.30556],710:[0,.69444,0,0,.5],711:[0,.62847,0,0,.5],713:[0,.56778,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.66786,0,0,.27778],730:[0,.69444,0,0,.75],732:[0,.66786,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.68333,0,0,.625],916:[0,.68333,0,0,.83334],920:[0,.68333,0,0,.77778],923:[0,.68333,0,0,.69445],926:[0,.68333,0,0,.66667],928:[0,.68333,0,0,.75],931:[0,.68333,0,0,.72222],933:[0,.68333,0,0,.77778],934:[0,.68333,0,0,.72222],936:[0,.68333,0,0,.77778],937:[0,.68333,0,0,.72222],8211:[0,.43056,.02778,0,.5],8212:[0,.43056,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5],8224:[.19444,.69444,0,0,.44445],8225:[.19444,.69444,0,0,.44445],8230:[0,.123,0,0,1.172],8242:[0,.55556,0,0,.275],8407:[0,.71444,.15382,0,.5],8463:[0,.68889,0,0,.54028],8465:[0,.69444,0,0,.72222],8467:[0,.69444,0,.11111,.41667],8472:[.19444,.43056,0,.11111,.63646],8476:[0,.69444,0,0,.72222],8501:[0,.69444,0,0,.61111],8592:[-.13313,.36687,0,0,1],8593:[.19444,.69444,0,0,.5],8594:[-.13313,.36687,0,0,1],8595:[.19444,.69444,0,0,.5],8596:[-.13313,.36687,0,0,1],8597:[.25,.75,0,0,.5],8598:[.19444,.69444,0,0,1],8599:[.19444,.69444,0,0,1],8600:[.19444,.69444,0,0,1],8601:[.19444,.69444,0,0,1],8614:[.011,.511,0,0,1],8617:[.011,.511,0,0,1.126],8618:[.011,.511,0,0,1.126],8636:[-.13313,.36687,0,0,1],8637:[-.13313,.36687,0,0,1],8640:[-.13313,.36687,0,0,1],8641:[-.13313,.36687,0,0,1],8652:[.011,.671,0,0,1],8656:[-.13313,.36687,0,0,1],8657:[.19444,.69444,0,0,.61111],8658:[-.13313,.36687,0,0,1],8659:[.19444,.69444,0,0,.61111],8660:[-.13313,.36687,0,0,1],8661:[.25,.75,0,0,.61111],8704:[0,.69444,0,0,.55556],8706:[0,.69444,.05556,.08334,.5309],8707:[0,.69444,0,0,.55556],8709:[.05556,.75,0,0,.5],8711:[0,.68333,0,0,.83334],8712:[.0391,.5391,0,0,.66667],8715:[.0391,.5391,0,0,.66667],8722:[.08333,.58333,0,0,.77778],8723:[.08333,.58333,0,0,.77778],8725:[.25,.75,0,0,.5],8726:[.25,.75,0,0,.5],8727:[-.03472,.46528,0,0,.5],8728:[-.05555,.44445,0,0,.5],8729:[-.05555,.44445,0,0,.5],8730:[.2,.8,0,0,.83334],8733:[0,.43056,0,0,.77778],8734:[0,.43056,0,0,1],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.27778],8741:[.25,.75,0,0,.5],8743:[0,.55556,0,0,.66667],8744:[0,.55556,0,0,.66667],8745:[0,.55556,0,0,.66667],8746:[0,.55556,0,0,.66667],8747:[.19444,.69444,.11111,0,.41667],8764:[-.13313,.36687,0,0,.77778],8768:[.19444,.69444,0,0,.27778],8771:[-.03625,.46375,0,0,.77778],8773:[-.022,.589,0,0,.778],8776:[-.01688,.48312,0,0,.77778],8781:[-.03625,.46375,0,0,.77778],8784:[-.133,.673,0,0,.778],8801:[-.03625,.46375,0,0,.77778],8804:[.13597,.63597,0,0,.77778],8805:[.13597,.63597,0,0,.77778],8810:[.0391,.5391,0,0,1],8811:[.0391,.5391,0,0,1],8826:[.0391,.5391,0,0,.77778],8827:[.0391,.5391,0,0,.77778],8834:[.0391,.5391,0,0,.77778],8835:[.0391,.5391,0,0,.77778],8838:[.13597,.63597,0,0,.77778],8839:[.13597,.63597,0,0,.77778],8846:[0,.55556,0,0,.66667],8849:[.13597,.63597,0,0,.77778],8850:[.13597,.63597,0,0,.77778],8851:[0,.55556,0,0,.66667],8852:[0,.55556,0,0,.66667],8853:[.08333,.58333,0,0,.77778],8854:[.08333,.58333,0,0,.77778],8855:[.08333,.58333,0,0,.77778],8856:[.08333,.58333,0,0,.77778],8857:[.08333,.58333,0,0,.77778],8866:[0,.69444,0,0,.61111],8867:[0,.69444,0,0,.61111],8868:[0,.69444,0,0,.77778],8869:[0,.69444,0,0,.77778],8872:[.249,.75,0,0,.867],8900:[-.05555,.44445,0,0,.5],8901:[-.05555,.44445,0,0,.27778],8902:[-.03472,.46528,0,0,.5],8904:[.005,.505,0,0,.9],8942:[.03,.903,0,0,.278],8943:[-.19,.313,0,0,1.172],8945:[-.1,.823,0,0,1.282],8968:[.25,.75,0,0,.44445],8969:[.25,.75,0,0,.44445],8970:[.25,.75,0,0,.44445],8971:[.25,.75,0,0,.44445],8994:[-.14236,.35764,0,0,1],8995:[-.14236,.35764,0,0,1],9136:[.244,.744,0,0,.412],9137:[.244,.745,0,0,.412],9651:[.19444,.69444,0,0,.88889],9657:[-.03472,.46528,0,0,.5],9661:[.19444,.69444,0,0,.88889],9667:[-.03472,.46528,0,0,.5],9711:[.19444,.69444,0,0,1],9824:[.12963,.69444,0,0,.77778],9825:[.12963,.69444,0,0,.77778],9826:[.12963,.69444,0,0,.77778],9827:[.12963,.69444,0,0,.77778],9837:[0,.75,0,0,.38889],9838:[.19444,.69444,0,0,.38889],9839:[.19444,.69444,0,0,.38889],10216:[.25,.75,0,0,.38889],10217:[.25,.75,0,0,.38889],10222:[.244,.744,0,0,.412],10223:[.244,.745,0,0,.412],10229:[.011,.511,0,0,1.609],10230:[.011,.511,0,0,1.638],10231:[.011,.511,0,0,1.859],10232:[.024,.525,0,0,1.609],10233:[.024,.525,0,0,1.638],10234:[.024,.525,0,0,1.858],10236:[.011,.511,0,0,1.638],10815:[0,.68333,0,0,.75],10927:[.13597,.63597,0,0,.77778],10928:[.13597,.63597,0,0,.77778],57376:[.19444,.69444,0,0,0]},"Math-BoldItalic":{32:[0,0,0,0,.25],48:[0,.44444,0,0,.575],49:[0,.44444,0,0,.575],50:[0,.44444,0,0,.575],51:[.19444,.44444,0,0,.575],52:[.19444,.44444,0,0,.575],53:[.19444,.44444,0,0,.575],54:[0,.64444,0,0,.575],55:[.19444,.44444,0,0,.575],56:[0,.64444,0,0,.575],57:[.19444,.44444,0,0,.575],65:[0,.68611,0,0,.86944],66:[0,.68611,.04835,0,.8664],67:[0,.68611,.06979,0,.81694],68:[0,.68611,.03194,0,.93812],69:[0,.68611,.05451,0,.81007],70:[0,.68611,.15972,0,.68889],71:[0,.68611,0,0,.88673],72:[0,.68611,.08229,0,.98229],73:[0,.68611,.07778,0,.51111],74:[0,.68611,.10069,0,.63125],75:[0,.68611,.06979,0,.97118],76:[0,.68611,0,0,.75555],77:[0,.68611,.11424,0,1.14201],78:[0,.68611,.11424,0,.95034],79:[0,.68611,.03194,0,.83666],80:[0,.68611,.15972,0,.72309],81:[.19444,.68611,0,0,.86861],82:[0,.68611,.00421,0,.87235],83:[0,.68611,.05382,0,.69271],84:[0,.68611,.15972,0,.63663],85:[0,.68611,.11424,0,.80027],86:[0,.68611,.25555,0,.67778],87:[0,.68611,.15972,0,1.09305],88:[0,.68611,.07778,0,.94722],89:[0,.68611,.25555,0,.67458],90:[0,.68611,.06979,0,.77257],97:[0,.44444,0,0,.63287],98:[0,.69444,0,0,.52083],99:[0,.44444,0,0,.51342],100:[0,.69444,0,0,.60972],101:[0,.44444,0,0,.55361],102:[.19444,.69444,.11042,0,.56806],103:[.19444,.44444,.03704,0,.5449],104:[0,.69444,0,0,.66759],105:[0,.69326,0,0,.4048],106:[.19444,.69326,.0622,0,.47083],107:[0,.69444,.01852,0,.6037],108:[0,.69444,.0088,0,.34815],109:[0,.44444,0,0,1.0324],110:[0,.44444,0,0,.71296],111:[0,.44444,0,0,.58472],112:[.19444,.44444,0,0,.60092],113:[.19444,.44444,.03704,0,.54213],114:[0,.44444,.03194,0,.5287],115:[0,.44444,0,0,.53125],116:[0,.63492,0,0,.41528],117:[0,.44444,0,0,.68102],118:[0,.44444,.03704,0,.56666],119:[0,.44444,.02778,0,.83148],120:[0,.44444,0,0,.65903],121:[.19444,.44444,.03704,0,.59028],122:[0,.44444,.04213,0,.55509],160:[0,0,0,0,.25],915:[0,.68611,.15972,0,.65694],916:[0,.68611,0,0,.95833],920:[0,.68611,.03194,0,.86722],923:[0,.68611,0,0,.80555],926:[0,.68611,.07458,0,.84125],928:[0,.68611,.08229,0,.98229],931:[0,.68611,.05451,0,.88507],933:[0,.68611,.15972,0,.67083],934:[0,.68611,0,0,.76666],936:[0,.68611,.11653,0,.71402],937:[0,.68611,.04835,0,.8789],945:[0,.44444,0,0,.76064],946:[.19444,.69444,.03403,0,.65972],947:[.19444,.44444,.06389,0,.59003],948:[0,.69444,.03819,0,.52222],949:[0,.44444,0,0,.52882],950:[.19444,.69444,.06215,0,.50833],951:[.19444,.44444,.03704,0,.6],952:[0,.69444,.03194,0,.5618],953:[0,.44444,0,0,.41204],954:[0,.44444,0,0,.66759],955:[0,.69444,0,0,.67083],956:[.19444,.44444,0,0,.70787],957:[0,.44444,.06898,0,.57685],958:[.19444,.69444,.03021,0,.50833],959:[0,.44444,0,0,.58472],960:[0,.44444,.03704,0,.68241],961:[.19444,.44444,0,0,.6118],962:[.09722,.44444,.07917,0,.42361],963:[0,.44444,.03704,0,.68588],964:[0,.44444,.13472,0,.52083],965:[0,.44444,.03704,0,.63055],966:[.19444,.44444,0,0,.74722],967:[.19444,.44444,0,0,.71805],968:[.19444,.69444,.03704,0,.75833],969:[0,.44444,.03704,0,.71782],977:[0,.69444,0,0,.69155],981:[.19444,.69444,0,0,.7125],982:[0,.44444,.03194,0,.975],1009:[.19444,.44444,0,0,.6118],1013:[0,.44444,0,0,.48333],57649:[0,.44444,0,0,.39352],57911:[.19444,.44444,0,0,.43889]},"Math-Italic":{32:[0,0,0,0,.25],48:[0,.43056,0,0,.5],49:[0,.43056,0,0,.5],50:[0,.43056,0,0,.5],51:[.19444,.43056,0,0,.5],52:[.19444,.43056,0,0,.5],53:[.19444,.43056,0,0,.5],54:[0,.64444,0,0,.5],55:[.19444,.43056,0,0,.5],56:[0,.64444,0,0,.5],57:[.19444,.43056,0,0,.5],65:[0,.68333,0,.13889,.75],66:[0,.68333,.05017,.08334,.75851],67:[0,.68333,.07153,.08334,.71472],68:[0,.68333,.02778,.05556,.82792],69:[0,.68333,.05764,.08334,.7382],70:[0,.68333,.13889,.08334,.64306],71:[0,.68333,0,.08334,.78625],72:[0,.68333,.08125,.05556,.83125],73:[0,.68333,.07847,.11111,.43958],74:[0,.68333,.09618,.16667,.55451],75:[0,.68333,.07153,.05556,.84931],76:[0,.68333,0,.02778,.68056],77:[0,.68333,.10903,.08334,.97014],78:[0,.68333,.10903,.08334,.80347],79:[0,.68333,.02778,.08334,.76278],80:[0,.68333,.13889,.08334,.64201],81:[.19444,.68333,0,.08334,.79056],82:[0,.68333,.00773,.08334,.75929],83:[0,.68333,.05764,.08334,.6132],84:[0,.68333,.13889,.08334,.58438],85:[0,.68333,.10903,.02778,.68278],86:[0,.68333,.22222,0,.58333],87:[0,.68333,.13889,0,.94445],88:[0,.68333,.07847,.08334,.82847],89:[0,.68333,.22222,0,.58056],90:[0,.68333,.07153,.08334,.68264],97:[0,.43056,0,0,.52859],98:[0,.69444,0,0,.42917],99:[0,.43056,0,.05556,.43276],100:[0,.69444,0,.16667,.52049],101:[0,.43056,0,.05556,.46563],102:[.19444,.69444,.10764,.16667,.48959],103:[.19444,.43056,.03588,.02778,.47697],104:[0,.69444,0,0,.57616],105:[0,.65952,0,0,.34451],106:[.19444,.65952,.05724,0,.41181],107:[0,.69444,.03148,0,.5206],108:[0,.69444,.01968,.08334,.29838],109:[0,.43056,0,0,.87801],110:[0,.43056,0,0,.60023],111:[0,.43056,0,.05556,.48472],112:[.19444,.43056,0,.08334,.50313],113:[.19444,.43056,.03588,.08334,.44641],114:[0,.43056,.02778,.05556,.45116],115:[0,.43056,0,.05556,.46875],116:[0,.61508,0,.08334,.36111],117:[0,.43056,0,.02778,.57246],118:[0,.43056,.03588,.02778,.48472],119:[0,.43056,.02691,.08334,.71592],120:[0,.43056,0,.02778,.57153],121:[.19444,.43056,.03588,.05556,.49028],122:[0,.43056,.04398,.05556,.46505],160:[0,0,0,0,.25],915:[0,.68333,.13889,.08334,.61528],916:[0,.68333,0,.16667,.83334],920:[0,.68333,.02778,.08334,.76278],923:[0,.68333,0,.16667,.69445],926:[0,.68333,.07569,.08334,.74236],928:[0,.68333,.08125,.05556,.83125],931:[0,.68333,.05764,.08334,.77986],933:[0,.68333,.13889,.05556,.58333],934:[0,.68333,0,.08334,.66667],936:[0,.68333,.11,.05556,.61222],937:[0,.68333,.05017,.08334,.7724],945:[0,.43056,.0037,.02778,.6397],946:[.19444,.69444,.05278,.08334,.56563],947:[.19444,.43056,.05556,0,.51773],948:[0,.69444,.03785,.05556,.44444],949:[0,.43056,0,.08334,.46632],950:[.19444,.69444,.07378,.08334,.4375],951:[.19444,.43056,.03588,.05556,.49653],952:[0,.69444,.02778,.08334,.46944],953:[0,.43056,0,.05556,.35394],954:[0,.43056,0,0,.57616],955:[0,.69444,0,0,.58334],956:[.19444,.43056,0,.02778,.60255],957:[0,.43056,.06366,.02778,.49398],958:[.19444,.69444,.04601,.11111,.4375],959:[0,.43056,0,.05556,.48472],960:[0,.43056,.03588,0,.57003],961:[.19444,.43056,0,.08334,.51702],962:[.09722,.43056,.07986,.08334,.36285],963:[0,.43056,.03588,0,.57141],964:[0,.43056,.1132,.02778,.43715],965:[0,.43056,.03588,.02778,.54028],966:[.19444,.43056,0,.08334,.65417],967:[.19444,.43056,0,.05556,.62569],968:[.19444,.69444,.03588,.11111,.65139],969:[0,.43056,.03588,0,.62245],977:[0,.69444,0,.08334,.59144],981:[.19444,.69444,0,.08334,.59583],982:[0,.43056,.02778,0,.82813],1009:[.19444,.43056,0,.08334,.51702],1013:[0,.43056,0,.05556,.4059],57649:[0,.43056,0,.02778,.32246],57911:[.19444,.43056,0,.08334,.38403]},"SansSerif-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.36667],34:[0,.69444,0,0,.55834],35:[.19444,.69444,0,0,.91667],36:[.05556,.75,0,0,.55],37:[.05556,.75,0,0,1.02912],38:[0,.69444,0,0,.83056],39:[0,.69444,0,0,.30556],40:[.25,.75,0,0,.42778],41:[.25,.75,0,0,.42778],42:[0,.75,0,0,.55],43:[.11667,.61667,0,0,.85556],44:[.10556,.13056,0,0,.30556],45:[0,.45833,0,0,.36667],46:[0,.13056,0,0,.30556],47:[.25,.75,0,0,.55],48:[0,.69444,0,0,.55],49:[0,.69444,0,0,.55],50:[0,.69444,0,0,.55],51:[0,.69444,0,0,.55],52:[0,.69444,0,0,.55],53:[0,.69444,0,0,.55],54:[0,.69444,0,0,.55],55:[0,.69444,0,0,.55],56:[0,.69444,0,0,.55],57:[0,.69444,0,0,.55],58:[0,.45833,0,0,.30556],59:[.10556,.45833,0,0,.30556],61:[-.09375,.40625,0,0,.85556],63:[0,.69444,0,0,.51945],64:[0,.69444,0,0,.73334],65:[0,.69444,0,0,.73334],66:[0,.69444,0,0,.73334],67:[0,.69444,0,0,.70278],68:[0,.69444,0,0,.79445],69:[0,.69444,0,0,.64167],70:[0,.69444,0,0,.61111],71:[0,.69444,0,0,.73334],72:[0,.69444,0,0,.79445],73:[0,.69444,0,0,.33056],74:[0,.69444,0,0,.51945],75:[0,.69444,0,0,.76389],76:[0,.69444,0,0,.58056],77:[0,.69444,0,0,.97778],78:[0,.69444,0,0,.79445],79:[0,.69444,0,0,.79445],80:[0,.69444,0,0,.70278],81:[.10556,.69444,0,0,.79445],82:[0,.69444,0,0,.70278],83:[0,.69444,0,0,.61111],84:[0,.69444,0,0,.73334],85:[0,.69444,0,0,.76389],86:[0,.69444,.01528,0,.73334],87:[0,.69444,.01528,0,1.03889],88:[0,.69444,0,0,.73334],89:[0,.69444,.0275,0,.73334],90:[0,.69444,0,0,.67223],91:[.25,.75,0,0,.34306],93:[.25,.75,0,0,.34306],94:[0,.69444,0,0,.55],95:[.35,.10833,.03056,0,.55],97:[0,.45833,0,0,.525],98:[0,.69444,0,0,.56111],99:[0,.45833,0,0,.48889],100:[0,.69444,0,0,.56111],101:[0,.45833,0,0,.51111],102:[0,.69444,.07639,0,.33611],103:[.19444,.45833,.01528,0,.55],104:[0,.69444,0,0,.56111],105:[0,.69444,0,0,.25556],106:[.19444,.69444,0,0,.28611],107:[0,.69444,0,0,.53056],108:[0,.69444,0,0,.25556],109:[0,.45833,0,0,.86667],110:[0,.45833,0,0,.56111],111:[0,.45833,0,0,.55],112:[.19444,.45833,0,0,.56111],113:[.19444,.45833,0,0,.56111],114:[0,.45833,.01528,0,.37222],115:[0,.45833,0,0,.42167],116:[0,.58929,0,0,.40417],117:[0,.45833,0,0,.56111],118:[0,.45833,.01528,0,.5],119:[0,.45833,.01528,0,.74445],120:[0,.45833,0,0,.5],121:[.19444,.45833,.01528,0,.5],122:[0,.45833,0,0,.47639],126:[.35,.34444,0,0,.55],160:[0,0,0,0,.25],168:[0,.69444,0,0,.55],176:[0,.69444,0,0,.73334],180:[0,.69444,0,0,.55],184:[.17014,0,0,0,.48889],305:[0,.45833,0,0,.25556],567:[.19444,.45833,0,0,.28611],710:[0,.69444,0,0,.55],711:[0,.63542,0,0,.55],713:[0,.63778,0,0,.55],728:[0,.69444,0,0,.55],729:[0,.69444,0,0,.30556],730:[0,.69444,0,0,.73334],732:[0,.69444,0,0,.55],733:[0,.69444,0,0,.55],915:[0,.69444,0,0,.58056],916:[0,.69444,0,0,.91667],920:[0,.69444,0,0,.85556],923:[0,.69444,0,0,.67223],926:[0,.69444,0,0,.73334],928:[0,.69444,0,0,.79445],931:[0,.69444,0,0,.79445],933:[0,.69444,0,0,.85556],934:[0,.69444,0,0,.79445],936:[0,.69444,0,0,.85556],937:[0,.69444,0,0,.79445],8211:[0,.45833,.03056,0,.55],8212:[0,.45833,.03056,0,1.10001],8216:[0,.69444,0,0,.30556],8217:[0,.69444,0,0,.30556],8220:[0,.69444,0,0,.55834],8221:[0,.69444,0,0,.55834]},"SansSerif-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.05733,0,.31945],34:[0,.69444,.00316,0,.5],35:[.19444,.69444,.05087,0,.83334],36:[.05556,.75,.11156,0,.5],37:[.05556,.75,.03126,0,.83334],38:[0,.69444,.03058,0,.75834],39:[0,.69444,.07816,0,.27778],40:[.25,.75,.13164,0,.38889],41:[.25,.75,.02536,0,.38889],42:[0,.75,.11775,0,.5],43:[.08333,.58333,.02536,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,.01946,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,.13164,0,.5],48:[0,.65556,.11156,0,.5],49:[0,.65556,.11156,0,.5],50:[0,.65556,.11156,0,.5],51:[0,.65556,.11156,0,.5],52:[0,.65556,.11156,0,.5],53:[0,.65556,.11156,0,.5],54:[0,.65556,.11156,0,.5],55:[0,.65556,.11156,0,.5],56:[0,.65556,.11156,0,.5],57:[0,.65556,.11156,0,.5],58:[0,.44444,.02502,0,.27778],59:[.125,.44444,.02502,0,.27778],61:[-.13,.37,.05087,0,.77778],63:[0,.69444,.11809,0,.47222],64:[0,.69444,.07555,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,.08293,0,.66667],67:[0,.69444,.11983,0,.63889],68:[0,.69444,.07555,0,.72223],69:[0,.69444,.11983,0,.59722],70:[0,.69444,.13372,0,.56945],71:[0,.69444,.11983,0,.66667],72:[0,.69444,.08094,0,.70834],73:[0,.69444,.13372,0,.27778],74:[0,.69444,.08094,0,.47222],75:[0,.69444,.11983,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,.08094,0,.875],78:[0,.69444,.08094,0,.70834],79:[0,.69444,.07555,0,.73611],80:[0,.69444,.08293,0,.63889],81:[.125,.69444,.07555,0,.73611],82:[0,.69444,.08293,0,.64584],83:[0,.69444,.09205,0,.55556],84:[0,.69444,.13372,0,.68056],85:[0,.69444,.08094,0,.6875],86:[0,.69444,.1615,0,.66667],87:[0,.69444,.1615,0,.94445],88:[0,.69444,.13372,0,.66667],89:[0,.69444,.17261,0,.66667],90:[0,.69444,.11983,0,.61111],91:[.25,.75,.15942,0,.28889],93:[.25,.75,.08719,0,.28889],94:[0,.69444,.0799,0,.5],95:[.35,.09444,.08616,0,.5],97:[0,.44444,.00981,0,.48056],98:[0,.69444,.03057,0,.51667],99:[0,.44444,.08336,0,.44445],100:[0,.69444,.09483,0,.51667],101:[0,.44444,.06778,0,.44445],102:[0,.69444,.21705,0,.30556],103:[.19444,.44444,.10836,0,.5],104:[0,.69444,.01778,0,.51667],105:[0,.67937,.09718,0,.23889],106:[.19444,.67937,.09162,0,.26667],107:[0,.69444,.08336,0,.48889],108:[0,.69444,.09483,0,.23889],109:[0,.44444,.01778,0,.79445],110:[0,.44444,.01778,0,.51667],111:[0,.44444,.06613,0,.5],112:[.19444,.44444,.0389,0,.51667],113:[.19444,.44444,.04169,0,.51667],114:[0,.44444,.10836,0,.34167],115:[0,.44444,.0778,0,.38333],116:[0,.57143,.07225,0,.36111],117:[0,.44444,.04169,0,.51667],118:[0,.44444,.10836,0,.46111],119:[0,.44444,.10836,0,.68334],120:[0,.44444,.09169,0,.46111],121:[.19444,.44444,.10836,0,.46111],122:[0,.44444,.08752,0,.43472],126:[.35,.32659,.08826,0,.5],160:[0,0,0,0,.25],168:[0,.67937,.06385,0,.5],176:[0,.69444,0,0,.73752],184:[.17014,0,0,0,.44445],305:[0,.44444,.04169,0,.23889],567:[.19444,.44444,.04169,0,.26667],710:[0,.69444,.0799,0,.5],711:[0,.63194,.08432,0,.5],713:[0,.60889,.08776,0,.5],714:[0,.69444,.09205,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,.09483,0,.5],729:[0,.67937,.07774,0,.27778],730:[0,.69444,0,0,.73752],732:[0,.67659,.08826,0,.5],733:[0,.69444,.09205,0,.5],915:[0,.69444,.13372,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,.07555,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,.12816,0,.66667],928:[0,.69444,.08094,0,.70834],931:[0,.69444,.11983,0,.72222],933:[0,.69444,.09031,0,.77778],934:[0,.69444,.04603,0,.72222],936:[0,.69444,.09031,0,.77778],937:[0,.69444,.08293,0,.72222],8211:[0,.44444,.08616,0,.5],8212:[0,.44444,.08616,0,1],8216:[0,.69444,.07816,0,.27778],8217:[0,.69444,.07816,0,.27778],8220:[0,.69444,.14205,0,.5],8221:[0,.69444,.00316,0,.5]},"SansSerif-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.31945],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.75834],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,0,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.65556,0,0,.5],49:[0,.65556,0,0,.5],50:[0,.65556,0,0,.5],51:[0,.65556,0,0,.5],52:[0,.65556,0,0,.5],53:[0,.65556,0,0,.5],54:[0,.65556,0,0,.5],55:[0,.65556,0,0,.5],56:[0,.65556,0,0,.5],57:[0,.65556,0,0,.5],58:[0,.44444,0,0,.27778],59:[.125,.44444,0,0,.27778],61:[-.13,.37,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,0,0,.66667],67:[0,.69444,0,0,.63889],68:[0,.69444,0,0,.72223],69:[0,.69444,0,0,.59722],70:[0,.69444,0,0,.56945],71:[0,.69444,0,0,.66667],72:[0,.69444,0,0,.70834],73:[0,.69444,0,0,.27778],74:[0,.69444,0,0,.47222],75:[0,.69444,0,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,0,0,.875],78:[0,.69444,0,0,.70834],79:[0,.69444,0,0,.73611],80:[0,.69444,0,0,.63889],81:[.125,.69444,0,0,.73611],82:[0,.69444,0,0,.64584],83:[0,.69444,0,0,.55556],84:[0,.69444,0,0,.68056],85:[0,.69444,0,0,.6875],86:[0,.69444,.01389,0,.66667],87:[0,.69444,.01389,0,.94445],88:[0,.69444,0,0,.66667],89:[0,.69444,.025,0,.66667],90:[0,.69444,0,0,.61111],91:[.25,.75,0,0,.28889],93:[.25,.75,0,0,.28889],94:[0,.69444,0,0,.5],95:[.35,.09444,.02778,0,.5],97:[0,.44444,0,0,.48056],98:[0,.69444,0,0,.51667],99:[0,.44444,0,0,.44445],100:[0,.69444,0,0,.51667],101:[0,.44444,0,0,.44445],102:[0,.69444,.06944,0,.30556],103:[.19444,.44444,.01389,0,.5],104:[0,.69444,0,0,.51667],105:[0,.67937,0,0,.23889],106:[.19444,.67937,0,0,.26667],107:[0,.69444,0,0,.48889],108:[0,.69444,0,0,.23889],109:[0,.44444,0,0,.79445],110:[0,.44444,0,0,.51667],111:[0,.44444,0,0,.5],112:[.19444,.44444,0,0,.51667],113:[.19444,.44444,0,0,.51667],114:[0,.44444,.01389,0,.34167],115:[0,.44444,0,0,.38333],116:[0,.57143,0,0,.36111],117:[0,.44444,0,0,.51667],118:[0,.44444,.01389,0,.46111],119:[0,.44444,.01389,0,.68334],120:[0,.44444,0,0,.46111],121:[.19444,.44444,.01389,0,.46111],122:[0,.44444,0,0,.43472],126:[.35,.32659,0,0,.5],160:[0,0,0,0,.25],168:[0,.67937,0,0,.5],176:[0,.69444,0,0,.66667],184:[.17014,0,0,0,.44445],305:[0,.44444,0,0,.23889],567:[.19444,.44444,0,0,.26667],710:[0,.69444,0,0,.5],711:[0,.63194,0,0,.5],713:[0,.60889,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.67937,0,0,.27778],730:[0,.69444,0,0,.66667],732:[0,.67659,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.69444,0,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,0,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,0,0,.66667],928:[0,.69444,0,0,.70834],931:[0,.69444,0,0,.72222],933:[0,.69444,0,0,.77778],934:[0,.69444,0,0,.72222],936:[0,.69444,0,0,.77778],937:[0,.69444,0,0,.72222],8211:[0,.44444,.02778,0,.5],8212:[0,.44444,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5]},"Script-Regular":{32:[0,0,0,0,.25],65:[0,.7,.22925,0,.80253],66:[0,.7,.04087,0,.90757],67:[0,.7,.1689,0,.66619],68:[0,.7,.09371,0,.77443],69:[0,.7,.18583,0,.56162],70:[0,.7,.13634,0,.89544],71:[0,.7,.17322,0,.60961],72:[0,.7,.29694,0,.96919],73:[0,.7,.19189,0,.80907],74:[.27778,.7,.19189,0,1.05159],75:[0,.7,.31259,0,.91364],76:[0,.7,.19189,0,.87373],77:[0,.7,.15981,0,1.08031],78:[0,.7,.3525,0,.9015],79:[0,.7,.08078,0,.73787],80:[0,.7,.08078,0,1.01262],81:[0,.7,.03305,0,.88282],82:[0,.7,.06259,0,.85],83:[0,.7,.19189,0,.86767],84:[0,.7,.29087,0,.74697],85:[0,.7,.25815,0,.79996],86:[0,.7,.27523,0,.62204],87:[0,.7,.27523,0,.80532],88:[0,.7,.26006,0,.94445],89:[0,.7,.2939,0,.70961],90:[0,.7,.24037,0,.8212],160:[0,0,0,0,.25]},"Size1-Regular":{32:[0,0,0,0,.25],40:[.35001,.85,0,0,.45834],41:[.35001,.85,0,0,.45834],47:[.35001,.85,0,0,.57778],91:[.35001,.85,0,0,.41667],92:[.35001,.85,0,0,.57778],93:[.35001,.85,0,0,.41667],123:[.35001,.85,0,0,.58334],125:[.35001,.85,0,0,.58334],160:[0,0,0,0,.25],710:[0,.72222,0,0,.55556],732:[0,.72222,0,0,.55556],770:[0,.72222,0,0,.55556],771:[0,.72222,0,0,.55556],8214:[-99e-5,.601,0,0,.77778],8593:[1e-5,.6,0,0,.66667],8595:[1e-5,.6,0,0,.66667],8657:[1e-5,.6,0,0,.77778],8659:[1e-5,.6,0,0,.77778],8719:[.25001,.75,0,0,.94445],8720:[.25001,.75,0,0,.94445],8721:[.25001,.75,0,0,1.05556],8730:[.35001,.85,0,0,1],8739:[-.00599,.606,0,0,.33333],8741:[-.00599,.606,0,0,.55556],8747:[.30612,.805,.19445,0,.47222],8748:[.306,.805,.19445,0,.47222],8749:[.306,.805,.19445,0,.47222],8750:[.30612,.805,.19445,0,.47222],8896:[.25001,.75,0,0,.83334],8897:[.25001,.75,0,0,.83334],8898:[.25001,.75,0,0,.83334],8899:[.25001,.75,0,0,.83334],8968:[.35001,.85,0,0,.47222],8969:[.35001,.85,0,0,.47222],8970:[.35001,.85,0,0,.47222],8971:[.35001,.85,0,0,.47222],9168:[-99e-5,.601,0,0,.66667],10216:[.35001,.85,0,0,.47222],10217:[.35001,.85,0,0,.47222],10752:[.25001,.75,0,0,1.11111],10753:[.25001,.75,0,0,1.11111],10754:[.25001,.75,0,0,1.11111],10756:[.25001,.75,0,0,.83334],10758:[.25001,.75,0,0,.83334]},"Size2-Regular":{32:[0,0,0,0,.25],40:[.65002,1.15,0,0,.59722],41:[.65002,1.15,0,0,.59722],47:[.65002,1.15,0,0,.81111],91:[.65002,1.15,0,0,.47222],92:[.65002,1.15,0,0,.81111],93:[.65002,1.15,0,0,.47222],123:[.65002,1.15,0,0,.66667],125:[.65002,1.15,0,0,.66667],160:[0,0,0,0,.25],710:[0,.75,0,0,1],732:[0,.75,0,0,1],770:[0,.75,0,0,1],771:[0,.75,0,0,1],8719:[.55001,1.05,0,0,1.27778],8720:[.55001,1.05,0,0,1.27778],8721:[.55001,1.05,0,0,1.44445],8730:[.65002,1.15,0,0,1],8747:[.86225,1.36,.44445,0,.55556],8748:[.862,1.36,.44445,0,.55556],8749:[.862,1.36,.44445,0,.55556],8750:[.86225,1.36,.44445,0,.55556],8896:[.55001,1.05,0,0,1.11111],8897:[.55001,1.05,0,0,1.11111],8898:[.55001,1.05,0,0,1.11111],8899:[.55001,1.05,0,0,1.11111],8968:[.65002,1.15,0,0,.52778],8969:[.65002,1.15,0,0,.52778],8970:[.65002,1.15,0,0,.52778],8971:[.65002,1.15,0,0,.52778],10216:[.65002,1.15,0,0,.61111],10217:[.65002,1.15,0,0,.61111],10752:[.55001,1.05,0,0,1.51112],10753:[.55001,1.05,0,0,1.51112],10754:[.55001,1.05,0,0,1.51112],10756:[.55001,1.05,0,0,1.11111],10758:[.55001,1.05,0,0,1.11111]},"Size3-Regular":{32:[0,0,0,0,.25],40:[.95003,1.45,0,0,.73611],41:[.95003,1.45,0,0,.73611],47:[.95003,1.45,0,0,1.04445],91:[.95003,1.45,0,0,.52778],92:[.95003,1.45,0,0,1.04445],93:[.95003,1.45,0,0,.52778],123:[.95003,1.45,0,0,.75],125:[.95003,1.45,0,0,.75],160:[0,0,0,0,.25],710:[0,.75,0,0,1.44445],732:[0,.75,0,0,1.44445],770:[0,.75,0,0,1.44445],771:[0,.75,0,0,1.44445],8730:[.95003,1.45,0,0,1],8968:[.95003,1.45,0,0,.58334],8969:[.95003,1.45,0,0,.58334],8970:[.95003,1.45,0,0,.58334],8971:[.95003,1.45,0,0,.58334],10216:[.95003,1.45,0,0,.75],10217:[.95003,1.45,0,0,.75]},"Size4-Regular":{32:[0,0,0,0,.25],40:[1.25003,1.75,0,0,.79167],41:[1.25003,1.75,0,0,.79167],47:[1.25003,1.75,0,0,1.27778],91:[1.25003,1.75,0,0,.58334],92:[1.25003,1.75,0,0,1.27778],93:[1.25003,1.75,0,0,.58334],123:[1.25003,1.75,0,0,.80556],125:[1.25003,1.75,0,0,.80556],160:[0,0,0,0,.25],710:[0,.825,0,0,1.8889],732:[0,.825,0,0,1.8889],770:[0,.825,0,0,1.8889],771:[0,.825,0,0,1.8889],8730:[1.25003,1.75,0,0,1],8968:[1.25003,1.75,0,0,.63889],8969:[1.25003,1.75,0,0,.63889],8970:[1.25003,1.75,0,0,.63889],8971:[1.25003,1.75,0,0,.63889],9115:[.64502,1.155,0,0,.875],9116:[1e-5,.6,0,0,.875],9117:[.64502,1.155,0,0,.875],9118:[.64502,1.155,0,0,.875],9119:[1e-5,.6,0,0,.875],9120:[.64502,1.155,0,0,.875],9121:[.64502,1.155,0,0,.66667],9122:[-99e-5,.601,0,0,.66667],9123:[.64502,1.155,0,0,.66667],9124:[.64502,1.155,0,0,.66667],9125:[-99e-5,.601,0,0,.66667],9126:[.64502,1.155,0,0,.66667],9127:[1e-5,.9,0,0,.88889],9128:[.65002,1.15,0,0,.88889],9129:[.90001,0,0,0,.88889],9130:[0,.3,0,0,.88889],9131:[1e-5,.9,0,0,.88889],9132:[.65002,1.15,0,0,.88889],9133:[.90001,0,0,0,.88889],9143:[.88502,.915,0,0,1.05556],10216:[1.25003,1.75,0,0,.80556],10217:[1.25003,1.75,0,0,.80556],57344:[-.00499,.605,0,0,1.05556],57345:[-.00499,.605,0,0,1.05556],57680:[0,.12,0,0,.45],57681:[0,.12,0,0,.45],57682:[0,.12,0,0,.45],57683:[0,.12,0,0,.45]},"Typewriter-Regular":{32:[0,0,0,0,.525],33:[0,.61111,0,0,.525],34:[0,.61111,0,0,.525],35:[0,.61111,0,0,.525],36:[.08333,.69444,0,0,.525],37:[.08333,.69444,0,0,.525],38:[0,.61111,0,0,.525],39:[0,.61111,0,0,.525],40:[.08333,.69444,0,0,.525],41:[.08333,.69444,0,0,.525],42:[0,.52083,0,0,.525],43:[-.08056,.53055,0,0,.525],44:[.13889,.125,0,0,.525],45:[-.08056,.53055,0,0,.525],46:[0,.125,0,0,.525],47:[.08333,.69444,0,0,.525],48:[0,.61111,0,0,.525],49:[0,.61111,0,0,.525],50:[0,.61111,0,0,.525],51:[0,.61111,0,0,.525],52:[0,.61111,0,0,.525],53:[0,.61111,0,0,.525],54:[0,.61111,0,0,.525],55:[0,.61111,0,0,.525],56:[0,.61111,0,0,.525],57:[0,.61111,0,0,.525],58:[0,.43056,0,0,.525],59:[.13889,.43056,0,0,.525],60:[-.05556,.55556,0,0,.525],61:[-.19549,.41562,0,0,.525],62:[-.05556,.55556,0,0,.525],63:[0,.61111,0,0,.525],64:[0,.61111,0,0,.525],65:[0,.61111,0,0,.525],66:[0,.61111,0,0,.525],67:[0,.61111,0,0,.525],68:[0,.61111,0,0,.525],69:[0,.61111,0,0,.525],70:[0,.61111,0,0,.525],71:[0,.61111,0,0,.525],72:[0,.61111,0,0,.525],73:[0,.61111,0,0,.525],74:[0,.61111,0,0,.525],75:[0,.61111,0,0,.525],76:[0,.61111,0,0,.525],77:[0,.61111,0,0,.525],78:[0,.61111,0,0,.525],79:[0,.61111,0,0,.525],80:[0,.61111,0,0,.525],81:[.13889,.61111,0,0,.525],82:[0,.61111,0,0,.525],83:[0,.61111,0,0,.525],84:[0,.61111,0,0,.525],85:[0,.61111,0,0,.525],86:[0,.61111,0,0,.525],87:[0,.61111,0,0,.525],88:[0,.61111,0,0,.525],89:[0,.61111,0,0,.525],90:[0,.61111,0,0,.525],91:[.08333,.69444,0,0,.525],92:[.08333,.69444,0,0,.525],93:[.08333,.69444,0,0,.525],94:[0,.61111,0,0,.525],95:[.09514,0,0,0,.525],96:[0,.61111,0,0,.525],97:[0,.43056,0,0,.525],98:[0,.61111,0,0,.525],99:[0,.43056,0,0,.525],100:[0,.61111,0,0,.525],101:[0,.43056,0,0,.525],102:[0,.61111,0,0,.525],103:[.22222,.43056,0,0,.525],104:[0,.61111,0,0,.525],105:[0,.61111,0,0,.525],106:[.22222,.61111,0,0,.525],107:[0,.61111,0,0,.525],108:[0,.61111,0,0,.525],109:[0,.43056,0,0,.525],110:[0,.43056,0,0,.525],111:[0,.43056,0,0,.525],112:[.22222,.43056,0,0,.525],113:[.22222,.43056,0,0,.525],114:[0,.43056,0,0,.525],115:[0,.43056,0,0,.525],116:[0,.55358,0,0,.525],117:[0,.43056,0,0,.525],118:[0,.43056,0,0,.525],119:[0,.43056,0,0,.525],120:[0,.43056,0,0,.525],121:[.22222,.43056,0,0,.525],122:[0,.43056,0,0,.525],123:[.08333,.69444,0,0,.525],124:[.08333,.69444,0,0,.525],125:[.08333,.69444,0,0,.525],126:[0,.61111,0,0,.525],127:[0,.61111,0,0,.525],160:[0,0,0,0,.525],176:[0,.61111,0,0,.525],184:[.19445,0,0,0,.525],305:[0,.43056,0,0,.525],567:[.22222,.43056,0,0,.525],711:[0,.56597,0,0,.525],713:[0,.56555,0,0,.525],714:[0,.61111,0,0,.525],715:[0,.61111,0,0,.525],728:[0,.61111,0,0,.525],730:[0,.61111,0,0,.525],770:[0,.61111,0,0,.525],771:[0,.61111,0,0,.525],776:[0,.61111,0,0,.525],915:[0,.61111,0,0,.525],916:[0,.61111,0,0,.525],920:[0,.61111,0,0,.525],923:[0,.61111,0,0,.525],926:[0,.61111,0,0,.525],928:[0,.61111,0,0,.525],931:[0,.61111,0,0,.525],933:[0,.61111,0,0,.525],934:[0,.61111,0,0,.525],936:[0,.61111,0,0,.525],937:[0,.61111,0,0,.525],8216:[0,.61111,0,0,.525],8217:[0,.61111,0,0,.525],8242:[0,.61111,0,0,.525],9251:[.11111,.21944,0,0,.525]}},Jb={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25],defaultRuleThickness:[.04,.049,.049],bigOpSpacing1:[.111,.111,.111],bigOpSpacing2:[.166,.166,.166],bigOpSpacing3:[.2,.2,.2],bigOpSpacing4:[.6,.611,.611],bigOpSpacing5:[.1,.143,.143],sqrtRuleThickness:[.04,.04,.04],ptPerEm:[10,10,10],doubleRuleSep:[.2,.2,.2],arrayRuleWidth:[.04,.04,.04],fboxsep:[.3,.3,.3],fboxrule:[.04,.04,.04]},Zz={\u00C5:"A",\u00D0:"D",\u00DE:"o",\u00E5:"a",\u00F0:"d",\u00FE:"o",\u0410:"A",\u0411:"B",\u0412:"B",\u0413:"F",\u0414:"A",\u0415:"E",\u0416:"K",\u0417:"3",\u0418:"N",\u0419:"N",\u041A:"K",\u041B:"N",\u041C:"M",\u041D:"H",\u041E:"O",\u041F:"N",\u0420:"P",\u0421:"C",\u0422:"T",\u0423:"y",\u0424:"O",\u0425:"X",\u0426:"U",\u0427:"h",\u0428:"W",\u0429:"W",\u042A:"B",\u042B:"X",\u042C:"B",\u042D:"3",\u042E:"X",\u042F:"R",\u0430:"a",\u0431:"b",\u0432:"a",\u0433:"r",\u0434:"y",\u0435:"e",\u0436:"m",\u0437:"e",\u0438:"n",\u0439:"n",\u043A:"n",\u043B:"n",\u043C:"m",\u043D:"n",\u043E:"o",\u043F:"n",\u0440:"p",\u0441:"c",\u0442:"o",\u0443:"y",\u0444:"b",\u0445:"x",\u0446:"n",\u0447:"n",\u0448:"w",\u0449:"w",\u044A:"a",\u044B:"m",\u044C:"a",\u044D:"e",\u044E:"m",\u044F:"r"};o(axe,"setFontMetrics");o(M7,"getCharacterMetrics");l7={};o(sxe,"getGlobalMetrics");oxe=[[1,1,1],[2,1,1],[3,1,1],[4,2,1],[5,2,1],[6,3,1],[7,4,2],[8,6,3],[9,7,6],[10,8,7],[11,10,9]],Jz=[.5,.6,.7,.8,.9,1,1.2,1.44,1.728,2.074,2.488],eG=o(function(e,r){return r.size<2?e:oxe[e-1][r.size-1]},"sizeAtStyle"),d4=class t{static{o(this,"Options")}constructor(e){this.style=void 0,this.color=void 0,this.size=void 0,this.textSize=void 0,this.phantom=void 0,this.font=void 0,this.fontFamily=void 0,this.fontWeight=void 0,this.fontShape=void 0,this.sizeMultiplier=void 0,this.maxSize=void 0,this.minRuleThickness=void 0,this._fontMetrics=void 0,this.style=e.style,this.color=e.color,this.size=e.size||t.BASESIZE,this.textSize=e.textSize||this.size,this.phantom=!!e.phantom,this.font=e.font||"",this.fontFamily=e.fontFamily||"",this.fontWeight=e.fontWeight||"",this.fontShape=e.fontShape||"",this.sizeMultiplier=Jz[this.size-1],this.maxSize=e.maxSize,this.minRuleThickness=e.minRuleThickness,this._fontMetrics=void 0}extend(e){var r={style:this.style,size:this.size,textSize:this.textSize,color:this.color,phantom:this.phantom,font:this.font,fontFamily:this.fontFamily,fontWeight:this.fontWeight,fontShape:this.fontShape,maxSize:this.maxSize,minRuleThickness:this.minRuleThickness};for(var n in e)e.hasOwnProperty(n)&&(r[n]=e[n]);return new t(r)}havingStyle(e){return this.style===e?this:this.extend({style:e,size:eG(this.textSize,e)})}havingCrampedStyle(){return this.havingStyle(this.style.cramp())}havingSize(e){return this.size===e&&this.textSize===e?this:this.extend({style:this.style.text(),size:e,textSize:e,sizeMultiplier:Jz[e-1]})}havingBaseStyle(e){e=e||this.style.text();var r=eG(t.BASESIZE,e);return this.size===r&&this.textSize===t.BASESIZE&&this.style===e?this:this.extend({style:e,size:r})}havingBaseSizing(){var e;switch(this.style.id){case 4:case 5:e=3;break;case 6:case 7:e=1;break;default:e=6}return this.extend({style:this.style.text(),size:e})}withColor(e){return this.extend({color:e})}withPhantom(){return this.extend({phantom:!0})}withFont(e){return this.extend({font:e})}withTextFontFamily(e){return this.extend({fontFamily:e,font:""})}withTextFontWeight(e){return this.extend({fontWeight:e,font:""})}withTextFontShape(e){return this.extend({fontShape:e,font:""})}sizingClasses(e){return e.size!==this.size?["sizing","reset-size"+e.size,"size"+this.size]:[]}baseSizingClasses(){return this.size!==t.BASESIZE?["sizing","reset-size"+this.size,"size"+t.BASESIZE]:[]}fontMetrics(){return this._fontMetrics||(this._fontMetrics=sxe(this.size)),this._fontMetrics}getColor(){return this.phantom?"transparent":this.color}};d4.BASESIZE=6;w7={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:803/800,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:803/800},lxe={ex:!0,em:!0,mu:!0},DG=o(function(e){return typeof e!="string"&&(e=e.unit),e in w7||e in lxe||e==="ex"},"validUnit"),Hn=o(function(e,r){var n;if(e.unit in w7)n=w7[e.unit]/r.fontMetrics().ptPerEm/r.sizeMultiplier;else if(e.unit==="mu")n=r.fontMetrics().cssEmPerMu;else{var i;if(r.style.isTight()?i=r.havingStyle(r.style.text()):i=r,e.unit==="ex")n=i.fontMetrics().xHeight;else if(e.unit==="em")n=i.fontMetrics().quad;else throw new nt("Invalid unit: '"+e.unit+"'");i!==r&&(n*=i.sizeMultiplier/r.sizeMultiplier)}return Math.min(e.number*n,r.maxSize)},"calculateSize"),ct=o(function(e){return+e.toFixed(4)+"em"},"makeEm"),dh=o(function(e){return e.filter(r=>r).join(" ")},"createClass"),RG=o(function(e,r,n){if(this.classes=e||[],this.attributes={},this.height=0,this.depth=0,this.maxFontSize=0,this.style=n||{},r){r.style.isTight()&&this.classes.push("mtight");var i=r.getColor();i&&(this.style.color=i)}},"initNode"),NG=o(function(e){var r=document.createElement(e);r.className=dh(this.classes);for(var n in this.style)this.style.hasOwnProperty(n)&&(r.style[n]=this.style[n]);for(var i in this.attributes)this.attributes.hasOwnProperty(i)&&r.setAttribute(i,this.attributes[i]);for(var a=0;a",r},"toMarkup"),jf=class{static{o(this,"Span")}constructor(e,r,n,i){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,RG.call(this,e,n,i),this.children=r||[]}setAttribute(e,r){this.attributes[e]=r}hasClass(e){return Vt.contains(this.classes,e)}toNode(){return NG.call(this,"span")}toMarkup(){return MG.call(this,"span")}},iy=class{static{o(this,"Anchor")}constructor(e,r,n,i){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,RG.call(this,r,i),this.children=n||[],this.setAttribute("href",e)}setAttribute(e,r){this.attributes[e]=r}hasClass(e){return Vt.contains(this.classes,e)}toNode(){return NG.call(this,"a")}toMarkup(){return MG.call(this,"a")}},T7=class{static{o(this,"Img")}constructor(e,r,n){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=r,this.src=e,this.classes=["mord"],this.style=n}hasClass(e){return Vt.contains(this.classes,e)}toNode(){var e=document.createElement("img");e.src=this.src,e.alt=this.alt,e.className="mord";for(var r in this.style)this.style.hasOwnProperty(r)&&(e.style[r]=this.style[r]);return e}toMarkup(){var e=''+Vt.escape(this.alt)+'0&&(r=document.createElement("span"),r.style.marginRight=ct(this.italic)),this.classes.length>0&&(r=r||document.createElement("span"),r.className=dh(this.classes));for(var n in this.style)this.style.hasOwnProperty(n)&&(r=r||document.createElement("span"),r.style[n]=this.style[n]);return r?(r.appendChild(e),r):e}toMarkup(){var e=!1,r="0&&(n+="margin-right:"+this.italic+"em;");for(var i in this.style)this.style.hasOwnProperty(i)&&(n+=Vt.hyphenate(i)+":"+this.style[i]+";");n&&(e=!0,r+=' style="'+Vt.escape(n)+'"');var a=Vt.escape(this.text);return e?(r+=">",r+=a,r+="",r):a}},ll=class{static{o(this,"SvgNode")}constructor(e,r){this.children=void 0,this.attributes=void 0,this.children=e||[],this.attributes=r||{}}toNode(){var e="http://www.w3.org/2000/svg",r=document.createElementNS(e,"svg");for(var n in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,n)&&r.setAttribute(n,this.attributes[n]);for(var i=0;i':''}},ay=class{static{o(this,"LineNode")}constructor(e){this.attributes=void 0,this.attributes=e||{}}toNode(){var e="http://www.w3.org/2000/svg",r=document.createElementNS(e,"line");for(var n in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,n)&&r.setAttribute(n,this.attributes[n]);return r}toMarkup(){var e="","\\gt",!0);G(U,ee,xe,"\u2208","\\in",!0);G(U,ee,xe,"\uE020","\\@not");G(U,ee,xe,"\u2282","\\subset",!0);G(U,ee,xe,"\u2283","\\supset",!0);G(U,ee,xe,"\u2286","\\subseteq",!0);G(U,ee,xe,"\u2287","\\supseteq",!0);G(U,ve,xe,"\u2288","\\nsubseteq",!0);G(U,ve,xe,"\u2289","\\nsupseteq",!0);G(U,ee,xe,"\u22A8","\\models");G(U,ee,xe,"\u2190","\\leftarrow",!0);G(U,ee,xe,"\u2264","\\le");G(U,ee,xe,"\u2264","\\leq",!0);G(U,ee,xe,"<","\\lt",!0);G(U,ee,xe,"\u2192","\\rightarrow",!0);G(U,ee,xe,"\u2192","\\to");G(U,ve,xe,"\u2271","\\ngeq",!0);G(U,ve,xe,"\u2270","\\nleq",!0);G(U,ee,lu,"\xA0","\\ ");G(U,ee,lu,"\xA0","\\space");G(U,ee,lu,"\xA0","\\nobreakspace");G(Qe,ee,lu,"\xA0","\\ ");G(Qe,ee,lu,"\xA0"," ");G(Qe,ee,lu,"\xA0","\\space");G(Qe,ee,lu,"\xA0","\\nobreakspace");G(U,ee,lu,null,"\\nobreak");G(U,ee,lu,null,"\\allowbreak");G(U,ee,b4,",",",");G(U,ee,b4,";",";");G(U,ve,bt,"\u22BC","\\barwedge",!0);G(U,ve,bt,"\u22BB","\\veebar",!0);G(U,ee,bt,"\u2299","\\odot",!0);G(U,ee,bt,"\u2295","\\oplus",!0);G(U,ee,bt,"\u2297","\\otimes",!0);G(U,ee,Le,"\u2202","\\partial",!0);G(U,ee,bt,"\u2298","\\oslash",!0);G(U,ve,bt,"\u229A","\\circledcirc",!0);G(U,ve,bt,"\u22A1","\\boxdot",!0);G(U,ee,bt,"\u25B3","\\bigtriangleup");G(U,ee,bt,"\u25BD","\\bigtriangledown");G(U,ee,bt,"\u2020","\\dagger");G(U,ee,bt,"\u22C4","\\diamond");G(U,ee,bt,"\u22C6","\\star");G(U,ee,bt,"\u25C3","\\triangleleft");G(U,ee,bt,"\u25B9","\\triangleright");G(U,ee,js,"{","\\{");G(Qe,ee,Le,"{","\\{");G(Qe,ee,Le,"{","\\textbraceleft");G(U,ee,Xa,"}","\\}");G(Qe,ee,Le,"}","\\}");G(Qe,ee,Le,"}","\\textbraceright");G(U,ee,js,"{","\\lbrace");G(U,ee,Xa,"}","\\rbrace");G(U,ee,js,"[","\\lbrack",!0);G(Qe,ee,Le,"[","\\lbrack",!0);G(U,ee,Xa,"]","\\rbrack",!0);G(Qe,ee,Le,"]","\\rbrack",!0);G(U,ee,js,"(","\\lparen",!0);G(U,ee,Xa,")","\\rparen",!0);G(Qe,ee,Le,"<","\\textless",!0);G(Qe,ee,Le,">","\\textgreater",!0);G(U,ee,js,"\u230A","\\lfloor",!0);G(U,ee,Xa,"\u230B","\\rfloor",!0);G(U,ee,js,"\u2308","\\lceil",!0);G(U,ee,Xa,"\u2309","\\rceil",!0);G(U,ee,Le,"\\","\\backslash");G(U,ee,Le,"\u2223","|");G(U,ee,Le,"\u2223","\\vert");G(Qe,ee,Le,"|","\\textbar",!0);G(U,ee,Le,"\u2225","\\|");G(U,ee,Le,"\u2225","\\Vert");G(Qe,ee,Le,"\u2225","\\textbardbl");G(Qe,ee,Le,"~","\\textasciitilde");G(Qe,ee,Le,"\\","\\textbackslash");G(Qe,ee,Le,"^","\\textasciicircum");G(U,ee,xe,"\u2191","\\uparrow",!0);G(U,ee,xe,"\u21D1","\\Uparrow",!0);G(U,ee,xe,"\u2193","\\downarrow",!0);G(U,ee,xe,"\u21D3","\\Downarrow",!0);G(U,ee,xe,"\u2195","\\updownarrow",!0);G(U,ee,xe,"\u21D5","\\Updownarrow",!0);G(U,ee,xi,"\u2210","\\coprod");G(U,ee,xi,"\u22C1","\\bigvee");G(U,ee,xi,"\u22C0","\\bigwedge");G(U,ee,xi,"\u2A04","\\biguplus");G(U,ee,xi,"\u22C2","\\bigcap");G(U,ee,xi,"\u22C3","\\bigcup");G(U,ee,xi,"\u222B","\\int");G(U,ee,xi,"\u222B","\\intop");G(U,ee,xi,"\u222C","\\iint");G(U,ee,xi,"\u222D","\\iiint");G(U,ee,xi,"\u220F","\\prod");G(U,ee,xi,"\u2211","\\sum");G(U,ee,xi,"\u2A02","\\bigotimes");G(U,ee,xi,"\u2A01","\\bigoplus");G(U,ee,xi,"\u2A00","\\bigodot");G(U,ee,xi,"\u222E","\\oint");G(U,ee,xi,"\u222F","\\oiint");G(U,ee,xi,"\u2230","\\oiiint");G(U,ee,xi,"\u2A06","\\bigsqcup");G(U,ee,xi,"\u222B","\\smallint");G(Qe,ee,vp,"\u2026","\\textellipsis");G(U,ee,vp,"\u2026","\\mathellipsis");G(Qe,ee,vp,"\u2026","\\ldots",!0);G(U,ee,vp,"\u2026","\\ldots",!0);G(U,ee,vp,"\u22EF","\\@cdots",!0);G(U,ee,vp,"\u22F1","\\ddots",!0);G(U,ee,Le,"\u22EE","\\varvdots");G(U,ee,Pn,"\u02CA","\\acute");G(U,ee,Pn,"\u02CB","\\grave");G(U,ee,Pn,"\xA8","\\ddot");G(U,ee,Pn,"~","\\tilde");G(U,ee,Pn,"\u02C9","\\bar");G(U,ee,Pn,"\u02D8","\\breve");G(U,ee,Pn,"\u02C7","\\check");G(U,ee,Pn,"^","\\hat");G(U,ee,Pn,"\u20D7","\\vec");G(U,ee,Pn,"\u02D9","\\dot");G(U,ee,Pn,"\u02DA","\\mathring");G(U,ee,Ut,"\uE131","\\@imath");G(U,ee,Ut,"\uE237","\\@jmath");G(U,ee,Le,"\u0131","\u0131");G(U,ee,Le,"\u0237","\u0237");G(Qe,ee,Le,"\u0131","\\i",!0);G(Qe,ee,Le,"\u0237","\\j",!0);G(Qe,ee,Le,"\xDF","\\ss",!0);G(Qe,ee,Le,"\xE6","\\ae",!0);G(Qe,ee,Le,"\u0153","\\oe",!0);G(Qe,ee,Le,"\xF8","\\o",!0);G(Qe,ee,Le,"\xC6","\\AE",!0);G(Qe,ee,Le,"\u0152","\\OE",!0);G(Qe,ee,Le,"\xD8","\\O",!0);G(Qe,ee,Pn,"\u02CA","\\'");G(Qe,ee,Pn,"\u02CB","\\`");G(Qe,ee,Pn,"\u02C6","\\^");G(Qe,ee,Pn,"\u02DC","\\~");G(Qe,ee,Pn,"\u02C9","\\=");G(Qe,ee,Pn,"\u02D8","\\u");G(Qe,ee,Pn,"\u02D9","\\.");G(Qe,ee,Pn,"\xB8","\\c");G(Qe,ee,Pn,"\u02DA","\\r");G(Qe,ee,Pn,"\u02C7","\\v");G(Qe,ee,Pn,"\xA8",'\\"');G(Qe,ee,Pn,"\u02DD","\\H");G(Qe,ee,Pn,"\u25EF","\\textcircled");IG={"--":!0,"---":!0,"``":!0,"''":!0};G(Qe,ee,Le,"\u2013","--",!0);G(Qe,ee,Le,"\u2013","\\textendash");G(Qe,ee,Le,"\u2014","---",!0);G(Qe,ee,Le,"\u2014","\\textemdash");G(Qe,ee,Le,"\u2018","`",!0);G(Qe,ee,Le,"\u2018","\\textquoteleft");G(Qe,ee,Le,"\u2019","'",!0);G(Qe,ee,Le,"\u2019","\\textquoteright");G(Qe,ee,Le,"\u201C","``",!0);G(Qe,ee,Le,"\u201C","\\textquotedblleft");G(Qe,ee,Le,"\u201D","''",!0);G(Qe,ee,Le,"\u201D","\\textquotedblright");G(U,ee,Le,"\xB0","\\degree",!0);G(Qe,ee,Le,"\xB0","\\degree");G(Qe,ee,Le,"\xB0","\\textdegree",!0);G(U,ee,Le,"\xA3","\\pounds");G(U,ee,Le,"\xA3","\\mathsterling",!0);G(Qe,ee,Le,"\xA3","\\pounds");G(Qe,ee,Le,"\xA3","\\textsterling",!0);G(U,ve,Le,"\u2720","\\maltese");G(Qe,ve,Le,"\u2720","\\maltese");rG='0123456789/@."';for(e4=0;e40)return ol(a,h,i,r,s.concat(f));if(u){var d,p;if(u==="boldsymbol"){var m=mxe(a,i,r,s,n);d=m.fontName,p=[m.fontClass]}else l?(d=BG[u].fontName,p=[u]):(d=a4(u,r.fontWeight,r.fontShape),p=[u,r.fontWeight,r.fontShape]);if(w4(a,d,i).metrics)return ol(a,d,i,r,s.concat(p));if(IG.hasOwnProperty(a)&&d.slice(0,10)==="Typewriter"){for(var g=[],y=0;y{if(dh(t.classes)!==dh(e.classes)||t.skew!==e.skew||t.maxFontSize!==e.maxFontSize)return!1;if(t.classes.length===1){var r=t.classes[0];if(r==="mbin"||r==="mord")return!1}for(var n in t.style)if(t.style.hasOwnProperty(n)&&t.style[n]!==e.style[n])return!1;for(var i in e.style)if(e.style.hasOwnProperty(i)&&t.style[i]!==e.style[i])return!1;return!0},"canCombine"),vxe=o(t=>{for(var e=0;er&&(r=s.height),s.depth>n&&(n=s.depth),s.maxFontSize>i&&(i=s.maxFontSize)}e.height=r,e.depth=n,e.maxFontSize=i},"sizeElementFromChildren"),ds=o(function(e,r,n,i){var a=new jf(e,r,n,i);return I7(a),a},"makeSpan"),OG=o((t,e,r,n)=>new jf(t,e,r,n),"makeSvgSpan"),xxe=o(function(e,r,n){var i=ds([e],[],r);return i.height=Math.max(n||r.fontMetrics().defaultRuleThickness,r.minRuleThickness),i.style.borderBottomWidth=ct(i.height),i.maxFontSize=1,i},"makeLineSpan"),bxe=o(function(e,r,n,i){var a=new iy(e,r,n,i);return I7(a),a},"makeAnchor"),PG=o(function(e){var r=new Xf(e);return I7(r),r},"makeFragment"),wxe=o(function(e,r){return e instanceof Xf?ds([],[e],r):e},"wrapFragment"),Txe=o(function(e){if(e.positionType==="individualShift"){for(var r=e.children,n=[r[0]],i=-r[0].shift-r[0].elem.depth,a=i,s=1;s{var r=ds(["mspace"],[],e),n=Hn(t,e);return r.style.marginRight=ct(n),r},"makeGlue"),a4=o(function(e,r,n){var i="";switch(e){case"amsrm":i="AMS";break;case"textrm":i="Main";break;case"textsf":i="SansSerif";break;case"texttt":i="Typewriter";break;default:i=e}var a;return r==="textbf"&&n==="textit"?a="BoldItalic":r==="textbf"?a="Bold":r==="textit"?a="Italic":a="Regular",i+"-"+a},"retrieveTextFontName"),BG={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathnormal:{variant:"italic",fontName:"Math-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},FG={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},Cxe=o(function(e,r){var[n,i,a]=FG[e],s=new Jl(n),l=new ll([s],{width:ct(i),height:ct(a),style:"width:"+ct(i),viewBox:"0 0 "+1e3*i+" "+1e3*a,preserveAspectRatio:"xMinYMin"}),u=OG(["overlay"],[l],r);return u.height=a,u.style.height=ct(a),u.style.width=ct(i),u},"staticSvg"),Be={fontMap:BG,makeSymbol:ol,mathsym:pxe,makeSpan:ds,makeSvgSpan:OG,makeLineSpan:xxe,makeAnchor:bxe,makeFragment:PG,wrapFragment:wxe,makeVList:kxe,makeOrd:gxe,makeGlue:Exe,staticSvg:Cxe,svgData:FG,tryCombineChars:vxe},Un={number:3,unit:"mu"},Wf={number:4,unit:"mu"},nu={number:5,unit:"mu"},Sxe={mord:{mop:Un,mbin:Wf,mrel:nu,minner:Un},mop:{mord:Un,mop:Un,mrel:nu,minner:Un},mbin:{mord:Wf,mop:Wf,mopen:Wf,minner:Wf},mrel:{mord:nu,mop:nu,mopen:nu,minner:nu},mopen:{},mclose:{mop:Un,mbin:Wf,mrel:nu,minner:Un},mpunct:{mord:Un,mop:Un,mrel:nu,mopen:Un,mclose:Un,mpunct:Un,minner:Un},minner:{mord:Un,mop:Un,mbin:Wf,mrel:nu,mopen:Un,mpunct:Un,minner:Un}},Axe={mord:{mop:Un},mop:{mord:Un,mop:Un},mbin:{},mrel:{},mopen:{},mclose:{mop:Un},mpunct:{},minner:{mop:Un}},zG={},m4={},g4={};o(vt,"defineFunction");o(Kf,"defineFunctionBuilders");y4=o(function(e){return e.type==="ordgroup"&&e.body.length===1?e.body[0]:e},"normalizeArgument"),ui=o(function(e){return e.type==="ordgroup"?e.body:[e]},"ordargument"),su=Be.makeSpan,_xe=["leftmost","mbin","mopen","mrel","mop","mpunct"],Lxe=["rightmost","mrel","mclose","mpunct"],Dxe={display:Ht.DISPLAY,text:Ht.TEXT,script:Ht.SCRIPT,scriptscript:Ht.SCRIPTSCRIPT},Rxe={mord:"mord",mop:"mop",mbin:"mbin",mrel:"mrel",mopen:"mopen",mclose:"mclose",mpunct:"mpunct",minner:"minner"},Ri=o(function(e,r,n,i){i===void 0&&(i=[null,null]);for(var a=[],s=0;s{var v=y.classes[0],x=g.classes[0];v==="mbin"&&Vt.contains(Lxe,x)?y.classes[0]="mord":x==="mbin"&&Vt.contains(_xe,v)&&(g.classes[0]="mord")},{node:d},p,m),aG(a,(g,y)=>{var v=E7(y),x=E7(g),b=v&&x?g.hasClass("mtight")?Axe[v][x]:Sxe[v][x]:null;if(b)return Be.makeGlue(b,h)},{node:d},p,m),a},"buildExpression"),aG=o(function t(e,r,n,i,a){i&&e.push(i);for(var s=0;sp=>{e.splice(d+1,0,p),s++})(s)}i&&e.pop()},"traverseNonSpaceNodes"),GG=o(function(e){return e instanceof Xf||e instanceof iy||e instanceof jf&&e.hasClass("enclosing")?e:null},"checkPartialGroup"),Nxe=o(function t(e,r){var n=GG(e);if(n){var i=n.children;if(i.length){if(r==="right")return t(i[i.length-1],"right");if(r==="left")return t(i[0],"left")}}return e},"getOutermostNode"),E7=o(function(e,r){return e?(r&&(e=Nxe(e,r)),Rxe[e.classes[0]]||null):null},"getTypeOfDomTree"),sy=o(function(e,r){var n=["nulldelimiter"].concat(e.baseSizingClasses());return su(r.concat(n))},"makeNullDelimiter"),Cr=o(function(e,r,n){if(!e)return su();if(m4[e.type]){var i=m4[e.type](e,r);if(n&&r.size!==n.size){i=su(r.sizingClasses(n),[i],r);var a=r.sizeMultiplier/n.sizeMultiplier;i.height*=a,i.depth*=a}return i}else throw new nt("Got group of unknown type: '"+e.type+"'")},"buildGroup");o(s4,"buildHTMLUnbreakable");o(C7,"buildHTML");o($G,"newDocumentFragment");ps=class{static{o(this,"MathNode")}constructor(e,r,n){this.type=void 0,this.attributes=void 0,this.children=void 0,this.classes=void 0,this.type=e,this.attributes={},this.children=r||[],this.classes=n||[]}setAttribute(e,r){this.attributes[e]=r}getAttribute(e){return this.attributes[e]}toNode(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var r in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,r)&&e.setAttribute(r,this.attributes[r]);this.classes.length>0&&(e.className=dh(this.classes));for(var n=0;n0&&(e+=' class ="'+Vt.escape(dh(this.classes))+'"'),e+=">";for(var n=0;n",e}toText(){return this.children.map(e=>e.toText()).join("")}},qf=class{static{o(this,"TextNode")}constructor(e){this.text=void 0,this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return Vt.escape(this.toText())}toText(){return this.text}},S7=class{static{o(this,"SpaceNode")}constructor(e){this.width=void 0,this.character=void 0,this.width=e,e>=.05555&&e<=.05556?this.character="\u200A":e>=.1666&&e<=.1667?this.character="\u2009":e>=.2222&&e<=.2223?this.character="\u2005":e>=.2777&&e<=.2778?this.character="\u2005\u200A":e>=-.05556&&e<=-.05555?this.character="\u200A\u2063":e>=-.1667&&e<=-.1666?this.character="\u2009\u2063":e>=-.2223&&e<=-.2222?this.character="\u205F\u2063":e>=-.2778&&e<=-.2777?this.character="\u2005\u2063":this.character=null}toNode(){if(this.character)return document.createTextNode(this.character);var e=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return e.setAttribute("width",ct(this.width)),e}toMarkup(){return this.character?""+this.character+"":''}toText(){return this.character?this.character:" "}},et={MathNode:ps,TextNode:qf,SpaceNode:S7,newDocumentFragment:$G},_o=o(function(e,r,n){return wn[r][e]&&wn[r][e].replace&&e.charCodeAt(0)!==55349&&!(IG.hasOwnProperty(e)&&n&&(n.fontFamily&&n.fontFamily.slice(4,6)==="tt"||n.font&&n.font.slice(4,6)==="tt"))&&(e=wn[r][e].replace),new et.TextNode(e)},"makeText"),O7=o(function(e){return e.length===1?e[0]:new et.MathNode("mrow",e)},"makeRow"),P7=o(function(e,r){if(r.fontFamily==="texttt")return"monospace";if(r.fontFamily==="textsf")return r.fontShape==="textit"&&r.fontWeight==="textbf"?"sans-serif-bold-italic":r.fontShape==="textit"?"sans-serif-italic":r.fontWeight==="textbf"?"bold-sans-serif":"sans-serif";if(r.fontShape==="textit"&&r.fontWeight==="textbf")return"bold-italic";if(r.fontShape==="textit")return"italic";if(r.fontWeight==="textbf")return"bold";var n=r.font;if(!n||n==="mathnormal")return null;var i=e.mode;if(n==="mathit")return"italic";if(n==="boldsymbol")return e.type==="textord"?"bold":"bold-italic";if(n==="mathbf")return"bold";if(n==="mathbb")return"double-struck";if(n==="mathfrak")return"fraktur";if(n==="mathscr"||n==="mathcal")return"script";if(n==="mathsf")return"sans-serif";if(n==="mathtt")return"monospace";var a=e.text;if(Vt.contains(["\\imath","\\jmath"],a))return null;wn[i][a]&&wn[i][a].replace&&(a=wn[i][a].replace);var s=Be.fontMap[n].fontName;return M7(a,s,i)?Be.fontMap[n].variant:null},"getVariant"),gs=o(function(e,r,n){if(e.length===1){var i=fn(e[0],r);return n&&i instanceof ps&&i.type==="mo"&&(i.setAttribute("lspace","0em"),i.setAttribute("rspace","0em")),[i]}for(var a=[],s,l=0;l0&&(d.text=d.text.slice(0,1)+"\u0338"+d.text.slice(1),a.pop())}}}a.push(u),s=u}return a},"buildExpression"),ph=o(function(e,r,n){return O7(gs(e,r,n))},"buildExpressionRow"),fn=o(function(e,r){if(!e)return new et.MathNode("mrow");if(g4[e.type]){var n=g4[e.type](e,r);return n}else throw new nt("Got group of unknown type: '"+e.type+"'")},"buildGroup");o(sG,"buildMathML");VG=o(function(e){return new d4({style:e.displayMode?Ht.DISPLAY:Ht.TEXT,maxSize:e.maxSize,minRuleThickness:e.minRuleThickness})},"optionsFromSettings"),UG=o(function(e,r){if(r.displayMode){var n=["katex-display"];r.leqno&&n.push("leqno"),r.fleqn&&n.push("fleqn"),e=Be.makeSpan(n,[e])}return e},"displayWrap"),Mxe=o(function(e,r,n){var i=VG(n),a;if(n.output==="mathml")return sG(e,r,i,n.displayMode,!0);if(n.output==="html"){var s=C7(e,i);a=Be.makeSpan(["katex"],[s])}else{var l=sG(e,r,i,n.displayMode,!1),u=C7(e,i);a=Be.makeSpan(["katex"],[l,u])}return UG(a,n)},"buildTree"),Ixe=o(function(e,r,n){var i=VG(n),a=C7(e,i),s=Be.makeSpan(["katex"],[a]);return UG(s,n)},"buildHTMLTree"),Oxe={widehat:"^",widecheck:"\u02C7",widetilde:"~",utilde:"~",overleftarrow:"\u2190",underleftarrow:"\u2190",xleftarrow:"\u2190",overrightarrow:"\u2192",underrightarrow:"\u2192",xrightarrow:"\u2192",underbrace:"\u23DF",overbrace:"\u23DE",overgroup:"\u23E0",undergroup:"\u23E1",overleftrightarrow:"\u2194",underleftrightarrow:"\u2194",xleftrightarrow:"\u2194",Overrightarrow:"\u21D2",xRightarrow:"\u21D2",overleftharpoon:"\u21BC",xleftharpoonup:"\u21BC",overrightharpoon:"\u21C0",xrightharpoonup:"\u21C0",xLeftarrow:"\u21D0",xLeftrightarrow:"\u21D4",xhookleftarrow:"\u21A9",xhookrightarrow:"\u21AA",xmapsto:"\u21A6",xrightharpoondown:"\u21C1",xleftharpoondown:"\u21BD",xrightleftharpoons:"\u21CC",xleftrightharpoons:"\u21CB",xtwoheadleftarrow:"\u219E",xtwoheadrightarrow:"\u21A0",xlongequal:"=",xtofrom:"\u21C4",xrightleftarrows:"\u21C4",xrightequilibrium:"\u21CC",xleftequilibrium:"\u21CB","\\cdrightarrow":"\u2192","\\cdleftarrow":"\u2190","\\cdlongequal":"="},Pxe=o(function(e){var r=new et.MathNode("mo",[new et.TextNode(Oxe[e.replace(/^\\/,"")])]);return r.setAttribute("stretchy","true"),r},"mathMLnode"),Bxe={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],"\\cdrightarrow":[["rightarrow"],3,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],"\\cdleftarrow":[["leftarrow"],3,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],"\\cdlongequal":[["longequal"],3,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},Fxe=o(function(e){return e.type==="ordgroup"?e.body.length:1},"groupLength"),zxe=o(function(e,r){function n(){var l=4e5,u=e.label.slice(1);if(Vt.contains(["widehat","widecheck","widetilde","utilde"],u)){var h=e,f=Fxe(h.base),d,p,m;if(f>5)u==="widehat"||u==="widecheck"?(d=420,l=2364,m=.42,p=u+"4"):(d=312,l=2340,m=.34,p="tilde4");else{var g=[1,1,2,2,3,3][f];u==="widehat"||u==="widecheck"?(l=[0,1062,2364,2364,2364][g],d=[0,239,300,360,420][g],m=[0,.24,.3,.3,.36,.42][g],p=u+g):(l=[0,600,1033,2339,2340][g],d=[0,260,286,306,312][g],m=[0,.26,.286,.3,.306,.34][g],p="tilde"+g)}var y=new Jl(p),v=new ll([y],{width:"100%",height:ct(m),viewBox:"0 0 "+l+" "+d,preserveAspectRatio:"none"});return{span:Be.makeSvgSpan([],[v],r),minWidth:0,height:m}}else{var x=[],b=Bxe[u],[w,S,T]=b,E=T/1e3,_=w.length,A,L;if(_===1){var M=b[3];A=["hide-tail"],L=[M]}else if(_===2)A=["halfarrow-left","halfarrow-right"],L=["xMinYMin","xMaxYMin"];else if(_===3)A=["brace-left","brace-center","brace-right"],L=["xMinYMin","xMidYMin","xMaxYMin"];else throw new Error(`Correct katexImagesData or update code here to support + `+_+" children.");for(var N=0;N<_;N++){var k=new Jl(w[N]),I=new ll([k],{width:"400em",height:ct(E),viewBox:"0 0 "+l+" "+T,preserveAspectRatio:L[N]+" slice"}),C=Be.makeSvgSpan([A[N]],[I],r);if(_===1)return{span:C,minWidth:S,height:E};C.style.height=ct(E),x.push(C)}return{span:Be.makeSpan(["stretchy"],x,r),minWidth:S,height:E}}}o(n,"buildSvgSpan_");var{span:i,minWidth:a,height:s}=n();return i.height=s,i.style.height=ct(s),a>0&&(i.style.minWidth=ct(a)),i},"svgSpan"),Gxe=o(function(e,r,n,i,a){var s,l=e.height+e.depth+n+i;if(/fbox|color|angl/.test(r)){if(s=Be.makeSpan(["stretchy",r],[],a),r==="fbox"){var u=a.color&&a.getColor();u&&(s.style.borderColor=u)}}else{var h=[];/^[bx]cancel$/.test(r)&&h.push(new ay({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(r)&&h.push(new ay({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var f=new ll(h,{width:"100%",height:ct(l)});s=Be.makeSvgSpan([],[f],a)}return s.height=l,s.style.height=ct(l),s},"encloseSpan"),ou={encloseSpan:Gxe,mathMLnode:Pxe,svgSpan:zxe};o(ir,"assertNodeType");o(B7,"assertSymbolNodeType");o(T4,"checkSymbolNodeType");F7=o((t,e)=>{var r,n,i;t&&t.type==="supsub"?(n=ir(t.base,"accent"),r=n.base,t.base=r,i=uxe(Cr(t,e)),t.base=n):(n=ir(t,"accent"),r=n.base);var a=Cr(r,e.havingCrampedStyle()),s=n.isShifty&&Vt.isCharacterBox(r),l=0;if(s){var u=Vt.getBaseElem(r),h=Cr(u,e.havingCrampedStyle());l=tG(h).skew}var f=n.label==="\\c",d=f?a.height+a.depth:Math.min(a.height,e.fontMetrics().xHeight),p;if(n.isStretchy)p=ou.svgSpan(n,e),p=Be.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:a},{type:"elem",elem:p,wrapperClasses:["svg-align"],wrapperStyle:l>0?{width:"calc(100% - "+ct(2*l)+")",marginLeft:ct(2*l)}:void 0}]},e);else{var m,g;n.label==="\\vec"?(m=Be.staticSvg("vec",e),g=Be.svgData.vec[1]):(m=Be.makeOrd({mode:n.mode,text:n.label},e,"textord"),m=tG(m),m.italic=0,g=m.width,f&&(d+=m.depth)),p=Be.makeSpan(["accent-body"],[m]);var y=n.label==="\\textcircled";y&&(p.classes.push("accent-full"),d=a.height);var v=l;y||(v-=g/2),p.style.left=ct(v),n.label==="\\textcircled"&&(p.style.top=".2em"),p=Be.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:a},{type:"kern",size:-d},{type:"elem",elem:p}]},e)}var x=Be.makeSpan(["mord","accent"],[p],e);return i?(i.children[0]=x,i.height=Math.max(x.height,i.height),i.classes[0]="mord",i):x},"htmlBuilder$a"),HG=o((t,e)=>{var r=t.isStretchy?ou.mathMLnode(t.label):new et.MathNode("mo",[_o(t.label,t.mode)]),n=new et.MathNode("mover",[fn(t.base,e),r]);return n.setAttribute("accent","true"),n},"mathmlBuilder$9"),$xe=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map(t=>"\\"+t).join("|"));vt({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:o((t,e)=>{var r=y4(e[0]),n=!$xe.test(t.funcName),i=!n||t.funcName==="\\widehat"||t.funcName==="\\widetilde"||t.funcName==="\\widecheck";return{type:"accent",mode:t.parser.mode,label:t.funcName,isStretchy:n,isShifty:i,base:r}},"handler"),htmlBuilder:F7,mathmlBuilder:HG});vt({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\c","\\r","\\H","\\v","\\textcircled"],props:{numArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["primitive"]},handler:o((t,e)=>{var r=e[0],n=t.parser.mode;return n==="math"&&(t.parser.settings.reportNonstrict("mathVsTextAccents","LaTeX's accent "+t.funcName+" works only in text mode"),n="text"),{type:"accent",mode:n,label:t.funcName,isStretchy:!1,isShifty:!0,base:r}},"handler"),htmlBuilder:F7,mathmlBuilder:HG});vt({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],props:{numArgs:1},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=e[0];return{type:"accentUnder",mode:r.mode,label:n,base:i}},"handler"),htmlBuilder:o((t,e)=>{var r=Cr(t.base,e),n=ou.svgSpan(t,e),i=t.label==="\\utilde"?.12:0,a=Be.makeVList({positionType:"top",positionData:r.height,children:[{type:"elem",elem:n,wrapperClasses:["svg-align"]},{type:"kern",size:i},{type:"elem",elem:r}]},e);return Be.makeSpan(["mord","accentunder"],[a],e)},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=ou.mathMLnode(t.label),n=new et.MathNode("munder",[fn(t.base,e),r]);return n.setAttribute("accentunder","true"),n},"mathmlBuilder")});o4=o(t=>{var e=new et.MathNode("mpadded",t?[t]:[]);return e.setAttribute("width","+0.6em"),e.setAttribute("lspace","0.3em"),e},"paddedNode");vt({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium","\\\\cdrightarrow","\\\\cdleftarrow","\\\\cdlongequal"],props:{numArgs:1,numOptionalArgs:1},handler(t,e,r){var{parser:n,funcName:i}=t;return{type:"xArrow",mode:n.mode,label:i,body:e[0],below:r[0]}},htmlBuilder(t,e){var r=e.style,n=e.havingStyle(r.sup()),i=Be.wrapFragment(Cr(t.body,n,e),e),a=t.label.slice(0,2)==="\\x"?"x":"cd";i.classes.push(a+"-arrow-pad");var s;t.below&&(n=e.havingStyle(r.sub()),s=Be.wrapFragment(Cr(t.below,n,e),e),s.classes.push(a+"-arrow-pad"));var l=ou.svgSpan(t,e),u=-e.fontMetrics().axisHeight+.5*l.height,h=-e.fontMetrics().axisHeight-.5*l.height-.111;(i.depth>.25||t.label==="\\xleftequilibrium")&&(h-=i.depth);var f;if(s){var d=-e.fontMetrics().axisHeight+s.height+.5*l.height+.111;f=Be.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:h},{type:"elem",elem:l,shift:u},{type:"elem",elem:s,shift:d}]},e)}else f=Be.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:h},{type:"elem",elem:l,shift:u}]},e);return f.children[0].children[0].children[1].classes.push("svg-align"),Be.makeSpan(["mrel","x-arrow"],[f],e)},mathmlBuilder(t,e){var r=ou.mathMLnode(t.label);r.setAttribute("minsize",t.label.charAt(0)==="x"?"1.75em":"3.0em");var n;if(t.body){var i=o4(fn(t.body,e));if(t.below){var a=o4(fn(t.below,e));n=new et.MathNode("munderover",[r,a,i])}else n=new et.MathNode("mover",[r,i])}else if(t.below){var s=o4(fn(t.below,e));n=new et.MathNode("munder",[r,s])}else n=o4(),n=new et.MathNode("mover",[r,n]);return n}});Vxe=Be.makeSpan;o(YG,"htmlBuilder$9");o(WG,"mathmlBuilder$8");vt({type:"mclass",names:["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],props:{numArgs:1,primitive:!0},handler(t,e){var{parser:r,funcName:n}=t,i=e[0];return{type:"mclass",mode:r.mode,mclass:"m"+n.slice(5),body:ui(i),isCharacterBox:Vt.isCharacterBox(i)}},htmlBuilder:YG,mathmlBuilder:WG});k4=o(t=>{var e=t.type==="ordgroup"&&t.body.length?t.body[0]:t;return e.type==="atom"&&(e.family==="bin"||e.family==="rel")?"m"+e.family:"mord"},"binrelClass");vt({type:"mclass",names:["\\@binrel"],props:{numArgs:2},handler(t,e){var{parser:r}=t;return{type:"mclass",mode:r.mode,mclass:k4(e[0]),body:ui(e[1]),isCharacterBox:Vt.isCharacterBox(e[1])}}});vt({type:"mclass",names:["\\stackrel","\\overset","\\underset"],props:{numArgs:2},handler(t,e){var{parser:r,funcName:n}=t,i=e[1],a=e[0],s;n!=="\\stackrel"?s=k4(i):s="mrel";var l={type:"op",mode:i.mode,limits:!0,alwaysHandleSupSub:!0,parentIsSupSub:!1,symbol:!1,suppressBaseShift:n!=="\\stackrel",body:ui(i)},u={type:"supsub",mode:a.mode,base:l,sup:n==="\\underset"?null:a,sub:n==="\\underset"?a:null};return{type:"mclass",mode:r.mode,mclass:s,body:[u],isCharacterBox:Vt.isCharacterBox(u)}},htmlBuilder:YG,mathmlBuilder:WG});vt({type:"pmb",names:["\\pmb"],props:{numArgs:1,allowedInText:!0},handler(t,e){var{parser:r}=t;return{type:"pmb",mode:r.mode,mclass:k4(e[0]),body:ui(e[0])}},htmlBuilder(t,e){var r=Ri(t.body,e,!0),n=Be.makeSpan([t.mclass],r,e);return n.style.textShadow="0.02em 0.01em 0.04px",n},mathmlBuilder(t,e){var r=gs(t.body,e),n=new et.MathNode("mstyle",r);return n.setAttribute("style","text-shadow: 0.02em 0.01em 0.04px"),n}});Uxe={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},oG=o(()=>({type:"styling",body:[],mode:"math",style:"display"}),"newCell"),lG=o(t=>t.type==="textord"&&t.text==="@","isStartOfArrow"),Hxe=o((t,e)=>(t.type==="mathord"||t.type==="atom")&&t.text===e,"isLabelEnd");o(Yxe,"cdArrow");o(Wxe,"parseCD");vt({type:"cdlabel",names:["\\\\cdleft","\\\\cdright"],props:{numArgs:1},handler(t,e){var{parser:r,funcName:n}=t;return{type:"cdlabel",mode:r.mode,side:n.slice(4),label:e[0]}},htmlBuilder(t,e){var r=e.havingStyle(e.style.sup()),n=Be.wrapFragment(Cr(t.label,r,e),e);return n.classes.push("cd-label-"+t.side),n.style.bottom=ct(.8-n.depth),n.height=0,n.depth=0,n},mathmlBuilder(t,e){var r=new et.MathNode("mrow",[fn(t.label,e)]);return r=new et.MathNode("mpadded",[r]),r.setAttribute("width","0"),t.side==="left"&&r.setAttribute("lspace","-1width"),r.setAttribute("voffset","0.7em"),r=new et.MathNode("mstyle",[r]),r.setAttribute("displaystyle","false"),r.setAttribute("scriptlevel","1"),r}});vt({type:"cdlabelparent",names:["\\\\cdparent"],props:{numArgs:1},handler(t,e){var{parser:r}=t;return{type:"cdlabelparent",mode:r.mode,fragment:e[0]}},htmlBuilder(t,e){var r=Be.wrapFragment(Cr(t.fragment,e),e);return r.classes.push("cd-vert-arrow"),r},mathmlBuilder(t,e){return new et.MathNode("mrow",[fn(t.fragment,e)])}});vt({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler(t,e){for(var{parser:r}=t,n=ir(e[0],"ordgroup"),i=n.body,a="",s=0;s=1114111)throw new nt("\\@char with invalid code point "+a);return u<=65535?h=String.fromCharCode(u):(u-=65536,h=String.fromCharCode((u>>10)+55296,(u&1023)+56320)),{type:"textord",mode:r.mode,text:h}}});qG=o((t,e)=>{var r=Ri(t.body,e.withColor(t.color),!1);return Be.makeFragment(r)},"htmlBuilder$8"),XG=o((t,e)=>{var r=gs(t.body,e.withColor(t.color)),n=new et.MathNode("mstyle",r);return n.setAttribute("mathcolor",t.color),n},"mathmlBuilder$7");vt({type:"color",names:["\\textcolor"],props:{numArgs:2,allowedInText:!0,argTypes:["color","original"]},handler(t,e){var{parser:r}=t,n=ir(e[0],"color-token").color,i=e[1];return{type:"color",mode:r.mode,color:n,body:ui(i)}},htmlBuilder:qG,mathmlBuilder:XG});vt({type:"color",names:["\\color"],props:{numArgs:1,allowedInText:!0,argTypes:["color"]},handler(t,e){var{parser:r,breakOnTokenText:n}=t,i=ir(e[0],"color-token").color;r.gullet.macros.set("\\current@color",i);var a=r.parseExpression(!0,n);return{type:"color",mode:r.mode,color:i,body:a}},htmlBuilder:qG,mathmlBuilder:XG});vt({type:"cr",names:["\\\\"],props:{numArgs:0,numOptionalArgs:0,allowedInText:!0},handler(t,e,r){var{parser:n}=t,i=n.gullet.future().text==="["?n.parseSizeGroup(!0):null,a=!n.settings.displayMode||!n.settings.useStrictBehavior("newLineInDisplayMode","In LaTeX, \\\\ or \\newline does nothing in display mode");return{type:"cr",mode:n.mode,newLine:a,size:i&&ir(i,"size").value}},htmlBuilder(t,e){var r=Be.makeSpan(["mspace"],[],e);return t.newLine&&(r.classes.push("newline"),t.size&&(r.style.marginTop=ct(Hn(t.size,e)))),r},mathmlBuilder(t,e){var r=new et.MathNode("mspace");return t.newLine&&(r.setAttribute("linebreak","newline"),t.size&&r.setAttribute("height",ct(Hn(t.size,e)))),r}});A7={"\\global":"\\global","\\long":"\\\\globallong","\\\\globallong":"\\\\globallong","\\def":"\\gdef","\\gdef":"\\gdef","\\edef":"\\xdef","\\xdef":"\\xdef","\\let":"\\\\globallet","\\futurelet":"\\\\globalfuture"},jG=o(t=>{var e=t.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(e))throw new nt("Expected a control sequence",t);return e},"checkControlSequence"),qxe=o(t=>{var e=t.gullet.popToken();return e.text==="="&&(e=t.gullet.popToken(),e.text===" "&&(e=t.gullet.popToken())),e},"getRHS"),KG=o((t,e,r,n)=>{var i=t.gullet.macros.get(r.text);i==null&&(r.noexpand=!0,i={tokens:[r],numArgs:0,unexpandable:!t.gullet.isExpandable(r.text)}),t.gullet.macros.set(e,i,n)},"letCommand");vt({type:"internal",names:["\\global","\\long","\\\\globallong"],props:{numArgs:0,allowedInText:!0},handler(t){var{parser:e,funcName:r}=t;e.consumeSpaces();var n=e.fetch();if(A7[n.text])return(r==="\\global"||r==="\\\\globallong")&&(n.text=A7[n.text]),ir(e.parseFunction(),"internal");throw new nt("Invalid token after macro prefix",n)}});vt({type:"internal",names:["\\def","\\gdef","\\edef","\\xdef"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(t){var{parser:e,funcName:r}=t,n=e.gullet.popToken(),i=n.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(i))throw new nt("Expected a control sequence",n);for(var a=0,s,l=[[]];e.gullet.future().text!=="{";)if(n=e.gullet.popToken(),n.text==="#"){if(e.gullet.future().text==="{"){s=e.gullet.future(),l[a].push("{");break}if(n=e.gullet.popToken(),!/^[1-9]$/.test(n.text))throw new nt('Invalid argument number "'+n.text+'"');if(parseInt(n.text)!==a+1)throw new nt('Argument number "'+n.text+'" out of order');a++,l.push([])}else{if(n.text==="EOF")throw new nt("Expected a macro definition");l[a].push(n.text)}var{tokens:u}=e.gullet.consumeArg();return s&&u.unshift(s),(r==="\\edef"||r==="\\xdef")&&(u=e.gullet.expandTokens(u),u.reverse()),e.gullet.macros.set(i,{tokens:u,numArgs:a,delimiters:l},r===A7[r]),{type:"internal",mode:e.mode}}});vt({type:"internal",names:["\\let","\\\\globallet"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(t){var{parser:e,funcName:r}=t,n=jG(e.gullet.popToken());e.gullet.consumeSpaces();var i=qxe(e);return KG(e,n,i,r==="\\\\globallet"),{type:"internal",mode:e.mode}}});vt({type:"internal",names:["\\futurelet","\\\\globalfuture"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(t){var{parser:e,funcName:r}=t,n=jG(e.gullet.popToken()),i=e.gullet.popToken(),a=e.gullet.popToken();return KG(e,n,a,r==="\\\\globalfuture"),e.gullet.pushToken(a),e.gullet.pushToken(i),{type:"internal",mode:e.mode}}});ey=o(function(e,r,n){var i=wn.math[e]&&wn.math[e].replace,a=M7(i||e,r,n);if(!a)throw new Error("Unsupported symbol "+e+" and font size "+r+".");return a},"getMetrics"),z7=o(function(e,r,n,i){var a=n.havingBaseStyle(r),s=Be.makeSpan(i.concat(a.sizingClasses(n)),[e],n),l=a.sizeMultiplier/n.sizeMultiplier;return s.height*=l,s.depth*=l,s.maxFontSize=a.sizeMultiplier,s},"styleWrap"),QG=o(function(e,r,n){var i=r.havingBaseStyle(n),a=(1-r.sizeMultiplier/i.sizeMultiplier)*r.fontMetrics().axisHeight;e.classes.push("delimcenter"),e.style.top=ct(a),e.height-=a,e.depth+=a},"centerSpan"),Xxe=o(function(e,r,n,i,a,s){var l=Be.makeSymbol(e,"Main-Regular",a,i),u=z7(l,r,i,s);return n&&QG(u,i,r),u},"makeSmallDelim"),jxe=o(function(e,r,n,i){return Be.makeSymbol(e,"Size"+r+"-Regular",n,i)},"mathrmSize"),ZG=o(function(e,r,n,i,a,s){var l=jxe(e,r,a,i),u=z7(Be.makeSpan(["delimsizing","size"+r],[l],i),Ht.TEXT,i,s);return n&&QG(u,i,Ht.TEXT),u},"makeLargeDelim"),h7=o(function(e,r,n){var i;r==="Size1-Regular"?i="delim-size1":i="delim-size4";var a=Be.makeSpan(["delimsizinginner",i],[Be.makeSpan([],[Be.makeSymbol(e,r,n)])]);return{type:"elem",elem:a}},"makeGlyphSpan"),f7=o(function(e,r,n){var i=Zl["Size4-Regular"][e.charCodeAt(0)]?Zl["Size4-Regular"][e.charCodeAt(0)][4]:Zl["Size1-Regular"][e.charCodeAt(0)][4],a=new Jl("inner",nxe(e,Math.round(1e3*r))),s=new ll([a],{width:ct(i),height:ct(r),style:"width:"+ct(i),viewBox:"0 0 "+1e3*i+" "+Math.round(1e3*r),preserveAspectRatio:"xMinYMin"}),l=Be.makeSvgSpan([],[s],n);return l.height=r,l.style.height=ct(r),l.style.width=ct(i),{type:"elem",elem:l}},"makeInner"),_7=.008,l4={type:"kern",size:-1*_7},Kxe=["|","\\lvert","\\rvert","\\vert"],Qxe=["\\|","\\lVert","\\rVert","\\Vert"],JG=o(function(e,r,n,i,a,s){var l,u,h,f,d="",p=0;l=h=f=e,u=null;var m="Size1-Regular";e==="\\uparrow"?h=f="\u23D0":e==="\\Uparrow"?h=f="\u2016":e==="\\downarrow"?l=h="\u23D0":e==="\\Downarrow"?l=h="\u2016":e==="\\updownarrow"?(l="\\uparrow",h="\u23D0",f="\\downarrow"):e==="\\Updownarrow"?(l="\\Uparrow",h="\u2016",f="\\Downarrow"):Vt.contains(Kxe,e)?(h="\u2223",d="vert",p=333):Vt.contains(Qxe,e)?(h="\u2225",d="doublevert",p=556):e==="["||e==="\\lbrack"?(l="\u23A1",h="\u23A2",f="\u23A3",m="Size4-Regular",d="lbrack",p=667):e==="]"||e==="\\rbrack"?(l="\u23A4",h="\u23A5",f="\u23A6",m="Size4-Regular",d="rbrack",p=667):e==="\\lfloor"||e==="\u230A"?(h=l="\u23A2",f="\u23A3",m="Size4-Regular",d="lfloor",p=667):e==="\\lceil"||e==="\u2308"?(l="\u23A1",h=f="\u23A2",m="Size4-Regular",d="lceil",p=667):e==="\\rfloor"||e==="\u230B"?(h=l="\u23A5",f="\u23A6",m="Size4-Regular",d="rfloor",p=667):e==="\\rceil"||e==="\u2309"?(l="\u23A4",h=f="\u23A5",m="Size4-Regular",d="rceil",p=667):e==="("||e==="\\lparen"?(l="\u239B",h="\u239C",f="\u239D",m="Size4-Regular",d="lparen",p=875):e===")"||e==="\\rparen"?(l="\u239E",h="\u239F",f="\u23A0",m="Size4-Regular",d="rparen",p=875):e==="\\{"||e==="\\lbrace"?(l="\u23A7",u="\u23A8",f="\u23A9",h="\u23AA",m="Size4-Regular"):e==="\\}"||e==="\\rbrace"?(l="\u23AB",u="\u23AC",f="\u23AD",h="\u23AA",m="Size4-Regular"):e==="\\lgroup"||e==="\u27EE"?(l="\u23A7",f="\u23A9",h="\u23AA",m="Size4-Regular"):e==="\\rgroup"||e==="\u27EF"?(l="\u23AB",f="\u23AD",h="\u23AA",m="Size4-Regular"):e==="\\lmoustache"||e==="\u23B0"?(l="\u23A7",f="\u23AD",h="\u23AA",m="Size4-Regular"):(e==="\\rmoustache"||e==="\u23B1")&&(l="\u23AB",f="\u23A9",h="\u23AA",m="Size4-Regular");var g=ey(l,m,a),y=g.height+g.depth,v=ey(h,m,a),x=v.height+v.depth,b=ey(f,m,a),w=b.height+b.depth,S=0,T=1;if(u!==null){var E=ey(u,m,a);S=E.height+E.depth,T=2}var _=y+w+S,A=Math.max(0,Math.ceil((r-_)/(T*x))),L=_+A*T*x,M=i.fontMetrics().axisHeight;n&&(M*=i.sizeMultiplier);var N=L/2-M,k=[];if(d.length>0){var I=L-y-w,C=Math.round(L*1e3),O=ixe(d,Math.round(I*1e3)),D=new Jl(d,O),P=(p/1e3).toFixed(3)+"em",F=(C/1e3).toFixed(3)+"em",B=new ll([D],{width:P,height:F,viewBox:"0 0 "+p+" "+C}),$=Be.makeSvgSpan([],[B],i);$.height=C/1e3,$.style.width=P,$.style.height=F,k.push({type:"elem",elem:$})}else{if(k.push(h7(f,m,a)),k.push(l4),u===null){var z=L-y-w+2*_7;k.push(f7(h,z,i))}else{var Y=(L-y-w-S)/2+2*_7;k.push(f7(h,Y,i)),k.push(l4),k.push(h7(u,m,a)),k.push(l4),k.push(f7(h,Y,i))}k.push(l4),k.push(h7(l,m,a))}var Q=i.havingBaseStyle(Ht.TEXT),X=Be.makeVList({positionType:"bottom",positionData:N,children:k},Q);return z7(Be.makeSpan(["delimsizing","mult"],[X],Q),Ht.TEXT,i,s)},"makeStackedDelim"),d7=80,p7=.08,m7=o(function(e,r,n,i,a){var s=rxe(e,i,n),l=new Jl(e,s),u=new ll([l],{width:"400em",height:ct(r),viewBox:"0 0 400000 "+n,preserveAspectRatio:"xMinYMin slice"});return Be.makeSvgSpan(["hide-tail"],[u],a)},"sqrtSvg"),Zxe=o(function(e,r){var n=r.havingBaseSizing(),i=n$("\\surd",e*n.sizeMultiplier,r$,n),a=n.sizeMultiplier,s=Math.max(0,r.minRuleThickness-r.fontMetrics().sqrtRuleThickness),l,u=0,h=0,f=0,d;return i.type==="small"?(f=1e3+1e3*s+d7,e<1?a=1:e<1.4&&(a=.7),u=(1+s+p7)/a,h=(1+s)/a,l=m7("sqrtMain",u,f,s,r),l.style.minWidth="0.853em",d=.833/a):i.type==="large"?(f=(1e3+d7)*ty[i.size],h=(ty[i.size]+s)/a,u=(ty[i.size]+s+p7)/a,l=m7("sqrtSize"+i.size,u,f,s,r),l.style.minWidth="1.02em",d=1/a):(u=e+s+p7,h=e+s,f=Math.floor(1e3*e+s)+d7,l=m7("sqrtTall",u,f,s,r),l.style.minWidth="0.742em",d=1.056),l.height=h,l.style.height=ct(u),{span:l,advanceWidth:d,ruleWidth:(r.fontMetrics().sqrtRuleThickness+s)*a}},"makeSqrtImage"),e$=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\u230A","\u230B","\\lceil","\\rceil","\u2308","\u2309","\\surd"],Jxe=["\\uparrow","\\downarrow","\\updownarrow","\\Uparrow","\\Downarrow","\\Updownarrow","|","\\|","\\vert","\\Vert","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\u27EE","\u27EF","\\lmoustache","\\rmoustache","\u23B0","\u23B1"],t$=["<",">","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"],ty=[0,1.2,1.8,2.4,3],ebe=o(function(e,r,n,i,a){if(e==="<"||e==="\\lt"||e==="\u27E8"?e="\\langle":(e===">"||e==="\\gt"||e==="\u27E9")&&(e="\\rangle"),Vt.contains(e$,e)||Vt.contains(t$,e))return ZG(e,r,!1,n,i,a);if(Vt.contains(Jxe,e))return JG(e,ty[r],!1,n,i,a);throw new nt("Illegal delimiter: '"+e+"'")},"makeSizedDelim"),tbe=[{type:"small",style:Ht.SCRIPTSCRIPT},{type:"small",style:Ht.SCRIPT},{type:"small",style:Ht.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],rbe=[{type:"small",style:Ht.SCRIPTSCRIPT},{type:"small",style:Ht.SCRIPT},{type:"small",style:Ht.TEXT},{type:"stack"}],r$=[{type:"small",style:Ht.SCRIPTSCRIPT},{type:"small",style:Ht.SCRIPT},{type:"small",style:Ht.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],nbe=o(function(e){if(e.type==="small")return"Main-Regular";if(e.type==="large")return"Size"+e.size+"-Regular";if(e.type==="stack")return"Size4-Regular";throw new Error("Add support for delim type '"+e.type+"' here.")},"delimTypeToFont"),n$=o(function(e,r,n,i){for(var a=Math.min(2,3-i.style.size),s=a;sr)return n[s]}return n[n.length-1]},"traverseSequence"),i$=o(function(e,r,n,i,a,s){e==="<"||e==="\\lt"||e==="\u27E8"?e="\\langle":(e===">"||e==="\\gt"||e==="\u27E9")&&(e="\\rangle");var l;Vt.contains(t$,e)?l=tbe:Vt.contains(e$,e)?l=r$:l=rbe;var u=n$(e,r,l,i);return u.type==="small"?Xxe(e,u.style,n,i,a,s):u.type==="large"?ZG(e,u.size,n,i,a,s):JG(e,r,n,i,a,s)},"makeCustomSizedDelim"),ibe=o(function(e,r,n,i,a,s){var l=i.fontMetrics().axisHeight*i.sizeMultiplier,u=901,h=5/i.fontMetrics().ptPerEm,f=Math.max(r-l,n+l),d=Math.max(f/500*u,2*f-h);return i$(e,d,!0,i,a,s)},"makeLeftRightDelim"),au={sqrtImage:Zxe,sizedDelim:ebe,sizeToMaxHeight:ty,customSizedDelim:i$,leftRightDelim:ibe},cG={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},abe=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\u230A","\u230B","\\lceil","\\rceil","\u2308","\u2309","<",">","\\langle","\u27E8","\\rangle","\u27E9","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\u27EE","\u27EF","\\lmoustache","\\rmoustache","\u23B0","\u23B1","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];o(E4,"checkDelimiter");vt({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1,argTypes:["primitive"]},handler:o((t,e)=>{var r=E4(e[0],t);return{type:"delimsizing",mode:t.parser.mode,size:cG[t.funcName].size,mclass:cG[t.funcName].mclass,delim:r.text}},"handler"),htmlBuilder:o((t,e)=>t.delim==="."?Be.makeSpan([t.mclass]):au.sizedDelim(t.delim,t.size,e,t.mode,[t.mclass]),"htmlBuilder"),mathmlBuilder:o(t=>{var e=[];t.delim!=="."&&e.push(_o(t.delim,t.mode));var r=new et.MathNode("mo",e);t.mclass==="mopen"||t.mclass==="mclose"?r.setAttribute("fence","true"):r.setAttribute("fence","false"),r.setAttribute("stretchy","true");var n=ct(au.sizeToMaxHeight[t.size]);return r.setAttribute("minsize",n),r.setAttribute("maxsize",n),r},"mathmlBuilder")});o(uG,"assertParsed");vt({type:"leftright-right",names:["\\right"],props:{numArgs:1,primitive:!0},handler:o((t,e)=>{var r=t.parser.gullet.macros.get("\\current@color");if(r&&typeof r!="string")throw new nt("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:t.parser.mode,delim:E4(e[0],t).text,color:r}},"handler")});vt({type:"leftright",names:["\\left"],props:{numArgs:1,primitive:!0},handler:o((t,e)=>{var r=E4(e[0],t),n=t.parser;++n.leftrightDepth;var i=n.parseExpression(!1);--n.leftrightDepth,n.expect("\\right",!1);var a=ir(n.parseFunction(),"leftright-right");return{type:"leftright",mode:n.mode,body:i,left:r.text,right:a.delim,rightColor:a.color}},"handler"),htmlBuilder:o((t,e)=>{uG(t);for(var r=Ri(t.body,e,!0,["mopen","mclose"]),n=0,i=0,a=!1,s=0;s{uG(t);var r=gs(t.body,e);if(t.left!=="."){var n=new et.MathNode("mo",[_o(t.left,t.mode)]);n.setAttribute("fence","true"),r.unshift(n)}if(t.right!=="."){var i=new et.MathNode("mo",[_o(t.right,t.mode)]);i.setAttribute("fence","true"),t.rightColor&&i.setAttribute("mathcolor",t.rightColor),r.push(i)}return O7(r)},"mathmlBuilder")});vt({type:"middle",names:["\\middle"],props:{numArgs:1,primitive:!0},handler:o((t,e)=>{var r=E4(e[0],t);if(!t.parser.leftrightDepth)throw new nt("\\middle without preceding \\left",r);return{type:"middle",mode:t.parser.mode,delim:r.text}},"handler"),htmlBuilder:o((t,e)=>{var r;if(t.delim===".")r=sy(e,[]);else{r=au.sizedDelim(t.delim,1,e,t.mode,[]);var n={delim:t.delim,options:e};r.isMiddle=n}return r},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=t.delim==="\\vert"||t.delim==="|"?_o("|","text"):_o(t.delim,t.mode),n=new et.MathNode("mo",[r]);return n.setAttribute("fence","true"),n.setAttribute("lspace","0.05em"),n.setAttribute("rspace","0.05em"),n},"mathmlBuilder")});G7=o((t,e)=>{var r=Be.wrapFragment(Cr(t.body,e),e),n=t.label.slice(1),i=e.sizeMultiplier,a,s=0,l=Vt.isCharacterBox(t.body);if(n==="sout")a=Be.makeSpan(["stretchy","sout"]),a.height=e.fontMetrics().defaultRuleThickness/i,s=-.5*e.fontMetrics().xHeight;else if(n==="phase"){var u=Hn({number:.6,unit:"pt"},e),h=Hn({number:.35,unit:"ex"},e),f=e.havingBaseSizing();i=i/f.sizeMultiplier;var d=r.height+r.depth+u+h;r.style.paddingLeft=ct(d/2+u);var p=Math.floor(1e3*d*i),m=exe(p),g=new ll([new Jl("phase",m)],{width:"400em",height:ct(p/1e3),viewBox:"0 0 400000 "+p,preserveAspectRatio:"xMinYMin slice"});a=Be.makeSvgSpan(["hide-tail"],[g],e),a.style.height=ct(d),s=r.depth+u+h}else{/cancel/.test(n)?l||r.classes.push("cancel-pad"):n==="angl"?r.classes.push("anglpad"):r.classes.push("boxpad");var y=0,v=0,x=0;/box/.test(n)?(x=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness),y=e.fontMetrics().fboxsep+(n==="colorbox"?0:x),v=y):n==="angl"?(x=Math.max(e.fontMetrics().defaultRuleThickness,e.minRuleThickness),y=4*x,v=Math.max(0,.25-r.depth)):(y=l?.2:0,v=y),a=ou.encloseSpan(r,n,y,v,e),/fbox|boxed|fcolorbox/.test(n)?(a.style.borderStyle="solid",a.style.borderWidth=ct(x)):n==="angl"&&x!==.049&&(a.style.borderTopWidth=ct(x),a.style.borderRightWidth=ct(x)),s=r.depth+v,t.backgroundColor&&(a.style.backgroundColor=t.backgroundColor,t.borderColor&&(a.style.borderColor=t.borderColor))}var b;if(t.backgroundColor)b=Be.makeVList({positionType:"individualShift",children:[{type:"elem",elem:a,shift:s},{type:"elem",elem:r,shift:0}]},e);else{var w=/cancel|phase/.test(n)?["svg-align"]:[];b=Be.makeVList({positionType:"individualShift",children:[{type:"elem",elem:r,shift:0},{type:"elem",elem:a,shift:s,wrapperClasses:w}]},e)}return/cancel/.test(n)&&(b.height=r.height,b.depth=r.depth),/cancel/.test(n)&&!l?Be.makeSpan(["mord","cancel-lap"],[b],e):Be.makeSpan(["mord"],[b],e)},"htmlBuilder$7"),$7=o((t,e)=>{var r=0,n=new et.MathNode(t.label.indexOf("colorbox")>-1?"mpadded":"menclose",[fn(t.body,e)]);switch(t.label){case"\\cancel":n.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":n.setAttribute("notation","downdiagonalstrike");break;case"\\phase":n.setAttribute("notation","phasorangle");break;case"\\sout":n.setAttribute("notation","horizontalstrike");break;case"\\fbox":n.setAttribute("notation","box");break;case"\\angl":n.setAttribute("notation","actuarial");break;case"\\fcolorbox":case"\\colorbox":if(r=e.fontMetrics().fboxsep*e.fontMetrics().ptPerEm,n.setAttribute("width","+"+2*r+"pt"),n.setAttribute("height","+"+2*r+"pt"),n.setAttribute("lspace",r+"pt"),n.setAttribute("voffset",r+"pt"),t.label==="\\fcolorbox"){var i=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness);n.setAttribute("style","border: "+i+"em solid "+String(t.borderColor))}break;case"\\xcancel":n.setAttribute("notation","updiagonalstrike downdiagonalstrike");break}return t.backgroundColor&&n.setAttribute("mathbackground",t.backgroundColor),n},"mathmlBuilder$6");vt({type:"enclose",names:["\\colorbox"],props:{numArgs:2,allowedInText:!0,argTypes:["color","text"]},handler(t,e,r){var{parser:n,funcName:i}=t,a=ir(e[0],"color-token").color,s=e[1];return{type:"enclose",mode:n.mode,label:i,backgroundColor:a,body:s}},htmlBuilder:G7,mathmlBuilder:$7});vt({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,allowedInText:!0,argTypes:["color","color","text"]},handler(t,e,r){var{parser:n,funcName:i}=t,a=ir(e[0],"color-token").color,s=ir(e[1],"color-token").color,l=e[2];return{type:"enclose",mode:n.mode,label:i,backgroundColor:s,borderColor:a,body:l}},htmlBuilder:G7,mathmlBuilder:$7});vt({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler(t,e){var{parser:r}=t;return{type:"enclose",mode:r.mode,label:"\\fbox",body:e[0]}}});vt({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\sout","\\phase"],props:{numArgs:1},handler(t,e){var{parser:r,funcName:n}=t,i=e[0];return{type:"enclose",mode:r.mode,label:n,body:i}},htmlBuilder:G7,mathmlBuilder:$7});vt({type:"enclose",names:["\\angl"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!1},handler(t,e){var{parser:r}=t;return{type:"enclose",mode:r.mode,label:"\\angl",body:e[0]}}});a$={};o(ec,"defineEnvironment");s$={};o(le,"defineMacro");o(hG,"getHLines");C4=o(t=>{var e=t.parser.settings;if(!e.displayMode)throw new nt("{"+t.envName+"} can be used only in display mode.")},"validateAmsEnvironmentContext");o(V7,"getAutoTag");o(mh,"parseArray");o(U7,"dCellStyle");tc=o(function(e,r){var n,i,a=e.body.length,s=e.hLinesBeforeRow,l=0,u=new Array(a),h=[],f=Math.max(r.fontMetrics().arrayRuleWidth,r.minRuleThickness),d=1/r.fontMetrics().ptPerEm,p=5*d;if(e.colSeparationType&&e.colSeparationType==="small"){var m=r.havingStyle(Ht.SCRIPT).sizeMultiplier;p=.2778*(m/r.sizeMultiplier)}var g=e.colSeparationType==="CD"?Hn({number:3,unit:"ex"},r):12*d,y=3*d,v=e.arraystretch*g,x=.7*v,b=.3*v,w=0;function S(ke){for(var Ie=0;Ie0&&(w+=.25),h.push({pos:w,isDashed:ke[Ie]})}for(o(S,"setHLinePos"),S(s[0]),n=0;n0&&(N+=b,_ke))for(n=0;n=l)){var J=void 0;(i>0||e.hskipBeforeAndAfter)&&(J=Vt.deflt(Y.pregap,p),J!==0&&(O=Be.makeSpan(["arraycolsep"],[]),O.style.width=ct(J),C.push(O)));var Z=[];for(n=0;n0){for(var se=Be.makeLineSpan("hline",r,f),ce=Be.makeLineSpan("hdashline",r,f),ue=[{type:"elem",elem:u,shift:0}];h.length>0;){var te=h.pop(),De=te.pos-k;te.isDashed?ue.push({type:"elem",elem:ce,shift:De}):ue.push({type:"elem",elem:se,shift:De})}u=Be.makeVList({positionType:"individualShift",children:ue},r)}if(P.length===0)return Be.makeSpan(["mord"],[u],r);var oe=Be.makeVList({positionType:"individualShift",children:P},r);return oe=Be.makeSpan(["tag"],[oe],r),Be.makeFragment([u,oe])},"htmlBuilder"),sbe={c:"center ",l:"left ",r:"right "},rc=o(function(e,r){for(var n=[],i=new et.MathNode("mtd",[],["mtr-glue"]),a=new et.MathNode("mtd",[],["mml-eqn-num"]),s=0;s0){var g=e.cols,y="",v=!1,x=0,b=g.length;g[0].type==="separator"&&(p+="top ",x=1),g[g.length-1].type==="separator"&&(p+="bottom ",b-=1);for(var w=x;w0?"left ":"",p+=A[A.length-1].length>0?"right ":"";for(var L=1;L-1?"alignat":"align",a=e.envName==="split",s=mh(e.parser,{cols:n,addJot:!0,autoTag:a?void 0:V7(e.envName),emptySingleRow:!0,colSeparationType:i,maxNumCols:a?2:void 0,leqno:e.parser.settings.leqno},"display"),l,u=0,h={type:"ordgroup",mode:e.mode,body:[]};if(r[0]&&r[0].type==="ordgroup"){for(var f="",d=0;d0&&m&&(v=1),n[g]={type:"align",align:y,pregap:v,postgap:0}}return s.colSeparationType=m?"align":"alignat",s},"alignedHandler");ec({type:"array",names:["array","darray"],props:{numArgs:1},handler(t,e){var r=T4(e[0]),n=r?[e[0]]:ir(e[0],"ordgroup").body,i=n.map(function(s){var l=B7(s),u=l.text;if("lcr".indexOf(u)!==-1)return{type:"align",align:u};if(u==="|")return{type:"separator",separator:"|"};if(u===":")return{type:"separator",separator:":"};throw new nt("Unknown column alignment: "+u,s)}),a={cols:i,hskipBeforeAndAfter:!0,maxNumCols:i.length};return mh(t.parser,a,U7(t.envName))},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix","matrix*","pmatrix*","bmatrix*","Bmatrix*","vmatrix*","Vmatrix*"],props:{numArgs:0},handler(t){var e={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[t.envName.replace("*","")],r="c",n={hskipBeforeAndAfter:!1,cols:[{type:"align",align:r}]};if(t.envName.charAt(t.envName.length-1)==="*"){var i=t.parser;if(i.consumeSpaces(),i.fetch().text==="["){if(i.consume(),i.consumeSpaces(),r=i.fetch().text,"lcr".indexOf(r)===-1)throw new nt("Expected l or c or r",i.nextToken);i.consume(),i.consumeSpaces(),i.expect("]"),i.consume(),n.cols=[{type:"align",align:r}]}}var a=mh(t.parser,n,U7(t.envName)),s=Math.max(0,...a.body.map(l=>l.length));return a.cols=new Array(s).fill({type:"align",align:r}),e?{type:"leftright",mode:t.mode,body:[a],left:e[0],right:e[1],rightColor:void 0}:a},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["smallmatrix"],props:{numArgs:0},handler(t){var e={arraystretch:.5},r=mh(t.parser,e,"script");return r.colSeparationType="small",r},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["subarray"],props:{numArgs:1},handler(t,e){var r=T4(e[0]),n=r?[e[0]]:ir(e[0],"ordgroup").body,i=n.map(function(s){var l=B7(s),u=l.text;if("lc".indexOf(u)!==-1)return{type:"align",align:u};throw new nt("Unknown column alignment: "+u,s)});if(i.length>1)throw new nt("{subarray} can contain only one column");var a={cols:i,hskipBeforeAndAfter:!1,arraystretch:.5};if(a=mh(t.parser,a,"script"),a.body.length>0&&a.body[0].length>1)throw new nt("{subarray} can contain only one column");return a},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler(t){var e={arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},r=mh(t.parser,e,U7(t.envName));return{type:"leftright",mode:t.mode,body:[r],left:t.envName.indexOf("r")>-1?".":"\\{",right:t.envName.indexOf("r")>-1?"\\}":".",rightColor:void 0}},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:o$,htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler(t){Vt.contains(["gather","gather*"],t.envName)&&C4(t);var e={cols:[{type:"align",align:"c"}],addJot:!0,colSeparationType:"gather",autoTag:V7(t.envName),emptySingleRow:!0,leqno:t.parser.settings.leqno};return mh(t.parser,e,"display")},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:o$,htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["equation","equation*"],props:{numArgs:0},handler(t){C4(t);var e={autoTag:V7(t.envName),emptySingleRow:!0,singleRow:!0,maxNumCols:1,leqno:t.parser.settings.leqno};return mh(t.parser,e,"display")},htmlBuilder:tc,mathmlBuilder:rc});ec({type:"array",names:["CD"],props:{numArgs:0},handler(t){return C4(t),Wxe(t.parser)},htmlBuilder:tc,mathmlBuilder:rc});le("\\nonumber","\\gdef\\@eqnsw{0}");le("\\notag","\\nonumber");vt({type:"text",names:["\\hline","\\hdashline"],props:{numArgs:0,allowedInText:!0,allowedInMath:!0},handler(t,e){throw new nt(t.funcName+" valid only within array environment")}});fG=a$;vt({type:"environment",names:["\\begin","\\end"],props:{numArgs:1,argTypes:["text"]},handler(t,e){var{parser:r,funcName:n}=t,i=e[0];if(i.type!=="ordgroup")throw new nt("Invalid environment name",i);for(var a="",s=0;s{var r=t.font,n=e.withFont(r);return Cr(t.body,n)},"htmlBuilder$5"),c$=o((t,e)=>{var r=t.font,n=e.withFont(r);return fn(t.body,n)},"mathmlBuilder$4"),dG={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak","\\bm":"\\boldsymbol"};vt({type:"font",names:["\\mathrm","\\mathit","\\mathbf","\\mathnormal","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],props:{numArgs:1,allowedInArgument:!0},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=y4(e[0]),a=n;return a in dG&&(a=dG[a]),{type:"font",mode:r.mode,font:a.slice(1),body:i}},"handler"),htmlBuilder:l$,mathmlBuilder:c$});vt({type:"mclass",names:["\\boldsymbol","\\bm"],props:{numArgs:1},handler:o((t,e)=>{var{parser:r}=t,n=e[0],i=Vt.isCharacterBox(n);return{type:"mclass",mode:r.mode,mclass:k4(n),body:[{type:"font",mode:r.mode,font:"boldsymbol",body:n}],isCharacterBox:i}},"handler")});vt({type:"font",names:["\\rm","\\sf","\\tt","\\bf","\\it","\\cal"],props:{numArgs:0,allowedInText:!0},handler:o((t,e)=>{var{parser:r,funcName:n,breakOnTokenText:i}=t,{mode:a}=r,s=r.parseExpression(!0,i),l="math"+n.slice(1);return{type:"font",mode:a,font:l,body:{type:"ordgroup",mode:r.mode,body:s}}},"handler"),htmlBuilder:l$,mathmlBuilder:c$});u$=o((t,e)=>{var r=e;return t==="display"?r=r.id>=Ht.SCRIPT.id?r.text():Ht.DISPLAY:t==="text"&&r.size===Ht.DISPLAY.size?r=Ht.TEXT:t==="script"?r=Ht.SCRIPT:t==="scriptscript"&&(r=Ht.SCRIPTSCRIPT),r},"adjustStyle"),H7=o((t,e)=>{var r=u$(t.size,e.style),n=r.fracNum(),i=r.fracDen(),a;a=e.havingStyle(n);var s=Cr(t.numer,a,e);if(t.continued){var l=8.5/e.fontMetrics().ptPerEm,u=3.5/e.fontMetrics().ptPerEm;s.height=s.height0?g=3*p:g=7*p,y=e.fontMetrics().denom1):(d>0?(m=e.fontMetrics().num2,g=p):(m=e.fontMetrics().num3,g=3*p),y=e.fontMetrics().denom2);var v;if(f){var b=e.fontMetrics().axisHeight;m-s.depth-(b+.5*d){var r=new et.MathNode("mfrac",[fn(t.numer,e),fn(t.denom,e)]);if(!t.hasBarLine)r.setAttribute("linethickness","0px");else if(t.barSize){var n=Hn(t.barSize,e);r.setAttribute("linethickness",ct(n))}var i=u$(t.size,e.style);if(i.size!==e.style.size){r=new et.MathNode("mstyle",[r]);var a=i.size===Ht.DISPLAY.size?"true":"false";r.setAttribute("displaystyle",a),r.setAttribute("scriptlevel","0")}if(t.leftDelim!=null||t.rightDelim!=null){var s=[];if(t.leftDelim!=null){var l=new et.MathNode("mo",[new et.TextNode(t.leftDelim.replace("\\",""))]);l.setAttribute("fence","true"),s.push(l)}if(s.push(r),t.rightDelim!=null){var u=new et.MathNode("mo",[new et.TextNode(t.rightDelim.replace("\\",""))]);u.setAttribute("fence","true"),s.push(u)}return O7(s)}return r},"mathmlBuilder$3");vt({type:"genfrac",names:["\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac","\\\\bracefrac","\\\\brackfrac"],props:{numArgs:2,allowedInArgument:!0},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=e[0],a=e[1],s,l=null,u=null,h="auto";switch(n){case"\\dfrac":case"\\frac":case"\\tfrac":s=!0;break;case"\\\\atopfrac":s=!1;break;case"\\dbinom":case"\\binom":case"\\tbinom":s=!1,l="(",u=")";break;case"\\\\bracefrac":s=!1,l="\\{",u="\\}";break;case"\\\\brackfrac":s=!1,l="[",u="]";break;default:throw new Error("Unrecognized genfrac command")}switch(n){case"\\dfrac":case"\\dbinom":h="display";break;case"\\tfrac":case"\\tbinom":h="text";break}return{type:"genfrac",mode:r.mode,continued:!1,numer:i,denom:a,hasBarLine:s,leftDelim:l,rightDelim:u,size:h,barSize:null}},"handler"),htmlBuilder:H7,mathmlBuilder:Y7});vt({type:"genfrac",names:["\\cfrac"],props:{numArgs:2},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=e[0],a=e[1];return{type:"genfrac",mode:r.mode,continued:!0,numer:i,denom:a,hasBarLine:!0,leftDelim:null,rightDelim:null,size:"display",barSize:null}},"handler")});vt({type:"infix",names:["\\over","\\choose","\\atop","\\brace","\\brack"],props:{numArgs:0,infix:!0},handler(t){var{parser:e,funcName:r,token:n}=t,i;switch(r){case"\\over":i="\\frac";break;case"\\choose":i="\\binom";break;case"\\atop":i="\\\\atopfrac";break;case"\\brace":i="\\\\bracefrac";break;case"\\brack":i="\\\\brackfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",mode:e.mode,replaceWith:i,token:n}}});pG=["display","text","script","scriptscript"],mG=o(function(e){var r=null;return e.length>0&&(r=e,r=r==="."?null:r),r},"delimFromValue");vt({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,allowedInArgument:!0,argTypes:["math","math","size","text","math","math"]},handler(t,e){var{parser:r}=t,n=e[4],i=e[5],a=y4(e[0]),s=a.type==="atom"&&a.family==="open"?mG(a.text):null,l=y4(e[1]),u=l.type==="atom"&&l.family==="close"?mG(l.text):null,h=ir(e[2],"size"),f,d=null;h.isBlank?f=!0:(d=h.value,f=d.number>0);var p="auto",m=e[3];if(m.type==="ordgroup"){if(m.body.length>0){var g=ir(m.body[0],"textord");p=pG[Number(g.text)]}}else m=ir(m,"textord"),p=pG[Number(m.text)];return{type:"genfrac",mode:r.mode,numer:n,denom:i,continued:!1,hasBarLine:f,barSize:d,leftDelim:s,rightDelim:u,size:p}},htmlBuilder:H7,mathmlBuilder:Y7});vt({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler(t,e){var{parser:r,funcName:n,token:i}=t;return{type:"infix",mode:r.mode,replaceWith:"\\\\abovefrac",size:ir(e[0],"size").value,token:i}}});vt({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=e[0],a=z2e(ir(e[1],"infix").size),s=e[2],l=a.number>0;return{type:"genfrac",mode:r.mode,numer:i,denom:s,continued:!1,hasBarLine:l,barSize:a,leftDelim:null,rightDelim:null,size:"auto"}},"handler"),htmlBuilder:H7,mathmlBuilder:Y7});h$=o((t,e)=>{var r=e.style,n,i;t.type==="supsub"?(n=t.sup?Cr(t.sup,e.havingStyle(r.sup()),e):Cr(t.sub,e.havingStyle(r.sub()),e),i=ir(t.base,"horizBrace")):i=ir(t,"horizBrace");var a=Cr(i.base,e.havingBaseStyle(Ht.DISPLAY)),s=ou.svgSpan(i,e),l;if(i.isOver?(l=Be.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:a},{type:"kern",size:.1},{type:"elem",elem:s}]},e),l.children[0].children[0].children[1].classes.push("svg-align")):(l=Be.makeVList({positionType:"bottom",positionData:a.depth+.1+s.height,children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:a}]},e),l.children[0].children[0].children[0].classes.push("svg-align")),n){var u=Be.makeSpan(["mord",i.isOver?"mover":"munder"],[l],e);i.isOver?l=Be.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:u},{type:"kern",size:.2},{type:"elem",elem:n}]},e):l=Be.makeVList({positionType:"bottom",positionData:u.depth+.2+n.height+n.depth,children:[{type:"elem",elem:n},{type:"kern",size:.2},{type:"elem",elem:u}]},e)}return Be.makeSpan(["mord",i.isOver?"mover":"munder"],[l],e)},"htmlBuilder$3"),obe=o((t,e)=>{var r=ou.mathMLnode(t.label);return new et.MathNode(t.isOver?"mover":"munder",[fn(t.base,e),r])},"mathmlBuilder$2");vt({type:"horizBrace",names:["\\overbrace","\\underbrace"],props:{numArgs:1},handler(t,e){var{parser:r,funcName:n}=t;return{type:"horizBrace",mode:r.mode,label:n,isOver:/^\\over/.test(n),base:e[0]}},htmlBuilder:h$,mathmlBuilder:obe});vt({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:o((t,e)=>{var{parser:r}=t,n=e[1],i=ir(e[0],"url").url;return r.settings.isTrusted({command:"\\href",url:i})?{type:"href",mode:r.mode,href:i,body:ui(n)}:r.formatUnsupportedCmd("\\href")},"handler"),htmlBuilder:o((t,e)=>{var r=Ri(t.body,e,!1);return Be.makeAnchor(t.href,[],r,e)},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=ph(t.body,e);return r instanceof ps||(r=new ps("mrow",[r])),r.setAttribute("href",t.href),r},"mathmlBuilder")});vt({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:o((t,e)=>{var{parser:r}=t,n=ir(e[0],"url").url;if(!r.settings.isTrusted({command:"\\url",url:n}))return r.formatUnsupportedCmd("\\url");for(var i=[],a=0;a{var{parser:r,funcName:n,token:i}=t,a=ir(e[0],"raw").string,s=e[1];r.settings.strict&&r.settings.reportNonstrict("htmlExtension","HTML extension is disabled on strict mode");var l,u={};switch(n){case"\\htmlClass":u.class=a,l={command:"\\htmlClass",class:a};break;case"\\htmlId":u.id=a,l={command:"\\htmlId",id:a};break;case"\\htmlStyle":u.style=a,l={command:"\\htmlStyle",style:a};break;case"\\htmlData":{for(var h=a.split(","),f=0;f{var r=Ri(t.body,e,!1),n=["enclosing"];t.attributes.class&&n.push(...t.attributes.class.trim().split(/\s+/));var i=Be.makeSpan(n,r,e);for(var a in t.attributes)a!=="class"&&t.attributes.hasOwnProperty(a)&&i.setAttribute(a,t.attributes[a]);return i},"htmlBuilder"),mathmlBuilder:o((t,e)=>ph(t.body,e),"mathmlBuilder")});vt({type:"htmlmathml",names:["\\html@mathml"],props:{numArgs:2,allowedInText:!0},handler:o((t,e)=>{var{parser:r}=t;return{type:"htmlmathml",mode:r.mode,html:ui(e[0]),mathml:ui(e[1])}},"handler"),htmlBuilder:o((t,e)=>{var r=Ri(t.html,e,!1);return Be.makeFragment(r)},"htmlBuilder"),mathmlBuilder:o((t,e)=>ph(t.mathml,e),"mathmlBuilder")});g7=o(function(e){if(/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(e))return{number:+e,unit:"bp"};var r=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(e);if(!r)throw new nt("Invalid size: '"+e+"' in \\includegraphics");var n={number:+(r[1]+r[2]),unit:r[3]};if(!DG(n))throw new nt("Invalid unit: '"+n.unit+"' in \\includegraphics.");return n},"sizeData");vt({type:"includegraphics",names:["\\includegraphics"],props:{numArgs:1,numOptionalArgs:1,argTypes:["raw","url"],allowedInText:!1},handler:o((t,e,r)=>{var{parser:n}=t,i={number:0,unit:"em"},a={number:.9,unit:"em"},s={number:0,unit:"em"},l="";if(r[0])for(var u=ir(r[0],"raw").string,h=u.split(","),f=0;f{var r=Hn(t.height,e),n=0;t.totalheight.number>0&&(n=Hn(t.totalheight,e)-r);var i=0;t.width.number>0&&(i=Hn(t.width,e));var a={height:ct(r+n)};i>0&&(a.width=ct(i)),n>0&&(a.verticalAlign=ct(-n));var s=new T7(t.src,t.alt,a);return s.height=r,s.depth=n,s},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=new et.MathNode("mglyph",[]);r.setAttribute("alt",t.alt);var n=Hn(t.height,e),i=0;if(t.totalheight.number>0&&(i=Hn(t.totalheight,e)-n,r.setAttribute("valign",ct(-i))),r.setAttribute("height",ct(n+i)),t.width.number>0){var a=Hn(t.width,e);r.setAttribute("width",ct(a))}return r.setAttribute("src",t.src),r},"mathmlBuilder")});vt({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],primitive:!0,allowedInText:!0},handler(t,e){var{parser:r,funcName:n}=t,i=ir(e[0],"size");if(r.settings.strict){var a=n[1]==="m",s=i.value.unit==="mu";a?(s||r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+n+" supports only mu units, "+("not "+i.value.unit+" units")),r.mode!=="math"&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+n+" works only in math mode")):s&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+n+" doesn't support mu units")}return{type:"kern",mode:r.mode,dimension:i.value}},htmlBuilder(t,e){return Be.makeGlue(t.dimension,e)},mathmlBuilder(t,e){var r=Hn(t.dimension,e);return new et.SpaceNode(r)}});vt({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],props:{numArgs:1,allowedInText:!0},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=e[0];return{type:"lap",mode:r.mode,alignment:n.slice(5),body:i}},"handler"),htmlBuilder:o((t,e)=>{var r;t.alignment==="clap"?(r=Be.makeSpan([],[Cr(t.body,e)]),r=Be.makeSpan(["inner"],[r],e)):r=Be.makeSpan(["inner"],[Cr(t.body,e)]);var n=Be.makeSpan(["fix"],[]),i=Be.makeSpan([t.alignment],[r,n],e),a=Be.makeSpan(["strut"]);return a.style.height=ct(i.height+i.depth),i.depth&&(a.style.verticalAlign=ct(-i.depth)),i.children.unshift(a),i=Be.makeSpan(["thinbox"],[i],e),Be.makeSpan(["mord","vbox"],[i],e)},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=new et.MathNode("mpadded",[fn(t.body,e)]);if(t.alignment!=="rlap"){var n=t.alignment==="llap"?"-1":"-0.5";r.setAttribute("lspace",n+"width")}return r.setAttribute("width","0px"),r},"mathmlBuilder")});vt({type:"styling",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(t,e){var{funcName:r,parser:n}=t,i=n.mode;n.switchMode("math");var a=r==="\\("?"\\)":"$",s=n.parseExpression(!1,a);return n.expect(a),n.switchMode(i),{type:"styling",mode:n.mode,style:"text",body:s}}});vt({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(t,e){throw new nt("Mismatched "+t.funcName)}});gG=o((t,e)=>{switch(e.style.size){case Ht.DISPLAY.size:return t.display;case Ht.TEXT.size:return t.text;case Ht.SCRIPT.size:return t.script;case Ht.SCRIPTSCRIPT.size:return t.scriptscript;default:return t.text}},"chooseMathStyle");vt({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4,primitive:!0},handler:o((t,e)=>{var{parser:r}=t;return{type:"mathchoice",mode:r.mode,display:ui(e[0]),text:ui(e[1]),script:ui(e[2]),scriptscript:ui(e[3])}},"handler"),htmlBuilder:o((t,e)=>{var r=gG(t,e),n=Ri(r,e,!1);return Be.makeFragment(n)},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=gG(t,e);return ph(r,e)},"mathmlBuilder")});f$=o((t,e,r,n,i,a,s)=>{t=Be.makeSpan([],[t]);var l=r&&Vt.isCharacterBox(r),u,h;if(e){var f=Cr(e,n.havingStyle(i.sup()),n);h={elem:f,kern:Math.max(n.fontMetrics().bigOpSpacing1,n.fontMetrics().bigOpSpacing3-f.depth)}}if(r){var d=Cr(r,n.havingStyle(i.sub()),n);u={elem:d,kern:Math.max(n.fontMetrics().bigOpSpacing2,n.fontMetrics().bigOpSpacing4-d.height)}}var p;if(h&&u){var m=n.fontMetrics().bigOpSpacing5+u.elem.height+u.elem.depth+u.kern+t.depth+s;p=Be.makeVList({positionType:"bottom",positionData:m,children:[{type:"kern",size:n.fontMetrics().bigOpSpacing5},{type:"elem",elem:u.elem,marginLeft:ct(-a)},{type:"kern",size:u.kern},{type:"elem",elem:t},{type:"kern",size:h.kern},{type:"elem",elem:h.elem,marginLeft:ct(a)},{type:"kern",size:n.fontMetrics().bigOpSpacing5}]},n)}else if(u){var g=t.height-s;p=Be.makeVList({positionType:"top",positionData:g,children:[{type:"kern",size:n.fontMetrics().bigOpSpacing5},{type:"elem",elem:u.elem,marginLeft:ct(-a)},{type:"kern",size:u.kern},{type:"elem",elem:t}]},n)}else if(h){var y=t.depth+s;p=Be.makeVList({positionType:"bottom",positionData:y,children:[{type:"elem",elem:t},{type:"kern",size:h.kern},{type:"elem",elem:h.elem,marginLeft:ct(a)},{type:"kern",size:n.fontMetrics().bigOpSpacing5}]},n)}else return t;var v=[p];if(u&&a!==0&&!l){var x=Be.makeSpan(["mspace"],[],n);x.style.marginRight=ct(a),v.unshift(x)}return Be.makeSpan(["mop","op-limits"],v,n)},"assembleSupSub"),d$=["\\smallint"],xp=o((t,e)=>{var r,n,i=!1,a;t.type==="supsub"?(r=t.sup,n=t.sub,a=ir(t.base,"op"),i=!0):a=ir(t,"op");var s=e.style,l=!1;s.size===Ht.DISPLAY.size&&a.symbol&&!Vt.contains(d$,a.name)&&(l=!0);var u;if(a.symbol){var h=l?"Size2-Regular":"Size1-Regular",f="";if((a.name==="\\oiint"||a.name==="\\oiiint")&&(f=a.name.slice(1),a.name=f==="oiint"?"\\iint":"\\iiint"),u=Be.makeSymbol(a.name,h,"math",e,["mop","op-symbol",l?"large-op":"small-op"]),f.length>0){var d=u.italic,p=Be.staticSvg(f+"Size"+(l?"2":"1"),e);u=Be.makeVList({positionType:"individualShift",children:[{type:"elem",elem:u,shift:0},{type:"elem",elem:p,shift:l?.08:0}]},e),a.name="\\"+f,u.classes.unshift("mop"),u.italic=d}}else if(a.body){var m=Ri(a.body,e,!0);m.length===1&&m[0]instanceof ms?(u=m[0],u.classes[0]="mop"):u=Be.makeSpan(["mop"],m,e)}else{for(var g=[],y=1;y{var r;if(t.symbol)r=new ps("mo",[_o(t.name,t.mode)]),Vt.contains(d$,t.name)&&r.setAttribute("largeop","false");else if(t.body)r=new ps("mo",gs(t.body,e));else{r=new ps("mi",[new qf(t.name.slice(1))]);var n=new ps("mo",[_o("\u2061","text")]);t.parentIsSupSub?r=new ps("mrow",[r,n]):r=$G([r,n])}return r},"mathmlBuilder$1"),lbe={"\u220F":"\\prod","\u2210":"\\coprod","\u2211":"\\sum","\u22C0":"\\bigwedge","\u22C1":"\\bigvee","\u22C2":"\\bigcap","\u22C3":"\\bigcup","\u2A00":"\\bigodot","\u2A01":"\\bigoplus","\u2A02":"\\bigotimes","\u2A04":"\\biguplus","\u2A06":"\\bigsqcup"};vt({type:"op",names:["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint","\u220F","\u2210","\u2211","\u22C0","\u22C1","\u22C2","\u22C3","\u2A00","\u2A01","\u2A02","\u2A04","\u2A06"],props:{numArgs:0},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=n;return i.length===1&&(i=lbe[i]),{type:"op",mode:r.mode,limits:!0,parentIsSupSub:!1,symbol:!0,name:i}},"handler"),htmlBuilder:xp,mathmlBuilder:oy});vt({type:"op",names:["\\mathop"],props:{numArgs:1,primitive:!0},handler:o((t,e)=>{var{parser:r}=t,n=e[0];return{type:"op",mode:r.mode,limits:!1,parentIsSupSub:!1,symbol:!1,body:ui(n)}},"handler"),htmlBuilder:xp,mathmlBuilder:oy});cbe={"\u222B":"\\int","\u222C":"\\iint","\u222D":"\\iiint","\u222E":"\\oint","\u222F":"\\oiint","\u2230":"\\oiiint"};vt({type:"op",names:["\\arcsin","\\arccos","\\arctan","\\arctg","\\arcctg","\\arg","\\ch","\\cos","\\cosec","\\cosh","\\cot","\\cotg","\\coth","\\csc","\\ctg","\\cth","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\sh","\\tan","\\tanh","\\tg","\\th"],props:{numArgs:0},handler(t){var{parser:e,funcName:r}=t;return{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!1,name:r}},htmlBuilder:xp,mathmlBuilder:oy});vt({type:"op",names:["\\det","\\gcd","\\inf","\\lim","\\max","\\min","\\Pr","\\sup"],props:{numArgs:0},handler(t){var{parser:e,funcName:r}=t;return{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:!1,name:r}},htmlBuilder:xp,mathmlBuilder:oy});vt({type:"op",names:["\\int","\\iint","\\iiint","\\oint","\\oiint","\\oiiint","\u222B","\u222C","\u222D","\u222E","\u222F","\u2230"],props:{numArgs:0},handler(t){var{parser:e,funcName:r}=t,n=r;return n.length===1&&(n=cbe[n]),{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!0,name:n}},htmlBuilder:xp,mathmlBuilder:oy});p$=o((t,e)=>{var r,n,i=!1,a;t.type==="supsub"?(r=t.sup,n=t.sub,a=ir(t.base,"operatorname"),i=!0):a=ir(t,"operatorname");var s;if(a.body.length>0){for(var l=a.body.map(d=>{var p=d.text;return typeof p=="string"?{type:"textord",mode:d.mode,text:p}:d}),u=Ri(l,e.withFont("mathrm"),!0),h=0;h{for(var r=gs(t.body,e.withFont("mathrm")),n=!0,i=0;if.toText()).join("");r=[new et.TextNode(l)]}var u=new et.MathNode("mi",r);u.setAttribute("mathvariant","normal");var h=new et.MathNode("mo",[_o("\u2061","text")]);return t.parentIsSupSub?new et.MathNode("mrow",[u,h]):et.newDocumentFragment([u,h])},"mathmlBuilder");vt({type:"operatorname",names:["\\operatorname@","\\operatornamewithlimits"],props:{numArgs:1},handler:o((t,e)=>{var{parser:r,funcName:n}=t,i=e[0];return{type:"operatorname",mode:r.mode,body:ui(i),alwaysHandleSupSub:n==="\\operatornamewithlimits",limits:!1,parentIsSupSub:!1}},"handler"),htmlBuilder:p$,mathmlBuilder:ube});le("\\operatorname","\\@ifstar\\operatornamewithlimits\\operatorname@");Kf({type:"ordgroup",htmlBuilder(t,e){return t.semisimple?Be.makeFragment(Ri(t.body,e,!1)):Be.makeSpan(["mord"],Ri(t.body,e,!0),e)},mathmlBuilder(t,e){return ph(t.body,e,!0)}});vt({type:"overline",names:["\\overline"],props:{numArgs:1},handler(t,e){var{parser:r}=t,n=e[0];return{type:"overline",mode:r.mode,body:n}},htmlBuilder(t,e){var r=Cr(t.body,e.havingCrampedStyle()),n=Be.makeLineSpan("overline-line",e),i=e.fontMetrics().defaultRuleThickness,a=Be.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r},{type:"kern",size:3*i},{type:"elem",elem:n},{type:"kern",size:i}]},e);return Be.makeSpan(["mord","overline"],[a],e)},mathmlBuilder(t,e){var r=new et.MathNode("mo",[new et.TextNode("\u203E")]);r.setAttribute("stretchy","true");var n=new et.MathNode("mover",[fn(t.body,e),r]);return n.setAttribute("accent","true"),n}});vt({type:"phantom",names:["\\phantom"],props:{numArgs:1,allowedInText:!0},handler:o((t,e)=>{var{parser:r}=t,n=e[0];return{type:"phantom",mode:r.mode,body:ui(n)}},"handler"),htmlBuilder:o((t,e)=>{var r=Ri(t.body,e.withPhantom(),!1);return Be.makeFragment(r)},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=gs(t.body,e);return new et.MathNode("mphantom",r)},"mathmlBuilder")});vt({type:"hphantom",names:["\\hphantom"],props:{numArgs:1,allowedInText:!0},handler:o((t,e)=>{var{parser:r}=t,n=e[0];return{type:"hphantom",mode:r.mode,body:n}},"handler"),htmlBuilder:o((t,e)=>{var r=Be.makeSpan([],[Cr(t.body,e.withPhantom())]);if(r.height=0,r.depth=0,r.children)for(var n=0;n{var r=gs(ui(t.body),e),n=new et.MathNode("mphantom",r),i=new et.MathNode("mpadded",[n]);return i.setAttribute("height","0px"),i.setAttribute("depth","0px"),i},"mathmlBuilder")});vt({type:"vphantom",names:["\\vphantom"],props:{numArgs:1,allowedInText:!0},handler:o((t,e)=>{var{parser:r}=t,n=e[0];return{type:"vphantom",mode:r.mode,body:n}},"handler"),htmlBuilder:o((t,e)=>{var r=Be.makeSpan(["inner"],[Cr(t.body,e.withPhantom())]),n=Be.makeSpan(["fix"],[]);return Be.makeSpan(["mord","rlap"],[r,n],e)},"htmlBuilder"),mathmlBuilder:o((t,e)=>{var r=gs(ui(t.body),e),n=new et.MathNode("mphantom",r),i=new et.MathNode("mpadded",[n]);return i.setAttribute("width","0px"),i},"mathmlBuilder")});vt({type:"raisebox",names:["\\raisebox"],props:{numArgs:2,argTypes:["size","hbox"],allowedInText:!0},handler(t,e){var{parser:r}=t,n=ir(e[0],"size").value,i=e[1];return{type:"raisebox",mode:r.mode,dy:n,body:i}},htmlBuilder(t,e){var r=Cr(t.body,e),n=Hn(t.dy,e);return Be.makeVList({positionType:"shift",positionData:-n,children:[{type:"elem",elem:r}]},e)},mathmlBuilder(t,e){var r=new et.MathNode("mpadded",[fn(t.body,e)]),n=t.dy.number+t.dy.unit;return r.setAttribute("voffset",n),r}});vt({type:"internal",names:["\\relax"],props:{numArgs:0,allowedInText:!0},handler(t){var{parser:e}=t;return{type:"internal",mode:e.mode}}});vt({type:"rule",names:["\\rule"],props:{numArgs:2,numOptionalArgs:1,argTypes:["size","size","size"]},handler(t,e,r){var{parser:n}=t,i=r[0],a=ir(e[0],"size"),s=ir(e[1],"size");return{type:"rule",mode:n.mode,shift:i&&ir(i,"size").value,width:a.value,height:s.value}},htmlBuilder(t,e){var r=Be.makeSpan(["mord","rule"],[],e),n=Hn(t.width,e),i=Hn(t.height,e),a=t.shift?Hn(t.shift,e):0;return r.style.borderRightWidth=ct(n),r.style.borderTopWidth=ct(i),r.style.bottom=ct(a),r.width=n,r.height=i+a,r.depth=-a,r.maxFontSize=i*1.125*e.sizeMultiplier,r},mathmlBuilder(t,e){var r=Hn(t.width,e),n=Hn(t.height,e),i=t.shift?Hn(t.shift,e):0,a=e.color&&e.getColor()||"black",s=new et.MathNode("mspace");s.setAttribute("mathbackground",a),s.setAttribute("width",ct(r)),s.setAttribute("height",ct(n));var l=new et.MathNode("mpadded",[s]);return i>=0?l.setAttribute("height",ct(i)):(l.setAttribute("height",ct(i)),l.setAttribute("depth",ct(-i))),l.setAttribute("voffset",ct(i)),l}});o(m$,"sizingGroup");yG=["\\tiny","\\sixptsize","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"],hbe=o((t,e)=>{var r=e.havingSize(t.size);return m$(t.body,r,e)},"htmlBuilder");vt({type:"sizing",names:yG,props:{numArgs:0,allowedInText:!0},handler:o((t,e)=>{var{breakOnTokenText:r,funcName:n,parser:i}=t,a=i.parseExpression(!1,r);return{type:"sizing",mode:i.mode,size:yG.indexOf(n)+1,body:a}},"handler"),htmlBuilder:hbe,mathmlBuilder:o((t,e)=>{var r=e.havingSize(t.size),n=gs(t.body,r),i=new et.MathNode("mstyle",n);return i.setAttribute("mathsize",ct(r.sizeMultiplier)),i},"mathmlBuilder")});vt({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:o((t,e,r)=>{var{parser:n}=t,i=!1,a=!1,s=r[0]&&ir(r[0],"ordgroup");if(s)for(var l="",u=0;u{var r=Be.makeSpan([],[Cr(t.body,e)]);if(!t.smashHeight&&!t.smashDepth)return r;if(t.smashHeight&&(r.height=0,r.children))for(var n=0;n{var r=new et.MathNode("mpadded",[fn(t.body,e)]);return t.smashHeight&&r.setAttribute("height","0px"),t.smashDepth&&r.setAttribute("depth","0px"),r},"mathmlBuilder")});vt({type:"sqrt",names:["\\sqrt"],props:{numArgs:1,numOptionalArgs:1},handler(t,e,r){var{parser:n}=t,i=r[0],a=e[0];return{type:"sqrt",mode:n.mode,body:a,index:i}},htmlBuilder(t,e){var r=Cr(t.body,e.havingCrampedStyle());r.height===0&&(r.height=e.fontMetrics().xHeight),r=Be.wrapFragment(r,e);var n=e.fontMetrics(),i=n.defaultRuleThickness,a=i;e.style.idr.height+r.depth+s&&(s=(s+d-r.height-r.depth)/2);var p=u.height-r.height-s-h;r.style.paddingLeft=ct(f);var m=Be.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r,wrapperClasses:["svg-align"]},{type:"kern",size:-(r.height+p)},{type:"elem",elem:u},{type:"kern",size:h}]},e);if(t.index){var g=e.havingStyle(Ht.SCRIPTSCRIPT),y=Cr(t.index,g,e),v=.6*(m.height-m.depth),x=Be.makeVList({positionType:"shift",positionData:-v,children:[{type:"elem",elem:y}]},e),b=Be.makeSpan(["root"],[x]);return Be.makeSpan(["mord","sqrt"],[b,m],e)}else return Be.makeSpan(["mord","sqrt"],[m],e)},mathmlBuilder(t,e){var{body:r,index:n}=t;return n?new et.MathNode("mroot",[fn(r,e),fn(n,e)]):new et.MathNode("msqrt",[fn(r,e)])}});vG={display:Ht.DISPLAY,text:Ht.TEXT,script:Ht.SCRIPT,scriptscript:Ht.SCRIPTSCRIPT};vt({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(t,e){var{breakOnTokenText:r,funcName:n,parser:i}=t,a=i.parseExpression(!0,r),s=n.slice(1,n.length-5);return{type:"styling",mode:i.mode,style:s,body:a}},htmlBuilder(t,e){var r=vG[t.style],n=e.havingStyle(r).withFont("");return m$(t.body,n,e)},mathmlBuilder(t,e){var r=vG[t.style],n=e.havingStyle(r),i=gs(t.body,n),a=new et.MathNode("mstyle",i),s={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]},l=s[t.style];return a.setAttribute("scriptlevel",l[0]),a.setAttribute("displaystyle",l[1]),a}});fbe=o(function(e,r){var n=e.base;if(n)if(n.type==="op"){var i=n.limits&&(r.style.size===Ht.DISPLAY.size||n.alwaysHandleSupSub);return i?xp:null}else if(n.type==="operatorname"){var a=n.alwaysHandleSupSub&&(r.style.size===Ht.DISPLAY.size||n.limits);return a?p$:null}else{if(n.type==="accent")return Vt.isCharacterBox(n.base)?F7:null;if(n.type==="horizBrace"){var s=!e.sub;return s===n.isOver?h$:null}else return null}else return null},"htmlBuilderDelegate");Kf({type:"supsub",htmlBuilder(t,e){var r=fbe(t,e);if(r)return r(t,e);var{base:n,sup:i,sub:a}=t,s=Cr(n,e),l,u,h=e.fontMetrics(),f=0,d=0,p=n&&Vt.isCharacterBox(n);if(i){var m=e.havingStyle(e.style.sup());l=Cr(i,m,e),p||(f=s.height-m.fontMetrics().supDrop*m.sizeMultiplier/e.sizeMultiplier)}if(a){var g=e.havingStyle(e.style.sub());u=Cr(a,g,e),p||(d=s.depth+g.fontMetrics().subDrop*g.sizeMultiplier/e.sizeMultiplier)}var y;e.style===Ht.DISPLAY?y=h.sup1:e.style.cramped?y=h.sup3:y=h.sup2;var v=e.sizeMultiplier,x=ct(.5/h.ptPerEm/v),b=null;if(u){var w=t.base&&t.base.type==="op"&&t.base.name&&(t.base.name==="\\oiint"||t.base.name==="\\oiiint");(s instanceof ms||w)&&(b=ct(-s.italic))}var S;if(l&&u){f=Math.max(f,y,l.depth+.25*h.xHeight),d=Math.max(d,h.sub2);var T=h.defaultRuleThickness,E=4*T;if(f-l.depth-(u.height-d)0&&(f+=_,d-=_)}var A=[{type:"elem",elem:u,shift:d,marginRight:x,marginLeft:b},{type:"elem",elem:l,shift:-f,marginRight:x}];S=Be.makeVList({positionType:"individualShift",children:A},e)}else if(u){d=Math.max(d,h.sub1,u.height-.8*h.xHeight);var L=[{type:"elem",elem:u,marginLeft:b,marginRight:x}];S=Be.makeVList({positionType:"shift",positionData:d,children:L},e)}else if(l)f=Math.max(f,y,l.depth+.25*h.xHeight),S=Be.makeVList({positionType:"shift",positionData:-f,children:[{type:"elem",elem:l,marginRight:x}]},e);else throw new Error("supsub must have either sup or sub.");var M=E7(s,"right")||"mord";return Be.makeSpan([M],[s,Be.makeSpan(["msupsub"],[S])],e)},mathmlBuilder(t,e){var r=!1,n,i;t.base&&t.base.type==="horizBrace"&&(i=!!t.sup,i===t.base.isOver&&(r=!0,n=t.base.isOver)),t.base&&(t.base.type==="op"||t.base.type==="operatorname")&&(t.base.parentIsSupSub=!0);var a=[fn(t.base,e)];t.sub&&a.push(fn(t.sub,e)),t.sup&&a.push(fn(t.sup,e));var s;if(r)s=n?"mover":"munder";else if(t.sub)if(t.sup){var h=t.base;h&&h.type==="op"&&h.limits&&e.style===Ht.DISPLAY||h&&h.type==="operatorname"&&h.alwaysHandleSupSub&&(e.style===Ht.DISPLAY||h.limits)?s="munderover":s="msubsup"}else{var u=t.base;u&&u.type==="op"&&u.limits&&(e.style===Ht.DISPLAY||u.alwaysHandleSupSub)||u&&u.type==="operatorname"&&u.alwaysHandleSupSub&&(u.limits||e.style===Ht.DISPLAY)?s="munder":s="msub"}else{var l=t.base;l&&l.type==="op"&&l.limits&&(e.style===Ht.DISPLAY||l.alwaysHandleSupSub)||l&&l.type==="operatorname"&&l.alwaysHandleSupSub&&(l.limits||e.style===Ht.DISPLAY)?s="mover":s="msup"}return new et.MathNode(s,a)}});Kf({type:"atom",htmlBuilder(t,e){return Be.mathsym(t.text,t.mode,e,["m"+t.family])},mathmlBuilder(t,e){var r=new et.MathNode("mo",[_o(t.text,t.mode)]);if(t.family==="bin"){var n=P7(t,e);n==="bold-italic"&&r.setAttribute("mathvariant",n)}else t.family==="punct"?r.setAttribute("separator","true"):(t.family==="open"||t.family==="close")&&r.setAttribute("stretchy","false");return r}});g$={mi:"italic",mn:"normal",mtext:"normal"};Kf({type:"mathord",htmlBuilder(t,e){return Be.makeOrd(t,e,"mathord")},mathmlBuilder(t,e){var r=new et.MathNode("mi",[_o(t.text,t.mode,e)]),n=P7(t,e)||"italic";return n!==g$[r.type]&&r.setAttribute("mathvariant",n),r}});Kf({type:"textord",htmlBuilder(t,e){return Be.makeOrd(t,e,"textord")},mathmlBuilder(t,e){var r=_o(t.text,t.mode,e),n=P7(t,e)||"normal",i;return t.mode==="text"?i=new et.MathNode("mtext",[r]):/[0-9]/.test(t.text)?i=new et.MathNode("mn",[r]):t.text==="\\prime"?i=new et.MathNode("mo",[r]):i=new et.MathNode("mi",[r]),n!==g$[i.type]&&i.setAttribute("mathvariant",n),i}});y7={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},v7={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};Kf({type:"spacing",htmlBuilder(t,e){if(v7.hasOwnProperty(t.text)){var r=v7[t.text].className||"";if(t.mode==="text"){var n=Be.makeOrd(t,e,"textord");return n.classes.push(r),n}else return Be.makeSpan(["mspace",r],[Be.mathsym(t.text,t.mode,e)],e)}else{if(y7.hasOwnProperty(t.text))return Be.makeSpan(["mspace",y7[t.text]],[],e);throw new nt('Unknown type of space "'+t.text+'"')}},mathmlBuilder(t,e){var r;if(v7.hasOwnProperty(t.text))r=new et.MathNode("mtext",[new et.TextNode("\xA0")]);else{if(y7.hasOwnProperty(t.text))return new et.MathNode("mspace");throw new nt('Unknown type of space "'+t.text+'"')}return r}});xG=o(()=>{var t=new et.MathNode("mtd",[]);return t.setAttribute("width","50%"),t},"pad");Kf({type:"tag",mathmlBuilder(t,e){var r=new et.MathNode("mtable",[new et.MathNode("mtr",[xG(),new et.MathNode("mtd",[ph(t.body,e)]),xG(),new et.MathNode("mtd",[ph(t.tag,e)])])]);return r.setAttribute("width","100%"),r}});bG={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},wG={"\\textbf":"textbf","\\textmd":"textmd"},dbe={"\\textit":"textit","\\textup":"textup"},TG=o((t,e)=>{var r=t.font;if(r){if(bG[r])return e.withTextFontFamily(bG[r]);if(wG[r])return e.withTextFontWeight(wG[r]);if(r==="\\emph")return e.fontShape==="textit"?e.withTextFontShape("textup"):e.withTextFontShape("textit")}else return e;return e.withTextFontShape(dbe[r])},"optionsWithFont");vt({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup","\\emph"],props:{numArgs:1,argTypes:["text"],allowedInArgument:!0,allowedInText:!0},handler(t,e){var{parser:r,funcName:n}=t,i=e[0];return{type:"text",mode:r.mode,body:ui(i),font:n}},htmlBuilder(t,e){var r=TG(t,e),n=Ri(t.body,r,!0);return Be.makeSpan(["mord","text"],n,r)},mathmlBuilder(t,e){var r=TG(t,e);return ph(t.body,r)}});vt({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler(t,e){var{parser:r}=t;return{type:"underline",mode:r.mode,body:e[0]}},htmlBuilder(t,e){var r=Cr(t.body,e),n=Be.makeLineSpan("underline-line",e),i=e.fontMetrics().defaultRuleThickness,a=Be.makeVList({positionType:"top",positionData:r.height,children:[{type:"kern",size:i},{type:"elem",elem:n},{type:"kern",size:3*i},{type:"elem",elem:r}]},e);return Be.makeSpan(["mord","underline"],[a],e)},mathmlBuilder(t,e){var r=new et.MathNode("mo",[new et.TextNode("\u203E")]);r.setAttribute("stretchy","true");var n=new et.MathNode("munder",[fn(t.body,e),r]);return n.setAttribute("accentunder","true"),n}});vt({type:"vcenter",names:["\\vcenter"],props:{numArgs:1,argTypes:["original"],allowedInText:!1},handler(t,e){var{parser:r}=t;return{type:"vcenter",mode:r.mode,body:e[0]}},htmlBuilder(t,e){var r=Cr(t.body,e),n=e.fontMetrics().axisHeight,i=.5*(r.height-n-(r.depth+n));return Be.makeVList({positionType:"shift",positionData:i,children:[{type:"elem",elem:r}]},e)},mathmlBuilder(t,e){return new et.MathNode("mpadded",[fn(t.body,e)],["vcenter"])}});vt({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler(t,e,r){throw new nt("\\verb ended by end of line instead of matching delimiter")},htmlBuilder(t,e){for(var r=kG(t),n=[],i=e.havingStyle(e.style.text()),a=0;at.body.replace(/ /g,t.star?"\u2423":"\xA0"),"makeVerb"),fh=zG,y$=`[ \r + ]`,pbe="\\\\[a-zA-Z@]+",mbe="\\\\[^\uD800-\uDFFF]",gbe="("+pbe+")"+y$+"*",ybe=`\\\\( +|[ \r ]+ +?)[ \r ]*`,L7="[\u0300-\u036F]",vbe=new RegExp(L7+"+$"),xbe="("+y$+"+)|"+(ybe+"|")+"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]"+(L7+"*")+"|[\uD800-\uDBFF][\uDC00-\uDFFF]"+(L7+"*")+"|\\\\verb\\*([^]).*?\\4|\\\\verb([^*a-zA-Z]).*?\\5"+("|"+gbe)+("|"+mbe+")"),v4=class{static{o(this,"Lexer")}constructor(e,r){this.input=void 0,this.settings=void 0,this.tokenRegex=void 0,this.catcodes=void 0,this.input=e,this.settings=r,this.tokenRegex=new RegExp(xbe,"g"),this.catcodes={"%":14,"~":13}}setCatcode(e,r){this.catcodes[e]=r}lex(){var e=this.input,r=this.tokenRegex.lastIndex;if(r===e.length)return new Ao("EOF",new Xs(this,r,r));var n=this.tokenRegex.exec(e);if(n===null||n.index!==r)throw new nt("Unexpected character: '"+e[r]+"'",new Ao(e[r],new Xs(this,r,r+1)));var i=n[6]||n[3]||(n[2]?"\\ ":" ");if(this.catcodes[i]===14){var a=e.indexOf(` +`,this.tokenRegex.lastIndex);return a===-1?(this.tokenRegex.lastIndex=e.length,this.settings.reportNonstrict("commentAtEnd","% comment has no terminating newline; LaTeX would fail because of commenting the end of math mode (e.g. $)")):this.tokenRegex.lastIndex=a+1,this.lex()}return new Ao(i,new Xs(this,r,this.tokenRegex.lastIndex))}},D7=class{static{o(this,"Namespace")}constructor(e,r){e===void 0&&(e={}),r===void 0&&(r={}),this.current=void 0,this.builtins=void 0,this.undefStack=void 0,this.current=r,this.builtins=e,this.undefStack=[]}beginGroup(){this.undefStack.push({})}endGroup(){if(this.undefStack.length===0)throw new nt("Unbalanced namespace destruction: attempt to pop global namespace; please report this as a bug");var e=this.undefStack.pop();for(var r in e)e.hasOwnProperty(r)&&(e[r]==null?delete this.current[r]:this.current[r]=e[r])}endGroups(){for(;this.undefStack.length>0;)this.endGroup()}has(e){return this.current.hasOwnProperty(e)||this.builtins.hasOwnProperty(e)}get(e){return this.current.hasOwnProperty(e)?this.current[e]:this.builtins[e]}set(e,r,n){if(n===void 0&&(n=!1),n){for(var i=0;i0&&(this.undefStack[this.undefStack.length-1][e]=r)}else{var a=this.undefStack[this.undefStack.length-1];a&&!a.hasOwnProperty(e)&&(a[e]=this.current[e])}r==null?delete this.current[e]:this.current[e]=r}},bbe=s$;le("\\noexpand",function(t){var e=t.popToken();return t.isExpandable(e.text)&&(e.noexpand=!0,e.treatAsRelax=!0),{tokens:[e],numArgs:0}});le("\\expandafter",function(t){var e=t.popToken();return t.expandOnce(!0),{tokens:[e],numArgs:0}});le("\\@firstoftwo",function(t){var e=t.consumeArgs(2);return{tokens:e[0],numArgs:0}});le("\\@secondoftwo",function(t){var e=t.consumeArgs(2);return{tokens:e[1],numArgs:0}});le("\\@ifnextchar",function(t){var e=t.consumeArgs(3);t.consumeSpaces();var r=t.future();return e[0].length===1&&e[0][0].text===r.text?{tokens:e[1],numArgs:0}:{tokens:e[2],numArgs:0}});le("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}");le("\\TextOrMath",function(t){var e=t.consumeArgs(2);return t.mode==="text"?{tokens:e[0],numArgs:0}:{tokens:e[1],numArgs:0}});EG={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15};le("\\char",function(t){var e=t.popToken(),r,n="";if(e.text==="'")r=8,e=t.popToken();else if(e.text==='"')r=16,e=t.popToken();else if(e.text==="`")if(e=t.popToken(),e.text[0]==="\\")n=e.text.charCodeAt(1);else{if(e.text==="EOF")throw new nt("\\char` missing argument");n=e.text.charCodeAt(0)}else r=10;if(r){if(n=EG[e.text],n==null||n>=r)throw new nt("Invalid base-"+r+" digit "+e.text);for(var i;(i=EG[t.future().text])!=null&&i{var n=t.consumeArg().tokens;if(n.length!==1)throw new nt("\\newcommand's first argument must be a macro name");var i=n[0].text,a=t.isDefined(i);if(a&&!e)throw new nt("\\newcommand{"+i+"} attempting to redefine "+(i+"; use \\renewcommand"));if(!a&&!r)throw new nt("\\renewcommand{"+i+"} when command "+i+" does not yet exist; use \\newcommand");var s=0;if(n=t.consumeArg().tokens,n.length===1&&n[0].text==="["){for(var l="",u=t.expandNextToken();u.text!=="]"&&u.text!=="EOF";)l+=u.text,u=t.expandNextToken();if(!l.match(/^\s*[0-9]+\s*$/))throw new nt("Invalid number of arguments: "+l);s=parseInt(l),n=t.consumeArg().tokens}return t.macros.set(i,{tokens:n,numArgs:s}),""},"newcommand");le("\\newcommand",t=>W7(t,!1,!0));le("\\renewcommand",t=>W7(t,!0,!1));le("\\providecommand",t=>W7(t,!0,!0));le("\\message",t=>{var e=t.consumeArgs(1)[0];return console.log(e.reverse().map(r=>r.text).join("")),""});le("\\errmessage",t=>{var e=t.consumeArgs(1)[0];return console.error(e.reverse().map(r=>r.text).join("")),""});le("\\show",t=>{var e=t.popToken(),r=e.text;return console.log(e,t.macros.get(r),fh[r],wn.math[r],wn.text[r]),""});le("\\bgroup","{");le("\\egroup","}");le("~","\\nobreakspace");le("\\lq","`");le("\\rq","'");le("\\aa","\\r a");le("\\AA","\\r A");le("\\textcopyright","\\html@mathml{\\textcircled{c}}{\\char`\xA9}");le("\\copyright","\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}");le("\\textregistered","\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`\xAE}");le("\u212C","\\mathscr{B}");le("\u2130","\\mathscr{E}");le("\u2131","\\mathscr{F}");le("\u210B","\\mathscr{H}");le("\u2110","\\mathscr{I}");le("\u2112","\\mathscr{L}");le("\u2133","\\mathscr{M}");le("\u211B","\\mathscr{R}");le("\u212D","\\mathfrak{C}");le("\u210C","\\mathfrak{H}");le("\u2128","\\mathfrak{Z}");le("\\Bbbk","\\Bbb{k}");le("\xB7","\\cdotp");le("\\llap","\\mathllap{\\textrm{#1}}");le("\\rlap","\\mathrlap{\\textrm{#1}}");le("\\clap","\\mathclap{\\textrm{#1}}");le("\\mathstrut","\\vphantom{(}");le("\\underbar","\\underline{\\text{#1}}");le("\\not",'\\html@mathml{\\mathrel{\\mathrlap\\@not}}{\\char"338}');le("\\neq","\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`\u2260}}");le("\\ne","\\neq");le("\u2260","\\neq");le("\\notin","\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}{\\mathrel{\\char`\u2209}}");le("\u2209","\\notin");le("\u2258","\\html@mathml{\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}}{\\mathrel{\\char`\u2258}}");le("\u2259","\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`\u2258}}");le("\u225A","\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`\u225A}}");le("\u225B","\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}{\\mathrel{\\char`\u225B}}");le("\u225D","\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}{\\mathrel{\\char`\u225D}}");le("\u225E","\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}{\\mathrel{\\char`\u225E}}");le("\u225F","\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`\u225F}}");le("\u27C2","\\perp");le("\u203C","\\mathclose{!\\mkern-0.8mu!}");le("\u220C","\\notni");le("\u231C","\\ulcorner");le("\u231D","\\urcorner");le("\u231E","\\llcorner");le("\u231F","\\lrcorner");le("\xA9","\\copyright");le("\xAE","\\textregistered");le("\uFE0F","\\textregistered");le("\\ulcorner",'\\html@mathml{\\@ulcorner}{\\mathop{\\char"231c}}');le("\\urcorner",'\\html@mathml{\\@urcorner}{\\mathop{\\char"231d}}');le("\\llcorner",'\\html@mathml{\\@llcorner}{\\mathop{\\char"231e}}');le("\\lrcorner",'\\html@mathml{\\@lrcorner}{\\mathop{\\char"231f}}');le("\\vdots","\\mathord{\\varvdots\\rule{0pt}{15pt}}");le("\u22EE","\\vdots");le("\\varGamma","\\mathit{\\Gamma}");le("\\varDelta","\\mathit{\\Delta}");le("\\varTheta","\\mathit{\\Theta}");le("\\varLambda","\\mathit{\\Lambda}");le("\\varXi","\\mathit{\\Xi}");le("\\varPi","\\mathit{\\Pi}");le("\\varSigma","\\mathit{\\Sigma}");le("\\varUpsilon","\\mathit{\\Upsilon}");le("\\varPhi","\\mathit{\\Phi}");le("\\varPsi","\\mathit{\\Psi}");le("\\varOmega","\\mathit{\\Omega}");le("\\substack","\\begin{subarray}{c}#1\\end{subarray}");le("\\colon","\\nobreak\\mskip2mu\\mathpunct{}\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu\\relax");le("\\boxed","\\fbox{$\\displaystyle{#1}$}");le("\\iff","\\DOTSB\\;\\Longleftrightarrow\\;");le("\\implies","\\DOTSB\\;\\Longrightarrow\\;");le("\\impliedby","\\DOTSB\\;\\Longleftarrow\\;");CG={",":"\\dotsc","\\not":"\\dotsb","+":"\\dotsb","=":"\\dotsb","<":"\\dotsb",">":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"};le("\\dots",function(t){var e="\\dotso",r=t.expandAfterFuture().text;return r in CG?e=CG[r]:(r.slice(0,4)==="\\not"||r in wn.math&&Vt.contains(["bin","rel"],wn.math[r].group))&&(e="\\dotsb"),e});q7={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};le("\\dotso",function(t){var e=t.future().text;return e in q7?"\\ldots\\,":"\\ldots"});le("\\dotsc",function(t){var e=t.future().text;return e in q7&&e!==","?"\\ldots\\,":"\\ldots"});le("\\cdots",function(t){var e=t.future().text;return e in q7?"\\@cdots\\,":"\\@cdots"});le("\\dotsb","\\cdots");le("\\dotsm","\\cdots");le("\\dotsi","\\!\\cdots");le("\\dotsx","\\ldots\\,");le("\\DOTSI","\\relax");le("\\DOTSB","\\relax");le("\\DOTSX","\\relax");le("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax");le("\\,","\\tmspace+{3mu}{.1667em}");le("\\thinspace","\\,");le("\\>","\\mskip{4mu}");le("\\:","\\tmspace+{4mu}{.2222em}");le("\\medspace","\\:");le("\\;","\\tmspace+{5mu}{.2777em}");le("\\thickspace","\\;");le("\\!","\\tmspace-{3mu}{.1667em}");le("\\negthinspace","\\!");le("\\negmedspace","\\tmspace-{4mu}{.2222em}");le("\\negthickspace","\\tmspace-{5mu}{.277em}");le("\\enspace","\\kern.5em ");le("\\enskip","\\hskip.5em\\relax");le("\\quad","\\hskip1em\\relax");le("\\qquad","\\hskip2em\\relax");le("\\tag","\\@ifstar\\tag@literal\\tag@paren");le("\\tag@paren","\\tag@literal{({#1})}");le("\\tag@literal",t=>{if(t.macros.get("\\df@tag"))throw new nt("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"});le("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}");le("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)");le("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}");le("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1");le("\\newline","\\\\\\relax");le("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");v$=ct(Zl["Main-Regular"][84][1]-.7*Zl["Main-Regular"][65][1]);le("\\LaTeX","\\textrm{\\html@mathml{"+("L\\kern-.36em\\raisebox{"+v$+"}{\\scriptstyle A}")+"\\kern-.15em\\TeX}{LaTeX}}");le("\\KaTeX","\\textrm{\\html@mathml{"+("K\\kern-.17em\\raisebox{"+v$+"}{\\scriptstyle A}")+"\\kern-.15em\\TeX}{KaTeX}}");le("\\hspace","\\@ifstar\\@hspacer\\@hspace");le("\\@hspace","\\hskip #1\\relax");le("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax");le("\\ordinarycolon",":");le("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}");le("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}');le("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}');le("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}');le("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}');le("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}');le("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}');le("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}');le("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}');le("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}');le("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}');le("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}');le("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}');le("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}');le("\u2237","\\dblcolon");le("\u2239","\\eqcolon");le("\u2254","\\coloneqq");le("\u2255","\\eqqcolon");le("\u2A74","\\Coloneqq");le("\\ratio","\\vcentcolon");le("\\coloncolon","\\dblcolon");le("\\colonequals","\\coloneqq");le("\\coloncolonequals","\\Coloneqq");le("\\equalscolon","\\eqqcolon");le("\\equalscoloncolon","\\Eqqcolon");le("\\colonminus","\\coloneq");le("\\coloncolonminus","\\Coloneq");le("\\minuscolon","\\eqcolon");le("\\minuscoloncolon","\\Eqcolon");le("\\coloncolonapprox","\\Colonapprox");le("\\coloncolonsim","\\Colonsim");le("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}");le("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}");le("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}");le("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}");le("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220C}}");le("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}");le("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}");le("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}");le("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}");le("\\varlimsup","\\DOTSB\\operatorname*{\\overline{lim}}");le("\\varliminf","\\DOTSB\\operatorname*{\\underline{lim}}");le("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{lim}}");le("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{lim}}");le("\\gvertneqq","\\html@mathml{\\@gvertneqq}{\u2269}");le("\\lvertneqq","\\html@mathml{\\@lvertneqq}{\u2268}");le("\\ngeqq","\\html@mathml{\\@ngeqq}{\u2271}");le("\\ngeqslant","\\html@mathml{\\@ngeqslant}{\u2271}");le("\\nleqq","\\html@mathml{\\@nleqq}{\u2270}");le("\\nleqslant","\\html@mathml{\\@nleqslant}{\u2270}");le("\\nshortmid","\\html@mathml{\\@nshortmid}{\u2224}");le("\\nshortparallel","\\html@mathml{\\@nshortparallel}{\u2226}");le("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{\u2288}");le("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{\u2289}");le("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{\u228A}");le("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{\u2ACB}");le("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{\u228B}");le("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{\u2ACC}");le("\\imath","\\html@mathml{\\@imath}{\u0131}");le("\\jmath","\\html@mathml{\\@jmath}{\u0237}");le("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`\u27E6}}");le("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`\u27E7}}");le("\u27E6","\\llbracket");le("\u27E7","\\rrbracket");le("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`\u2983}}");le("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`\u2984}}");le("\u2983","\\lBrace");le("\u2984","\\rBrace");le("\\minuso","\\mathbin{\\html@mathml{{\\mathrlap{\\mathchoice{\\kern{0.145em}}{\\kern{0.145em}}{\\kern{0.1015em}}{\\kern{0.0725em}}\\circ}{-}}}{\\char`\u29B5}}");le("\u29B5","\\minuso");le("\\darr","\\downarrow");le("\\dArr","\\Downarrow");le("\\Darr","\\Downarrow");le("\\lang","\\langle");le("\\rang","\\rangle");le("\\uarr","\\uparrow");le("\\uArr","\\Uparrow");le("\\Uarr","\\Uparrow");le("\\N","\\mathbb{N}");le("\\R","\\mathbb{R}");le("\\Z","\\mathbb{Z}");le("\\alef","\\aleph");le("\\alefsym","\\aleph");le("\\Alpha","\\mathrm{A}");le("\\Beta","\\mathrm{B}");le("\\bull","\\bullet");le("\\Chi","\\mathrm{X}");le("\\clubs","\\clubsuit");le("\\cnums","\\mathbb{C}");le("\\Complex","\\mathbb{C}");le("\\Dagger","\\ddagger");le("\\diamonds","\\diamondsuit");le("\\empty","\\emptyset");le("\\Epsilon","\\mathrm{E}");le("\\Eta","\\mathrm{H}");le("\\exist","\\exists");le("\\harr","\\leftrightarrow");le("\\hArr","\\Leftrightarrow");le("\\Harr","\\Leftrightarrow");le("\\hearts","\\heartsuit");le("\\image","\\Im");le("\\infin","\\infty");le("\\Iota","\\mathrm{I}");le("\\isin","\\in");le("\\Kappa","\\mathrm{K}");le("\\larr","\\leftarrow");le("\\lArr","\\Leftarrow");le("\\Larr","\\Leftarrow");le("\\lrarr","\\leftrightarrow");le("\\lrArr","\\Leftrightarrow");le("\\Lrarr","\\Leftrightarrow");le("\\Mu","\\mathrm{M}");le("\\natnums","\\mathbb{N}");le("\\Nu","\\mathrm{N}");le("\\Omicron","\\mathrm{O}");le("\\plusmn","\\pm");le("\\rarr","\\rightarrow");le("\\rArr","\\Rightarrow");le("\\Rarr","\\Rightarrow");le("\\real","\\Re");le("\\reals","\\mathbb{R}");le("\\Reals","\\mathbb{R}");le("\\Rho","\\mathrm{P}");le("\\sdot","\\cdot");le("\\sect","\\S");le("\\spades","\\spadesuit");le("\\sub","\\subset");le("\\sube","\\subseteq");le("\\supe","\\supseteq");le("\\Tau","\\mathrm{T}");le("\\thetasym","\\vartheta");le("\\weierp","\\wp");le("\\Zeta","\\mathrm{Z}");le("\\argmin","\\DOTSB\\operatorname*{arg\\,min}");le("\\argmax","\\DOTSB\\operatorname*{arg\\,max}");le("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits");le("\\bra","\\mathinner{\\langle{#1}|}");le("\\ket","\\mathinner{|{#1}\\rangle}");le("\\braket","\\mathinner{\\langle{#1}\\rangle}");le("\\Bra","\\left\\langle#1\\right|");le("\\Ket","\\left|#1\\right\\rangle");x$=o(t=>e=>{var r=e.consumeArg().tokens,n=e.consumeArg().tokens,i=e.consumeArg().tokens,a=e.consumeArg().tokens,s=e.macros.get("|"),l=e.macros.get("\\|");e.macros.beginGroup();var u=o(d=>p=>{t&&(p.macros.set("|",s),i.length&&p.macros.set("\\|",l));var m=d;if(!d&&i.length){var g=p.future();g.text==="|"&&(p.popToken(),m=!0)}return{tokens:m?i:n,numArgs:0}},"midMacro");e.macros.set("|",u(!1)),i.length&&e.macros.set("\\|",u(!0));var h=e.consumeArg().tokens,f=e.expandTokens([...a,...h,...r]);return e.macros.endGroup(),{tokens:f.reverse(),numArgs:0}},"braketHelper");le("\\bra@ket",x$(!1));le("\\bra@set",x$(!0));le("\\Braket","\\bra@ket{\\left\\langle}{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}");le("\\Set","\\bra@set{\\left\\{\\:}{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}");le("\\set","\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}");le("\\angln","{\\angl n}");le("\\blue","\\textcolor{##6495ed}{#1}");le("\\orange","\\textcolor{##ffa500}{#1}");le("\\pink","\\textcolor{##ff00af}{#1}");le("\\red","\\textcolor{##df0030}{#1}");le("\\green","\\textcolor{##28ae7b}{#1}");le("\\gray","\\textcolor{gray}{#1}");le("\\purple","\\textcolor{##9d38bd}{#1}");le("\\blueA","\\textcolor{##ccfaff}{#1}");le("\\blueB","\\textcolor{##80f6ff}{#1}");le("\\blueC","\\textcolor{##63d9ea}{#1}");le("\\blueD","\\textcolor{##11accd}{#1}");le("\\blueE","\\textcolor{##0c7f99}{#1}");le("\\tealA","\\textcolor{##94fff5}{#1}");le("\\tealB","\\textcolor{##26edd5}{#1}");le("\\tealC","\\textcolor{##01d1c1}{#1}");le("\\tealD","\\textcolor{##01a995}{#1}");le("\\tealE","\\textcolor{##208170}{#1}");le("\\greenA","\\textcolor{##b6ffb0}{#1}");le("\\greenB","\\textcolor{##8af281}{#1}");le("\\greenC","\\textcolor{##74cf70}{#1}");le("\\greenD","\\textcolor{##1fab54}{#1}");le("\\greenE","\\textcolor{##0d923f}{#1}");le("\\goldA","\\textcolor{##ffd0a9}{#1}");le("\\goldB","\\textcolor{##ffbb71}{#1}");le("\\goldC","\\textcolor{##ff9c39}{#1}");le("\\goldD","\\textcolor{##e07d10}{#1}");le("\\goldE","\\textcolor{##a75a05}{#1}");le("\\redA","\\textcolor{##fca9a9}{#1}");le("\\redB","\\textcolor{##ff8482}{#1}");le("\\redC","\\textcolor{##f9685d}{#1}");le("\\redD","\\textcolor{##e84d39}{#1}");le("\\redE","\\textcolor{##bc2612}{#1}");le("\\maroonA","\\textcolor{##ffbde0}{#1}");le("\\maroonB","\\textcolor{##ff92c6}{#1}");le("\\maroonC","\\textcolor{##ed5fa6}{#1}");le("\\maroonD","\\textcolor{##ca337c}{#1}");le("\\maroonE","\\textcolor{##9e034e}{#1}");le("\\purpleA","\\textcolor{##ddd7ff}{#1}");le("\\purpleB","\\textcolor{##c6b9fc}{#1}");le("\\purpleC","\\textcolor{##aa87ff}{#1}");le("\\purpleD","\\textcolor{##7854ab}{#1}");le("\\purpleE","\\textcolor{##543b78}{#1}");le("\\mintA","\\textcolor{##f5f9e8}{#1}");le("\\mintB","\\textcolor{##edf2df}{#1}");le("\\mintC","\\textcolor{##e0e5cc}{#1}");le("\\grayA","\\textcolor{##f6f7f7}{#1}");le("\\grayB","\\textcolor{##f0f1f2}{#1}");le("\\grayC","\\textcolor{##e3e5e6}{#1}");le("\\grayD","\\textcolor{##d6d8da}{#1}");le("\\grayE","\\textcolor{##babec2}{#1}");le("\\grayF","\\textcolor{##888d93}{#1}");le("\\grayG","\\textcolor{##626569}{#1}");le("\\grayH","\\textcolor{##3b3e40}{#1}");le("\\grayI","\\textcolor{##21242c}{#1}");le("\\kaBlue","\\textcolor{##314453}{#1}");le("\\kaGreen","\\textcolor{##71B307}{#1}");b$={"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0},R7=class{static{o(this,"MacroExpander")}constructor(e,r,n){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=r,this.expansionCount=0,this.feed(e),this.macros=new D7(bbe,r.macros),this.mode=n,this.stack=[]}feed(e){this.lexer=new v4(e,this.settings)}switchMode(e){this.mode=e}beginGroup(){this.macros.beginGroup()}endGroup(){this.macros.endGroup()}endGroups(){this.macros.endGroups()}future(){return this.stack.length===0&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]}popToken(){return this.future(),this.stack.pop()}pushToken(e){this.stack.push(e)}pushTokens(e){this.stack.push(...e)}scanArgument(e){var r,n,i;if(e){if(this.consumeSpaces(),this.future().text!=="[")return null;r=this.popToken(),{tokens:i,end:n}=this.consumeArg(["]"])}else({tokens:i,start:r,end:n}=this.consumeArg());return this.pushToken(new Ao("EOF",n.loc)),this.pushTokens(i),r.range(n,"")}consumeSpaces(){for(;;){var e=this.future();if(e.text===" ")this.stack.pop();else break}}consumeArg(e){var r=[],n=e&&e.length>0;n||this.consumeSpaces();var i=this.future(),a,s=0,l=0;do{if(a=this.popToken(),r.push(a),a.text==="{")++s;else if(a.text==="}"){if(--s,s===-1)throw new nt("Extra }",a)}else if(a.text==="EOF")throw new nt("Unexpected end of input in a macro argument, expected '"+(e&&n?e[l]:"}")+"'",a);if(e&&n)if((s===0||s===1&&e[l]==="{")&&a.text===e[l]){if(++l,l===e.length){r.splice(-l,l);break}}else l=0}while(s!==0||n);return i.text==="{"&&r[r.length-1].text==="}"&&(r.pop(),r.shift()),r.reverse(),{tokens:r,start:i,end:a}}consumeArgs(e,r){if(r){if(r.length!==e+1)throw new nt("The length of delimiters doesn't match the number of args!");for(var n=r[0],i=0;ithis.settings.maxExpand)throw new nt("Too many expansions: infinite loop or need to increase maxExpand setting")}expandOnce(e){var r=this.popToken(),n=r.text,i=r.noexpand?null:this._getExpansion(n);if(i==null||e&&i.unexpandable){if(e&&i==null&&n[0]==="\\"&&!this.isDefined(n))throw new nt("Undefined control sequence: "+n);return this.pushToken(r),!1}this.countExpansion(1);var a=i.tokens,s=this.consumeArgs(i.numArgs,i.delimiters);if(i.numArgs){a=a.slice();for(var l=a.length-1;l>=0;--l){var u=a[l];if(u.text==="#"){if(l===0)throw new nt("Incomplete placeholder at end of macro body",u);if(u=a[--l],u.text==="#")a.splice(l+1,1);else if(/^[1-9]$/.test(u.text))a.splice(l,2,...s[+u.text-1]);else throw new nt("Not a valid argument number",u)}}}return this.pushTokens(a),a.length}expandAfterFuture(){return this.expandOnce(),this.future()}expandNextToken(){for(;;)if(this.expandOnce()===!1){var e=this.stack.pop();return e.treatAsRelax&&(e.text="\\relax"),e}throw new Error}expandMacro(e){return this.macros.has(e)?this.expandTokens([new Ao(e)]):void 0}expandTokens(e){var r=[],n=this.stack.length;for(this.pushTokens(e);this.stack.length>n;)if(this.expandOnce(!0)===!1){var i=this.stack.pop();i.treatAsRelax&&(i.noexpand=!1,i.treatAsRelax=!1),r.push(i)}return this.countExpansion(r.length),r}expandMacroAsText(e){var r=this.expandMacro(e);return r&&r.map(n=>n.text).join("")}_getExpansion(e){var r=this.macros.get(e);if(r==null)return r;if(e.length===1){var n=this.lexer.catcodes[e];if(n!=null&&n!==13)return}var i=typeof r=="function"?r(this):r;if(typeof i=="string"){var a=0;if(i.indexOf("#")!==-1)for(var s=i.replace(/##/g,"");s.indexOf("#"+(a+1))!==-1;)++a;for(var l=new v4(i,this.settings),u=[],h=l.lex();h.text!=="EOF";)u.push(h),h=l.lex();u.reverse();var f={tokens:u,numArgs:a};return f}return i}isDefined(e){return this.macros.has(e)||fh.hasOwnProperty(e)||wn.math.hasOwnProperty(e)||wn.text.hasOwnProperty(e)||b$.hasOwnProperty(e)}isExpandable(e){var r=this.macros.get(e);return r!=null?typeof r=="string"||typeof r=="function"||!r.unexpandable:fh.hasOwnProperty(e)&&!fh[e].primitive}},SG=/^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/,c4=Object.freeze({"\u208A":"+","\u208B":"-","\u208C":"=","\u208D":"(","\u208E":")","\u2080":"0","\u2081":"1","\u2082":"2","\u2083":"3","\u2084":"4","\u2085":"5","\u2086":"6","\u2087":"7","\u2088":"8","\u2089":"9","\u2090":"a","\u2091":"e","\u2095":"h","\u1D62":"i","\u2C7C":"j","\u2096":"k","\u2097":"l","\u2098":"m","\u2099":"n","\u2092":"o","\u209A":"p","\u1D63":"r","\u209B":"s","\u209C":"t","\u1D64":"u","\u1D65":"v","\u2093":"x","\u1D66":"\u03B2","\u1D67":"\u03B3","\u1D68":"\u03C1","\u1D69":"\u03D5","\u1D6A":"\u03C7","\u207A":"+","\u207B":"-","\u207C":"=","\u207D":"(","\u207E":")","\u2070":"0","\xB9":"1","\xB2":"2","\xB3":"3","\u2074":"4","\u2075":"5","\u2076":"6","\u2077":"7","\u2078":"8","\u2079":"9","\u1D2C":"A","\u1D2E":"B","\u1D30":"D","\u1D31":"E","\u1D33":"G","\u1D34":"H","\u1D35":"I","\u1D36":"J","\u1D37":"K","\u1D38":"L","\u1D39":"M","\u1D3A":"N","\u1D3C":"O","\u1D3E":"P","\u1D3F":"R","\u1D40":"T","\u1D41":"U","\u2C7D":"V","\u1D42":"W","\u1D43":"a","\u1D47":"b","\u1D9C":"c","\u1D48":"d","\u1D49":"e","\u1DA0":"f","\u1D4D":"g",\u02B0:"h","\u2071":"i",\u02B2:"j","\u1D4F":"k",\u02E1:"l","\u1D50":"m",\u207F:"n","\u1D52":"o","\u1D56":"p",\u02B3:"r",\u02E2:"s","\u1D57":"t","\u1D58":"u","\u1D5B":"v",\u02B7:"w",\u02E3:"x",\u02B8:"y","\u1DBB":"z","\u1D5D":"\u03B2","\u1D5E":"\u03B3","\u1D5F":"\u03B4","\u1D60":"\u03D5","\u1D61":"\u03C7","\u1DBF":"\u03B8"}),x7={"\u0301":{text:"\\'",math:"\\acute"},"\u0300":{text:"\\`",math:"\\grave"},"\u0308":{text:'\\"',math:"\\ddot"},"\u0303":{text:"\\~",math:"\\tilde"},"\u0304":{text:"\\=",math:"\\bar"},"\u0306":{text:"\\u",math:"\\breve"},"\u030C":{text:"\\v",math:"\\check"},"\u0302":{text:"\\^",math:"\\hat"},"\u0307":{text:"\\.",math:"\\dot"},"\u030A":{text:"\\r",math:"\\mathring"},"\u030B":{text:"\\H"},"\u0327":{text:"\\c"}},AG={\u00E1:"a\u0301",\u00E0:"a\u0300",\u00E4:"a\u0308",\u01DF:"a\u0308\u0304",\u00E3:"a\u0303",\u0101:"a\u0304",\u0103:"a\u0306",\u1EAF:"a\u0306\u0301",\u1EB1:"a\u0306\u0300",\u1EB5:"a\u0306\u0303",\u01CE:"a\u030C",\u00E2:"a\u0302",\u1EA5:"a\u0302\u0301",\u1EA7:"a\u0302\u0300",\u1EAB:"a\u0302\u0303",\u0227:"a\u0307",\u01E1:"a\u0307\u0304",\u00E5:"a\u030A",\u01FB:"a\u030A\u0301",\u1E03:"b\u0307",\u0107:"c\u0301",\u1E09:"c\u0327\u0301",\u010D:"c\u030C",\u0109:"c\u0302",\u010B:"c\u0307",\u00E7:"c\u0327",\u010F:"d\u030C",\u1E0B:"d\u0307",\u1E11:"d\u0327",\u00E9:"e\u0301",\u00E8:"e\u0300",\u00EB:"e\u0308",\u1EBD:"e\u0303",\u0113:"e\u0304",\u1E17:"e\u0304\u0301",\u1E15:"e\u0304\u0300",\u0115:"e\u0306",\u1E1D:"e\u0327\u0306",\u011B:"e\u030C",\u00EA:"e\u0302",\u1EBF:"e\u0302\u0301",\u1EC1:"e\u0302\u0300",\u1EC5:"e\u0302\u0303",\u0117:"e\u0307",\u0229:"e\u0327",\u1E1F:"f\u0307",\u01F5:"g\u0301",\u1E21:"g\u0304",\u011F:"g\u0306",\u01E7:"g\u030C",\u011D:"g\u0302",\u0121:"g\u0307",\u0123:"g\u0327",\u1E27:"h\u0308",\u021F:"h\u030C",\u0125:"h\u0302",\u1E23:"h\u0307",\u1E29:"h\u0327",\u00ED:"i\u0301",\u00EC:"i\u0300",\u00EF:"i\u0308",\u1E2F:"i\u0308\u0301",\u0129:"i\u0303",\u012B:"i\u0304",\u012D:"i\u0306",\u01D0:"i\u030C",\u00EE:"i\u0302",\u01F0:"j\u030C",\u0135:"j\u0302",\u1E31:"k\u0301",\u01E9:"k\u030C",\u0137:"k\u0327",\u013A:"l\u0301",\u013E:"l\u030C",\u013C:"l\u0327",\u1E3F:"m\u0301",\u1E41:"m\u0307",\u0144:"n\u0301",\u01F9:"n\u0300",\u00F1:"n\u0303",\u0148:"n\u030C",\u1E45:"n\u0307",\u0146:"n\u0327",\u00F3:"o\u0301",\u00F2:"o\u0300",\u00F6:"o\u0308",\u022B:"o\u0308\u0304",\u00F5:"o\u0303",\u1E4D:"o\u0303\u0301",\u1E4F:"o\u0303\u0308",\u022D:"o\u0303\u0304",\u014D:"o\u0304",\u1E53:"o\u0304\u0301",\u1E51:"o\u0304\u0300",\u014F:"o\u0306",\u01D2:"o\u030C",\u00F4:"o\u0302",\u1ED1:"o\u0302\u0301",\u1ED3:"o\u0302\u0300",\u1ED7:"o\u0302\u0303",\u022F:"o\u0307",\u0231:"o\u0307\u0304",\u0151:"o\u030B",\u1E55:"p\u0301",\u1E57:"p\u0307",\u0155:"r\u0301",\u0159:"r\u030C",\u1E59:"r\u0307",\u0157:"r\u0327",\u015B:"s\u0301",\u1E65:"s\u0301\u0307",\u0161:"s\u030C",\u1E67:"s\u030C\u0307",\u015D:"s\u0302",\u1E61:"s\u0307",\u015F:"s\u0327",\u1E97:"t\u0308",\u0165:"t\u030C",\u1E6B:"t\u0307",\u0163:"t\u0327",\u00FA:"u\u0301",\u00F9:"u\u0300",\u00FC:"u\u0308",\u01D8:"u\u0308\u0301",\u01DC:"u\u0308\u0300",\u01D6:"u\u0308\u0304",\u01DA:"u\u0308\u030C",\u0169:"u\u0303",\u1E79:"u\u0303\u0301",\u016B:"u\u0304",\u1E7B:"u\u0304\u0308",\u016D:"u\u0306",\u01D4:"u\u030C",\u00FB:"u\u0302",\u016F:"u\u030A",\u0171:"u\u030B",\u1E7D:"v\u0303",\u1E83:"w\u0301",\u1E81:"w\u0300",\u1E85:"w\u0308",\u0175:"w\u0302",\u1E87:"w\u0307",\u1E98:"w\u030A",\u1E8D:"x\u0308",\u1E8B:"x\u0307",\u00FD:"y\u0301",\u1EF3:"y\u0300",\u00FF:"y\u0308",\u1EF9:"y\u0303",\u0233:"y\u0304",\u0177:"y\u0302",\u1E8F:"y\u0307",\u1E99:"y\u030A",\u017A:"z\u0301",\u017E:"z\u030C",\u1E91:"z\u0302",\u017C:"z\u0307",\u00C1:"A\u0301",\u00C0:"A\u0300",\u00C4:"A\u0308",\u01DE:"A\u0308\u0304",\u00C3:"A\u0303",\u0100:"A\u0304",\u0102:"A\u0306",\u1EAE:"A\u0306\u0301",\u1EB0:"A\u0306\u0300",\u1EB4:"A\u0306\u0303",\u01CD:"A\u030C",\u00C2:"A\u0302",\u1EA4:"A\u0302\u0301",\u1EA6:"A\u0302\u0300",\u1EAA:"A\u0302\u0303",\u0226:"A\u0307",\u01E0:"A\u0307\u0304",\u00C5:"A\u030A",\u01FA:"A\u030A\u0301",\u1E02:"B\u0307",\u0106:"C\u0301",\u1E08:"C\u0327\u0301",\u010C:"C\u030C",\u0108:"C\u0302",\u010A:"C\u0307",\u00C7:"C\u0327",\u010E:"D\u030C",\u1E0A:"D\u0307",\u1E10:"D\u0327",\u00C9:"E\u0301",\u00C8:"E\u0300",\u00CB:"E\u0308",\u1EBC:"E\u0303",\u0112:"E\u0304",\u1E16:"E\u0304\u0301",\u1E14:"E\u0304\u0300",\u0114:"E\u0306",\u1E1C:"E\u0327\u0306",\u011A:"E\u030C",\u00CA:"E\u0302",\u1EBE:"E\u0302\u0301",\u1EC0:"E\u0302\u0300",\u1EC4:"E\u0302\u0303",\u0116:"E\u0307",\u0228:"E\u0327",\u1E1E:"F\u0307",\u01F4:"G\u0301",\u1E20:"G\u0304",\u011E:"G\u0306",\u01E6:"G\u030C",\u011C:"G\u0302",\u0120:"G\u0307",\u0122:"G\u0327",\u1E26:"H\u0308",\u021E:"H\u030C",\u0124:"H\u0302",\u1E22:"H\u0307",\u1E28:"H\u0327",\u00CD:"I\u0301",\u00CC:"I\u0300",\u00CF:"I\u0308",\u1E2E:"I\u0308\u0301",\u0128:"I\u0303",\u012A:"I\u0304",\u012C:"I\u0306",\u01CF:"I\u030C",\u00CE:"I\u0302",\u0130:"I\u0307",\u0134:"J\u0302",\u1E30:"K\u0301",\u01E8:"K\u030C",\u0136:"K\u0327",\u0139:"L\u0301",\u013D:"L\u030C",\u013B:"L\u0327",\u1E3E:"M\u0301",\u1E40:"M\u0307",\u0143:"N\u0301",\u01F8:"N\u0300",\u00D1:"N\u0303",\u0147:"N\u030C",\u1E44:"N\u0307",\u0145:"N\u0327",\u00D3:"O\u0301",\u00D2:"O\u0300",\u00D6:"O\u0308",\u022A:"O\u0308\u0304",\u00D5:"O\u0303",\u1E4C:"O\u0303\u0301",\u1E4E:"O\u0303\u0308",\u022C:"O\u0303\u0304",\u014C:"O\u0304",\u1E52:"O\u0304\u0301",\u1E50:"O\u0304\u0300",\u014E:"O\u0306",\u01D1:"O\u030C",\u00D4:"O\u0302",\u1ED0:"O\u0302\u0301",\u1ED2:"O\u0302\u0300",\u1ED6:"O\u0302\u0303",\u022E:"O\u0307",\u0230:"O\u0307\u0304",\u0150:"O\u030B",\u1E54:"P\u0301",\u1E56:"P\u0307",\u0154:"R\u0301",\u0158:"R\u030C",\u1E58:"R\u0307",\u0156:"R\u0327",\u015A:"S\u0301",\u1E64:"S\u0301\u0307",\u0160:"S\u030C",\u1E66:"S\u030C\u0307",\u015C:"S\u0302",\u1E60:"S\u0307",\u015E:"S\u0327",\u0164:"T\u030C",\u1E6A:"T\u0307",\u0162:"T\u0327",\u00DA:"U\u0301",\u00D9:"U\u0300",\u00DC:"U\u0308",\u01D7:"U\u0308\u0301",\u01DB:"U\u0308\u0300",\u01D5:"U\u0308\u0304",\u01D9:"U\u0308\u030C",\u0168:"U\u0303",\u1E78:"U\u0303\u0301",\u016A:"U\u0304",\u1E7A:"U\u0304\u0308",\u016C:"U\u0306",\u01D3:"U\u030C",\u00DB:"U\u0302",\u016E:"U\u030A",\u0170:"U\u030B",\u1E7C:"V\u0303",\u1E82:"W\u0301",\u1E80:"W\u0300",\u1E84:"W\u0308",\u0174:"W\u0302",\u1E86:"W\u0307",\u1E8C:"X\u0308",\u1E8A:"X\u0307",\u00DD:"Y\u0301",\u1EF2:"Y\u0300",\u0178:"Y\u0308",\u1EF8:"Y\u0303",\u0232:"Y\u0304",\u0176:"Y\u0302",\u1E8E:"Y\u0307",\u0179:"Z\u0301",\u017D:"Z\u030C",\u1E90:"Z\u0302",\u017B:"Z\u0307",\u03AC:"\u03B1\u0301",\u1F70:"\u03B1\u0300",\u1FB1:"\u03B1\u0304",\u1FB0:"\u03B1\u0306",\u03AD:"\u03B5\u0301",\u1F72:"\u03B5\u0300",\u03AE:"\u03B7\u0301",\u1F74:"\u03B7\u0300",\u03AF:"\u03B9\u0301",\u1F76:"\u03B9\u0300",\u03CA:"\u03B9\u0308",\u0390:"\u03B9\u0308\u0301",\u1FD2:"\u03B9\u0308\u0300",\u1FD1:"\u03B9\u0304",\u1FD0:"\u03B9\u0306",\u03CC:"\u03BF\u0301",\u1F78:"\u03BF\u0300",\u03CD:"\u03C5\u0301",\u1F7A:"\u03C5\u0300",\u03CB:"\u03C5\u0308",\u03B0:"\u03C5\u0308\u0301",\u1FE2:"\u03C5\u0308\u0300",\u1FE1:"\u03C5\u0304",\u1FE0:"\u03C5\u0306",\u03CE:"\u03C9\u0301",\u1F7C:"\u03C9\u0300",\u038E:"\u03A5\u0301",\u1FEA:"\u03A5\u0300",\u03AB:"\u03A5\u0308",\u1FE9:"\u03A5\u0304",\u1FE8:"\u03A5\u0306",\u038F:"\u03A9\u0301",\u1FFA:"\u03A9\u0300"},x4=class t{static{o(this,"Parser")}constructor(e,r){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new R7(e,r,this.mode),this.settings=r,this.leftrightDepth=0}expect(e,r){if(r===void 0&&(r=!0),this.fetch().text!==e)throw new nt("Expected '"+e+"', got '"+this.fetch().text+"'",this.fetch());r&&this.consume()}consume(){this.nextToken=null}fetch(){return this.nextToken==null&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken}switchMode(e){this.mode=e,this.gullet.switchMode(e)}parse(){this.settings.globalGroup||this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");try{var e=this.parseExpression(!1);return this.expect("EOF"),this.settings.globalGroup||this.gullet.endGroup(),e}finally{this.gullet.endGroups()}}subparse(e){var r=this.nextToken;this.consume(),this.gullet.pushToken(new Ao("}")),this.gullet.pushTokens(e);var n=this.parseExpression(!1);return this.expect("}"),this.nextToken=r,n}parseExpression(e,r){for(var n=[];;){this.mode==="math"&&this.consumeSpaces();var i=this.fetch();if(t.endOfExpression.indexOf(i.text)!==-1||r&&i.text===r||e&&fh[i.text]&&fh[i.text].infix)break;var a=this.parseAtom(r);if(a){if(a.type==="internal")continue}else break;n.push(a)}return this.mode==="text"&&this.formLigatures(n),this.handleInfixNodes(n)}handleInfixNodes(e){for(var r=-1,n,i=0;i=0&&this.settings.reportNonstrict("unicodeTextInMathMode",'Latin-1/Unicode text character "'+r[0]+'" used in math mode',e);var l=wn[this.mode][r].group,u=Xs.range(e),h;if(hxe.hasOwnProperty(l)){var f=l;h={type:"atom",mode:this.mode,family:f,loc:u,text:r}}else h={type:l,mode:this.mode,loc:u,text:r};s=h}else if(r.charCodeAt(0)>=128)this.settings.strict&&(LG(r.charCodeAt(0))?this.mode==="math"&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+r[0]+'" used in math mode',e):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+r[0]+'"'+(" ("+r.charCodeAt(0)+")"),e)),s={type:"textord",mode:"text",loc:Xs.range(e),text:r};else return null;if(this.consume(),a)for(var d=0;d{e.tagName==="A"&&e.hasAttribute("target")&&e.setAttribute(t,e.getAttribute("target")??"")}),bp.default.addHook("afterSanitizeAttributes",e=>{e.tagName==="A"&&e.hasAttribute(t)&&(e.setAttribute("target",e.getAttribute(t)??""),e.removeAttribute(t),e.getAttribute("target")==="_blank"&&e.setAttribute("rel","noopener"))})}var bp,Qf,Cbe,Sbe,A$,C$,qr,_be,Lbe,Dbe,Rbe,_$,Nbe,yr,Mbe,Ibe,gh,K7,Obe,Pbe,S$,Q7,Ni,Zf,yh,We,rr=R(()=>{"use strict";bp=Xi(o7(),1),Qf=//gi,Cbe=o(t=>t?_$(t).replace(/\\n/g,"#br#").split("#br#"):[""],"getRows"),Sbe=(()=>{let t=!1;return()=>{t||(Abe(),t=!0)}})();o(Abe,"setupDompurifyHooks");A$=o(t=>(Sbe(),bp.default.sanitize(t)),"removeScript"),C$=o((t,e)=>{if(e.flowchart?.htmlLabels!==!1){let r=e.securityLevel;r==="antiscript"||r==="strict"?t=A$(t):r!=="loose"&&(t=_$(t),t=t.replace(//g,">"),t=t.replace(/=/g,"="),t=Rbe(t))}return t},"sanitizeMore"),qr=o((t,e)=>t&&(e.dompurifyConfig?t=bp.default.sanitize(C$(t,e),e.dompurifyConfig).toString():t=bp.default.sanitize(C$(t,e),{FORBID_TAGS:["style"]}).toString(),t),"sanitizeText"),_be=o((t,e)=>typeof t=="string"?qr(t,e):t.flat().map(r=>qr(r,e)),"sanitizeTextOrArray"),Lbe=o(t=>Qf.test(t),"hasBreaks"),Dbe=o(t=>t.split(Qf),"splitBreaks"),Rbe=o(t=>t.replace(/#br#/g,"
"),"placeholderToBreak"),_$=o(t=>t.replace(Qf,"#br#"),"breakToPlaceholder"),Nbe=o(t=>{let e="";return t&&(e=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,e=e.replaceAll(/\(/g,"\\("),e=e.replaceAll(/\)/g,"\\)")),e},"getUrl"),yr=o(t=>!(t===!1||["false","null","0"].includes(String(t).trim().toLowerCase())),"evaluate"),Mbe=o(function(...t){let e=t.filter(r=>!isNaN(r));return Math.max(...e)},"getMax"),Ibe=o(function(...t){let e=t.filter(r=>!isNaN(r));return Math.min(...e)},"getMin"),gh=o(function(t){let e=t.split(/(,)/),r=[];for(let n=0;n0&&n+1Math.max(0,t.split(e).length-1),"countOccurrence"),Obe=o((t,e)=>{let r=K7(t,"~"),n=K7(e,"~");return r===1&&n===1},"shouldCombineSets"),Pbe=o(t=>{let e=K7(t,"~"),r=!1;if(e<=1)return t;e%2!==0&&t.startsWith("~")&&(t=t.substring(1),r=!0);let n=[...t],i=n.indexOf("~"),a=n.lastIndexOf("~");for(;i!==-1&&a!==-1&&i!==a;)n[i]="<",n[a]=">",i=n.indexOf("~"),a=n.lastIndexOf("~");return r&&n.unshift("~"),n.join("")},"processSet"),S$=o(()=>window.MathMLElement!==void 0,"isMathMLSupported"),Q7=/\$\$(.*)\$\$/g,Ni=o(t=>(t.match(Q7)?.length??0)>0,"hasKatex"),Zf=o(async(t,e)=>{t=await yh(t,e);let r=document.createElement("div");r.innerHTML=t,r.id="katex-temp",r.style.visibility="hidden",r.style.position="absolute",r.style.top="0",document.querySelector("body")?.insertAdjacentElement("beforeend",r);let i={width:r.clientWidth,height:r.clientHeight};return r.remove(),i},"calculateMathMLDimensions"),yh=o(async(t,e)=>{if(!Ni(t))return t;if(!(S$()||e.legacyMathML||e.forceLegacyMathML))return t.replace(Q7,"MathML is unsupported in this environment.");let{default:r}=await Promise.resolve().then(()=>(E$(),k$)),n=e.forceLegacyMathML||!S$()&&e.legacyMathML?"htmlAndMathml":"mathml";return t.split(Qf).map(i=>Ni(i)?`
${i}
`:`
${i}
`).join("").replace(Q7,(i,a)=>r.renderToString(a,{throwOnError:!0,displayMode:!0,output:n}).replace(/\n/g," ").replace(//g,""))},"renderKatex"),We={getRows:Cbe,sanitizeText:qr,sanitizeTextOrArray:_be,hasBreaks:Lbe,splitBreaks:Dbe,lineBreakRegex:Qf,removeScript:A$,getUrl:Nbe,evaluate:yr,getMax:Mbe,getMin:Ibe}});var Bbe,Fbe,Sr,Lo,Yn=R(()=>{"use strict";ut();Bbe=o(function(t,e){for(let r of e)t.attr(r[0],r[1])},"d3Attrs"),Fbe=o(function(t,e,r){let n=new Map;return r?(n.set("width","100%"),n.set("style",`max-width: ${e}px;`)):(n.set("height",t),n.set("width",e)),n},"calculateSvgSizeAttrs"),Sr=o(function(t,e,r,n){let i=Fbe(e,r,n);Bbe(t,i)},"configureSvgSize"),Lo=o(function(t,e,r,n){let i=e.node().getBBox(),a=i.width,s=i.height;V.info(`SVG bounds: ${a}x${s}`,i);let l=0,u=0;V.info(`Graph bounds: ${l}x${u}`,t),l=a+r*2,u=s+r*2,V.info(`Calculated bounds: ${l}x${u}`),Sr(e,u,l,n);let h=`${i.x-r} ${i.y-r} ${i.width+2*r} ${i.height+2*r}`;e.attr("viewBox",h)},"setupGraphViewbox")});var S4,zbe,L$,D$,Z7=R(()=>{"use strict";ut();S4={},zbe=o((t,e,r)=>{let n="";return t in S4&&S4[t]?n=S4[t](r):V.warn(`No theme found for ${t}`),` & { + font-family: ${r.fontFamily}; + font-size: ${r.fontSize}; + fill: ${r.textColor} + } + + /* Classes common for multiple diagrams */ + + & .error-icon { + fill: ${r.errorBkgColor}; + } + & .error-text { + fill: ${r.errorTextColor}; + stroke: ${r.errorTextColor}; + } + + & .edge-thickness-normal { + stroke-width: 1px; + } + & .edge-thickness-thick { + stroke-width: 3.5px + } + & .edge-pattern-solid { + stroke-dasharray: 0; + } + & .edge-thickness-invisible { + stroke-width: 0; + fill: none; + } + & .edge-pattern-dashed{ + stroke-dasharray: 3; + } + .edge-pattern-dotted { + stroke-dasharray: 2; + } + + & .marker { + fill: ${r.lineColor}; + stroke: ${r.lineColor}; + } + & .marker.cross { + stroke: ${r.lineColor}; + } + + & svg { + font-family: ${r.fontFamily}; + font-size: ${r.fontSize}; + } + & p { + margin: 0 + } + + ${n} + + ${e} +`},"getStyles"),L$=o((t,e)=>{e!==void 0&&(S4[t]=e)},"addStylesForDiagram"),D$=zbe});var ly={};hr(ly,{clear:()=>vr,getAccDescription:()=>Lr,getAccTitle:()=>Ar,getDiagramTitle:()=>Xr,setAccDescription:()=>_r,setAccTitle:()=>kr,setDiagramTitle:()=>nn});var J7,eS,tS,rS,vr,kr,Ar,_r,Lr,nn,Xr,bi=R(()=>{"use strict";rr();qs();J7="",eS="",tS="",rS=o(t=>qr(t,Or()),"sanitizeText"),vr=o(()=>{J7="",tS="",eS=""},"clear"),kr=o(t=>{J7=rS(t).replace(/^\s+/g,"")},"setAccTitle"),Ar=o(()=>J7,"getAccTitle"),_r=o(t=>{tS=rS(t).replace(/\n\s+/g,` +`)},"setAccDescription"),Lr=o(()=>tS,"getAccDescription"),nn=o(t=>{eS=rS(t)},"setDiagramTitle"),Xr=o(()=>eS,"getDiagramTitle")});var R$,Gbe,de,iS,_4,$be,aS,Vbe,A4,Jf,cy,nS,_t=R(()=>{"use strict";Hf();ut();qs();rr();Yn();Z7();bi();R$=V,Gbe=$1,de=Or,iS=Zb,_4=uh,$be=o(t=>qr(t,de()),"sanitizeText"),aS=Lo,Vbe=o(()=>ly,"getCommonDb"),A4={},Jf=o((t,e,r)=>{A4[t]&&R$.warn(`Diagram with id ${t} already registered. Overwriting.`),A4[t]=e,r&&$C(t,r),L$(t,e.styles),e.injectUtils?.(R$,Gbe,de,$be,aS,Vbe(),()=>{})},"registerDiagram"),cy=o(t=>{if(t in A4)return A4[t];throw new nS(t)},"getDiagram"),nS=class extends Error{static{o(this,"DiagramNotFoundError")}constructor(e){super(`Diagram ${e} not found.`)}}});var ul,vh,ja,cl,nc,uy,sS,oS,L4,D4,N$,Ube,Hbe,Ybe,Wbe,qbe,Xbe,jbe,Kbe,Qbe,Zbe,Jbe,e4e,t4e,r4e,n4e,i4e,a4e,M$,s4e,o4e,I$,l4e,c4e,u4e,h4e,xh,f4e,d4e,p4e,m4e,g4e,hy,lS=R(()=>{"use strict";_t();rr();bi();ul=[],vh=[""],ja="global",cl="",nc=[{alias:"global",label:{text:"global"},type:{text:"global"},tags:null,link:null,parentBoundary:""}],uy=[],sS="",oS=!1,L4=4,D4=2,Ube=o(function(){return N$},"getC4Type"),Hbe=o(function(t){N$=qr(t,de())},"setC4Type"),Ybe=o(function(t,e,r,n,i,a,s,l,u){if(t==null||e===void 0||e===null||r===void 0||r===null||n===void 0||n===null)return;let h={},f=uy.find(d=>d.from===e&&d.to===r);if(f?h=f:uy.push(h),h.type=t,h.from=e,h.to=r,h.label={text:n},i==null)h.techn={text:""};else if(typeof i=="object"){let[d,p]=Object.entries(i)[0];h[d]={text:p}}else h.techn={text:i};if(a==null)h.descr={text:""};else if(typeof a=="object"){let[d,p]=Object.entries(a)[0];h[d]={text:p}}else h.descr={text:a};if(typeof s=="object"){let[d,p]=Object.entries(s)[0];h[d]=p}else h.sprite=s;if(typeof l=="object"){let[d,p]=Object.entries(l)[0];h[d]=p}else h.tags=l;if(typeof u=="object"){let[d,p]=Object.entries(u)[0];h[d]=p}else h.link=u;h.wrap=xh()},"addRel"),Wbe=o(function(t,e,r,n,i,a,s){if(e===null||r===null)return;let l={},u=ul.find(h=>h.alias===e);if(u&&e===u.alias?l=u:(l.alias=e,ul.push(l)),r==null?l.label={text:""}:l.label={text:r},n==null)l.descr={text:""};else if(typeof n=="object"){let[h,f]=Object.entries(n)[0];l[h]={text:f}}else l.descr={text:n};if(typeof i=="object"){let[h,f]=Object.entries(i)[0];l[h]=f}else l.sprite=i;if(typeof a=="object"){let[h,f]=Object.entries(a)[0];l[h]=f}else l.tags=a;if(typeof s=="object"){let[h,f]=Object.entries(s)[0];l[h]=f}else l.link=s;l.typeC4Shape={text:t},l.parentBoundary=ja,l.wrap=xh()},"addPersonOrSystem"),qbe=o(function(t,e,r,n,i,a,s,l){if(e===null||r===null)return;let u={},h=ul.find(f=>f.alias===e);if(h&&e===h.alias?u=h:(u.alias=e,ul.push(u)),r==null?u.label={text:""}:u.label={text:r},n==null)u.techn={text:""};else if(typeof n=="object"){let[f,d]=Object.entries(n)[0];u[f]={text:d}}else u.techn={text:n};if(i==null)u.descr={text:""};else if(typeof i=="object"){let[f,d]=Object.entries(i)[0];u[f]={text:d}}else u.descr={text:i};if(typeof a=="object"){let[f,d]=Object.entries(a)[0];u[f]=d}else u.sprite=a;if(typeof s=="object"){let[f,d]=Object.entries(s)[0];u[f]=d}else u.tags=s;if(typeof l=="object"){let[f,d]=Object.entries(l)[0];u[f]=d}else u.link=l;u.wrap=xh(),u.typeC4Shape={text:t},u.parentBoundary=ja},"addContainer"),Xbe=o(function(t,e,r,n,i,a,s,l){if(e===null||r===null)return;let u={},h=ul.find(f=>f.alias===e);if(h&&e===h.alias?u=h:(u.alias=e,ul.push(u)),r==null?u.label={text:""}:u.label={text:r},n==null)u.techn={text:""};else if(typeof n=="object"){let[f,d]=Object.entries(n)[0];u[f]={text:d}}else u.techn={text:n};if(i==null)u.descr={text:""};else if(typeof i=="object"){let[f,d]=Object.entries(i)[0];u[f]={text:d}}else u.descr={text:i};if(typeof a=="object"){let[f,d]=Object.entries(a)[0];u[f]=d}else u.sprite=a;if(typeof s=="object"){let[f,d]=Object.entries(s)[0];u[f]=d}else u.tags=s;if(typeof l=="object"){let[f,d]=Object.entries(l)[0];u[f]=d}else u.link=l;u.wrap=xh(),u.typeC4Shape={text:t},u.parentBoundary=ja},"addComponent"),jbe=o(function(t,e,r,n,i){if(t===null||e===null)return;let a={},s=nc.find(l=>l.alias===t);if(s&&t===s.alias?a=s:(a.alias=t,nc.push(a)),e==null?a.label={text:""}:a.label={text:e},r==null)a.type={text:"system"};else if(typeof r=="object"){let[l,u]=Object.entries(r)[0];a[l]={text:u}}else a.type={text:r};if(typeof n=="object"){let[l,u]=Object.entries(n)[0];a[l]=u}else a.tags=n;if(typeof i=="object"){let[l,u]=Object.entries(i)[0];a[l]=u}else a.link=i;a.parentBoundary=ja,a.wrap=xh(),cl=ja,ja=t,vh.push(cl)},"addPersonOrSystemBoundary"),Kbe=o(function(t,e,r,n,i){if(t===null||e===null)return;let a={},s=nc.find(l=>l.alias===t);if(s&&t===s.alias?a=s:(a.alias=t,nc.push(a)),e==null?a.label={text:""}:a.label={text:e},r==null)a.type={text:"container"};else if(typeof r=="object"){let[l,u]=Object.entries(r)[0];a[l]={text:u}}else a.type={text:r};if(typeof n=="object"){let[l,u]=Object.entries(n)[0];a[l]=u}else a.tags=n;if(typeof i=="object"){let[l,u]=Object.entries(i)[0];a[l]=u}else a.link=i;a.parentBoundary=ja,a.wrap=xh(),cl=ja,ja=t,vh.push(cl)},"addContainerBoundary"),Qbe=o(function(t,e,r,n,i,a,s,l){if(e===null||r===null)return;let u={},h=nc.find(f=>f.alias===e);if(h&&e===h.alias?u=h:(u.alias=e,nc.push(u)),r==null?u.label={text:""}:u.label={text:r},n==null)u.type={text:"node"};else if(typeof n=="object"){let[f,d]=Object.entries(n)[0];u[f]={text:d}}else u.type={text:n};if(i==null)u.descr={text:""};else if(typeof i=="object"){let[f,d]=Object.entries(i)[0];u[f]={text:d}}else u.descr={text:i};if(typeof s=="object"){let[f,d]=Object.entries(s)[0];u[f]=d}else u.tags=s;if(typeof l=="object"){let[f,d]=Object.entries(l)[0];u[f]=d}else u.link=l;u.nodeType=t,u.parentBoundary=ja,u.wrap=xh(),cl=ja,ja=e,vh.push(cl)},"addDeploymentNode"),Zbe=o(function(){ja=cl,vh.pop(),cl=vh.pop(),vh.push(cl)},"popBoundaryParseStack"),Jbe=o(function(t,e,r,n,i,a,s,l,u,h,f){let d=ul.find(p=>p.alias===e);if(!(d===void 0&&(d=nc.find(p=>p.alias===e),d===void 0))){if(r!=null)if(typeof r=="object"){let[p,m]=Object.entries(r)[0];d[p]=m}else d.bgColor=r;if(n!=null)if(typeof n=="object"){let[p,m]=Object.entries(n)[0];d[p]=m}else d.fontColor=n;if(i!=null)if(typeof i=="object"){let[p,m]=Object.entries(i)[0];d[p]=m}else d.borderColor=i;if(a!=null)if(typeof a=="object"){let[p,m]=Object.entries(a)[0];d[p]=m}else d.shadowing=a;if(s!=null)if(typeof s=="object"){let[p,m]=Object.entries(s)[0];d[p]=m}else d.shape=s;if(l!=null)if(typeof l=="object"){let[p,m]=Object.entries(l)[0];d[p]=m}else d.sprite=l;if(u!=null)if(typeof u=="object"){let[p,m]=Object.entries(u)[0];d[p]=m}else d.techn=u;if(h!=null)if(typeof h=="object"){let[p,m]=Object.entries(h)[0];d[p]=m}else d.legendText=h;if(f!=null)if(typeof f=="object"){let[p,m]=Object.entries(f)[0];d[p]=m}else d.legendSprite=f}},"updateElStyle"),e4e=o(function(t,e,r,n,i,a,s){let l=uy.find(u=>u.from===e&&u.to===r);if(l!==void 0){if(n!=null)if(typeof n=="object"){let[u,h]=Object.entries(n)[0];l[u]=h}else l.textColor=n;if(i!=null)if(typeof i=="object"){let[u,h]=Object.entries(i)[0];l[u]=h}else l.lineColor=i;if(a!=null)if(typeof a=="object"){let[u,h]=Object.entries(a)[0];l[u]=parseInt(h)}else l.offsetX=parseInt(a);if(s!=null)if(typeof s=="object"){let[u,h]=Object.entries(s)[0];l[u]=parseInt(h)}else l.offsetY=parseInt(s)}},"updateRelStyle"),t4e=o(function(t,e,r){let n=L4,i=D4;if(typeof e=="object"){let a=Object.values(e)[0];n=parseInt(a)}else n=parseInt(e);if(typeof r=="object"){let a=Object.values(r)[0];i=parseInt(a)}else i=parseInt(r);n>=1&&(L4=n),i>=1&&(D4=i)},"updateLayoutConfig"),r4e=o(function(){return L4},"getC4ShapeInRow"),n4e=o(function(){return D4},"getC4BoundaryInRow"),i4e=o(function(){return ja},"getCurrentBoundaryParse"),a4e=o(function(){return cl},"getParentBoundaryParse"),M$=o(function(t){return t==null?ul:ul.filter(e=>e.parentBoundary===t)},"getC4ShapeArray"),s4e=o(function(t){return ul.find(e=>e.alias===t)},"getC4Shape"),o4e=o(function(t){return Object.keys(M$(t))},"getC4ShapeKeys"),I$=o(function(t){return t==null?nc:nc.filter(e=>e.parentBoundary===t)},"getBoundaries"),l4e=I$,c4e=o(function(){return uy},"getRels"),u4e=o(function(){return sS},"getTitle"),h4e=o(function(t){oS=t},"setWrap"),xh=o(function(){return oS},"autoWrap"),f4e=o(function(){ul=[],nc=[{alias:"global",label:{text:"global"},type:{text:"global"},tags:null,link:null,parentBoundary:""}],cl="",ja="global",vh=[""],uy=[],vh=[""],sS="",oS=!1,L4=4,D4=2},"clear"),d4e={SOLID:0,DOTTED:1,NOTE:2,SOLID_CROSS:3,DOTTED_CROSS:4,SOLID_OPEN:5,DOTTED_OPEN:6,LOOP_START:10,LOOP_END:11,ALT_START:12,ALT_ELSE:13,ALT_END:14,OPT_START:15,OPT_END:16,ACTIVE_START:17,ACTIVE_END:18,PAR_START:19,PAR_AND:20,PAR_END:21,RECT_START:22,RECT_END:23,SOLID_POINT:24,DOTTED_POINT:25},p4e={FILLED:0,OPEN:1},m4e={LEFTOF:0,RIGHTOF:1,OVER:2},g4e=o(function(t){sS=qr(t,de())},"setTitle"),hy={addPersonOrSystem:Wbe,addPersonOrSystemBoundary:jbe,addContainer:qbe,addContainerBoundary:Kbe,addComponent:Xbe,addDeploymentNode:Qbe,popBoundaryParseStack:Zbe,addRel:Ybe,updateElStyle:Jbe,updateRelStyle:e4e,updateLayoutConfig:t4e,autoWrap:xh,setWrap:h4e,getC4ShapeArray:M$,getC4Shape:s4e,getC4ShapeKeys:o4e,getBoundaries:I$,getBoundarys:l4e,getCurrentBoundaryParse:i4e,getParentBoundaryParse:a4e,getRels:c4e,getTitle:u4e,getC4Type:Ube,getC4ShapeInRow:r4e,getC4BoundaryInRow:n4e,setAccTitle:kr,getAccTitle:Ar,getAccDescription:Lr,setAccDescription:_r,getConfig:o(()=>de().c4,"getConfig"),clear:f4e,LINETYPE:d4e,ARROWTYPE:p4e,PLACEMENT:m4e,setTitle:g4e,setC4Type:Hbe}});function ed(t,e){return t==null||e==null?NaN:te?1:t>=e?0:NaN}var cS=R(()=>{"use strict";o(ed,"ascending")});function uS(t,e){return t==null||e==null?NaN:et?1:e>=t?0:NaN}var O$=R(()=>{"use strict";o(uS,"descending")});function td(t){let e,r,n;t.length!==2?(e=ed,r=o((l,u)=>ed(t(l),u),"compare2"),n=o((l,u)=>t(l)-u,"delta")):(e=t===ed||t===uS?t:y4e,r=t,n=t);function i(l,u,h=0,f=l.length){if(h>>1;r(l[d],u)<0?h=d+1:f=d}while(h>>1;r(l[d],u)<=0?h=d+1:f=d}while(hh&&n(l[d-1],u)>-n(l[d],u)?d-1:d}return o(s,"center"),{left:i,center:s,right:a}}function y4e(){return 0}var hS=R(()=>{"use strict";cS();O$();o(td,"bisector");o(y4e,"zero")});function fS(t){return t===null?NaN:+t}var P$=R(()=>{"use strict";o(fS,"number")});var B$,F$,v4e,x4e,dS,z$=R(()=>{"use strict";cS();hS();P$();B$=td(ed),F$=B$.right,v4e=B$.left,x4e=td(fS).center,dS=F$});function G$({_intern:t,_key:e},r){let n=e(r);return t.has(n)?t.get(n):r}function b4e({_intern:t,_key:e},r){let n=e(r);return t.has(n)?t.get(n):(t.set(n,r),r)}function w4e({_intern:t,_key:e},r){let n=e(r);return t.has(n)&&(r=t.get(n),t.delete(n)),r}function T4e(t){return t!==null&&typeof t=="object"?t.valueOf():t}var wp,$$=R(()=>{"use strict";wp=class extends Map{static{o(this,"InternMap")}constructor(e,r=T4e){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:r}}),e!=null)for(let[n,i]of e)this.set(n,i)}get(e){return super.get(G$(this,e))}has(e){return super.has(G$(this,e))}set(e,r){return super.set(b4e(this,e),r)}delete(e){return super.delete(w4e(this,e))}};o(G$,"intern_get");o(b4e,"intern_set");o(w4e,"intern_delete");o(T4e,"keyof")});function R4(t,e,r){let n=(e-t)/Math.max(0,r),i=Math.floor(Math.log10(n)),a=n/Math.pow(10,i),s=a>=k4e?10:a>=E4e?5:a>=C4e?2:1,l,u,h;return i<0?(h=Math.pow(10,-i)/s,l=Math.round(t*h),u=Math.round(e*h),l/he&&--u,h=-h):(h=Math.pow(10,i)*s,l=Math.round(t/h),u=Math.round(e/h),l*he&&--u),u0))return[];if(t===e)return[t];let n=e=i))return[];let l=a-i+1,u=new Array(l);if(n)if(s<0)for(let h=0;h{"use strict";k4e=Math.sqrt(50),E4e=Math.sqrt(10),C4e=Math.sqrt(2);o(R4,"tickSpec");o(N4,"ticks");o(fy,"tickIncrement");o(Tp,"tickStep")});function M4(t,e){let r;if(e===void 0)for(let n of t)n!=null&&(r=n)&&(r=n);else{let n=-1;for(let i of t)(i=e(i,++n,t))!=null&&(r=i)&&(r=i)}return r}var U$=R(()=>{"use strict";o(M4,"max")});function I4(t,e){let r;if(e===void 0)for(let n of t)n!=null&&(r>n||r===void 0&&n>=n)&&(r=n);else{let n=-1;for(let i of t)(i=e(i,++n,t))!=null&&(r>i||r===void 0&&i>=i)&&(r=i)}return r}var H$=R(()=>{"use strict";o(I4,"min")});function O4(t,e,r){t=+t,e=+e,r=(i=arguments.length)<2?(e=t,t=0,1):i<3?1:+r;for(var n=-1,i=Math.max(0,Math.ceil((e-t)/r))|0,a=new Array(i);++n{"use strict";o(O4,"range")});var bh=R(()=>{"use strict";z$();hS();U$();H$();Y$();V$();$$()});function pS(t){return t}var W$=R(()=>{"use strict";o(pS,"default")});function S4e(t){return"translate("+t+",0)"}function A4e(t){return"translate(0,"+t+")"}function _4e(t){return e=>+t(e)}function L4e(t,e){return e=Math.max(0,t.bandwidth()-e*2)/2,t.round()&&(e=Math.round(e)),r=>+t(r)+e}function D4e(){return!this.__axis}function X$(t,e){var r=[],n=null,i=null,a=6,s=6,l=3,u=typeof window<"u"&&window.devicePixelRatio>1?0:.5,h=t===B4||t===P4?-1:1,f=t===P4||t===mS?"x":"y",d=t===B4||t===gS?S4e:A4e;function p(m){var g=n??(e.ticks?e.ticks.apply(e,r):e.domain()),y=i??(e.tickFormat?e.tickFormat.apply(e,r):pS),v=Math.max(a,0)+l,x=e.range(),b=+x[0]+u,w=+x[x.length-1]+u,S=(e.bandwidth?L4e:_4e)(e.copy(),u),T=m.selection?m.selection():m,E=T.selectAll(".domain").data([null]),_=T.selectAll(".tick").data(g,e).order(),A=_.exit(),L=_.enter().append("g").attr("class","tick"),M=_.select("line"),N=_.select("text");E=E.merge(E.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),_=_.merge(L),M=M.merge(L.append("line").attr("stroke","currentColor").attr(f+"2",h*a)),N=N.merge(L.append("text").attr("fill","currentColor").attr(f,h*v).attr("dy",t===B4?"0em":t===gS?"0.71em":"0.32em")),m!==T&&(E=E.transition(m),_=_.transition(m),M=M.transition(m),N=N.transition(m),A=A.transition(m).attr("opacity",q$).attr("transform",function(k){return isFinite(k=S(k))?d(k+u):this.getAttribute("transform")}),L.attr("opacity",q$).attr("transform",function(k){var I=this.parentNode.__axis;return d((I&&isFinite(I=I(k))?I:S(k))+u)})),A.remove(),E.attr("d",t===P4||t===mS?s?"M"+h*s+","+b+"H"+u+"V"+w+"H"+h*s:"M"+u+","+b+"V"+w:s?"M"+b+","+h*s+"V"+u+"H"+w+"V"+h*s:"M"+b+","+u+"H"+w),_.attr("opacity",1).attr("transform",function(k){return d(S(k)+u)}),M.attr(f+"2",h*a),N.attr(f,h*v).text(y),T.filter(D4e).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===mS?"start":t===P4?"end":"middle"),T.each(function(){this.__axis=S})}return o(p,"axis"),p.scale=function(m){return arguments.length?(e=m,p):e},p.ticks=function(){return r=Array.from(arguments),p},p.tickArguments=function(m){return arguments.length?(r=m==null?[]:Array.from(m),p):r.slice()},p.tickValues=function(m){return arguments.length?(n=m==null?null:Array.from(m),p):n&&n.slice()},p.tickFormat=function(m){return arguments.length?(i=m,p):i},p.tickSize=function(m){return arguments.length?(a=s=+m,p):a},p.tickSizeInner=function(m){return arguments.length?(a=+m,p):a},p.tickSizeOuter=function(m){return arguments.length?(s=+m,p):s},p.tickPadding=function(m){return arguments.length?(l=+m,p):l},p.offset=function(m){return arguments.length?(u=+m,p):u},p}function yS(t){return X$(B4,t)}function vS(t){return X$(gS,t)}var B4,mS,gS,P4,q$,j$=R(()=>{"use strict";W$();B4=1,mS=2,gS=3,P4=4,q$=1e-6;o(S4e,"translateX");o(A4e,"translateY");o(_4e,"number");o(L4e,"center");o(D4e,"entering");o(X$,"axis");o(yS,"axisTop");o(vS,"axisBottom")});var K$=R(()=>{"use strict";j$()});function Z$(){for(var t=0,e=arguments.length,r={},n;t=0&&(n=r.slice(i+1),r=r.slice(0,i)),r&&!e.hasOwnProperty(r))throw new Error("unknown type: "+r);return{type:r,name:n}})}function M4e(t,e){for(var r=0,n=t.length,i;r{"use strict";R4e={value:o(()=>{},"value")};o(Z$,"dispatch");o(F4,"Dispatch");o(N4e,"parseTypenames");F4.prototype=Z$.prototype={constructor:F4,on:o(function(t,e){var r=this._,n=N4e(t+"",r),i,a=-1,s=n.length;if(arguments.length<2){for(;++a0)for(var r=new Array(i),n=0,i,a;n{"use strict";J$()});var z4,wS,TS=R(()=>{"use strict";z4="http://www.w3.org/1999/xhtml",wS={svg:"http://www.w3.org/2000/svg",xhtml:z4,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"}});function ic(t){var e=t+="",r=e.indexOf(":");return r>=0&&(e=t.slice(0,r))!=="xmlns"&&(t=t.slice(r+1)),wS.hasOwnProperty(e)?{space:wS[e],local:t}:t}var G4=R(()=>{"use strict";TS();o(ic,"default")});function I4e(t){return function(){var e=this.ownerDocument,r=this.namespaceURI;return r===z4&&e.documentElement.namespaceURI===z4?e.createElement(t):e.createElementNS(r,t)}}function O4e(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function dy(t){var e=ic(t);return(e.local?O4e:I4e)(e)}var kS=R(()=>{"use strict";G4();TS();o(I4e,"creatorInherit");o(O4e,"creatorFixed");o(dy,"default")});function P4e(){}function wh(t){return t==null?P4e:function(){return this.querySelector(t)}}var $4=R(()=>{"use strict";o(P4e,"none");o(wh,"default")});function ES(t){typeof t!="function"&&(t=wh(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i{"use strict";hl();$4();o(ES,"default")});function CS(t){return t==null?[]:Array.isArray(t)?t:Array.from(t)}var tV=R(()=>{"use strict";o(CS,"array")});function B4e(){return[]}function kp(t){return t==null?B4e:function(){return this.querySelectorAll(t)}}var SS=R(()=>{"use strict";o(B4e,"empty");o(kp,"default")});function F4e(t){return function(){return CS(t.apply(this,arguments))}}function AS(t){typeof t=="function"?t=F4e(t):t=kp(t);for(var e=this._groups,r=e.length,n=[],i=[],a=0;a{"use strict";hl();tV();SS();o(F4e,"arrayAll");o(AS,"default")});function Ep(t){return function(){return this.matches(t)}}function V4(t){return function(e){return e.matches(t)}}var py=R(()=>{"use strict";o(Ep,"default");o(V4,"childMatcher")});function G4e(t){return function(){return z4e.call(this.children,t)}}function $4e(){return this.firstElementChild}function _S(t){return this.select(t==null?$4e:G4e(typeof t=="function"?t:V4(t)))}var z4e,nV=R(()=>{"use strict";py();z4e=Array.prototype.find;o(G4e,"childFind");o($4e,"childFirst");o(_S,"default")});function U4e(){return Array.from(this.children)}function H4e(t){return function(){return V4e.call(this.children,t)}}function LS(t){return this.selectAll(t==null?U4e:H4e(typeof t=="function"?t:V4(t)))}var V4e,iV=R(()=>{"use strict";py();V4e=Array.prototype.filter;o(U4e,"children");o(H4e,"childrenFilter");o(LS,"default")});function DS(t){typeof t!="function"&&(t=Ep(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i{"use strict";hl();py();o(DS,"default")});function my(t){return new Array(t.length)}var RS=R(()=>{"use strict";o(my,"default")});function NS(){return new Zn(this._enter||this._groups.map(my),this._parents)}function gy(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}var MS=R(()=>{"use strict";RS();hl();o(NS,"default");o(gy,"EnterNode");gy.prototype={constructor:gy,appendChild:o(function(t){return this._parent.insertBefore(t,this._next)},"appendChild"),insertBefore:o(function(t,e){return this._parent.insertBefore(t,e)},"insertBefore"),querySelector:o(function(t){return this._parent.querySelector(t)},"querySelector"),querySelectorAll:o(function(t){return this._parent.querySelectorAll(t)},"querySelectorAll")}});function IS(t){return function(){return t}}var sV=R(()=>{"use strict";o(IS,"default")});function Y4e(t,e,r,n,i,a){for(var s=0,l,u=e.length,h=a.length;s=w&&(w=b+1);!(T=v[w])&&++w{"use strict";hl();MS();sV();o(Y4e,"bindIndex");o(W4e,"bindKey");o(q4e,"datum");o(OS,"default");o(X4e,"arraylike")});function PS(){return new Zn(this._exit||this._groups.map(my),this._parents)}var lV=R(()=>{"use strict";RS();hl();o(PS,"default")});function BS(t,e,r){var n=this.enter(),i=this,a=this.exit();return typeof t=="function"?(n=t(n),n&&(n=n.selection())):n=n.append(t+""),e!=null&&(i=e(i),i&&(i=i.selection())),r==null?a.remove():r(a),n&&i?n.merge(i).order():i}var cV=R(()=>{"use strict";o(BS,"default")});function FS(t){for(var e=t.selection?t.selection():t,r=this._groups,n=e._groups,i=r.length,a=n.length,s=Math.min(i,a),l=new Array(i),u=0;u{"use strict";hl();o(FS,"default")});function zS(){for(var t=this._groups,e=-1,r=t.length;++e=0;)(s=n[i])&&(a&&s.compareDocumentPosition(a)^4&&a.parentNode.insertBefore(s,a),a=s);return this}var hV=R(()=>{"use strict";o(zS,"default")});function GS(t){t||(t=j4e);function e(d,p){return d&&p?t(d.__data__,p.__data__):!d-!p}o(e,"compareNode");for(var r=this._groups,n=r.length,i=new Array(n),a=0;ae?1:t>=e?0:NaN}var fV=R(()=>{"use strict";hl();o(GS,"default");o(j4e,"ascending")});function $S(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this}var dV=R(()=>{"use strict";o($S,"default")});function VS(){return Array.from(this)}var pV=R(()=>{"use strict";o(VS,"default")});function US(){for(var t=this._groups,e=0,r=t.length;e{"use strict";o(US,"default")});function HS(){let t=0;for(let e of this)++t;return t}var gV=R(()=>{"use strict";o(HS,"default")});function YS(){return!this.node()}var yV=R(()=>{"use strict";o(YS,"default")});function WS(t){for(var e=this._groups,r=0,n=e.length;r{"use strict";o(WS,"default")});function K4e(t){return function(){this.removeAttribute(t)}}function Q4e(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Z4e(t,e){return function(){this.setAttribute(t,e)}}function J4e(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function e3e(t,e){return function(){var r=e.apply(this,arguments);r==null?this.removeAttribute(t):this.setAttribute(t,r)}}function t3e(t,e){return function(){var r=e.apply(this,arguments);r==null?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,r)}}function qS(t,e){var r=ic(t);if(arguments.length<2){var n=this.node();return r.local?n.getAttributeNS(r.space,r.local):n.getAttribute(r)}return this.each((e==null?r.local?Q4e:K4e:typeof e=="function"?r.local?t3e:e3e:r.local?J4e:Z4e)(r,e))}var xV=R(()=>{"use strict";G4();o(K4e,"attrRemove");o(Q4e,"attrRemoveNS");o(Z4e,"attrConstant");o(J4e,"attrConstantNS");o(e3e,"attrFunction");o(t3e,"attrFunctionNS");o(qS,"default")});function yy(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}var XS=R(()=>{"use strict";o(yy,"default")});function r3e(t){return function(){this.style.removeProperty(t)}}function n3e(t,e,r){return function(){this.style.setProperty(t,e,r)}}function i3e(t,e,r){return function(){var n=e.apply(this,arguments);n==null?this.style.removeProperty(t):this.style.setProperty(t,n,r)}}function jS(t,e,r){return arguments.length>1?this.each((e==null?r3e:typeof e=="function"?i3e:n3e)(t,e,r??"")):Th(this.node(),t)}function Th(t,e){return t.style.getPropertyValue(e)||yy(t).getComputedStyle(t,null).getPropertyValue(e)}var KS=R(()=>{"use strict";XS();o(r3e,"styleRemove");o(n3e,"styleConstant");o(i3e,"styleFunction");o(jS,"default");o(Th,"styleValue")});function a3e(t){return function(){delete this[t]}}function s3e(t,e){return function(){this[t]=e}}function o3e(t,e){return function(){var r=e.apply(this,arguments);r==null?delete this[t]:this[t]=r}}function QS(t,e){return arguments.length>1?this.each((e==null?a3e:typeof e=="function"?o3e:s3e)(t,e)):this.node()[t]}var bV=R(()=>{"use strict";o(a3e,"propertyRemove");o(s3e,"propertyConstant");o(o3e,"propertyFunction");o(QS,"default")});function wV(t){return t.trim().split(/^|\s+/)}function ZS(t){return t.classList||new TV(t)}function TV(t){this._node=t,this._names=wV(t.getAttribute("class")||"")}function kV(t,e){for(var r=ZS(t),n=-1,i=e.length;++n{"use strict";o(wV,"classArray");o(ZS,"classList");o(TV,"ClassList");TV.prototype={add:o(function(t){var e=this._names.indexOf(t);e<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},"add"),remove:o(function(t){var e=this._names.indexOf(t);e>=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},"remove"),contains:o(function(t){return this._names.indexOf(t)>=0},"contains")};o(kV,"classedAdd");o(EV,"classedRemove");o(l3e,"classedTrue");o(c3e,"classedFalse");o(u3e,"classedFunction");o(JS,"default")});function h3e(){this.textContent=""}function f3e(t){return function(){this.textContent=t}}function d3e(t){return function(){var e=t.apply(this,arguments);this.textContent=e??""}}function eA(t){return arguments.length?this.each(t==null?h3e:(typeof t=="function"?d3e:f3e)(t)):this.node().textContent}var SV=R(()=>{"use strict";o(h3e,"textRemove");o(f3e,"textConstant");o(d3e,"textFunction");o(eA,"default")});function p3e(){this.innerHTML=""}function m3e(t){return function(){this.innerHTML=t}}function g3e(t){return function(){var e=t.apply(this,arguments);this.innerHTML=e??""}}function tA(t){return arguments.length?this.each(t==null?p3e:(typeof t=="function"?g3e:m3e)(t)):this.node().innerHTML}var AV=R(()=>{"use strict";o(p3e,"htmlRemove");o(m3e,"htmlConstant");o(g3e,"htmlFunction");o(tA,"default")});function y3e(){this.nextSibling&&this.parentNode.appendChild(this)}function rA(){return this.each(y3e)}var _V=R(()=>{"use strict";o(y3e,"raise");o(rA,"default")});function v3e(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function nA(){return this.each(v3e)}var LV=R(()=>{"use strict";o(v3e,"lower");o(nA,"default")});function iA(t){var e=typeof t=="function"?t:dy(t);return this.select(function(){return this.appendChild(e.apply(this,arguments))})}var DV=R(()=>{"use strict";kS();o(iA,"default")});function x3e(){return null}function aA(t,e){var r=typeof t=="function"?t:dy(t),n=e==null?x3e:typeof e=="function"?e:wh(e);return this.select(function(){return this.insertBefore(r.apply(this,arguments),n.apply(this,arguments)||null)})}var RV=R(()=>{"use strict";kS();$4();o(x3e,"constantNull");o(aA,"default")});function b3e(){var t=this.parentNode;t&&t.removeChild(this)}function sA(){return this.each(b3e)}var NV=R(()=>{"use strict";o(b3e,"remove");o(sA,"default")});function w3e(){var t=this.cloneNode(!1),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function T3e(){var t=this.cloneNode(!0),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function oA(t){return this.select(t?T3e:w3e)}var MV=R(()=>{"use strict";o(w3e,"selection_cloneShallow");o(T3e,"selection_cloneDeep");o(oA,"default")});function lA(t){return arguments.length?this.property("__data__",t):this.node().__data__}var IV=R(()=>{"use strict";o(lA,"default")});function k3e(t){return function(e){t.call(this,e,this.__data__)}}function E3e(t){return t.trim().split(/^|\s+/).map(function(e){var r="",n=e.indexOf(".");return n>=0&&(r=e.slice(n+1),e=e.slice(0,n)),{type:e,name:r}})}function C3e(t){return function(){var e=this.__on;if(e){for(var r=0,n=-1,i=e.length,a;r{"use strict";o(k3e,"contextListener");o(E3e,"parseTypenames");o(C3e,"onRemove");o(S3e,"onAdd");o(cA,"default")});function PV(t,e,r){var n=yy(t),i=n.CustomEvent;typeof i=="function"?i=new i(e,r):(i=n.document.createEvent("Event"),r?(i.initEvent(e,r.bubbles,r.cancelable),i.detail=r.detail):i.initEvent(e,!1,!1)),t.dispatchEvent(i)}function A3e(t,e){return function(){return PV(this,t,e)}}function _3e(t,e){return function(){return PV(this,t,e.apply(this,arguments))}}function uA(t,e){return this.each((typeof e=="function"?_3e:A3e)(t,e))}var BV=R(()=>{"use strict";XS();o(PV,"dispatchEvent");o(A3e,"dispatchConstant");o(_3e,"dispatchFunction");o(uA,"default")});function*hA(){for(var t=this._groups,e=0,r=t.length;e{"use strict";o(hA,"default")});function Zn(t,e){this._groups=t,this._parents=e}function zV(){return new Zn([[document.documentElement]],fA)}function L3e(){return this}var fA,cu,hl=R(()=>{"use strict";eV();rV();nV();iV();aV();oV();MS();lV();cV();uV();hV();fV();dV();pV();mV();gV();yV();vV();xV();KS();bV();CV();SV();AV();_V();LV();DV();RV();NV();MV();IV();OV();BV();FV();fA=[null];o(Zn,"Selection");o(zV,"selection");o(L3e,"selection_selection");Zn.prototype=zV.prototype={constructor:Zn,select:ES,selectAll:AS,selectChild:_S,selectChildren:LS,filter:DS,data:OS,enter:NS,exit:PS,join:BS,merge:FS,selection:L3e,order:zS,sort:GS,call:$S,nodes:VS,node:US,size:HS,empty:YS,each:WS,attr:qS,style:jS,property:QS,classed:JS,text:eA,html:tA,raise:rA,lower:nA,append:iA,insert:aA,remove:sA,clone:oA,datum:lA,on:cA,dispatch:uA,[Symbol.iterator]:hA};cu=zV});function $e(t){return typeof t=="string"?new Zn([[document.querySelector(t)]],[document.documentElement]):new Zn([[t]],fA)}var GV=R(()=>{"use strict";hl();o($e,"default")});var fl=R(()=>{"use strict";py();G4();GV();hl();$4();SS();KS()});var $V=R(()=>{"use strict"});function kh(t,e,r){t.prototype=e.prototype=r,r.constructor=t}function Cp(t,e){var r=Object.create(t.prototype);for(var n in e)r[n]=e[n];return r}var dA=R(()=>{"use strict";o(kh,"default");o(Cp,"extend")});function Eh(){}function UV(){return this.rgb().formatHex()}function B3e(){return this.rgb().formatHex8()}function F3e(){return KV(this).formatHsl()}function HV(){return this.rgb().formatRgb()}function pl(t){var e,r;return t=(t+"").trim().toLowerCase(),(e=D3e.exec(t))?(r=e[1].length,e=parseInt(e[1],16),r===6?YV(e):r===3?new la(e>>8&15|e>>4&240,e>>4&15|e&240,(e&15)<<4|e&15,1):r===8?U4(e>>24&255,e>>16&255,e>>8&255,(e&255)/255):r===4?U4(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|e&240,((e&15)<<4|e&15)/255):null):(e=R3e.exec(t))?new la(e[1],e[2],e[3],1):(e=N3e.exec(t))?new la(e[1]*255/100,e[2]*255/100,e[3]*255/100,1):(e=M3e.exec(t))?U4(e[1],e[2],e[3],e[4]):(e=I3e.exec(t))?U4(e[1]*255/100,e[2]*255/100,e[3]*255/100,e[4]):(e=O3e.exec(t))?XV(e[1],e[2]/100,e[3]/100,1):(e=P3e.exec(t))?XV(e[1],e[2]/100,e[3]/100,e[4]):VV.hasOwnProperty(t)?YV(VV[t]):t==="transparent"?new la(NaN,NaN,NaN,0):null}function YV(t){return new la(t>>16&255,t>>8&255,t&255,1)}function U4(t,e,r,n){return n<=0&&(t=e=r=NaN),new la(t,e,r,n)}function mA(t){return t instanceof Eh||(t=pl(t)),t?(t=t.rgb(),new la(t.r,t.g,t.b,t.opacity)):new la}function Ap(t,e,r,n){return arguments.length===1?mA(t):new la(t,e,r,n??1)}function la(t,e,r,n){this.r=+t,this.g=+e,this.b=+r,this.opacity=+n}function WV(){return`#${rd(this.r)}${rd(this.g)}${rd(this.b)}`}function z3e(){return`#${rd(this.r)}${rd(this.g)}${rd(this.b)}${rd((isNaN(this.opacity)?1:this.opacity)*255)}`}function qV(){let t=W4(this.opacity);return`${t===1?"rgb(":"rgba("}${nd(this.r)}, ${nd(this.g)}, ${nd(this.b)}${t===1?")":`, ${t})`}`}function W4(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function nd(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function rd(t){return t=nd(t),(t<16?"0":"")+t.toString(16)}function XV(t,e,r,n){return n<=0?t=e=r=NaN:r<=0||r>=1?t=e=NaN:e<=0&&(t=NaN),new dl(t,e,r,n)}function KV(t){if(t instanceof dl)return new dl(t.h,t.s,t.l,t.opacity);if(t instanceof Eh||(t=pl(t)),!t)return new dl;if(t instanceof dl)return t;t=t.rgb();var e=t.r/255,r=t.g/255,n=t.b/255,i=Math.min(e,r,n),a=Math.max(e,r,n),s=NaN,l=a-i,u=(a+i)/2;return l?(e===a?s=(r-n)/l+(r0&&u<1?0:s,new dl(s,l,u,t.opacity)}function QV(t,e,r,n){return arguments.length===1?KV(t):new dl(t,e,r,n??1)}function dl(t,e,r,n){this.h=+t,this.s=+e,this.l=+r,this.opacity=+n}function jV(t){return t=(t||0)%360,t<0?t+360:t}function H4(t){return Math.max(0,Math.min(1,t||0))}function pA(t,e,r){return(t<60?e+(r-e)*t/60:t<180?r:t<240?e+(r-e)*(240-t)/60:e)*255}var vy,Y4,Sp,xy,ac,D3e,R3e,N3e,M3e,I3e,O3e,P3e,VV,gA=R(()=>{"use strict";dA();o(Eh,"Color");vy=.7,Y4=1/vy,Sp="\\s*([+-]?\\d+)\\s*",xy="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",ac="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",D3e=/^#([0-9a-f]{3,8})$/,R3e=new RegExp(`^rgb\\(${Sp},${Sp},${Sp}\\)$`),N3e=new RegExp(`^rgb\\(${ac},${ac},${ac}\\)$`),M3e=new RegExp(`^rgba\\(${Sp},${Sp},${Sp},${xy}\\)$`),I3e=new RegExp(`^rgba\\(${ac},${ac},${ac},${xy}\\)$`),O3e=new RegExp(`^hsl\\(${xy},${ac},${ac}\\)$`),P3e=new RegExp(`^hsla\\(${xy},${ac},${ac},${xy}\\)$`),VV={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};kh(Eh,pl,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:UV,formatHex:UV,formatHex8:B3e,formatHsl:F3e,formatRgb:HV,toString:HV});o(UV,"color_formatHex");o(B3e,"color_formatHex8");o(F3e,"color_formatHsl");o(HV,"color_formatRgb");o(pl,"color");o(YV,"rgbn");o(U4,"rgba");o(mA,"rgbConvert");o(Ap,"rgb");o(la,"Rgb");kh(la,Ap,Cp(Eh,{brighter(t){return t=t==null?Y4:Math.pow(Y4,t),new la(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=t==null?vy:Math.pow(vy,t),new la(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new la(nd(this.r),nd(this.g),nd(this.b),W4(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:WV,formatHex:WV,formatHex8:z3e,formatRgb:qV,toString:qV}));o(WV,"rgb_formatHex");o(z3e,"rgb_formatHex8");o(qV,"rgb_formatRgb");o(W4,"clampa");o(nd,"clampi");o(rd,"hex");o(XV,"hsla");o(KV,"hslConvert");o(QV,"hsl");o(dl,"Hsl");kh(dl,QV,Cp(Eh,{brighter(t){return t=t==null?Y4:Math.pow(Y4,t),new dl(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=t==null?vy:Math.pow(vy,t),new dl(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+(this.h<0)*360,e=isNaN(t)||isNaN(this.s)?0:this.s,r=this.l,n=r+(r<.5?r:1-r)*e,i=2*r-n;return new la(pA(t>=240?t-240:t+120,i,n),pA(t,i,n),pA(t<120?t+240:t-120,i,n),this.opacity)},clamp(){return new dl(jV(this.h),H4(this.s),H4(this.l),W4(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){let t=W4(this.opacity);return`${t===1?"hsl(":"hsla("}${jV(this.h)}, ${H4(this.s)*100}%, ${H4(this.l)*100}%${t===1?")":`, ${t})`}`}}));o(jV,"clamph");o(H4,"clampt");o(pA,"hsl2rgb")});var ZV,JV,eU=R(()=>{"use strict";ZV=Math.PI/180,JV=180/Math.PI});function sU(t){if(t instanceof sc)return new sc(t.l,t.a,t.b,t.opacity);if(t instanceof uu)return oU(t);t instanceof la||(t=mA(t));var e=bA(t.r),r=bA(t.g),n=bA(t.b),i=yA((.2225045*e+.7168786*r+.0606169*n)/rU),a,s;return e===r&&r===n?a=s=i:(a=yA((.4360747*e+.3850649*r+.1430804*n)/tU),s=yA((.0139322*e+.0971045*r+.7141733*n)/nU)),new sc(116*i-16,500*(a-i),200*(i-s),t.opacity)}function wA(t,e,r,n){return arguments.length===1?sU(t):new sc(t,e,r,n??1)}function sc(t,e,r,n){this.l=+t,this.a=+e,this.b=+r,this.opacity=+n}function yA(t){return t>G3e?Math.pow(t,1/3):t/aU+iU}function vA(t){return t>_p?t*t*t:aU*(t-iU)}function xA(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function bA(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function $3e(t){if(t instanceof uu)return new uu(t.h,t.c,t.l,t.opacity);if(t instanceof sc||(t=sU(t)),t.a===0&&t.b===0)return new uu(NaN,0{"use strict";dA();gA();eU();q4=18,tU=.96422,rU=1,nU=.82521,iU=4/29,_p=6/29,aU=3*_p*_p,G3e=_p*_p*_p;o(sU,"labConvert");o(wA,"lab");o(sc,"Lab");kh(sc,wA,Cp(Eh,{brighter(t){return new sc(this.l+q4*(t??1),this.a,this.b,this.opacity)},darker(t){return new sc(this.l-q4*(t??1),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,e=isNaN(this.a)?t:t+this.a/500,r=isNaN(this.b)?t:t-this.b/200;return e=tU*vA(e),t=rU*vA(t),r=nU*vA(r),new la(xA(3.1338561*e-1.6168667*t-.4906146*r),xA(-.9787684*e+1.9161415*t+.033454*r),xA(.0719453*e-.2289914*t+1.4052427*r),this.opacity)}}));o(yA,"xyz2lab");o(vA,"lab2xyz");o(xA,"lrgb2rgb");o(bA,"rgb2lrgb");o($3e,"hclConvert");o(by,"hcl");o(uu,"Hcl");o(oU,"hcl2lab");kh(uu,by,Cp(Eh,{brighter(t){return new uu(this.h,this.c,this.l+q4*(t??1),this.opacity)},darker(t){return new uu(this.h,this.c,this.l-q4*(t??1),this.opacity)},rgb(){return oU(this).rgb()}}))});var Lp=R(()=>{"use strict";gA();lU()});function TA(t,e,r,n,i){var a=t*t,s=a*t;return((1-3*t+3*a-s)*e+(4-6*a+3*s)*r+(1+3*t+3*a-3*s)*n+s*i)/6}function kA(t){var e=t.length-1;return function(r){var n=r<=0?r=0:r>=1?(r=1,e-1):Math.floor(r*e),i=t[n],a=t[n+1],s=n>0?t[n-1]:2*i-a,l=n{"use strict";o(TA,"basis");o(kA,"default")});function CA(t){var e=t.length;return function(r){var n=Math.floor(((r%=1)<0?++r:r)*e),i=t[(n+e-1)%e],a=t[n%e],s=t[(n+1)%e],l=t[(n+2)%e];return TA((r-n/e)*e,i,a,s,l)}}var cU=R(()=>{"use strict";EA();o(CA,"default")});var Dp,SA=R(()=>{"use strict";Dp=o(t=>()=>t,"default")});function uU(t,e){return function(r){return t+r*e}}function V3e(t,e,r){return t=Math.pow(t,r),e=Math.pow(e,r)-t,r=1/r,function(n){return Math.pow(t+n*e,r)}}function hU(t,e){var r=e-t;return r?uU(t,r>180||r<-180?r-360*Math.round(r/360):r):Dp(isNaN(t)?e:t)}function fU(t){return(t=+t)==1?hu:function(e,r){return r-e?V3e(e,r,t):Dp(isNaN(e)?r:e)}}function hu(t,e){var r=e-t;return r?uU(t,r):Dp(isNaN(t)?e:t)}var AA=R(()=>{"use strict";SA();o(uU,"linear");o(V3e,"exponential");o(hU,"hue");o(fU,"gamma");o(hu,"nogamma")});function dU(t){return function(e){var r=e.length,n=new Array(r),i=new Array(r),a=new Array(r),s,l;for(s=0;s{"use strict";Lp();EA();cU();AA();id=o(function t(e){var r=fU(e);function n(i,a){var s=r((i=Ap(i)).r,(a=Ap(a)).r),l=r(i.g,a.g),u=r(i.b,a.b),h=hu(i.opacity,a.opacity);return function(f){return i.r=s(f),i.g=l(f),i.b=u(f),i.opacity=h(f),i+""}}return o(n,"rgb"),n.gamma=t,n},"rgbGamma")(1);o(dU,"rgbSpline");U3e=dU(kA),H3e=dU(CA)});function LA(t,e){e||(e=[]);var r=t?Math.min(e.length,t.length):0,n=e.slice(),i;return function(a){for(i=0;i{"use strict";o(LA,"default");o(pU,"isNumberArray")});function gU(t,e){var r=e?e.length:0,n=t?Math.min(r,t.length):0,i=new Array(n),a=new Array(r),s;for(s=0;s{"use strict";X4();o(gU,"genericArray")});function DA(t,e){var r=new Date;return t=+t,e=+e,function(n){return r.setTime(t*(1-n)+e*n),r}}var vU=R(()=>{"use strict";o(DA,"default")});function ji(t,e){return t=+t,e=+e,function(r){return t*(1-r)+e*r}}var wy=R(()=>{"use strict";o(ji,"default")});function RA(t,e){var r={},n={},i;(t===null||typeof t!="object")&&(t={}),(e===null||typeof e!="object")&&(e={});for(i in e)i in t?r[i]=Ch(t[i],e[i]):n[i]=e[i];return function(a){for(i in r)n[i]=r[i](a);return n}}var xU=R(()=>{"use strict";X4();o(RA,"default")});function Y3e(t){return function(){return t}}function W3e(t){return function(e){return t(e)+""}}function Rp(t,e){var r=MA.lastIndex=NA.lastIndex=0,n,i,a,s=-1,l=[],u=[];for(t=t+"",e=e+"";(n=MA.exec(t))&&(i=NA.exec(e));)(a=i.index)>r&&(a=e.slice(r,a),l[s]?l[s]+=a:l[++s]=a),(n=n[0])===(i=i[0])?l[s]?l[s]+=i:l[++s]=i:(l[++s]=null,u.push({i:s,x:ji(n,i)})),r=NA.lastIndex;return r{"use strict";wy();MA=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,NA=new RegExp(MA.source,"g");o(Y3e,"zero");o(W3e,"one");o(Rp,"default")});function Ch(t,e){var r=typeof e,n;return e==null||r==="boolean"?Dp(e):(r==="number"?ji:r==="string"?(n=pl(e))?(e=n,id):Rp:e instanceof pl?id:e instanceof Date?DA:pU(e)?LA:Array.isArray(e)?gU:typeof e.valueOf!="function"&&typeof e.toString!="function"||isNaN(e)?RA:ji)(t,e)}var X4=R(()=>{"use strict";Lp();_A();yU();vU();wy();xU();IA();SA();mU();o(Ch,"default")});function j4(t,e){return t=+t,e=+e,function(r){return Math.round(t*(1-r)+e*r)}}var bU=R(()=>{"use strict";o(j4,"default")});function Q4(t,e,r,n,i,a){var s,l,u;return(s=Math.sqrt(t*t+e*e))&&(t/=s,e/=s),(u=t*r+e*n)&&(r-=t*u,n-=e*u),(l=Math.sqrt(r*r+n*n))&&(r/=l,n/=l,u/=l),t*n{"use strict";wU=180/Math.PI,K4={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};o(Q4,"default")});function kU(t){let e=new(typeof DOMMatrix=="function"?DOMMatrix:WebKitCSSMatrix)(t+"");return e.isIdentity?K4:Q4(e.a,e.b,e.c,e.d,e.e,e.f)}function EU(t){return t==null?K4:(Z4||(Z4=document.createElementNS("http://www.w3.org/2000/svg","g")),Z4.setAttribute("transform",t),(t=Z4.transform.baseVal.consolidate())?(t=t.matrix,Q4(t.a,t.b,t.c,t.d,t.e,t.f)):K4)}var Z4,CU=R(()=>{"use strict";TU();o(kU,"parseCss");o(EU,"parseSvg")});function SU(t,e,r,n){function i(h){return h.length?h.pop()+" ":""}o(i,"pop");function a(h,f,d,p,m,g){if(h!==d||f!==p){var y=m.push("translate(",null,e,null,r);g.push({i:y-4,x:ji(h,d)},{i:y-2,x:ji(f,p)})}else(d||p)&&m.push("translate("+d+e+p+r)}o(a,"translate");function s(h,f,d,p){h!==f?(h-f>180?f+=360:f-h>180&&(h+=360),p.push({i:d.push(i(d)+"rotate(",null,n)-2,x:ji(h,f)})):f&&d.push(i(d)+"rotate("+f+n)}o(s,"rotate");function l(h,f,d,p){h!==f?p.push({i:d.push(i(d)+"skewX(",null,n)-2,x:ji(h,f)}):f&&d.push(i(d)+"skewX("+f+n)}o(l,"skewX");function u(h,f,d,p,m,g){if(h!==d||f!==p){var y=m.push(i(m)+"scale(",null,",",null,")");g.push({i:y-4,x:ji(h,d)},{i:y-2,x:ji(f,p)})}else(d!==1||p!==1)&&m.push(i(m)+"scale("+d+","+p+")")}return o(u,"scale"),function(h,f){var d=[],p=[];return h=t(h),f=t(f),a(h.translateX,h.translateY,f.translateX,f.translateY,d,p),s(h.rotate,f.rotate,d,p),l(h.skewX,f.skewX,d,p),u(h.scaleX,h.scaleY,f.scaleX,f.scaleY,d,p),h=f=null,function(m){for(var g=-1,y=p.length,v;++g{"use strict";wy();CU();o(SU,"interpolateTransform");OA=SU(kU,"px, ","px)","deg)"),PA=SU(EU,", ",")",")")});function _U(t){return function(e,r){var n=t((e=by(e)).h,(r=by(r)).h),i=hu(e.c,r.c),a=hu(e.l,r.l),s=hu(e.opacity,r.opacity);return function(l){return e.h=n(l),e.c=i(l),e.l=a(l),e.opacity=s(l),e+""}}}var BA,q3e,LU=R(()=>{"use strict";Lp();AA();o(_U,"hcl");BA=_U(hU),q3e=_U(hu)});var Np=R(()=>{"use strict";X4();wy();bU();IA();AU();_A();LU()});function Ay(){return ad||(NU(X3e),ad=Cy.now()+t3)}function X3e(){ad=0}function Sy(){this._call=this._time=this._next=null}function r3(t,e,r){var n=new Sy;return n.restart(t,e,r),n}function MU(){Ay(),++Mp;for(var t=J4,e;t;)(e=ad-t._time)>=0&&t._call.call(void 0,e),t=t._next;--Mp}function DU(){ad=(e3=Cy.now())+t3,Mp=ky=0;try{MU()}finally{Mp=0,K3e(),ad=0}}function j3e(){var t=Cy.now(),e=t-e3;e>RU&&(t3-=e,e3=t)}function K3e(){for(var t,e=J4,r,n=1/0;e;)e._call?(n>e._time&&(n=e._time),t=e,e=e._next):(r=e._next,e._next=null,e=t?t._next=r:J4=r);Ey=t,FA(n)}function FA(t){if(!Mp){ky&&(ky=clearTimeout(ky));var e=t-ad;e>24?(t<1/0&&(ky=setTimeout(DU,t-Cy.now()-t3)),Ty&&(Ty=clearInterval(Ty))):(Ty||(e3=Cy.now(),Ty=setInterval(j3e,RU)),Mp=1,NU(DU))}}var Mp,ky,Ty,RU,J4,Ey,e3,ad,t3,Cy,NU,zA=R(()=>{"use strict";Mp=0,ky=0,Ty=0,RU=1e3,e3=0,ad=0,t3=0,Cy=typeof performance=="object"&&performance.now?performance:Date,NU=typeof window=="object"&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};o(Ay,"now");o(X3e,"clearNow");o(Sy,"Timer");Sy.prototype=r3.prototype={constructor:Sy,restart:o(function(t,e,r){if(typeof t!="function")throw new TypeError("callback is not a function");r=(r==null?Ay():+r)+(e==null?0:+e),!this._next&&Ey!==this&&(Ey?Ey._next=this:J4=this,Ey=this),this._call=t,this._time=r,FA()},"restart"),stop:o(function(){this._call&&(this._call=null,this._time=1/0,FA())},"stop")};o(r3,"timer");o(MU,"timerFlush");o(DU,"wake");o(j3e,"poke");o(K3e,"nap");o(FA,"sleep")});function _y(t,e,r){var n=new Sy;return e=e==null?0:+e,n.restart(i=>{n.stop(),t(i+e)},e,r),n}var IU=R(()=>{"use strict";zA();o(_y,"default")});var n3=R(()=>{"use strict";zA();IU()});function fu(t,e,r,n,i,a){var s=t.__transition;if(!s)t.__transition={};else if(r in s)return;J3e(t,r,{name:e,index:n,group:i,on:Q3e,tween:Z3e,time:a.time,delay:a.delay,duration:a.duration,ease:a.ease,timer:null,state:BU})}function Dy(t,e){var r=Mi(t,e);if(r.state>BU)throw new Error("too late; already scheduled");return r}function ca(t,e){var r=Mi(t,e);if(r.state>i3)throw new Error("too late; already running");return r}function Mi(t,e){var r=t.__transition;if(!r||!(r=r[e]))throw new Error("transition not found");return r}function J3e(t,e,r){var n=t.__transition,i;n[e]=r,r.timer=r3(a,0,r.time);function a(h){r.state=OU,r.timer.restart(s,r.delay,r.time),r.delay<=h&&s(h-r.delay)}o(a,"schedule");function s(h){var f,d,p,m;if(r.state!==OU)return u();for(f in n)if(m=n[f],m.name===r.name){if(m.state===i3)return _y(s);m.state===PU?(m.state=Ly,m.timer.stop(),m.on.call("interrupt",t,t.__data__,m.index,m.group),delete n[f]):+f{"use strict";bS();n3();Q3e=xS("start","end","cancel","interrupt"),Z3e=[],BU=0,OU=1,a3=2,i3=3,PU=4,s3=5,Ly=6;o(fu,"default");o(Dy,"init");o(ca,"set");o(Mi,"get");o(J3e,"create")});function Ry(t,e){var r=t.__transition,n,i,a=!0,s;if(r){e=e==null?null:e+"";for(s in r){if((n=r[s]).name!==e){a=!1;continue}i=n.state>a3&&n.state{"use strict";ys();o(Ry,"default")});function GA(t){return this.each(function(){Ry(this,t)})}var zU=R(()=>{"use strict";FU();o(GA,"default")});function e5e(t,e){var r,n;return function(){var i=ca(this,t),a=i.tween;if(a!==r){n=r=a;for(var s=0,l=n.length;s{"use strict";ys();o(e5e,"tweenRemove");o(t5e,"tweenFunction");o($A,"default");o(Ip,"tweenValue")});function My(t,e){var r;return(typeof e=="number"?ji:e instanceof pl?id:(r=pl(e))?(e=r,id):Rp)(t,e)}var VA=R(()=>{"use strict";Lp();Np();o(My,"default")});function r5e(t){return function(){this.removeAttribute(t)}}function n5e(t){return function(){this.removeAttributeNS(t.space,t.local)}}function i5e(t,e,r){var n,i=r+"",a;return function(){var s=this.getAttribute(t);return s===i?null:s===n?a:a=e(n=s,r)}}function a5e(t,e,r){var n,i=r+"",a;return function(){var s=this.getAttributeNS(t.space,t.local);return s===i?null:s===n?a:a=e(n=s,r)}}function s5e(t,e,r){var n,i,a;return function(){var s,l=r(this),u;return l==null?void this.removeAttribute(t):(s=this.getAttribute(t),u=l+"",s===u?null:s===n&&u===i?a:(i=u,a=e(n=s,l)))}}function o5e(t,e,r){var n,i,a;return function(){var s,l=r(this),u;return l==null?void this.removeAttributeNS(t.space,t.local):(s=this.getAttributeNS(t.space,t.local),u=l+"",s===u?null:s===n&&u===i?a:(i=u,a=e(n=s,l)))}}function UA(t,e){var r=ic(t),n=r==="transform"?PA:My;return this.attrTween(t,typeof e=="function"?(r.local?o5e:s5e)(r,n,Ip(this,"attr."+t,e)):e==null?(r.local?n5e:r5e)(r):(r.local?a5e:i5e)(r,n,e))}var GU=R(()=>{"use strict";Np();fl();Ny();VA();o(r5e,"attrRemove");o(n5e,"attrRemoveNS");o(i5e,"attrConstant");o(a5e,"attrConstantNS");o(s5e,"attrFunction");o(o5e,"attrFunctionNS");o(UA,"default")});function l5e(t,e){return function(r){this.setAttribute(t,e.call(this,r))}}function c5e(t,e){return function(r){this.setAttributeNS(t.space,t.local,e.call(this,r))}}function u5e(t,e){var r,n;function i(){var a=e.apply(this,arguments);return a!==n&&(r=(n=a)&&c5e(t,a)),r}return o(i,"tween"),i._value=e,i}function h5e(t,e){var r,n;function i(){var a=e.apply(this,arguments);return a!==n&&(r=(n=a)&&l5e(t,a)),r}return o(i,"tween"),i._value=e,i}function HA(t,e){var r="attr."+t;if(arguments.length<2)return(r=this.tween(r))&&r._value;if(e==null)return this.tween(r,null);if(typeof e!="function")throw new Error;var n=ic(t);return this.tween(r,(n.local?u5e:h5e)(n,e))}var $U=R(()=>{"use strict";fl();o(l5e,"attrInterpolate");o(c5e,"attrInterpolateNS");o(u5e,"attrTweenNS");o(h5e,"attrTween");o(HA,"default")});function f5e(t,e){return function(){Dy(this,t).delay=+e.apply(this,arguments)}}function d5e(t,e){return e=+e,function(){Dy(this,t).delay=e}}function YA(t){var e=this._id;return arguments.length?this.each((typeof t=="function"?f5e:d5e)(e,t)):Mi(this.node(),e).delay}var VU=R(()=>{"use strict";ys();o(f5e,"delayFunction");o(d5e,"delayConstant");o(YA,"default")});function p5e(t,e){return function(){ca(this,t).duration=+e.apply(this,arguments)}}function m5e(t,e){return e=+e,function(){ca(this,t).duration=e}}function WA(t){var e=this._id;return arguments.length?this.each((typeof t=="function"?p5e:m5e)(e,t)):Mi(this.node(),e).duration}var UU=R(()=>{"use strict";ys();o(p5e,"durationFunction");o(m5e,"durationConstant");o(WA,"default")});function g5e(t,e){if(typeof e!="function")throw new Error;return function(){ca(this,t).ease=e}}function qA(t){var e=this._id;return arguments.length?this.each(g5e(e,t)):Mi(this.node(),e).ease}var HU=R(()=>{"use strict";ys();o(g5e,"easeConstant");o(qA,"default")});function y5e(t,e){return function(){var r=e.apply(this,arguments);if(typeof r!="function")throw new Error;ca(this,t).ease=r}}function XA(t){if(typeof t!="function")throw new Error;return this.each(y5e(this._id,t))}var YU=R(()=>{"use strict";ys();o(y5e,"easeVarying");o(XA,"default")});function jA(t){typeof t!="function"&&(t=Ep(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i{"use strict";fl();sd();o(jA,"default")});function KA(t){if(t._id!==this._id)throw new Error;for(var e=this._groups,r=t._groups,n=e.length,i=r.length,a=Math.min(n,i),s=new Array(n),l=0;l{"use strict";sd();o(KA,"default")});function v5e(t){return(t+"").trim().split(/^|\s+/).every(function(e){var r=e.indexOf(".");return r>=0&&(e=e.slice(0,r)),!e||e==="start"})}function x5e(t,e,r){var n,i,a=v5e(e)?Dy:ca;return function(){var s=a(this,t),l=s.on;l!==n&&(i=(n=l).copy()).on(e,r),s.on=i}}function QA(t,e){var r=this._id;return arguments.length<2?Mi(this.node(),r).on.on(t):this.each(x5e(r,t,e))}var XU=R(()=>{"use strict";ys();o(v5e,"start");o(x5e,"onFunction");o(QA,"default")});function b5e(t){return function(){var e=this.parentNode;for(var r in this.__transition)if(+r!==t)return;e&&e.removeChild(this)}}function ZA(){return this.on("end.remove",b5e(this._id))}var jU=R(()=>{"use strict";o(b5e,"removeFunction");o(ZA,"default")});function JA(t){var e=this._name,r=this._id;typeof t!="function"&&(t=wh(t));for(var n=this._groups,i=n.length,a=new Array(i),s=0;s{"use strict";fl();sd();ys();o(JA,"default")});function e8(t){var e=this._name,r=this._id;typeof t!="function"&&(t=kp(t));for(var n=this._groups,i=n.length,a=[],s=[],l=0;l{"use strict";fl();sd();ys();o(e8,"default")});function t8(){return new w5e(this._groups,this._parents)}var w5e,ZU=R(()=>{"use strict";fl();w5e=cu.prototype.constructor;o(t8,"default")});function T5e(t,e){var r,n,i;return function(){var a=Th(this,t),s=(this.style.removeProperty(t),Th(this,t));return a===s?null:a===r&&s===n?i:i=e(r=a,n=s)}}function JU(t){return function(){this.style.removeProperty(t)}}function k5e(t,e,r){var n,i=r+"",a;return function(){var s=Th(this,t);return s===i?null:s===n?a:a=e(n=s,r)}}function E5e(t,e,r){var n,i,a;return function(){var s=Th(this,t),l=r(this),u=l+"";return l==null&&(u=l=(this.style.removeProperty(t),Th(this,t))),s===u?null:s===n&&u===i?a:(i=u,a=e(n=s,l))}}function C5e(t,e){var r,n,i,a="style."+e,s="end."+a,l;return function(){var u=ca(this,t),h=u.on,f=u.value[a]==null?l||(l=JU(e)):void 0;(h!==r||i!==f)&&(n=(r=h).copy()).on(s,i=f),u.on=n}}function r8(t,e,r){var n=(t+="")=="transform"?OA:My;return e==null?this.styleTween(t,T5e(t,n)).on("end.style."+t,JU(t)):typeof e=="function"?this.styleTween(t,E5e(t,n,Ip(this,"style."+t,e))).each(C5e(this._id,t)):this.styleTween(t,k5e(t,n,e),r).on("end.style."+t,null)}var eH=R(()=>{"use strict";Np();fl();ys();Ny();VA();o(T5e,"styleNull");o(JU,"styleRemove");o(k5e,"styleConstant");o(E5e,"styleFunction");o(C5e,"styleMaybeRemove");o(r8,"default")});function S5e(t,e,r){return function(n){this.style.setProperty(t,e.call(this,n),r)}}function A5e(t,e,r){var n,i;function a(){var s=e.apply(this,arguments);return s!==i&&(n=(i=s)&&S5e(t,s,r)),n}return o(a,"tween"),a._value=e,a}function n8(t,e,r){var n="style."+(t+="");if(arguments.length<2)return(n=this.tween(n))&&n._value;if(e==null)return this.tween(n,null);if(typeof e!="function")throw new Error;return this.tween(n,A5e(t,e,r??""))}var tH=R(()=>{"use strict";o(S5e,"styleInterpolate");o(A5e,"styleTween");o(n8,"default")});function _5e(t){return function(){this.textContent=t}}function L5e(t){return function(){var e=t(this);this.textContent=e??""}}function i8(t){return this.tween("text",typeof t=="function"?L5e(Ip(this,"text",t)):_5e(t==null?"":t+""))}var rH=R(()=>{"use strict";Ny();o(_5e,"textConstant");o(L5e,"textFunction");o(i8,"default")});function D5e(t){return function(e){this.textContent=t.call(this,e)}}function R5e(t){var e,r;function n(){var i=t.apply(this,arguments);return i!==r&&(e=(r=i)&&D5e(i)),e}return o(n,"tween"),n._value=t,n}function a8(t){var e="text";if(arguments.length<1)return(e=this.tween(e))&&e._value;if(t==null)return this.tween(e,null);if(typeof t!="function")throw new Error;return this.tween(e,R5e(t))}var nH=R(()=>{"use strict";o(D5e,"textInterpolate");o(R5e,"textTween");o(a8,"default")});function s8(){for(var t=this._name,e=this._id,r=o3(),n=this._groups,i=n.length,a=0;a{"use strict";sd();ys();o(s8,"default")});function o8(){var t,e,r=this,n=r._id,i=r.size();return new Promise(function(a,s){var l={value:s},u={value:o(function(){--i===0&&a()},"value")};r.each(function(){var h=ca(this,n),f=h.on;f!==t&&(e=(t=f).copy(),e._.cancel.push(l),e._.interrupt.push(l),e._.end.push(u)),h.on=e}),i===0&&a()})}var aH=R(()=>{"use strict";ys();o(o8,"default")});function Ka(t,e,r,n){this._groups=t,this._parents=e,this._name=r,this._id=n}function sH(t){return cu().transition(t)}function o3(){return++N5e}var N5e,du,sd=R(()=>{"use strict";fl();GU();$U();VU();UU();HU();YU();WU();qU();XU();jU();KU();QU();ZU();eH();tH();rH();nH();iH();Ny();aH();N5e=0;o(Ka,"Transition");o(sH,"transition");o(o3,"newId");du=cu.prototype;Ka.prototype=sH.prototype={constructor:Ka,select:JA,selectAll:e8,selectChild:du.selectChild,selectChildren:du.selectChildren,filter:jA,merge:KA,selection:t8,transition:s8,call:du.call,nodes:du.nodes,node:du.node,size:du.size,empty:du.empty,each:du.each,on:QA,attr:UA,attrTween:HA,style:r8,styleTween:n8,text:i8,textTween:a8,remove:ZA,tween:$A,delay:YA,duration:WA,ease:qA,easeVarying:XA,end:o8,[Symbol.iterator]:du[Symbol.iterator]}});function l3(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var oH=R(()=>{"use strict";o(l3,"cubicInOut")});var l8=R(()=>{"use strict";oH()});function I5e(t,e){for(var r;!(r=t.__transition)||!(r=r[e]);)if(!(t=t.parentNode))throw new Error(`transition ${e} not found`);return r}function c8(t){var e,r;t instanceof Ka?(e=t._id,t=t._name):(e=o3(),(r=M5e).time=Ay(),t=t==null?null:t+"");for(var n=this._groups,i=n.length,a=0;a{"use strict";sd();ys();l8();n3();M5e={time:null,delay:0,duration:250,ease:l3};o(I5e,"inherit");o(c8,"default")});var cH=R(()=>{"use strict";fl();zU();lH();cu.prototype.interrupt=GA;cu.prototype.transition=c8});var c3=R(()=>{"use strict";cH()});var uH=R(()=>{"use strict"});var hH=R(()=>{"use strict"});var fH=R(()=>{"use strict"});function dH(t){return[+t[0],+t[1]]}function O5e(t){return[dH(t[0]),dH(t[1])]}function u8(t){return{type:t}}var Kpt,Qpt,Zpt,Jpt,emt,tmt,pH=R(()=>{"use strict";c3();uH();hH();fH();({abs:Kpt,max:Qpt,min:Zpt}=Math);o(dH,"number1");o(O5e,"number2");Jpt={name:"x",handles:["w","e"].map(u8),input:o(function(t,e){return t==null?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},"input"),output:o(function(t){return t&&[t[0][0],t[1][0]]},"output")},emt={name:"y",handles:["n","s"].map(u8),input:o(function(t,e){return t==null?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},"input"),output:o(function(t){return t&&[t[0][1],t[1][1]]},"output")},tmt={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(u8),input:o(function(t){return t==null?null:O5e(t)},"input"),output:o(function(t){return t},"output")};o(u8,"type")});var mH=R(()=>{"use strict";pH()});function gH(t){this._+=t[0];for(let e=1,r=t.length;e=0))throw new Error(`invalid digits: ${t}`);if(e>15)return gH;let r=10**e;return function(n){this._+=n[0];for(let i=1,a=n.length;i{"use strict";h8=Math.PI,f8=2*h8,od=1e-6,P5e=f8-od;o(gH,"append");o(B5e,"appendRound");ld=class{static{o(this,"Path")}constructor(e){this._x0=this._y0=this._x1=this._y1=null,this._="",this._append=e==null?gH:B5e(e)}moveTo(e,r){this._append`M${this._x0=this._x1=+e},${this._y0=this._y1=+r}`}closePath(){this._x1!==null&&(this._x1=this._x0,this._y1=this._y0,this._append`Z`)}lineTo(e,r){this._append`L${this._x1=+e},${this._y1=+r}`}quadraticCurveTo(e,r,n,i){this._append`Q${+e},${+r},${this._x1=+n},${this._y1=+i}`}bezierCurveTo(e,r,n,i,a,s){this._append`C${+e},${+r},${+n},${+i},${this._x1=+a},${this._y1=+s}`}arcTo(e,r,n,i,a){if(e=+e,r=+r,n=+n,i=+i,a=+a,a<0)throw new Error(`negative radius: ${a}`);let s=this._x1,l=this._y1,u=n-e,h=i-r,f=s-e,d=l-r,p=f*f+d*d;if(this._x1===null)this._append`M${this._x1=e},${this._y1=r}`;else if(p>od)if(!(Math.abs(d*u-h*f)>od)||!a)this._append`L${this._x1=e},${this._y1=r}`;else{let m=n-s,g=i-l,y=u*u+h*h,v=m*m+g*g,x=Math.sqrt(y),b=Math.sqrt(p),w=a*Math.tan((h8-Math.acos((y+p-v)/(2*x*b)))/2),S=w/b,T=w/x;Math.abs(S-1)>od&&this._append`L${e+S*f},${r+S*d}`,this._append`A${a},${a},0,0,${+(d*m>f*g)},${this._x1=e+T*u},${this._y1=r+T*h}`}}arc(e,r,n,i,a,s){if(e=+e,r=+r,n=+n,s=!!s,n<0)throw new Error(`negative radius: ${n}`);let l=n*Math.cos(i),u=n*Math.sin(i),h=e+l,f=r+u,d=1^s,p=s?i-a:a-i;this._x1===null?this._append`M${h},${f}`:(Math.abs(this._x1-h)>od||Math.abs(this._y1-f)>od)&&this._append`L${h},${f}`,n&&(p<0&&(p=p%f8+f8),p>P5e?this._append`A${n},${n},0,1,${d},${e-l},${r-u}A${n},${n},0,1,${d},${this._x1=h},${this._y1=f}`:p>od&&this._append`A${n},${n},0,${+(p>=h8)},${d},${this._x1=e+n*Math.cos(a)},${this._y1=r+n*Math.sin(a)}`)}rect(e,r,n,i){this._append`M${this._x0=this._x1=+e},${this._y0=this._y1=+r}h${n=+n}v${+i}h${-n}Z`}toString(){return this._}};o(yH,"path");yH.prototype=ld.prototype});var d8=R(()=>{"use strict";vH()});var xH=R(()=>{"use strict"});var bH=R(()=>{"use strict"});var wH=R(()=>{"use strict"});var TH=R(()=>{"use strict"});var kH=R(()=>{"use strict"});var EH=R(()=>{"use strict"});var CH=R(()=>{"use strict"});function p8(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)}function cd(t,e){if((r=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var r,n=t.slice(0,r);return[n.length>1?n[0]+n.slice(2):n,+t.slice(r+1)]}var Iy=R(()=>{"use strict";o(p8,"default");o(cd,"formatDecimalParts")});function ml(t){return t=cd(Math.abs(t)),t?t[1]:NaN}var Oy=R(()=>{"use strict";Iy();o(ml,"default")});function m8(t,e){return function(r,n){for(var i=r.length,a=[],s=0,l=t[0],u=0;i>0&&l>0&&(u+l+1>n&&(l=Math.max(1,n-u)),a.push(r.substring(i-=l,i+l)),!((u+=l+1)>n));)l=t[s=(s+1)%t.length];return a.reverse().join(e)}}var SH=R(()=>{"use strict";o(m8,"default")});function g8(t){return function(e){return e.replace(/[0-9]/g,function(r){return t[+r]})}}var AH=R(()=>{"use strict";o(g8,"default")});function Sh(t){if(!(e=F5e.exec(t)))throw new Error("invalid format: "+t);var e;return new u3({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function u3(t){this.fill=t.fill===void 0?" ":t.fill+"",this.align=t.align===void 0?">":t.align+"",this.sign=t.sign===void 0?"-":t.sign+"",this.symbol=t.symbol===void 0?"":t.symbol+"",this.zero=!!t.zero,this.width=t.width===void 0?void 0:+t.width,this.comma=!!t.comma,this.precision=t.precision===void 0?void 0:+t.precision,this.trim=!!t.trim,this.type=t.type===void 0?"":t.type+""}var F5e,y8=R(()=>{"use strict";F5e=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;o(Sh,"formatSpecifier");Sh.prototype=u3.prototype;o(u3,"FormatSpecifier");u3.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type}});function v8(t){e:for(var e=t.length,r=1,n=-1,i;r0&&(n=0);break}return n>0?t.slice(0,n)+t.slice(i+1):t}var _H=R(()=>{"use strict";o(v8,"default")});function b8(t,e){var r=cd(t,e);if(!r)return t+"";var n=r[0],i=r[1],a=i-(x8=Math.max(-8,Math.min(8,Math.floor(i/3)))*3)+1,s=n.length;return a===s?n:a>s?n+new Array(a-s+1).join("0"):a>0?n.slice(0,a)+"."+n.slice(a):"0."+new Array(1-a).join("0")+cd(t,Math.max(0,e+a-1))[0]}var x8,w8=R(()=>{"use strict";Iy();o(b8,"default")});function h3(t,e){var r=cd(t,e);if(!r)return t+"";var n=r[0],i=r[1];return i<0?"0."+new Array(-i).join("0")+n:n.length>i+1?n.slice(0,i+1)+"."+n.slice(i+1):n+new Array(i-n.length+2).join("0")}var LH=R(()=>{"use strict";Iy();o(h3,"default")});var T8,DH=R(()=>{"use strict";Iy();w8();LH();T8={"%":o((t,e)=>(t*100).toFixed(e),"%"),b:o(t=>Math.round(t).toString(2),"b"),c:o(t=>t+"","c"),d:p8,e:o((t,e)=>t.toExponential(e),"e"),f:o((t,e)=>t.toFixed(e),"f"),g:o((t,e)=>t.toPrecision(e),"g"),o:o(t=>Math.round(t).toString(8),"o"),p:o((t,e)=>h3(t*100,e),"p"),r:h3,s:b8,X:o(t=>Math.round(t).toString(16).toUpperCase(),"X"),x:o(t=>Math.round(t).toString(16),"x")}});function f3(t){return t}var RH=R(()=>{"use strict";o(f3,"default")});function k8(t){var e=t.grouping===void 0||t.thousands===void 0?f3:m8(NH.call(t.grouping,Number),t.thousands+""),r=t.currency===void 0?"":t.currency[0]+"",n=t.currency===void 0?"":t.currency[1]+"",i=t.decimal===void 0?".":t.decimal+"",a=t.numerals===void 0?f3:g8(NH.call(t.numerals,String)),s=t.percent===void 0?"%":t.percent+"",l=t.minus===void 0?"\u2212":t.minus+"",u=t.nan===void 0?"NaN":t.nan+"";function h(d){d=Sh(d);var p=d.fill,m=d.align,g=d.sign,y=d.symbol,v=d.zero,x=d.width,b=d.comma,w=d.precision,S=d.trim,T=d.type;T==="n"?(b=!0,T="g"):T8[T]||(w===void 0&&(w=12),S=!0,T="g"),(v||p==="0"&&m==="=")&&(v=!0,p="0",m="=");var E=y==="$"?r:y==="#"&&/[boxX]/.test(T)?"0"+T.toLowerCase():"",_=y==="$"?n:/[%p]/.test(T)?s:"",A=T8[T],L=/[defgprs%]/.test(T);w=w===void 0?6:/[gprs]/.test(T)?Math.max(1,Math.min(21,w)):Math.max(0,Math.min(20,w));function M(N){var k=E,I=_,C,O,D;if(T==="c")I=A(N)+I,N="";else{N=+N;var P=N<0||1/N<0;if(N=isNaN(N)?u:A(Math.abs(N),w),S&&(N=v8(N)),P&&+N==0&&g!=="+"&&(P=!1),k=(P?g==="("?g:l:g==="-"||g==="("?"":g)+k,I=(T==="s"?MH[8+x8/3]:"")+I+(P&&g==="("?")":""),L){for(C=-1,O=N.length;++CD||D>57){I=(D===46?i+N.slice(C+1):N.slice(C))+I,N=N.slice(0,C);break}}}b&&!v&&(N=e(N,1/0));var F=k.length+N.length+I.length,B=F>1)+k+N+I+B.slice(F);break;default:N=B+k+N+I;break}return a(N)}return o(M,"format"),M.toString=function(){return d+""},M}o(h,"newFormat");function f(d,p){var m=h((d=Sh(d),d.type="f",d)),g=Math.max(-8,Math.min(8,Math.floor(ml(p)/3)))*3,y=Math.pow(10,-g),v=MH[8+g/3];return function(x){return m(y*x)+v}}return o(f,"formatPrefix"),{format:h,formatPrefix:f}}var NH,MH,IH=R(()=>{"use strict";Oy();SH();AH();y8();_H();DH();w8();RH();NH=Array.prototype.map,MH=["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"];o(k8,"default")});function E8(t){return d3=k8(t),p3=d3.format,m3=d3.formatPrefix,d3}var d3,p3,m3,OH=R(()=>{"use strict";IH();E8({thousands:",",grouping:[3],currency:["$",""]});o(E8,"defaultLocale")});function g3(t){return Math.max(0,-ml(Math.abs(t)))}var PH=R(()=>{"use strict";Oy();o(g3,"default")});function y3(t,e){return Math.max(0,Math.max(-8,Math.min(8,Math.floor(ml(e)/3)))*3-ml(Math.abs(t)))}var BH=R(()=>{"use strict";Oy();o(y3,"default")});function v3(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,ml(e)-ml(t))+1}var FH=R(()=>{"use strict";Oy();o(v3,"default")});var C8=R(()=>{"use strict";OH();y8();PH();BH();FH()});var zH=R(()=>{"use strict"});var GH=R(()=>{"use strict"});var $H=R(()=>{"use strict"});var VH=R(()=>{"use strict"});function Ah(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t);break}return this}var Py=R(()=>{"use strict";o(Ah,"initRange")});function pu(){var t=new wp,e=[],r=[],n=S8;function i(a){let s=t.get(a);if(s===void 0){if(n!==S8)return n;t.set(a,s=e.push(a)-1)}return r[s%r.length]}return o(i,"scale"),i.domain=function(a){if(!arguments.length)return e.slice();e=[],t=new wp;for(let s of a)t.has(s)||t.set(s,e.push(s)-1);return i},i.range=function(a){return arguments.length?(r=Array.from(a),i):r.slice()},i.unknown=function(a){return arguments.length?(n=a,i):n},i.copy=function(){return pu(e,r).unknown(n)},Ah.apply(i,arguments),i}var S8,A8=R(()=>{"use strict";bh();Py();S8=Symbol("implicit");o(pu,"ordinal")});function Op(){var t=pu().unknown(void 0),e=t.domain,r=t.range,n=0,i=1,a,s,l=!1,u=0,h=0,f=.5;delete t.unknown;function d(){var p=e().length,m=i{"use strict";bh();Py();A8();o(Op,"band")});function _8(t){return function(){return t}}var HH=R(()=>{"use strict";o(_8,"constants")});function L8(t){return+t}var YH=R(()=>{"use strict";o(L8,"number")});function Pp(t){return t}function D8(t,e){return(e-=t=+t)?function(r){return(r-t)/e}:_8(isNaN(e)?NaN:.5)}function z5e(t,e){var r;return t>e&&(r=t,t=e,e=r),function(n){return Math.max(t,Math.min(e,n))}}function G5e(t,e,r){var n=t[0],i=t[1],a=e[0],s=e[1];return i2?$5e:G5e,u=h=null,d}o(f,"rescale");function d(p){return p==null||isNaN(p=+p)?a:(u||(u=l(t.map(n),e,r)))(n(s(p)))}return o(d,"scale"),d.invert=function(p){return s(i((h||(h=l(e,t.map(n),ji)))(p)))},d.domain=function(p){return arguments.length?(t=Array.from(p,L8),f()):t.slice()},d.range=function(p){return arguments.length?(e=Array.from(p),f()):e.slice()},d.rangeRound=function(p){return e=Array.from(p),r=j4,f()},d.clamp=function(p){return arguments.length?(s=p?!0:Pp,f()):s!==Pp},d.interpolate=function(p){return arguments.length?(r=p,f()):r},d.unknown=function(p){return arguments.length?(a=p,d):a},function(p,m){return n=p,i=m,f()}}function By(){return V5e()(Pp,Pp)}var WH,R8=R(()=>{"use strict";bh();Np();HH();YH();WH=[0,1];o(Pp,"identity");o(D8,"normalize");o(z5e,"clamper");o(G5e,"bimap");o($5e,"polymap");o(x3,"copy");o(V5e,"transformer");o(By,"continuous")});function N8(t,e,r,n){var i=Tp(t,e,r),a;switch(n=Sh(n??",f"),n.type){case"s":{var s=Math.max(Math.abs(t),Math.abs(e));return n.precision==null&&!isNaN(a=y3(i,s))&&(n.precision=a),m3(n,s)}case"":case"e":case"g":case"p":case"r":{n.precision==null&&!isNaN(a=v3(i,Math.max(Math.abs(t),Math.abs(e))))&&(n.precision=a-(n.type==="e"));break}case"f":case"%":{n.precision==null&&!isNaN(a=g3(i))&&(n.precision=a-(n.type==="%")*2);break}}return p3(n)}var qH=R(()=>{"use strict";bh();C8();o(N8,"tickFormat")});function U5e(t){var e=t.domain;return t.ticks=function(r){var n=e();return N4(n[0],n[n.length-1],r??10)},t.tickFormat=function(r,n){var i=e();return N8(i[0],i[i.length-1],r??10,n)},t.nice=function(r){r==null&&(r=10);var n=e(),i=0,a=n.length-1,s=n[i],l=n[a],u,h,f=10;for(l0;){if(h=fy(s,l,r),h===u)return n[i]=s,n[a]=l,e(n);if(h>0)s=Math.floor(s/h)*h,l=Math.ceil(l/h)*h;else if(h<0)s=Math.ceil(s*h)/h,l=Math.floor(l*h)/h;else break;u=h}return t},t}function gl(){var t=By();return t.copy=function(){return x3(t,gl())},Ah.apply(t,arguments),U5e(t)}var XH=R(()=>{"use strict";bh();R8();Py();qH();o(U5e,"linearish");o(gl,"linear")});function M8(t,e){t=t.slice();var r=0,n=t.length-1,i=t[r],a=t[n],s;return a{"use strict";o(M8,"nice")});function dn(t,e,r,n){function i(a){return t(a=arguments.length===0?new Date:new Date(+a)),a}return o(i,"interval"),i.floor=a=>(t(a=new Date(+a)),a),i.ceil=a=>(t(a=new Date(a-1)),e(a,1),t(a),a),i.round=a=>{let s=i(a),l=i.ceil(a);return a-s(e(a=new Date(+a),s==null?1:Math.floor(s)),a),i.range=(a,s,l)=>{let u=[];if(a=i.ceil(a),l=l==null?1:Math.floor(l),!(a0))return u;let h;do u.push(h=new Date(+a)),e(a,l),t(a);while(hdn(s=>{if(s>=s)for(;t(s),!a(s);)s.setTime(s-1)},(s,l)=>{if(s>=s)if(l<0)for(;++l<=0;)for(;e(s,-1),!a(s););else for(;--l>=0;)for(;e(s,1),!a(s););}),r&&(i.count=(a,s)=>(I8.setTime(+a),O8.setTime(+s),t(I8),t(O8),Math.floor(r(I8,O8))),i.every=a=>(a=Math.floor(a),!isFinite(a)||!(a>0)?null:a>1?i.filter(n?s=>n(s)%a===0:s=>i.count(0,s)%a===0):i)),i}var I8,O8,mu=R(()=>{"use strict";I8=new Date,O8=new Date;o(dn,"timeInterval")});var oc,KH,P8=R(()=>{"use strict";mu();oc=dn(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);oc.every=t=>(t=Math.floor(t),!isFinite(t)||!(t>0)?null:t>1?dn(e=>{e.setTime(Math.floor(e/t)*t)},(e,r)=>{e.setTime(+e+r*t)},(e,r)=>(r-e)/t):oc);KH=oc.range});var Ks,QH,B8=R(()=>{"use strict";mu();Ks=dn(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*1e3)},(t,e)=>(e-t)/1e3,t=>t.getUTCSeconds()),QH=Ks.range});var gu,H5e,b3,Y5e,F8=R(()=>{"use strict";mu();gu=dn(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*1e3)},(t,e)=>{t.setTime(+t+e*6e4)},(t,e)=>(e-t)/6e4,t=>t.getMinutes()),H5e=gu.range,b3=dn(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*6e4)},(t,e)=>(e-t)/6e4,t=>t.getUTCMinutes()),Y5e=b3.range});var yu,W5e,w3,q5e,z8=R(()=>{"use strict";mu();yu=dn(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*1e3-t.getMinutes()*6e4)},(t,e)=>{t.setTime(+t+e*36e5)},(t,e)=>(e-t)/36e5,t=>t.getHours()),W5e=yu.range,w3=dn(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*36e5)},(t,e)=>(e-t)/36e5,t=>t.getUTCHours()),q5e=w3.range});var Do,X5e,zy,j5e,T3,K5e,G8=R(()=>{"use strict";mu();Do=dn(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*6e4)/864e5,t=>t.getDate()-1),X5e=Do.range,zy=dn(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/864e5,t=>t.getUTCDate()-1),j5e=zy.range,T3=dn(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/864e5,t=>Math.floor(t/864e5)),K5e=T3.range});function fd(t){return dn(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(e,r)=>{e.setDate(e.getDate()+r*7)},(e,r)=>(r-e-(r.getTimezoneOffset()-e.getTimezoneOffset())*6e4)/6048e5)}function dd(t){return dn(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(e,r)=>{e.setUTCDate(e.getUTCDate()+r*7)},(e,r)=>(r-e)/6048e5)}var yl,_h,k3,E3,cc,C3,S3,JH,Q5e,Z5e,J5e,ewe,twe,rwe,pd,Bp,eY,tY,Lh,rY,nY,iY,nwe,iwe,awe,swe,owe,lwe,$8=R(()=>{"use strict";mu();o(fd,"timeWeekday");yl=fd(0),_h=fd(1),k3=fd(2),E3=fd(3),cc=fd(4),C3=fd(5),S3=fd(6),JH=yl.range,Q5e=_h.range,Z5e=k3.range,J5e=E3.range,ewe=cc.range,twe=C3.range,rwe=S3.range;o(dd,"utcWeekday");pd=dd(0),Bp=dd(1),eY=dd(2),tY=dd(3),Lh=dd(4),rY=dd(5),nY=dd(6),iY=pd.range,nwe=Bp.range,iwe=eY.range,awe=tY.range,swe=Lh.range,owe=rY.range,lwe=nY.range});var vu,cwe,A3,uwe,V8=R(()=>{"use strict";mu();vu=dn(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+(e.getFullYear()-t.getFullYear())*12,t=>t.getMonth()),cwe=vu.range,A3=dn(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+(e.getUTCFullYear()-t.getUTCFullYear())*12,t=>t.getUTCMonth()),uwe=A3.range});var Qs,hwe,vl,fwe,U8=R(()=>{"use strict";mu();Qs=dn(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());Qs.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:dn(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,r)=>{e.setFullYear(e.getFullYear()+r*t)});hwe=Qs.range,vl=dn(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());vl.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:dn(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,r)=>{e.setUTCFullYear(e.getUTCFullYear()+r*t)});fwe=vl.range});function sY(t,e,r,n,i,a){let s=[[Ks,1,1e3],[Ks,5,5*1e3],[Ks,15,15*1e3],[Ks,30,30*1e3],[a,1,6e4],[a,5,5*6e4],[a,15,15*6e4],[a,30,30*6e4],[i,1,36e5],[i,3,3*36e5],[i,6,6*36e5],[i,12,12*36e5],[n,1,864e5],[n,2,2*864e5],[r,1,6048e5],[e,1,2592e6],[e,3,3*2592e6],[t,1,31536e6]];function l(h,f,d){let p=fv).right(s,p);if(m===s.length)return t.every(Tp(h/31536e6,f/31536e6,d));if(m===0)return oc.every(Math.max(Tp(h,f,d),1));let[g,y]=s[p/s[m-1][2]{"use strict";bh();P8();B8();F8();z8();G8();$8();V8();U8();o(sY,"ticker");[pwe,mwe]=sY(vl,A3,pd,T3,w3,b3),[H8,Y8]=sY(Qs,vu,yl,Do,yu,gu)});var _3=R(()=>{"use strict";P8();B8();F8();z8();G8();$8();V8();U8();oY()});function W8(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function q8(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Gy(t,e,r){return{y:t,m:e,d:r,H:0,M:0,S:0,L:0}}function X8(t){var e=t.dateTime,r=t.date,n=t.time,i=t.periods,a=t.days,s=t.shortDays,l=t.months,u=t.shortMonths,h=$y(i),f=Vy(i),d=$y(a),p=Vy(a),m=$y(s),g=Vy(s),y=$y(l),v=Vy(l),x=$y(u),b=Vy(u),w={a:P,A:F,b:B,B:$,c:null,d:dY,e:dY,f:Fwe,g:Xwe,G:Kwe,H:Owe,I:Pwe,j:Bwe,L:vY,m:zwe,M:Gwe,p:z,q:Y,Q:gY,s:yY,S:$we,u:Vwe,U:Uwe,V:Hwe,w:Ywe,W:Wwe,x:null,X:null,y:qwe,Y:jwe,Z:Qwe,"%":mY},S={a:Q,A:X,b:ie,B:j,c:null,d:pY,e:pY,f:tTe,g:hTe,G:dTe,H:Zwe,I:Jwe,j:eTe,L:bY,m:rTe,M:nTe,p:J,q:Z,Q:gY,s:yY,S:iTe,u:aTe,U:sTe,V:oTe,w:lTe,W:cTe,x:null,X:null,y:uTe,Y:fTe,Z:pTe,"%":mY},T={a:M,A:N,b:k,B:I,c:C,d:hY,e:hY,f:Rwe,g:uY,G:cY,H:fY,I:fY,j:Awe,L:Dwe,m:Swe,M:_we,p:L,q:Cwe,Q:Mwe,s:Iwe,S:Lwe,u:bwe,U:wwe,V:Twe,w:xwe,W:kwe,x:O,X:D,y:uY,Y:cY,Z:Ewe,"%":Nwe};w.x=E(r,w),w.X=E(n,w),w.c=E(e,w),S.x=E(r,S),S.X=E(n,S),S.c=E(e,S);function E(H,q){return function(K){var se=[],ce=-1,ue=0,te=H.length,De,oe,ke;for(K instanceof Date||(K=new Date(+K));++ce53)return null;"w"in se||(se.w=1),"Z"in se?(ue=q8(Gy(se.y,0,1)),te=ue.getUTCDay(),ue=te>4||te===0?Bp.ceil(ue):Bp(ue),ue=zy.offset(ue,(se.V-1)*7),se.y=ue.getUTCFullYear(),se.m=ue.getUTCMonth(),se.d=ue.getUTCDate()+(se.w+6)%7):(ue=W8(Gy(se.y,0,1)),te=ue.getDay(),ue=te>4||te===0?_h.ceil(ue):_h(ue),ue=Do.offset(ue,(se.V-1)*7),se.y=ue.getFullYear(),se.m=ue.getMonth(),se.d=ue.getDate()+(se.w+6)%7)}else("W"in se||"U"in se)&&("w"in se||(se.w="u"in se?se.u%7:"W"in se?1:0),te="Z"in se?q8(Gy(se.y,0,1)).getUTCDay():W8(Gy(se.y,0,1)).getDay(),se.m=0,se.d="W"in se?(se.w+6)%7+se.W*7-(te+5)%7:se.w+se.U*7-(te+6)%7);return"Z"in se?(se.H+=se.Z/100|0,se.M+=se.Z%100,q8(se)):W8(se)}}o(_,"newParse");function A(H,q,K,se){for(var ce=0,ue=q.length,te=K.length,De,oe;ce=te)return-1;if(De=q.charCodeAt(ce++),De===37){if(De=q.charAt(ce++),oe=T[De in lY?q.charAt(ce++):De],!oe||(se=oe(H,K,se))<0)return-1}else if(De!=K.charCodeAt(se++))return-1}return se}o(A,"parseSpecifier");function L(H,q,K){var se=h.exec(q.slice(K));return se?(H.p=f.get(se[0].toLowerCase()),K+se[0].length):-1}o(L,"parsePeriod");function M(H,q,K){var se=m.exec(q.slice(K));return se?(H.w=g.get(se[0].toLowerCase()),K+se[0].length):-1}o(M,"parseShortWeekday");function N(H,q,K){var se=d.exec(q.slice(K));return se?(H.w=p.get(se[0].toLowerCase()),K+se[0].length):-1}o(N,"parseWeekday");function k(H,q,K){var se=x.exec(q.slice(K));return se?(H.m=b.get(se[0].toLowerCase()),K+se[0].length):-1}o(k,"parseShortMonth");function I(H,q,K){var se=y.exec(q.slice(K));return se?(H.m=v.get(se[0].toLowerCase()),K+se[0].length):-1}o(I,"parseMonth");function C(H,q,K){return A(H,e,q,K)}o(C,"parseLocaleDateTime");function O(H,q,K){return A(H,r,q,K)}o(O,"parseLocaleDate");function D(H,q,K){return A(H,n,q,K)}o(D,"parseLocaleTime");function P(H){return s[H.getDay()]}o(P,"formatShortWeekday");function F(H){return a[H.getDay()]}o(F,"formatWeekday");function B(H){return u[H.getMonth()]}o(B,"formatShortMonth");function $(H){return l[H.getMonth()]}o($,"formatMonth");function z(H){return i[+(H.getHours()>=12)]}o(z,"formatPeriod");function Y(H){return 1+~~(H.getMonth()/3)}o(Y,"formatQuarter");function Q(H){return s[H.getUTCDay()]}o(Q,"formatUTCShortWeekday");function X(H){return a[H.getUTCDay()]}o(X,"formatUTCWeekday");function ie(H){return u[H.getUTCMonth()]}o(ie,"formatUTCShortMonth");function j(H){return l[H.getUTCMonth()]}o(j,"formatUTCMonth");function J(H){return i[+(H.getUTCHours()>=12)]}o(J,"formatUTCPeriod");function Z(H){return 1+~~(H.getUTCMonth()/3)}return o(Z,"formatUTCQuarter"),{format:o(function(H){var q=E(H+="",w);return q.toString=function(){return H},q},"format"),parse:o(function(H){var q=_(H+="",!1);return q.toString=function(){return H},q},"parse"),utcFormat:o(function(H){var q=E(H+="",S);return q.toString=function(){return H},q},"utcFormat"),utcParse:o(function(H){var q=_(H+="",!0);return q.toString=function(){return H},q},"utcParse")}}function Pr(t,e,r){var n=t<0?"-":"",i=(n?-t:t)+"",a=i.length;return n+(a[e.toLowerCase(),r]))}function xwe(t,e,r){var n=Ki.exec(e.slice(r,r+1));return n?(t.w=+n[0],r+n[0].length):-1}function bwe(t,e,r){var n=Ki.exec(e.slice(r,r+1));return n?(t.u=+n[0],r+n[0].length):-1}function wwe(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.U=+n[0],r+n[0].length):-1}function Twe(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.V=+n[0],r+n[0].length):-1}function kwe(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.W=+n[0],r+n[0].length):-1}function cY(t,e,r){var n=Ki.exec(e.slice(r,r+4));return n?(t.y=+n[0],r+n[0].length):-1}function uY(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.y=+n[0]+(+n[0]>68?1900:2e3),r+n[0].length):-1}function Ewe(t,e,r){var n=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(r,r+6));return n?(t.Z=n[1]?0:-(n[2]+(n[3]||"00")),r+n[0].length):-1}function Cwe(t,e,r){var n=Ki.exec(e.slice(r,r+1));return n?(t.q=n[0]*3-3,r+n[0].length):-1}function Swe(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.m=n[0]-1,r+n[0].length):-1}function hY(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.d=+n[0],r+n[0].length):-1}function Awe(t,e,r){var n=Ki.exec(e.slice(r,r+3));return n?(t.m=0,t.d=+n[0],r+n[0].length):-1}function fY(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.H=+n[0],r+n[0].length):-1}function _we(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.M=+n[0],r+n[0].length):-1}function Lwe(t,e,r){var n=Ki.exec(e.slice(r,r+2));return n?(t.S=+n[0],r+n[0].length):-1}function Dwe(t,e,r){var n=Ki.exec(e.slice(r,r+3));return n?(t.L=+n[0],r+n[0].length):-1}function Rwe(t,e,r){var n=Ki.exec(e.slice(r,r+6));return n?(t.L=Math.floor(n[0]/1e3),r+n[0].length):-1}function Nwe(t,e,r){var n=gwe.exec(e.slice(r,r+1));return n?r+n[0].length:-1}function Mwe(t,e,r){var n=Ki.exec(e.slice(r));return n?(t.Q=+n[0],r+n[0].length):-1}function Iwe(t,e,r){var n=Ki.exec(e.slice(r));return n?(t.s=+n[0],r+n[0].length):-1}function dY(t,e){return Pr(t.getDate(),e,2)}function Owe(t,e){return Pr(t.getHours(),e,2)}function Pwe(t,e){return Pr(t.getHours()%12||12,e,2)}function Bwe(t,e){return Pr(1+Do.count(Qs(t),t),e,3)}function vY(t,e){return Pr(t.getMilliseconds(),e,3)}function Fwe(t,e){return vY(t,e)+"000"}function zwe(t,e){return Pr(t.getMonth()+1,e,2)}function Gwe(t,e){return Pr(t.getMinutes(),e,2)}function $we(t,e){return Pr(t.getSeconds(),e,2)}function Vwe(t){var e=t.getDay();return e===0?7:e}function Uwe(t,e){return Pr(yl.count(Qs(t)-1,t),e,2)}function xY(t){var e=t.getDay();return e>=4||e===0?cc(t):cc.ceil(t)}function Hwe(t,e){return t=xY(t),Pr(cc.count(Qs(t),t)+(Qs(t).getDay()===4),e,2)}function Ywe(t){return t.getDay()}function Wwe(t,e){return Pr(_h.count(Qs(t)-1,t),e,2)}function qwe(t,e){return Pr(t.getFullYear()%100,e,2)}function Xwe(t,e){return t=xY(t),Pr(t.getFullYear()%100,e,2)}function jwe(t,e){return Pr(t.getFullYear()%1e4,e,4)}function Kwe(t,e){var r=t.getDay();return t=r>=4||r===0?cc(t):cc.ceil(t),Pr(t.getFullYear()%1e4,e,4)}function Qwe(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Pr(e/60|0,"0",2)+Pr(e%60,"0",2)}function pY(t,e){return Pr(t.getUTCDate(),e,2)}function Zwe(t,e){return Pr(t.getUTCHours(),e,2)}function Jwe(t,e){return Pr(t.getUTCHours()%12||12,e,2)}function eTe(t,e){return Pr(1+zy.count(vl(t),t),e,3)}function bY(t,e){return Pr(t.getUTCMilliseconds(),e,3)}function tTe(t,e){return bY(t,e)+"000"}function rTe(t,e){return Pr(t.getUTCMonth()+1,e,2)}function nTe(t,e){return Pr(t.getUTCMinutes(),e,2)}function iTe(t,e){return Pr(t.getUTCSeconds(),e,2)}function aTe(t){var e=t.getUTCDay();return e===0?7:e}function sTe(t,e){return Pr(pd.count(vl(t)-1,t),e,2)}function wY(t){var e=t.getUTCDay();return e>=4||e===0?Lh(t):Lh.ceil(t)}function oTe(t,e){return t=wY(t),Pr(Lh.count(vl(t),t)+(vl(t).getUTCDay()===4),e,2)}function lTe(t){return t.getUTCDay()}function cTe(t,e){return Pr(Bp.count(vl(t)-1,t),e,2)}function uTe(t,e){return Pr(t.getUTCFullYear()%100,e,2)}function hTe(t,e){return t=wY(t),Pr(t.getUTCFullYear()%100,e,2)}function fTe(t,e){return Pr(t.getUTCFullYear()%1e4,e,4)}function dTe(t,e){var r=t.getUTCDay();return t=r>=4||r===0?Lh(t):Lh.ceil(t),Pr(t.getUTCFullYear()%1e4,e,4)}function pTe(){return"+0000"}function mY(){return"%"}function gY(t){return+t}function yY(t){return Math.floor(+t/1e3)}var lY,Ki,gwe,ywe,TY=R(()=>{"use strict";_3();o(W8,"localDate");o(q8,"utcDate");o(Gy,"newDate");o(X8,"formatLocale");lY={"-":"",_:" ",0:"0"},Ki=/^\s*\d+/,gwe=/^%/,ywe=/[\\^$*+?|[\]().{}]/g;o(Pr,"pad");o(vwe,"requote");o($y,"formatRe");o(Vy,"formatLookup");o(xwe,"parseWeekdayNumberSunday");o(bwe,"parseWeekdayNumberMonday");o(wwe,"parseWeekNumberSunday");o(Twe,"parseWeekNumberISO");o(kwe,"parseWeekNumberMonday");o(cY,"parseFullYear");o(uY,"parseYear");o(Ewe,"parseZone");o(Cwe,"parseQuarter");o(Swe,"parseMonthNumber");o(hY,"parseDayOfMonth");o(Awe,"parseDayOfYear");o(fY,"parseHour24");o(_we,"parseMinutes");o(Lwe,"parseSeconds");o(Dwe,"parseMilliseconds");o(Rwe,"parseMicroseconds");o(Nwe,"parseLiteralPercent");o(Mwe,"parseUnixTimestamp");o(Iwe,"parseUnixTimestampSeconds");o(dY,"formatDayOfMonth");o(Owe,"formatHour24");o(Pwe,"formatHour12");o(Bwe,"formatDayOfYear");o(vY,"formatMilliseconds");o(Fwe,"formatMicroseconds");o(zwe,"formatMonthNumber");o(Gwe,"formatMinutes");o($we,"formatSeconds");o(Vwe,"formatWeekdayNumberMonday");o(Uwe,"formatWeekNumberSunday");o(xY,"dISO");o(Hwe,"formatWeekNumberISO");o(Ywe,"formatWeekdayNumberSunday");o(Wwe,"formatWeekNumberMonday");o(qwe,"formatYear");o(Xwe,"formatYearISO");o(jwe,"formatFullYear");o(Kwe,"formatFullYearISO");o(Qwe,"formatZone");o(pY,"formatUTCDayOfMonth");o(Zwe,"formatUTCHour24");o(Jwe,"formatUTCHour12");o(eTe,"formatUTCDayOfYear");o(bY,"formatUTCMilliseconds");o(tTe,"formatUTCMicroseconds");o(rTe,"formatUTCMonthNumber");o(nTe,"formatUTCMinutes");o(iTe,"formatUTCSeconds");o(aTe,"formatUTCWeekdayNumberMonday");o(sTe,"formatUTCWeekNumberSunday");o(wY,"UTCdISO");o(oTe,"formatUTCWeekNumberISO");o(lTe,"formatUTCWeekdayNumberSunday");o(cTe,"formatUTCWeekNumberMonday");o(uTe,"formatUTCYear");o(hTe,"formatUTCYearISO");o(fTe,"formatUTCFullYear");o(dTe,"formatUTCFullYearISO");o(pTe,"formatUTCZone");o(mY,"formatLiteralPercent");o(gY,"formatUnixTimestamp");o(yY,"formatUnixTimestampSeconds")});function j8(t){return Fp=X8(t),md=Fp.format,kY=Fp.parse,EY=Fp.utcFormat,CY=Fp.utcParse,Fp}var Fp,md,kY,EY,CY,SY=R(()=>{"use strict";TY();j8({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});o(j8,"defaultLocale")});var K8=R(()=>{"use strict";SY()});function mTe(t){return new Date(t)}function gTe(t){return t instanceof Date?+t:+new Date(+t)}function AY(t,e,r,n,i,a,s,l,u,h){var f=By(),d=f.invert,p=f.domain,m=h(".%L"),g=h(":%S"),y=h("%I:%M"),v=h("%I %p"),x=h("%a %d"),b=h("%b %d"),w=h("%B"),S=h("%Y");function T(E){return(u(E){"use strict";_3();K8();R8();Py();jH();o(mTe,"date");o(gTe,"number");o(AY,"calendar");o(L3,"time")});var LY=R(()=>{"use strict";UH();XH();A8();_Y()});function Q8(t){for(var e=t.length/6|0,r=new Array(e),n=0;n{"use strict";o(Q8,"default")});var Z8,RY=R(()=>{"use strict";DY();Z8=Q8("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab")});var NY=R(()=>{"use strict";RY()});function Nn(t){return o(function(){return t},"constant")}var D3=R(()=>{"use strict";o(Nn,"default")});function IY(t){return t>1?0:t<-1?zp:Math.acos(t)}function e_(t){return t>=1?Uy:t<=-1?-Uy:Math.asin(t)}var J8,ua,Dh,MY,R3,xl,gd,Qi,zp,Uy,Gp,N3=R(()=>{"use strict";J8=Math.abs,ua=Math.atan2,Dh=Math.cos,MY=Math.max,R3=Math.min,xl=Math.sin,gd=Math.sqrt,Qi=1e-12,zp=Math.PI,Uy=zp/2,Gp=2*zp;o(IY,"acos");o(e_,"asin")});function M3(t){let e=3;return t.digits=function(r){if(!arguments.length)return e;if(r==null)e=null;else{let n=Math.floor(r);if(!(n>=0))throw new RangeError(`invalid digits: ${r}`);e=n}return t},()=>new ld(e)}var t_=R(()=>{"use strict";d8();o(M3,"withPath")});function yTe(t){return t.innerRadius}function vTe(t){return t.outerRadius}function xTe(t){return t.startAngle}function bTe(t){return t.endAngle}function wTe(t){return t&&t.padAngle}function TTe(t,e,r,n,i,a,s,l){var u=r-t,h=n-e,f=s-i,d=l-a,p=d*u-f*h;if(!(p*pC*C+O*O&&(A=M,L=N),{cx:A,cy:L,x01:-f,y01:-d,x11:A*(i/T-1),y11:L*(i/T-1)}}function bl(){var t=yTe,e=vTe,r=Nn(0),n=null,i=xTe,a=bTe,s=wTe,l=null,u=M3(h);function h(){var f,d,p=+t.apply(this,arguments),m=+e.apply(this,arguments),g=i.apply(this,arguments)-Uy,y=a.apply(this,arguments)-Uy,v=J8(y-g),x=y>g;if(l||(l=f=u()),mQi))l.moveTo(0,0);else if(v>Gp-Qi)l.moveTo(m*Dh(g),m*xl(g)),l.arc(0,0,m,g,y,!x),p>Qi&&(l.moveTo(p*Dh(y),p*xl(y)),l.arc(0,0,p,y,g,x));else{var b=g,w=y,S=g,T=y,E=v,_=v,A=s.apply(this,arguments)/2,L=A>Qi&&(n?+n.apply(this,arguments):gd(p*p+m*m)),M=R3(J8(m-p)/2,+r.apply(this,arguments)),N=M,k=M,I,C;if(L>Qi){var O=e_(L/p*xl(A)),D=e_(L/m*xl(A));(E-=O*2)>Qi?(O*=x?1:-1,S+=O,T-=O):(E=0,S=T=(g+y)/2),(_-=D*2)>Qi?(D*=x?1:-1,b+=D,w-=D):(_=0,b=w=(g+y)/2)}var P=m*Dh(b),F=m*xl(b),B=p*Dh(T),$=p*xl(T);if(M>Qi){var z=m*Dh(w),Y=m*xl(w),Q=p*Dh(S),X=p*xl(S),ie;if(vQi?k>Qi?(I=I3(Q,X,P,F,m,k,x),C=I3(z,Y,B,$,m,k,x),l.moveTo(I.cx+I.x01,I.cy+I.y01),kQi)||!(E>Qi)?l.lineTo(B,$):N>Qi?(I=I3(B,$,z,Y,p,-N,x),C=I3(P,F,Q,X,p,-N,x),l.lineTo(I.cx+I.x01,I.cy+I.y01),N{"use strict";D3();N3();t_();o(yTe,"arcInnerRadius");o(vTe,"arcOuterRadius");o(xTe,"arcStartAngle");o(bTe,"arcEndAngle");o(wTe,"arcPadAngle");o(TTe,"intersect");o(I3,"cornerTangents");o(bl,"default")});function Hy(t){return typeof t=="object"&&"length"in t?t:Array.from(t)}var Dyt,r_=R(()=>{"use strict";Dyt=Array.prototype.slice;o(Hy,"default")});function PY(t){this._context=t}function xu(t){return new PY(t)}var n_=R(()=>{"use strict";o(PY,"Linear");PY.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._point=0},"lineStart"),lineEnd:o(function(){(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._context.lineTo(t,e);break}},"point")};o(xu,"default")});function BY(t){return t[0]}function FY(t){return t[1]}var zY=R(()=>{"use strict";o(BY,"x");o(FY,"y")});function ha(t,e){var r=Nn(!0),n=null,i=xu,a=null,s=M3(l);t=typeof t=="function"?t:t===void 0?BY:Nn(t),e=typeof e=="function"?e:e===void 0?FY:Nn(e);function l(u){var h,f=(u=Hy(u)).length,d,p=!1,m;for(n==null&&(a=i(m=s())),h=0;h<=f;++h)!(h{"use strict";r_();D3();n_();t_();zY();o(ha,"default")});function i_(t,e){return et?1:e>=t?0:NaN}var $Y=R(()=>{"use strict";o(i_,"default")});function a_(t){return t}var VY=R(()=>{"use strict";o(a_,"default")});function O3(){var t=a_,e=i_,r=null,n=Nn(0),i=Nn(Gp),a=Nn(0);function s(l){var u,h=(l=Hy(l)).length,f,d,p=0,m=new Array(h),g=new Array(h),y=+n.apply(this,arguments),v=Math.min(Gp,Math.max(-Gp,i.apply(this,arguments)-y)),x,b=Math.min(Math.abs(v)/h,a.apply(this,arguments)),w=b*(v<0?-1:1),S;for(u=0;u0&&(p+=S);for(e!=null?m.sort(function(T,E){return e(g[T],g[E])}):r!=null&&m.sort(function(T,E){return r(l[T],l[E])}),u=0,d=p?(v-h*w)/p:0;u0?S*d:0)+w,g[f]={data:l[f],index:u,value:S,startAngle:y,endAngle:x,padAngle:b};return g}return o(s,"pie"),s.value=function(l){return arguments.length?(t=typeof l=="function"?l:Nn(+l),s):t},s.sortValues=function(l){return arguments.length?(e=l,r=null,s):e},s.sort=function(l){return arguments.length?(r=l,e=null,s):r},s.startAngle=function(l){return arguments.length?(n=typeof l=="function"?l:Nn(+l),s):n},s.endAngle=function(l){return arguments.length?(i=typeof l=="function"?l:Nn(+l),s):i},s.padAngle=function(l){return arguments.length?(a=typeof l=="function"?l:Nn(+l),s):a},s}var UY=R(()=>{"use strict";r_();D3();$Y();VY();N3();o(O3,"default")});function s_(t){return new P3(t,!0)}function o_(t){return new P3(t,!1)}var P3,HY=R(()=>{"use strict";P3=class{static{o(this,"Bump")}constructor(e,r){this._context=e,this._x=r}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line}point(e,r){switch(e=+e,r=+r,this._point){case 0:{this._point=1,this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break}case 1:this._point=2;default:{this._x?this._context.bezierCurveTo(this._x0=(this._x0+e)/2,this._y0,this._x0,r,e,r):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+r)/2,e,this._y0,e,r);break}}this._x0=e,this._y0=r}};o(s_,"bumpX");o(o_,"bumpY")});function Zs(){}var Yy=R(()=>{"use strict";o(Zs,"default")});function $p(t,e,r){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+r)/6)}function Wy(t){this._context=t}function vs(t){return new Wy(t)}var qy=R(()=>{"use strict";o($p,"point");o(Wy,"Basis");Wy.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 3:$p(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:$p(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e},"point")};o(vs,"default")});function YY(t){this._context=t}function B3(t){return new YY(t)}var WY=R(()=>{"use strict";Yy();qy();o(YY,"BasisClosed");YY.prototype={areaStart:Zs,areaEnd:Zs,lineStart:o(function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 1:{this._context.moveTo(this._x2,this._y2),this._context.closePath();break}case 2:{this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break}case 3:{this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4);break}}},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:$p(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e},"point")};o(B3,"default")});function qY(t){this._context=t}function F3(t){return new qY(t)}var XY=R(()=>{"use strict";qy();o(qY,"BasisOpen");qY.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},"lineStart"),lineEnd:o(function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var r=(this._x0+4*this._x1+t)/6,n=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(r,n):this._context.moveTo(r,n);break;case 3:this._point=4;default:$p(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e},"point")};o(F3,"default")});function jY(t,e){this._basis=new Wy(t),this._beta=e}var l_,KY=R(()=>{"use strict";qy();o(jY,"Bundle");jY.prototype={lineStart:o(function(){this._x=[],this._y=[],this._basis.lineStart()},"lineStart"),lineEnd:o(function(){var t=this._x,e=this._y,r=t.length-1;if(r>0)for(var n=t[0],i=e[0],a=t[r]-n,s=e[r]-i,l=-1,u;++l<=r;)u=l/r,this._basis.point(this._beta*t[l]+(1-this._beta)*(n+u*a),this._beta*e[l]+(1-this._beta)*(i+u*s));this._x=this._y=null,this._basis.lineEnd()},"lineEnd"),point:o(function(t,e){this._x.push(+t),this._y.push(+e)},"point")};l_=o(function t(e){function r(n){return e===1?new Wy(n):new jY(n,e)}return o(r,"bundle"),r.beta=function(n){return t(+n)},r},"custom")(.85)});function Vp(t,e,r){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-r),t._x2,t._y2)}function z3(t,e){this._context=t,this._k=(1-e)/6}var c_,Xy=R(()=>{"use strict";o(Vp,"point");o(z3,"Cardinal");z3.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Vp(this,this._x1,this._y1);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:Vp(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e},"point")};c_=o(function t(e){function r(n){return new z3(n,e)}return o(r,"cardinal"),r.tension=function(n){return t(+n)},r},"custom")(0)});function G3(t,e){this._context=t,this._k=(1-e)/6}var u_,h_=R(()=>{"use strict";Yy();Xy();o(G3,"CardinalClosed");G3.prototype={areaStart:Zs,areaEnd:Zs,lineStart:o(function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 1:{this._context.moveTo(this._x3,this._y3),this._context.closePath();break}case 2:{this._context.lineTo(this._x3,this._y3),this._context.closePath();break}case 3:{this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5);break}}},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Vp(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e},"point")};u_=o(function t(e){function r(n){return new G3(n,e)}return o(r,"cardinal"),r.tension=function(n){return t(+n)},r},"custom")(0)});function $3(t,e){this._context=t,this._k=(1-e)/6}var f_,d_=R(()=>{"use strict";Xy();o($3,"CardinalOpen");$3.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},"lineStart"),lineEnd:o(function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Vp(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e},"point")};f_=o(function t(e){function r(n){return new $3(n,e)}return o(r,"cardinal"),r.tension=function(n){return t(+n)},r},"custom")(0)});function jy(t,e,r){var n=t._x1,i=t._y1,a=t._x2,s=t._y2;if(t._l01_a>Qi){var l=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,u=3*t._l01_a*(t._l01_a+t._l12_a);n=(n*l-t._x0*t._l12_2a+t._x2*t._l01_2a)/u,i=(i*l-t._y0*t._l12_2a+t._y2*t._l01_2a)/u}if(t._l23_a>Qi){var h=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);a=(a*h+t._x1*t._l23_2a-e*t._l12_2a)/f,s=(s*h+t._y1*t._l23_2a-r*t._l12_2a)/f}t._context.bezierCurveTo(n,i,a,s,t._x2,t._y2)}function QY(t,e){this._context=t,this._alpha=e}var p_,V3=R(()=>{"use strict";N3();Xy();o(jy,"point");o(QY,"CatmullRom");QY.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){if(t=+t,e=+e,this._point){var r=this._x2-t,n=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(r*r+n*n,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:jy(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e},"point")};p_=o(function t(e){function r(n){return e?new QY(n,e):new z3(n,0)}return o(r,"catmullRom"),r.alpha=function(n){return t(+n)},r},"custom")(.5)});function ZY(t,e){this._context=t,this._alpha=e}var m_,JY=R(()=>{"use strict";h_();Yy();V3();o(ZY,"CatmullRomClosed");ZY.prototype={areaStart:Zs,areaEnd:Zs,lineStart:o(function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 1:{this._context.moveTo(this._x3,this._y3),this._context.closePath();break}case 2:{this._context.lineTo(this._x3,this._y3),this._context.closePath();break}case 3:{this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5);break}}},"lineEnd"),point:o(function(t,e){if(t=+t,e=+e,this._point){var r=this._x2-t,n=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(r*r+n*n,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:jy(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e},"point")};m_=o(function t(e){function r(n){return e?new ZY(n,e):new G3(n,0)}return o(r,"catmullRom"),r.alpha=function(n){return t(+n)},r},"custom")(.5)});function eW(t,e){this._context=t,this._alpha=e}var g_,tW=R(()=>{"use strict";d_();V3();o(eW,"CatmullRomOpen");eW.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},"lineStart"),lineEnd:o(function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){if(t=+t,e=+e,this._point){var r=this._x2-t,n=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(r*r+n*n,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:jy(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e},"point")};g_=o(function t(e){function r(n){return e?new eW(n,e):new $3(n,0)}return o(r,"catmullRom"),r.alpha=function(n){return t(+n)},r},"custom")(.5)});function rW(t){this._context=t}function U3(t){return new rW(t)}var nW=R(()=>{"use strict";Yy();o(rW,"LinearClosed");rW.prototype={areaStart:Zs,areaEnd:Zs,lineStart:o(function(){this._point=0},"lineStart"),lineEnd:o(function(){this._point&&this._context.closePath()},"lineEnd"),point:o(function(t,e){t=+t,e=+e,this._point?this._context.lineTo(t,e):(this._point=1,this._context.moveTo(t,e))},"point")};o(U3,"default")});function iW(t){return t<0?-1:1}function aW(t,e,r){var n=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(n||i<0&&-0),s=(r-t._y1)/(i||n<0&&-0),l=(a*i+s*n)/(n+i);return(iW(a)+iW(s))*Math.min(Math.abs(a),Math.abs(s),.5*Math.abs(l))||0}function sW(t,e){var r=t._x1-t._x0;return r?(3*(t._y1-t._y0)/r-e)/2:e}function y_(t,e,r){var n=t._x0,i=t._y0,a=t._x1,s=t._y1,l=(a-n)/3;t._context.bezierCurveTo(n+l,i+l*e,a-l,s-l*r,a,s)}function H3(t){this._context=t}function oW(t){this._context=new lW(t)}function lW(t){this._context=t}function v_(t){return new H3(t)}function x_(t){return new oW(t)}var cW=R(()=>{"use strict";o(iW,"sign");o(aW,"slope3");o(sW,"slope2");o(y_,"point");o(H3,"MonotoneX");H3.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},"lineStart"),lineEnd:o(function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:y_(this,this._t0,sW(this,this._t0));break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},"lineEnd"),point:o(function(t,e){var r=NaN;if(t=+t,e=+e,!(t===this._x1&&e===this._y1)){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,y_(this,sW(this,r=aW(this,t,e)),r);break;default:y_(this,this._t0,r=aW(this,t,e));break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e,this._t0=r}},"point")};o(oW,"MonotoneY");(oW.prototype=Object.create(H3.prototype)).point=function(t,e){H3.prototype.point.call(this,e,t)};o(lW,"ReflectContext");lW.prototype={moveTo:o(function(t,e){this._context.moveTo(e,t)},"moveTo"),closePath:o(function(){this._context.closePath()},"closePath"),lineTo:o(function(t,e){this._context.lineTo(e,t)},"lineTo"),bezierCurveTo:o(function(t,e,r,n,i,a){this._context.bezierCurveTo(e,t,n,r,a,i)},"bezierCurveTo")};o(v_,"monotoneX");o(x_,"monotoneY")});function hW(t){this._context=t}function uW(t){var e,r=t.length-1,n,i=new Array(r),a=new Array(r),s=new Array(r);for(i[0]=0,a[0]=2,s[0]=t[0]+2*t[1],e=1;e=0;--e)i[e]=(s[e]-i[e+1])/a[e];for(a[r-1]=(t[r]+i[r-1])/2,e=0;e{"use strict";o(hW,"Natural");hW.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x=[],this._y=[]},"lineStart"),lineEnd:o(function(){var t=this._x,e=this._y,r=t.length;if(r)if(this._line?this._context.lineTo(t[0],e[0]):this._context.moveTo(t[0],e[0]),r===2)this._context.lineTo(t[1],e[1]);else for(var n=uW(t),i=uW(e),a=0,s=1;s{"use strict";o(W3,"Step");W3.prototype={areaStart:o(function(){this._line=0},"areaStart"),areaEnd:o(function(){this._line=NaN},"areaEnd"),lineStart:o(function(){this._x=this._y=NaN,this._point=0},"lineStart"),lineEnd:o(function(){0=0&&(this._t=1-this._t,this._line=1-this._line)},"lineEnd"),point:o(function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:{if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var r=this._x*(1-this._t)+t*this._t;this._context.lineTo(r,this._y),this._context.lineTo(r,e)}break}}this._x=t,this._y=e},"point")};o(q3,"default");o(b_,"stepBefore");o(w_,"stepAfter")});var pW=R(()=>{"use strict";OY();GY();UY();WY();XY();qy();HY();KY();h_();d_();Xy();JY();tW();V3();nW();n_();cW();fW();dW()});var mW=R(()=>{"use strict"});var gW=R(()=>{"use strict"});function Rh(t,e,r){this.k=t,this.x=e,this.y=r}function k_(t){for(;!t.__zoom;)if(!(t=t.parentNode))return T_;return t.__zoom}var T_,E_=R(()=>{"use strict";o(Rh,"Transform");Rh.prototype={constructor:Rh,scale:o(function(t){return t===1?this:new Rh(this.k*t,this.x,this.y)},"scale"),translate:o(function(t,e){return t===0&e===0?this:new Rh(this.k,this.x+this.k*t,this.y+this.k*e)},"translate"),apply:o(function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},"apply"),applyX:o(function(t){return t*this.k+this.x},"applyX"),applyY:o(function(t){return t*this.k+this.y},"applyY"),invert:o(function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},"invert"),invertX:o(function(t){return(t-this.x)/this.k},"invertX"),invertY:o(function(t){return(t-this.y)/this.k},"invertY"),rescaleX:o(function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},"rescaleX"),rescaleY:o(function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},"rescaleY"),toString:o(function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"},"toString")};T_=new Rh(1,0,0);k_.prototype=Rh.prototype;o(k_,"transform")});var yW=R(()=>{"use strict"});var vW=R(()=>{"use strict";c3();mW();gW();E_();yW()});var xW=R(()=>{"use strict";vW();E_()});var Zt=R(()=>{"use strict";bh();K$();mH();xH();Lp();bH();wH();bS();$V();TH();l8();kH();CH();C8();zH();GH();Np();d8();$H();EH();VH();LY();NY();fl();pW();_3();K8();n3();c3();xW()});var bW=gi(Zi=>{"use strict";Object.defineProperty(Zi,"__esModule",{value:!0});Zi.BLANK_URL=Zi.relativeFirstCharacters=Zi.whitespaceEscapeCharsRegex=Zi.urlSchemeRegex=Zi.ctrlCharactersRegex=Zi.htmlCtrlEntityRegex=Zi.htmlEntitiesRegex=Zi.invalidProtocolRegex=void 0;Zi.invalidProtocolRegex=/^([^\w]*)(javascript|data|vbscript)/im;Zi.htmlEntitiesRegex=/&#(\w+)(^\w|;)?/g;Zi.htmlCtrlEntityRegex=/&(newline|tab);/gi;Zi.ctrlCharactersRegex=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim;Zi.urlSchemeRegex=/^.+(:|:)/gim;Zi.whitespaceEscapeCharsRegex=/(\\|%5[cC])((%(6[eE]|72|74))|[nrt])/g;Zi.relativeFirstCharacters=[".","/"];Zi.BLANK_URL="about:blank"});var Up=gi(X3=>{"use strict";Object.defineProperty(X3,"__esModule",{value:!0});X3.sanitizeUrl=void 0;var Na=bW();function kTe(t){return Na.relativeFirstCharacters.indexOf(t[0])>-1}o(kTe,"isRelativeUrlWithoutProtocol");function ETe(t){var e=t.replace(Na.ctrlCharactersRegex,"");return e.replace(Na.htmlEntitiesRegex,function(r,n){return String.fromCharCode(n)})}o(ETe,"decodeHtmlCharacters");function CTe(t){return URL.canParse(t)}o(CTe,"isValidUrl");function wW(t){try{return decodeURIComponent(t)}catch{return t}}o(wW,"decodeURI");function STe(t){if(!t)return Na.BLANK_URL;var e,r=wW(t.trim());do r=ETe(r).replace(Na.htmlCtrlEntityRegex,"").replace(Na.ctrlCharactersRegex,"").replace(Na.whitespaceEscapeCharsRegex,"").trim(),r=wW(r),e=r.match(Na.ctrlCharactersRegex)||r.match(Na.htmlEntitiesRegex)||r.match(Na.htmlCtrlEntityRegex)||r.match(Na.whitespaceEscapeCharsRegex);while(e&&e.length>0);var n=r;if(!n)return Na.BLANK_URL;if(kTe(n))return n;var i=n.trimStart(),a=i.match(Na.urlSchemeRegex);if(!a)return n;var s=a[0].toLowerCase().trim();if(Na.invalidProtocolRegex.test(s))return Na.BLANK_URL;var l=i.replace(/\\/g,"/");if(s==="mailto:"||s.includes("://"))return l;if(s==="http:"||s==="https:"){if(!CTe(l))return Na.BLANK_URL;var u=new URL(l);return u.protocol=u.protocol.toLowerCase(),u.hostname=u.hostname.toLowerCase(),u.toString()}return l}o(STe,"sanitizeUrl");X3.sanitizeUrl=STe});var C_,yd,j3,TW,kW,EW,wl,Ky,Qy=R(()=>{"use strict";C_=Xi(Up(),1);rr();yd=o((t,e)=>{let r=t.append("rect");if(r.attr("x",e.x),r.attr("y",e.y),r.attr("fill",e.fill),r.attr("stroke",e.stroke),r.attr("width",e.width),r.attr("height",e.height),e.name&&r.attr("name",e.name),e.rx&&r.attr("rx",e.rx),e.ry&&r.attr("ry",e.ry),e.attrs!==void 0)for(let n in e.attrs)r.attr(n,e.attrs[n]);return e.class&&r.attr("class",e.class),r},"drawRect"),j3=o((t,e)=>{let r={x:e.startx,y:e.starty,width:e.stopx-e.startx,height:e.stopy-e.starty,fill:e.fill,stroke:e.stroke,class:"rect"};yd(t,r).lower()},"drawBackgroundRect"),TW=o((t,e)=>{let r=e.text.replace(Qf," "),n=t.append("text");n.attr("x",e.x),n.attr("y",e.y),n.attr("class","legend"),n.style("text-anchor",e.anchor),e.class&&n.attr("class",e.class);let i=n.append("tspan");return i.attr("x",e.x+e.textMargin*2),i.text(r),n},"drawText"),kW=o((t,e,r,n)=>{let i=t.append("image");i.attr("x",e),i.attr("y",r);let a=(0,C_.sanitizeUrl)(n);i.attr("xlink:href",a)},"drawImage"),EW=o((t,e,r,n)=>{let i=t.append("use");i.attr("x",e),i.attr("y",r);let a=(0,C_.sanitizeUrl)(n);i.attr("xlink:href",`#${a}`)},"drawEmbeddedImage"),wl=o(()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0}),"getNoteRect"),Ky=o(()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0}),"getTextObj")});var CW,S_,SW,ATe,_Te,LTe,DTe,RTe,NTe,MTe,ITe,OTe,PTe,BTe,FTe,bu,Tl,AW=R(()=>{"use strict";rr();Qy();CW=Xi(Up(),1),S_=o(function(t,e){return yd(t,e)},"drawRect"),SW=o(function(t,e,r,n,i,a){let s=t.append("image");s.attr("width",e),s.attr("height",r),s.attr("x",n),s.attr("y",i);let l=a.startsWith("data:image/png;base64")?a:(0,CW.sanitizeUrl)(a);s.attr("xlink:href",l)},"drawImage"),ATe=o((t,e,r)=>{let n=t.append("g"),i=0;for(let a of e){let s=a.textColor?a.textColor:"#444444",l=a.lineColor?a.lineColor:"#444444",u=a.offsetX?parseInt(a.offsetX):0,h=a.offsetY?parseInt(a.offsetY):0,f="";if(i===0){let p=n.append("line");p.attr("x1",a.startPoint.x),p.attr("y1",a.startPoint.y),p.attr("x2",a.endPoint.x),p.attr("y2",a.endPoint.y),p.attr("stroke-width","1"),p.attr("stroke",l),p.style("fill","none"),a.type!=="rel_b"&&p.attr("marker-end","url("+f+"#arrowhead)"),(a.type==="birel"||a.type==="rel_b")&&p.attr("marker-start","url("+f+"#arrowend)"),i=-1}else{let p=n.append("path");p.attr("fill","none").attr("stroke-width","1").attr("stroke",l).attr("d","Mstartx,starty Qcontrolx,controly stopx,stopy ".replaceAll("startx",a.startPoint.x).replaceAll("starty",a.startPoint.y).replaceAll("controlx",a.startPoint.x+(a.endPoint.x-a.startPoint.x)/2-(a.endPoint.x-a.startPoint.x)/4).replaceAll("controly",a.startPoint.y+(a.endPoint.y-a.startPoint.y)/2).replaceAll("stopx",a.endPoint.x).replaceAll("stopy",a.endPoint.y)),a.type!=="rel_b"&&p.attr("marker-end","url("+f+"#arrowhead)"),(a.type==="birel"||a.type==="rel_b")&&p.attr("marker-start","url("+f+"#arrowend)")}let d=r.messageFont();bu(r)(a.label.text,n,Math.min(a.startPoint.x,a.endPoint.x)+Math.abs(a.endPoint.x-a.startPoint.x)/2+u,Math.min(a.startPoint.y,a.endPoint.y)+Math.abs(a.endPoint.y-a.startPoint.y)/2+h,a.label.width,a.label.height,{fill:s},d),a.techn&&a.techn.text!==""&&(d=r.messageFont(),bu(r)("["+a.techn.text+"]",n,Math.min(a.startPoint.x,a.endPoint.x)+Math.abs(a.endPoint.x-a.startPoint.x)/2+u,Math.min(a.startPoint.y,a.endPoint.y)+Math.abs(a.endPoint.y-a.startPoint.y)/2+r.messageFontSize+5+h,Math.max(a.label.width,a.techn.width),a.techn.height,{fill:s,"font-style":"italic"},d))}},"drawRels"),_Te=o(function(t,e,r){let n=t.append("g"),i=e.bgColor?e.bgColor:"none",a=e.borderColor?e.borderColor:"#444444",s=e.fontColor?e.fontColor:"black",l={"stroke-width":1,"stroke-dasharray":"7.0,7.0"};e.nodeType&&(l={"stroke-width":1});let u={x:e.x,y:e.y,fill:i,stroke:a,width:e.width,height:e.height,rx:2.5,ry:2.5,attrs:l};S_(n,u);let h=r.boundaryFont();h.fontWeight="bold",h.fontSize=h.fontSize+2,h.fontColor=s,bu(r)(e.label.text,n,e.x,e.y+e.label.Y,e.width,e.height,{fill:"#444444"},h),e.type&&e.type.text!==""&&(h=r.boundaryFont(),h.fontColor=s,bu(r)(e.type.text,n,e.x,e.y+e.type.Y,e.width,e.height,{fill:"#444444"},h)),e.descr&&e.descr.text!==""&&(h=r.boundaryFont(),h.fontSize=h.fontSize-2,h.fontColor=s,bu(r)(e.descr.text,n,e.x,e.y+e.descr.Y,e.width,e.height,{fill:"#444444"},h))},"drawBoundary"),LTe=o(function(t,e,r){let n=e.bgColor?e.bgColor:r[e.typeC4Shape.text+"_bg_color"],i=e.borderColor?e.borderColor:r[e.typeC4Shape.text+"_border_color"],a=e.fontColor?e.fontColor:"#FFFFFF",s="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACD0lEQVR4Xu2YoU4EMRCGT+4j8Ai8AhaH4QHgAUjQuFMECUgMIUgwJAgMhgQsAYUiJCiQIBBY+EITsjfTdme6V24v4c8vyGbb+ZjOtN0bNcvjQXmkH83WvYBWto6PLm6v7p7uH1/w2fXD+PBycX1Pv2l3IdDm/vn7x+dXQiAubRzoURa7gRZWd0iGRIiJbOnhnfYBQZNJjNbuyY2eJG8fkDE3bbG4ep6MHUAsgYxmE3nVs6VsBWJSGccsOlFPmLIViMzLOB7pCVO2AtHJMohH7Fh6zqitQK7m0rJvAVYgGcEpe//PLdDz65sM4pF9N7ICcXDKIB5Nv6j7tD0NoSdM2QrU9Gg0ewE1LqBhHR3BBdvj2vapnidjHxD/q6vd7Pvhr31AwcY8eXMTXAKECZZJFXuEq27aLgQK5uLMohCenGGuGewOxSjBvYBqeG6B+Nqiblggdjnc+ZXDy+FNFpFzw76O3UBAROuXh6FoiAcf5g9eTvUgzy0nWg6I8cXHRUpg5bOVBCo+KDpFajOf23GgPme7RSQ+lacIENUgJ6gg1k6HjgOlqnLqip4tEuhv0hNEMXUD0clyXE3p6pZA0S2nnvTlXwLJEZWlb7cTQH1+USgTN4VhAenm/wea1OCAOmqo6fE1WCb9WSKBah+rbUWPWAmE2Rvk0ApiB45eOyNAzU8xcTvj8KvkKEoOaIYeHNA3ZuygAvFMUO0AAAAASUVORK5CYII=";switch(e.typeC4Shape.text){case"person":s="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACD0lEQVR4Xu2YoU4EMRCGT+4j8Ai8AhaH4QHgAUjQuFMECUgMIUgwJAgMhgQsAYUiJCiQIBBY+EITsjfTdme6V24v4c8vyGbb+ZjOtN0bNcvjQXmkH83WvYBWto6PLm6v7p7uH1/w2fXD+PBycX1Pv2l3IdDm/vn7x+dXQiAubRzoURa7gRZWd0iGRIiJbOnhnfYBQZNJjNbuyY2eJG8fkDE3bbG4ep6MHUAsgYxmE3nVs6VsBWJSGccsOlFPmLIViMzLOB7pCVO2AtHJMohH7Fh6zqitQK7m0rJvAVYgGcEpe//PLdDz65sM4pF9N7ICcXDKIB5Nv6j7tD0NoSdM2QrU9Gg0ewE1LqBhHR3BBdvj2vapnidjHxD/q6vd7Pvhr31AwcY8eXMTXAKECZZJFXuEq27aLgQK5uLMohCenGGuGewOxSjBvYBqeG6B+Nqiblggdjnc+ZXDy+FNFpFzw76O3UBAROuXh6FoiAcf5g9eTvUgzy0nWg6I8cXHRUpg5bOVBCo+KDpFajOf23GgPme7RSQ+lacIENUgJ6gg1k6HjgOlqnLqip4tEuhv0hNEMXUD0clyXE3p6pZA0S2nnvTlXwLJEZWlb7cTQH1+USgTN4VhAenm/wea1OCAOmqo6fE1WCb9WSKBah+rbUWPWAmE2Rvk0ApiB45eOyNAzU8xcTvj8KvkKEoOaIYeHNA3ZuygAvFMUO0AAAAASUVORK5CYII=";break;case"external_person":s="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAB6ElEQVR4Xu2YLY+EMBCG9+dWr0aj0Wg0Go1Go0+j8Xdv2uTCvv1gpt0ebHKPuhDaeW4605Z9mJvx4AdXUyTUdd08z+u6flmWZRnHsWkafk9DptAwDPu+f0eAYtu2PEaGWuj5fCIZrBAC2eLBAnRCsEkkxmeaJp7iDJ2QMDdHsLg8SxKFEJaAo8lAXnmuOFIhTMpxxKATebo4UiFknuNo4OniSIXQyRxEA3YsnjGCVEjVXD7yLUAqxBGUyPv/Y4W2beMgGuS7kVQIBycH0fD+oi5pezQETxdHKmQKGk1eQEYldK+jw5GxPfZ9z7Mk0Qnhf1W1m3w//EUn5BDmSZsbR44QQLBEqrBHqOrmSKaQAxdnLArCrxZcM7A7ZKs4ioRq8LFC+NpC3WCBJsvpVw5edm9iEXFuyNfxXAgSwfrFQ1c0iNda8AdejvUgnktOtJQQxmcfFzGglc5WVCj7oDgFqU18boeFSs52CUh8LE8BIVQDT1ABrB0HtgSEYlX5doJnCwv9TXocKCaKbnwhdDKPq4lf3SwU3HLq4V/+WYhHVMa/3b4IlfyikAduCkcBc7mQ3/z/Qq/cTuikhkzB12Ae/mcJC9U+Vo8Ej1gWAtgbeGgFsAMHr50BIWOLCbezvhpBFUdY6EJuJ/QDW0XoMX60zZ0AAAAASUVORK5CYII=";break}let l=t.append("g");l.attr("class","person-man");let u=wl();switch(e.typeC4Shape.text){case"person":case"external_person":case"system":case"external_system":case"container":case"external_container":case"component":case"external_component":u.x=e.x,u.y=e.y,u.fill=n,u.width=e.width,u.height=e.height,u.stroke=i,u.rx=2.5,u.ry=2.5,u.attrs={"stroke-width":.5},S_(l,u);break;case"system_db":case"external_system_db":case"container_db":case"external_container_db":case"component_db":case"external_component_db":l.append("path").attr("fill",n).attr("stroke-width","0.5").attr("stroke",i).attr("d","Mstartx,startyc0,-10 half,-10 half,-10c0,0 half,0 half,10l0,heightc0,10 -half,10 -half,10c0,0 -half,0 -half,-10l0,-height".replaceAll("startx",e.x).replaceAll("starty",e.y).replaceAll("half",e.width/2).replaceAll("height",e.height)),l.append("path").attr("fill","none").attr("stroke-width","0.5").attr("stroke",i).attr("d","Mstartx,startyc0,10 half,10 half,10c0,0 half,0 half,-10".replaceAll("startx",e.x).replaceAll("starty",e.y).replaceAll("half",e.width/2));break;case"system_queue":case"external_system_queue":case"container_queue":case"external_container_queue":case"component_queue":case"external_component_queue":l.append("path").attr("fill",n).attr("stroke-width","0.5").attr("stroke",i).attr("d","Mstartx,startylwidth,0c5,0 5,half 5,halfc0,0 0,half -5,halfl-width,0c-5,0 -5,-half -5,-halfc0,0 0,-half 5,-half".replaceAll("startx",e.x).replaceAll("starty",e.y).replaceAll("width",e.width).replaceAll("half",e.height/2)),l.append("path").attr("fill","none").attr("stroke-width","0.5").attr("stroke",i).attr("d","Mstartx,startyc-5,0 -5,half -5,halfc0,half 5,half 5,half".replaceAll("startx",e.x+e.width).replaceAll("starty",e.y).replaceAll("half",e.height/2));break}let h=FTe(r,e.typeC4Shape.text);switch(l.append("text").attr("fill",a).attr("font-family",h.fontFamily).attr("font-size",h.fontSize-2).attr("font-style","italic").attr("lengthAdjust","spacing").attr("textLength",e.typeC4Shape.width).attr("x",e.x+e.width/2-e.typeC4Shape.width/2).attr("y",e.y+e.typeC4Shape.Y).text("<<"+e.typeC4Shape.text+">>"),e.typeC4Shape.text){case"person":case"external_person":SW(l,48,48,e.x+e.width/2-24,e.y+e.image.Y,s);break}let f=r[e.typeC4Shape.text+"Font"]();return f.fontWeight="bold",f.fontSize=f.fontSize+2,f.fontColor=a,bu(r)(e.label.text,l,e.x,e.y+e.label.Y,e.width,e.height,{fill:a},f),f=r[e.typeC4Shape.text+"Font"](),f.fontColor=a,e.techn&&e.techn?.text!==""?bu(r)(e.techn.text,l,e.x,e.y+e.techn.Y,e.width,e.height,{fill:a,"font-style":"italic"},f):e.type&&e.type.text!==""&&bu(r)(e.type.text,l,e.x,e.y+e.type.Y,e.width,e.height,{fill:a,"font-style":"italic"},f),e.descr&&e.descr.text!==""&&(f=r.personFont(),f.fontColor=a,bu(r)(e.descr.text,l,e.x,e.y+e.descr.Y,e.width,e.height,{fill:a},f)),e.height},"drawC4Shape"),DTe=o(function(t){t.append("defs").append("symbol").attr("id","database").attr("fill-rule","evenodd").attr("clip-rule","evenodd").append("path").attr("transform","scale(.5)").attr("d","M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z")},"insertDatabaseIcon"),RTe=o(function(t){t.append("defs").append("symbol").attr("id","computer").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z")},"insertComputerIcon"),NTe=o(function(t){t.append("defs").append("symbol").attr("id","clock").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z")},"insertClockIcon"),MTe=o(function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",9).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z")},"insertArrowHead"),ITe=o(function(t){t.append("defs").append("marker").attr("id","arrowend").attr("refX",1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 10 0 L 0 5 L 10 10 z")},"insertArrowEnd"),OTe=o(function(t){t.append("defs").append("marker").attr("id","filled-head").attr("refX",18).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"insertArrowFilledHead"),PTe=o(function(t){t.append("defs").append("marker").attr("id","sequencenumber").attr("refX",15).attr("refY",15).attr("markerWidth",60).attr("markerHeight",40).attr("orient","auto").append("circle").attr("cx",15).attr("cy",15).attr("r",6)},"insertDynamicNumber"),BTe=o(function(t){let r=t.append("defs").append("marker").attr("id","crosshead").attr("markerWidth",15).attr("markerHeight",8).attr("orient","auto").attr("refX",16).attr("refY",4);r.append("path").attr("fill","black").attr("stroke","#000000").style("stroke-dasharray","0, 0").attr("stroke-width","1px").attr("d","M 9,2 V 6 L16,4 Z"),r.append("path").attr("fill","none").attr("stroke","#000000").style("stroke-dasharray","0, 0").attr("stroke-width","1px").attr("d","M 0,1 L 6,7 M 6,1 L 0,7")},"insertArrowCrossHead"),FTe=o((t,e)=>({fontFamily:t[e+"FontFamily"],fontSize:t[e+"FontSize"],fontWeight:t[e+"FontWeight"]}),"getC4ShapeFont"),bu=function(){function t(i,a,s,l,u,h,f){let d=a.append("text").attr("x",s+u/2).attr("y",l+h/2+5).style("text-anchor","middle").text(i);n(d,f)}o(t,"byText");function e(i,a,s,l,u,h,f,d){let{fontSize:p,fontFamily:m,fontWeight:g}=d,y=i.split(We.lineBreakRegex);for(let v=0;v{"use strict";zTe=typeof global=="object"&&global&&global.Object===Object&&global,Q3=zTe});var GTe,$Te,Jn,Ro=R(()=>{"use strict";A_();GTe=typeof self=="object"&&self&&self.Object===Object&&self,$Te=Q3||GTe||Function("return this")(),Jn=$Te});var VTe,Ji,vd=R(()=>{"use strict";Ro();VTe=Jn.Symbol,Ji=VTe});function YTe(t){var e=UTe.call(t,Zy),r=t[Zy];try{t[Zy]=void 0;var n=!0}catch{}var i=HTe.call(t);return n&&(e?t[Zy]=r:delete t[Zy]),i}var _W,UTe,HTe,Zy,LW,DW=R(()=>{"use strict";vd();_W=Object.prototype,UTe=_W.hasOwnProperty,HTe=_W.toString,Zy=Ji?Ji.toStringTag:void 0;o(YTe,"getRawTag");LW=YTe});function XTe(t){return qTe.call(t)}var WTe,qTe,RW,NW=R(()=>{"use strict";WTe=Object.prototype,qTe=WTe.toString;o(XTe,"objectToString");RW=XTe});function QTe(t){return t==null?t===void 0?KTe:jTe:MW&&MW in Object(t)?LW(t):RW(t)}var jTe,KTe,MW,fa,wu=R(()=>{"use strict";vd();DW();NW();jTe="[object Null]",KTe="[object Undefined]",MW=Ji?Ji.toStringTag:void 0;o(QTe,"baseGetTag");fa=QTe});function ZTe(t){var e=typeof t;return t!=null&&(e=="object"||e=="function")}var pn,Js=R(()=>{"use strict";o(ZTe,"isObject");pn=ZTe});function nke(t){if(!pn(t))return!1;var e=fa(t);return e==eke||e==tke||e==JTe||e==rke}var JTe,eke,tke,rke,wi,Jy=R(()=>{"use strict";wu();Js();JTe="[object AsyncFunction]",eke="[object Function]",tke="[object GeneratorFunction]",rke="[object Proxy]";o(nke,"isFunction");wi=nke});var ike,Z3,IW=R(()=>{"use strict";Ro();ike=Jn["__core-js_shared__"],Z3=ike});function ake(t){return!!OW&&OW in t}var OW,PW,BW=R(()=>{"use strict";IW();OW=function(){var t=/[^.]+$/.exec(Z3&&Z3.keys&&Z3.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}();o(ake,"isMasked");PW=ake});function lke(t){if(t!=null){try{return oke.call(t)}catch{}try{return t+""}catch{}}return""}var ske,oke,Tu,__=R(()=>{"use strict";ske=Function.prototype,oke=ske.toString;o(lke,"toSource");Tu=lke});function gke(t){if(!pn(t)||PW(t))return!1;var e=wi(t)?mke:uke;return e.test(Tu(t))}var cke,uke,hke,fke,dke,pke,mke,FW,zW=R(()=>{"use strict";Jy();BW();Js();__();cke=/[\\^$.*+?()[\]{}|]/g,uke=/^\[object .+?Constructor\]$/,hke=Function.prototype,fke=Object.prototype,dke=hke.toString,pke=fke.hasOwnProperty,mke=RegExp("^"+dke.call(pke).replace(cke,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");o(gke,"baseIsNative");FW=gke});function yke(t,e){return t?.[e]}var GW,$W=R(()=>{"use strict";o(yke,"getValue");GW=yke});function vke(t,e){var r=GW(t,e);return FW(r)?r:void 0}var xs,Nh=R(()=>{"use strict";zW();$W();o(vke,"getNative");xs=vke});var xke,ku,ev=R(()=>{"use strict";Nh();xke=xs(Object,"create"),ku=xke});function bke(){this.__data__=ku?ku(null):{},this.size=0}var VW,UW=R(()=>{"use strict";ev();o(bke,"hashClear");VW=bke});function wke(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}var HW,YW=R(()=>{"use strict";o(wke,"hashDelete");HW=wke});function Cke(t){var e=this.__data__;if(ku){var r=e[t];return r===Tke?void 0:r}return Eke.call(e,t)?e[t]:void 0}var Tke,kke,Eke,WW,qW=R(()=>{"use strict";ev();Tke="__lodash_hash_undefined__",kke=Object.prototype,Eke=kke.hasOwnProperty;o(Cke,"hashGet");WW=Cke});function _ke(t){var e=this.__data__;return ku?e[t]!==void 0:Ake.call(e,t)}var Ske,Ake,XW,jW=R(()=>{"use strict";ev();Ske=Object.prototype,Ake=Ske.hasOwnProperty;o(_ke,"hashHas");XW=_ke});function Dke(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=ku&&e===void 0?Lke:e,this}var Lke,KW,QW=R(()=>{"use strict";ev();Lke="__lodash_hash_undefined__";o(Dke,"hashSet");KW=Dke});function Hp(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e{"use strict";UW();YW();qW();jW();QW();o(Hp,"Hash");Hp.prototype.clear=VW;Hp.prototype.delete=HW;Hp.prototype.get=WW;Hp.prototype.has=XW;Hp.prototype.set=KW;L_=Hp});function Rke(){this.__data__=[],this.size=0}var JW,eq=R(()=>{"use strict";o(Rke,"listCacheClear");JW=Rke});function Nke(t,e){return t===e||t!==t&&e!==e}var No,xd=R(()=>{"use strict";o(Nke,"eq");No=Nke});function Mke(t,e){for(var r=t.length;r--;)if(No(t[r][0],e))return r;return-1}var Mh,tv=R(()=>{"use strict";xd();o(Mke,"assocIndexOf");Mh=Mke});function Pke(t){var e=this.__data__,r=Mh(e,t);if(r<0)return!1;var n=e.length-1;return r==n?e.pop():Oke.call(e,r,1),--this.size,!0}var Ike,Oke,tq,rq=R(()=>{"use strict";tv();Ike=Array.prototype,Oke=Ike.splice;o(Pke,"listCacheDelete");tq=Pke});function Bke(t){var e=this.__data__,r=Mh(e,t);return r<0?void 0:e[r][1]}var nq,iq=R(()=>{"use strict";tv();o(Bke,"listCacheGet");nq=Bke});function Fke(t){return Mh(this.__data__,t)>-1}var aq,sq=R(()=>{"use strict";tv();o(Fke,"listCacheHas");aq=Fke});function zke(t,e){var r=this.__data__,n=Mh(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this}var oq,lq=R(()=>{"use strict";tv();o(zke,"listCacheSet");oq=zke});function Yp(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e{"use strict";eq();rq();iq();sq();lq();o(Yp,"ListCache");Yp.prototype.clear=JW;Yp.prototype.delete=tq;Yp.prototype.get=nq;Yp.prototype.has=aq;Yp.prototype.set=oq;Ih=Yp});var Gke,Oh,J3=R(()=>{"use strict";Nh();Ro();Gke=xs(Jn,"Map"),Oh=Gke});function $ke(){this.size=0,this.__data__={hash:new L_,map:new(Oh||Ih),string:new L_}}var cq,uq=R(()=>{"use strict";ZW();rv();J3();o($ke,"mapCacheClear");cq=$ke});function Vke(t){var e=typeof t;return e=="string"||e=="number"||e=="symbol"||e=="boolean"?t!=="__proto__":t===null}var hq,fq=R(()=>{"use strict";o(Vke,"isKeyable");hq=Vke});function Uke(t,e){var r=t.__data__;return hq(e)?r[typeof e=="string"?"string":"hash"]:r.map}var Ph,nv=R(()=>{"use strict";fq();o(Uke,"getMapData");Ph=Uke});function Hke(t){var e=Ph(this,t).delete(t);return this.size-=e?1:0,e}var dq,pq=R(()=>{"use strict";nv();o(Hke,"mapCacheDelete");dq=Hke});function Yke(t){return Ph(this,t).get(t)}var mq,gq=R(()=>{"use strict";nv();o(Yke,"mapCacheGet");mq=Yke});function Wke(t){return Ph(this,t).has(t)}var yq,vq=R(()=>{"use strict";nv();o(Wke,"mapCacheHas");yq=Wke});function qke(t,e){var r=Ph(this,t),n=r.size;return r.set(t,e),this.size+=r.size==n?0:1,this}var xq,bq=R(()=>{"use strict";nv();o(qke,"mapCacheSet");xq=qke});function Wp(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e{"use strict";uq();pq();gq();vq();bq();o(Wp,"MapCache");Wp.prototype.clear=cq;Wp.prototype.delete=dq;Wp.prototype.get=mq;Wp.prototype.has=yq;Wp.prototype.set=xq;bd=Wp});function D_(t,e){if(typeof t!="function"||e!=null&&typeof e!="function")throw new TypeError(Xke);var r=o(function(){var n=arguments,i=e?e.apply(this,n):n[0],a=r.cache;if(a.has(i))return a.get(i);var s=t.apply(this,n);return r.cache=a.set(i,s)||a,s},"memoized");return r.cache=new(D_.Cache||bd),r}var Xke,qp,R_=R(()=>{"use strict";e5();Xke="Expected a function";o(D_,"memoize");D_.Cache=bd;qp=D_});function jke(){this.__data__=new Ih,this.size=0}var wq,Tq=R(()=>{"use strict";rv();o(jke,"stackClear");wq=jke});function Kke(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r}var kq,Eq=R(()=>{"use strict";o(Kke,"stackDelete");kq=Kke});function Qke(t){return this.__data__.get(t)}var Cq,Sq=R(()=>{"use strict";o(Qke,"stackGet");Cq=Qke});function Zke(t){return this.__data__.has(t)}var Aq,_q=R(()=>{"use strict";o(Zke,"stackHas");Aq=Zke});function eEe(t,e){var r=this.__data__;if(r instanceof Ih){var n=r.__data__;if(!Oh||n.length{"use strict";rv();J3();e5();Jke=200;o(eEe,"stackSet");Lq=eEe});function Xp(t){var e=this.__data__=new Ih(t);this.size=e.size}var uc,iv=R(()=>{"use strict";rv();Tq();Eq();Sq();_q();Dq();o(Xp,"Stack");Xp.prototype.clear=wq;Xp.prototype.delete=kq;Xp.prototype.get=Cq;Xp.prototype.has=Aq;Xp.prototype.set=Lq;uc=Xp});var tEe,jp,N_=R(()=>{"use strict";Nh();tEe=function(){try{var t=xs(Object,"defineProperty");return t({},"",{}),t}catch{}}(),jp=tEe});function rEe(t,e,r){e=="__proto__"&&jp?jp(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}var hc,Kp=R(()=>{"use strict";N_();o(rEe,"baseAssignValue");hc=rEe});function nEe(t,e,r){(r!==void 0&&!No(t[e],r)||r===void 0&&!(e in t))&&hc(t,e,r)}var av,M_=R(()=>{"use strict";Kp();xd();o(nEe,"assignMergeValue");av=nEe});function iEe(t){return function(e,r,n){for(var i=-1,a=Object(e),s=n(e),l=s.length;l--;){var u=s[t?l:++i];if(r(a[u],u,a)===!1)break}return e}}var Rq,Nq=R(()=>{"use strict";o(iEe,"createBaseFor");Rq=iEe});var aEe,Qp,t5=R(()=>{"use strict";Nq();aEe=Rq(),Qp=aEe});function oEe(t,e){if(e)return t.slice();var r=t.length,n=Oq?Oq(r):new t.constructor(r);return t.copy(n),n}var Pq,Mq,sEe,Iq,Oq,r5,I_=R(()=>{"use strict";Ro();Pq=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Mq=Pq&&typeof module=="object"&&module&&!module.nodeType&&module,sEe=Mq&&Mq.exports===Pq,Iq=sEe?Jn.Buffer:void 0,Oq=Iq?Iq.allocUnsafe:void 0;o(oEe,"cloneBuffer");r5=oEe});var lEe,Zp,O_=R(()=>{"use strict";Ro();lEe=Jn.Uint8Array,Zp=lEe});function cEe(t){var e=new t.constructor(t.byteLength);return new Zp(e).set(new Zp(t)),e}var Jp,n5=R(()=>{"use strict";O_();o(cEe,"cloneArrayBuffer");Jp=cEe});function uEe(t,e){var r=e?Jp(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}var i5,P_=R(()=>{"use strict";n5();o(uEe,"cloneTypedArray");i5=uEe});function hEe(t,e){var r=-1,n=t.length;for(e||(e=Array(n));++r{"use strict";o(hEe,"copyArray");a5=hEe});var Bq,fEe,Fq,zq=R(()=>{"use strict";Js();Bq=Object.create,fEe=function(){function t(){}return o(t,"object"),function(e){if(!pn(e))return{};if(Bq)return Bq(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}(),Fq=fEe});function dEe(t,e){return function(r){return t(e(r))}}var s5,F_=R(()=>{"use strict";o(dEe,"overArg");s5=dEe});var pEe,em,o5=R(()=>{"use strict";F_();pEe=s5(Object.getPrototypeOf,Object),em=pEe});function gEe(t){var e=t&&t.constructor,r=typeof e=="function"&&e.prototype||mEe;return t===r}var mEe,fc,tm=R(()=>{"use strict";mEe=Object.prototype;o(gEe,"isPrototype");fc=gEe});function yEe(t){return typeof t.constructor=="function"&&!fc(t)?Fq(em(t)):{}}var l5,z_=R(()=>{"use strict";zq();o5();tm();o(yEe,"initCloneObject");l5=yEe});function vEe(t){return t!=null&&typeof t=="object"}var Wn,Mo=R(()=>{"use strict";o(vEe,"isObjectLike");Wn=vEe});function bEe(t){return Wn(t)&&fa(t)==xEe}var xEe,G_,Gq=R(()=>{"use strict";wu();Mo();xEe="[object Arguments]";o(bEe,"baseIsArguments");G_=bEe});var $q,wEe,TEe,kEe,kl,rm=R(()=>{"use strict";Gq();Mo();$q=Object.prototype,wEe=$q.hasOwnProperty,TEe=$q.propertyIsEnumerable,kEe=G_(function(){return arguments}())?G_:function(t){return Wn(t)&&wEe.call(t,"callee")&&!TEe.call(t,"callee")},kl=kEe});var EEe,wt,Bn=R(()=>{"use strict";EEe=Array.isArray,wt=EEe});function SEe(t){return typeof t=="number"&&t>-1&&t%1==0&&t<=CEe}var CEe,nm,c5=R(()=>{"use strict";CEe=9007199254740991;o(SEe,"isLength");nm=SEe});function AEe(t){return t!=null&&nm(t.length)&&!wi(t)}var ei,Io=R(()=>{"use strict";Jy();c5();o(AEe,"isArrayLike");ei=AEe});function _Ee(t){return Wn(t)&&ei(t)}var wd,u5=R(()=>{"use strict";Io();Mo();o(_Ee,"isArrayLikeObject");wd=_Ee});function LEe(){return!1}var Vq,Uq=R(()=>{"use strict";o(LEe,"stubFalse");Vq=LEe});var Wq,Hq,DEe,Yq,REe,NEe,El,im=R(()=>{"use strict";Ro();Uq();Wq=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Hq=Wq&&typeof module=="object"&&module&&!module.nodeType&&module,DEe=Hq&&Hq.exports===Wq,Yq=DEe?Jn.Buffer:void 0,REe=Yq?Yq.isBuffer:void 0,NEe=REe||Vq,El=NEe});function FEe(t){if(!Wn(t)||fa(t)!=MEe)return!1;var e=em(t);if(e===null)return!0;var r=PEe.call(e,"constructor")&&e.constructor;return typeof r=="function"&&r instanceof r&&qq.call(r)==BEe}var MEe,IEe,OEe,qq,PEe,BEe,Xq,jq=R(()=>{"use strict";wu();o5();Mo();MEe="[object Object]",IEe=Function.prototype,OEe=Object.prototype,qq=IEe.toString,PEe=OEe.hasOwnProperty,BEe=qq.call(Object);o(FEe,"isPlainObject");Xq=FEe});function c6e(t){return Wn(t)&&nm(t.length)&&!!Mn[fa(t)]}var zEe,GEe,$Ee,VEe,UEe,HEe,YEe,WEe,qEe,XEe,jEe,KEe,QEe,ZEe,JEe,e6e,t6e,r6e,n6e,i6e,a6e,s6e,o6e,l6e,Mn,Kq,Qq=R(()=>{"use strict";wu();c5();Mo();zEe="[object Arguments]",GEe="[object Array]",$Ee="[object Boolean]",VEe="[object Date]",UEe="[object Error]",HEe="[object Function]",YEe="[object Map]",WEe="[object Number]",qEe="[object Object]",XEe="[object RegExp]",jEe="[object Set]",KEe="[object String]",QEe="[object WeakMap]",ZEe="[object ArrayBuffer]",JEe="[object DataView]",e6e="[object Float32Array]",t6e="[object Float64Array]",r6e="[object Int8Array]",n6e="[object Int16Array]",i6e="[object Int32Array]",a6e="[object Uint8Array]",s6e="[object Uint8ClampedArray]",o6e="[object Uint16Array]",l6e="[object Uint32Array]",Mn={};Mn[e6e]=Mn[t6e]=Mn[r6e]=Mn[n6e]=Mn[i6e]=Mn[a6e]=Mn[s6e]=Mn[o6e]=Mn[l6e]=!0;Mn[zEe]=Mn[GEe]=Mn[ZEe]=Mn[$Ee]=Mn[JEe]=Mn[VEe]=Mn[UEe]=Mn[HEe]=Mn[YEe]=Mn[WEe]=Mn[qEe]=Mn[XEe]=Mn[jEe]=Mn[KEe]=Mn[QEe]=!1;o(c6e,"baseIsTypedArray");Kq=c6e});function u6e(t){return function(e){return t(e)}}var Oo,Td=R(()=>{"use strict";o(u6e,"baseUnary");Oo=u6e});var Zq,sv,h6e,$_,f6e,Po,ov=R(()=>{"use strict";A_();Zq=typeof exports=="object"&&exports&&!exports.nodeType&&exports,sv=Zq&&typeof module=="object"&&module&&!module.nodeType&&module,h6e=sv&&sv.exports===Zq,$_=h6e&&Q3.process,f6e=function(){try{var t=sv&&sv.require&&sv.require("util").types;return t||$_&&$_.binding&&$_.binding("util")}catch{}}(),Po=f6e});var Jq,d6e,Bh,lv=R(()=>{"use strict";Qq();Td();ov();Jq=Po&&Po.isTypedArray,d6e=Jq?Oo(Jq):Kq,Bh=d6e});function p6e(t,e){if(!(e==="constructor"&&typeof t[e]=="function")&&e!="__proto__")return t[e]}var cv,V_=R(()=>{"use strict";o(p6e,"safeGet");cv=p6e});function y6e(t,e,r){var n=t[e];(!(g6e.call(t,e)&&No(n,r))||r===void 0&&!(e in t))&&hc(t,e,r)}var m6e,g6e,dc,am=R(()=>{"use strict";Kp();xd();m6e=Object.prototype,g6e=m6e.hasOwnProperty;o(y6e,"assignValue");dc=y6e});function v6e(t,e,r,n){var i=!r;r||(r={});for(var a=-1,s=e.length;++a{"use strict";am();Kp();o(v6e,"copyObject");Bo=v6e});function x6e(t,e){for(var r=-1,n=Array(t);++r{"use strict";o(x6e,"baseTimes");eX=x6e});function T6e(t,e){var r=typeof t;return e=e??b6e,!!e&&(r=="number"||r!="symbol"&&w6e.test(t))&&t>-1&&t%1==0&&t{"use strict";b6e=9007199254740991,w6e=/^(?:0|[1-9]\d*)$/;o(T6e,"isIndex");Fh=T6e});function C6e(t,e){var r=wt(t),n=!r&&kl(t),i=!r&&!n&&El(t),a=!r&&!n&&!i&&Bh(t),s=r||n||i||a,l=s?eX(t.length,String):[],u=l.length;for(var h in t)(e||E6e.call(t,h))&&!(s&&(h=="length"||i&&(h=="offset"||h=="parent")||a&&(h=="buffer"||h=="byteLength"||h=="byteOffset")||Fh(h,u)))&&l.push(h);return l}var k6e,E6e,h5,U_=R(()=>{"use strict";tX();rm();Bn();im();uv();lv();k6e=Object.prototype,E6e=k6e.hasOwnProperty;o(C6e,"arrayLikeKeys");h5=C6e});function S6e(t){var e=[];if(t!=null)for(var r in Object(t))e.push(r);return e}var rX,nX=R(()=>{"use strict";o(S6e,"nativeKeysIn");rX=S6e});function L6e(t){if(!pn(t))return rX(t);var e=fc(t),r=[];for(var n in t)n=="constructor"&&(e||!_6e.call(t,n))||r.push(n);return r}var A6e,_6e,iX,aX=R(()=>{"use strict";Js();tm();nX();A6e=Object.prototype,_6e=A6e.hasOwnProperty;o(L6e,"baseKeysIn");iX=L6e});function D6e(t){return ei(t)?h5(t,!0):iX(t)}var bs,zh=R(()=>{"use strict";U_();aX();Io();o(D6e,"keysIn");bs=D6e});function R6e(t){return Bo(t,bs(t))}var sX,oX=R(()=>{"use strict";kd();zh();o(R6e,"toPlainObject");sX=R6e});function N6e(t,e,r,n,i,a,s){var l=cv(t,r),u=cv(e,r),h=s.get(u);if(h){av(t,r,h);return}var f=a?a(l,u,r+"",t,e,s):void 0,d=f===void 0;if(d){var p=wt(u),m=!p&&El(u),g=!p&&!m&&Bh(u);f=u,p||m||g?wt(l)?f=l:wd(l)?f=a5(l):m?(d=!1,f=r5(u,!0)):g?(d=!1,f=i5(u,!0)):f=[]:Xq(u)||kl(u)?(f=l,kl(l)?f=sX(l):(!pn(l)||wi(l))&&(f=l5(u))):d=!1}d&&(s.set(u,f),i(f,u,n,a,s),s.delete(u)),av(t,r,f)}var lX,cX=R(()=>{"use strict";M_();I_();P_();B_();z_();rm();Bn();u5();im();Jy();Js();jq();lv();V_();oX();o(N6e,"baseMergeDeep");lX=N6e});function uX(t,e,r,n,i){t!==e&&Qp(e,function(a,s){if(i||(i=new uc),pn(a))lX(t,e,s,r,uX,n,i);else{var l=n?n(cv(t,s),a,s+"",t,e,i):void 0;l===void 0&&(l=a),av(t,s,l)}},bs)}var hX,fX=R(()=>{"use strict";iv();M_();t5();cX();Js();zh();V_();o(uX,"baseMerge");hX=uX});function M6e(t){return t}var ea,Eu=R(()=>{"use strict";o(M6e,"identity");ea=M6e});function I6e(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)}var dX,pX=R(()=>{"use strict";o(I6e,"apply");dX=I6e});function O6e(t,e,r){return e=mX(e===void 0?t.length-1:e,0),function(){for(var n=arguments,i=-1,a=mX(n.length-e,0),s=Array(a);++i{"use strict";pX();mX=Math.max;o(O6e,"overRest");f5=O6e});function P6e(t){return function(){return t}}var ws,Y_=R(()=>{"use strict";o(P6e,"constant");ws=P6e});var B6e,gX,yX=R(()=>{"use strict";Y_();N_();Eu();B6e=jp?function(t,e){return jp(t,"toString",{configurable:!0,enumerable:!1,value:ws(e),writable:!0})}:ea,gX=B6e});function $6e(t){var e=0,r=0;return function(){var n=G6e(),i=z6e-(n-r);if(r=n,i>0){if(++e>=F6e)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}var F6e,z6e,G6e,vX,xX=R(()=>{"use strict";F6e=800,z6e=16,G6e=Date.now;o($6e,"shortOut");vX=$6e});var V6e,d5,W_=R(()=>{"use strict";yX();xX();V6e=vX(gX),d5=V6e});function U6e(t,e){return d5(f5(t,e,ea),t+"")}var pc,sm=R(()=>{"use strict";Eu();H_();W_();o(U6e,"baseRest");pc=U6e});function H6e(t,e,r){if(!pn(r))return!1;var n=typeof e;return(n=="number"?ei(r)&&Fh(e,r.length):n=="string"&&e in r)?No(r[e],t):!1}var eo,Ed=R(()=>{"use strict";xd();Io();uv();Js();o(H6e,"isIterateeCall");eo=H6e});function Y6e(t){return pc(function(e,r){var n=-1,i=r.length,a=i>1?r[i-1]:void 0,s=i>2?r[2]:void 0;for(a=t.length>3&&typeof a=="function"?(i--,a):void 0,s&&eo(r[0],r[1],s)&&(a=i<3?void 0:a,i=1),e=Object(e);++n{"use strict";sm();Ed();o(Y6e,"createAssigner");p5=Y6e});var W6e,Gh,X_=R(()=>{"use strict";fX();q_();W6e=p5(function(t,e,r){hX(t,e,r)}),Gh=W6e});function om(t,e){if(!t)return e;let r=`curve${t.charAt(0).toUpperCase()+t.slice(1)}`;return q6e[r]??e}function Q6e(t,e){let r=t.trim();if(r)return e.securityLevel!=="loose"?(0,TX.sanitizeUrl)(r):r}function CX(t,e){return!t||!e?0:Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))}function J6e(t){let e,r=0;t.forEach(i=>{r+=CX(i,e),e=i});let n=r/2;return Q_(t,n)}function eCe(t){return t.length===1?t[0]:J6e(t)}function rCe(t,e,r){let n=structuredClone(r);V.info("our points",n),e!=="start_left"&&e!=="start_right"&&n.reverse();let i=25+t,a=Q_(n,i),s=10+t*.5,l=Math.atan2(n[0].y-a.y,n[0].x-a.x),u={x:0,y:0};return e==="start_left"?(u.x=Math.sin(l+Math.PI)*s+(n[0].x+a.x)/2,u.y=-Math.cos(l+Math.PI)*s+(n[0].y+a.y)/2):e==="end_right"?(u.x=Math.sin(l-Math.PI)*s+(n[0].x+a.x)/2-5,u.y=-Math.cos(l-Math.PI)*s+(n[0].y+a.y)/2-5):e==="end_left"?(u.x=Math.sin(l)*s+(n[0].x+a.x)/2-5,u.y=-Math.cos(l)*s+(n[0].y+a.y)/2-5):(u.x=Math.sin(l)*s+(n[0].x+a.x)/2,u.y=-Math.cos(l)*s+(n[0].y+a.y)/2),u}function lm(t){let e="",r="";for(let n of t)n!==void 0&&(n.startsWith("color:")||n.startsWith("text-align:")?r=r+n+";":e=e+n+";");return{style:e,labelStyle:r}}function nCe(t){let e="",r="0123456789abcdef",n=r.length;for(let i=0;i{"use strict";TX=Xi(Up(),1);Zt();rr();r7();ut();Hf();cp();R_();X_();Vb();K_="\u200B",q6e={curveBasis:vs,curveBasisClosed:B3,curveBasisOpen:F3,curveBumpX:s_,curveBumpY:o_,curveBundle:l_,curveCardinalClosed:u_,curveCardinalOpen:f_,curveCardinal:c_,curveCatmullRomClosed:m_,curveCatmullRomOpen:g_,curveCatmullRom:p_,curveLinear:xu,curveLinearClosed:U3,curveMonotoneX:v_,curveMonotoneY:x_,curveNatural:Y3,curveStep:q3,curveStepAfter:w_,curveStepBefore:b_},X6e=/\s*(?:(\w+)(?=:):|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi,j6e=o(function(t,e){let r=kX(t,/(?:init\b)|(?:initialize\b)/),n={};if(Array.isArray(r)){let s=r.map(l=>l.args);fp(s),n=On(n,[...s])}else n=r.args;if(!n)return;let i=lp(t,e),a="config";return n[a]!==void 0&&(i==="flowchart-v2"&&(i="flowchart"),n[i]=n[a],delete n[a]),n},"detectInit"),kX=o(function(t,e=null){try{let r=new RegExp(`[%]{2}(?![{]${X6e.source})(?=[}][%]{2}).* +`,"ig");t=t.trim().replace(r,"").replace(/'/gm,'"'),V.debug(`Detecting diagram directive${e!==null?" type:"+e:""} based on the text:${t}`);let n,i=[];for(;(n=Vf.exec(t))!==null;)if(n.index===Vf.lastIndex&&Vf.lastIndex++,n&&!e||e&&n[1]?.match(e)||e&&n[2]?.match(e)){let a=n[1]?n[1]:n[2],s=n[3]?n[3].trim():n[4]?JSON.parse(n[4].trim()):null;i.push({type:a,args:s})}return i.length===0?{type:t,args:null}:i.length===1?i[0]:i}catch(r){return V.error(`ERROR: ${r.message} - Unable to parse directive type: '${e}' based on the text: '${t}'`),{type:void 0,args:null}}},"detectDirective"),EX=o(function(t){return t.replace(Vf,"")},"removeDirectives"),K6e=o(function(t,e){for(let[r,n]of e.entries())if(n.match(t))return r;return-1},"isSubstringInArray");o(om,"interpolateToCurve");o(Q6e,"formatUrl");Z6e=o((t,...e)=>{let r=t.split("."),n=r.length-1,i=r[n],a=window;for(let s=0;s{let r=Math.pow(10,e);return Math.round(t*r)/r},"roundNumber"),Q_=o((t,e)=>{let r,n=e;for(let i of t){if(r){let a=CX(i,r);if(a=1)return{x:i.x,y:i.y};if(s>0&&s<1)return{x:bX((1-s)*r.x+s*i.x,5),y:bX((1-s)*r.y+s*i.y,5)}}}r=i}throw new Error("Could not find a suitable point for the given distance")},"calculatePoint"),tCe=o((t,e,r)=>{V.info(`our points ${JSON.stringify(e)}`),e[0]!==r&&(e=e.reverse());let i=Q_(e,25),a=t?10:5,s=Math.atan2(e[0].y-i.y,e[0].x-i.x),l={x:0,y:0};return l.x=Math.sin(s)*a+(e[0].x+i.x)/2,l.y=-Math.cos(s)*a+(e[0].y+i.y)/2,l},"calcCardinalityPosition");o(rCe,"calcTerminalLabelPosition");o(lm,"getStylesFromArray");wX=0,Z_=o(()=>(wX++,"id-"+Math.random().toString(36).substr(2,12)+"-"+wX),"generateId");o(nCe,"makeRandomHex");J_=o(t=>nCe(t.length),"random"),iCe=o(function(){return{x:0,y:0,fill:void 0,anchor:"start",style:"#666",width:100,height:100,textMargin:0,rx:0,ry:0,valign:void 0,text:""}},"getTextObj"),aCe=o(function(t,e){let r=e.text.replace(We.lineBreakRegex," "),[,n]=mc(e.fontSize),i=t.append("text");i.attr("x",e.x),i.attr("y",e.y),i.style("text-anchor",e.anchor),i.style("font-family",e.fontFamily),i.style("font-size",n),i.style("font-weight",e.fontWeight),i.attr("fill",e.fill),e.class!==void 0&&i.attr("class",e.class);let a=i.append("tspan");return a.attr("x",e.x+e.textMargin*2),a.attr("fill",e.fill),a.text(r),i},"drawSimpleText"),e9=qp((t,e,r)=>{if(!t||(r=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",joinWith:"
"},r),We.lineBreakRegex.test(t)))return t;let n=t.split(" ").filter(Boolean),i=[],a="";return n.forEach((s,l)=>{let u=Cl(`${s} `,r),h=Cl(a,r);if(u>e){let{hyphenatedStrings:p,remainingWord:m}=sCe(s,e,"-",r);i.push(a,...p),a=m}else h+u>=e?(i.push(a),a=s):a=[a,s].filter(Boolean).join(" ");l+1===n.length&&i.push(a)}),i.filter(s=>s!=="").join(r.joinWith)},(t,e,r)=>`${t}${e}${r.fontSize}${r.fontWeight}${r.fontFamily}${r.joinWith}`),sCe=qp((t,e,r="-",n)=>{n=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",margin:0},n);let i=[...t],a=[],s="";return i.forEach((l,u)=>{let h=`${s}${l}`;if(Cl(h,n)>=e){let d=u+1,p=i.length===d,m=`${h}${r}`;a.push(p?h:m),s=""}else s=h}),{hyphenatedStrings:a,remainingWord:s}},(t,e,r="-",n)=>`${t}${e}${r}${n.fontSize}${n.fontWeight}${n.fontFamily}`);o(g5,"calculateTextHeight");o(Cl,"calculateTextWidth");t9=qp((t,e)=>{let{fontSize:r=12,fontFamily:n="Arial",fontWeight:i=400}=e;if(!t)return{width:0,height:0};let[,a]=mc(r),s=["sans-serif",n],l=t.split(We.lineBreakRegex),u=[],h=$e("body");if(!h.remove)return{width:0,height:0,lineHeight:0};let f=h.append("svg");for(let p of s){let m=0,g={width:0,height:0,lineHeight:0};for(let y of l){let v=iCe();v.text=y||K_;let x=aCe(f,v).style("font-size",a).style("font-weight",i).style("font-family",p),b=(x._groups||x)[0][0].getBBox();if(b.width===0&&b.height===0)throw new Error("svg element not in render tree");g.width=Math.round(Math.max(g.width,b.width)),m=Math.round(b.height),g.height+=m,g.lineHeight=Math.round(Math.max(g.lineHeight,m))}u.push(g)}f.remove();let d=isNaN(u[1].height)||isNaN(u[1].width)||isNaN(u[1].lineHeight)||u[0].height>u[1].height&&u[0].width>u[1].width&&u[0].lineHeight>u[1].lineHeight?0:1;return u[d]},(t,e)=>`${t}${e.fontSize}${e.fontWeight}${e.fontFamily}`),j_=class{constructor(e=!1,r){this.count=0;this.count=r?r.length:0,this.next=e?()=>this.count++:()=>Date.now()}static{o(this,"InitIDGenerator")}},oCe=o(function(t){return m5=m5||document.createElement("div"),t=escape(t).replace(/%26/g,"&").replace(/%23/g,"#").replace(/%3B/g,";"),m5.innerHTML=t,unescape(m5.textContent)},"entityDecode");o(r9,"isDetailedError");lCe=o((t,e,r,n)=>{if(!n)return;let i=t.node()?.getBBox();i&&t.append("text").text(n).attr("x",i.x+i.width/2).attr("y",-r).attr("class",e)},"insertTitle"),mc=o(t=>{if(typeof t=="number")return[t,t+"px"];let e=parseInt(t??"",10);return Number.isNaN(e)?[void 0,void 0]:t===String(e)?[e,t+"px"]:[e,t]},"parseFontSize");o(Ts,"cleanAndMerge");Lt={assignWithDepth:On,wrapLabel:e9,calculateTextHeight:g5,calculateTextWidth:Cl,calculateTextDimensions:t9,cleanAndMerge:Ts,detectInit:j6e,detectDirective:kX,isSubstringInArray:K6e,interpolateToCurve:om,calcLabelPosition:eCe,calcCardinalityPosition:tCe,calcTerminalLabelPosition:rCe,formatUrl:Q6e,getStylesFromArray:lm,generateId:Z_,random:J_,runFunc:Z6e,entityDecode:oCe,insertTitle:lCe,parseFontSize:mc,InitIDGenerator:j_},SX=o(function(t){let e=t;return e=e.replace(/style.*:\S*#.*;/g,function(r){return r.substring(0,r.length-1)}),e=e.replace(/classDef.*:\S*#.*;/g,function(r){return r.substring(0,r.length-1)}),e=e.replace(/#\w+;/g,function(r){let n=r.substring(1,r.length-1);return/^\+?\d+$/.test(n)?"\uFB02\xB0\xB0"+n+"\xB6\xDF":"\uFB02\xB0"+n+"\xB6\xDF"}),e},"encodeEntities"),to=o(function(t){return t.replace(/fl°°/g,"&#").replace(/fl°/g,"&").replace(/¶ß/g,";")},"decodeEntities"),y5=o((t,e,{counter:r=0,prefix:n,suffix:i})=>`${n?`${n}_`:""}${t}_${e}_${r}${i?`_${i}`:""}`,"getEdgeId")});function Sl(t,e,r,n,i){if(!e[t].width)if(r)e[t].text=e9(e[t].text,i,n),e[t].textLines=e[t].text.split(We.lineBreakRegex).length,e[t].width=i,e[t].height=g5(e[t].text,n);else{let a=e[t].text.split(We.lineBreakRegex);e[t].textLines=a.length;let s=0;e[t].height=0,e[t].width=0;for(let l of a)e[t].width=Math.max(Cl(l,n),e[t].width),s=g5(l,n),e[t].height=e[t].height+s}}function RX(t,e,r,n,i){let a=new w5(i);a.data.widthLimit=r.data.widthLimit/Math.min(n9,n.length);for(let[s,l]of n.entries()){let u=0;l.image={width:0,height:0,Y:0},l.sprite&&(l.image.width=48,l.image.height=48,l.image.Y=u,u=l.image.Y+l.image.height);let h=l.wrap&&Nt.wrap,f=v5(Nt);if(f.fontSize=f.fontSize+2,f.fontWeight="bold",Sl("label",l,h,f,a.data.widthLimit),l.label.Y=u+8,u=l.label.Y+l.label.height,l.type&&l.type.text!==""){l.type.text="["+l.type.text+"]";let g=v5(Nt);Sl("type",l,h,g,a.data.widthLimit),l.type.Y=u+5,u=l.type.Y+l.type.height}if(l.descr&&l.descr.text!==""){let g=v5(Nt);g.fontSize=g.fontSize-2,Sl("descr",l,h,g,a.data.widthLimit),l.descr.Y=u+20,u=l.descr.Y+l.descr.height}if(s==0||s%n9===0){let g=r.data.startx+Nt.diagramMarginX,y=r.data.stopy+Nt.diagramMarginY+u;a.setData(g,g,y,y)}else{let g=a.data.stopx!==a.data.startx?a.data.stopx+Nt.diagramMarginX:a.data.startx,y=a.data.starty;a.setData(g,g,y,y)}a.name=l.alias;let d=i.db.getC4ShapeArray(l.alias),p=i.db.getC4ShapeKeys(l.alias);p.length>0&&DX(a,t,d,p),e=l.alias;let m=i.db.getBoundarys(e);m.length>0&&RX(t,e,a,m,i),l.alias!=="global"&&LX(t,l,a),r.data.stopy=Math.max(a.data.stopy+Nt.c4ShapeMargin,r.data.stopy),r.data.stopx=Math.max(a.data.stopx+Nt.c4ShapeMargin,r.data.stopx),x5=Math.max(x5,r.data.stopx),b5=Math.max(b5,r.data.stopy)}}var x5,b5,_X,n9,Nt,w5,i9,hv,v5,cCe,LX,DX,ks,AX,uCe,hCe,fCe,a9,NX=R(()=>{"use strict";Zt();AW();ut();VC();rr();lS();_t();cp();xr();Yn();x5=0,b5=0,_X=4,n9=2;U1.yy=hy;Nt={},w5=class{static{o(this,"Bounds")}constructor(e){this.name="",this.data={},this.data.startx=void 0,this.data.stopx=void 0,this.data.starty=void 0,this.data.stopy=void 0,this.data.widthLimit=void 0,this.nextData={},this.nextData.startx=void 0,this.nextData.stopx=void 0,this.nextData.starty=void 0,this.nextData.stopy=void 0,this.nextData.cnt=0,i9(e.db.getConfig())}setData(e,r,n,i){this.nextData.startx=this.data.startx=e,this.nextData.stopx=this.data.stopx=r,this.nextData.starty=this.data.starty=n,this.nextData.stopy=this.data.stopy=i}updateVal(e,r,n,i){e[r]===void 0?e[r]=n:e[r]=i(n,e[r])}insert(e){this.nextData.cnt=this.nextData.cnt+1;let r=this.nextData.startx===this.nextData.stopx?this.nextData.stopx+e.margin:this.nextData.stopx+e.margin*2,n=r+e.width,i=this.nextData.starty+e.margin*2,a=i+e.height;(r>=this.data.widthLimit||n>=this.data.widthLimit||this.nextData.cnt>_X)&&(r=this.nextData.startx+e.margin+Nt.nextLinePaddingX,i=this.nextData.stopy+e.margin*2,this.nextData.stopx=n=r+e.width,this.nextData.starty=this.nextData.stopy,this.nextData.stopy=a=i+e.height,this.nextData.cnt=1),e.x=r,e.y=i,this.updateVal(this.data,"startx",r,Math.min),this.updateVal(this.data,"starty",i,Math.min),this.updateVal(this.data,"stopx",n,Math.max),this.updateVal(this.data,"stopy",a,Math.max),this.updateVal(this.nextData,"startx",r,Math.min),this.updateVal(this.nextData,"starty",i,Math.min),this.updateVal(this.nextData,"stopx",n,Math.max),this.updateVal(this.nextData,"stopy",a,Math.max)}init(e){this.name="",this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0,widthLimit:void 0},this.nextData={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0,cnt:0},i9(e.db.getConfig())}bumpLastMargin(e){this.data.stopx+=e,this.data.stopy+=e}},i9=o(function(t){On(Nt,t),t.fontFamily&&(Nt.personFontFamily=Nt.systemFontFamily=Nt.messageFontFamily=t.fontFamily),t.fontSize&&(Nt.personFontSize=Nt.systemFontSize=Nt.messageFontSize=t.fontSize),t.fontWeight&&(Nt.personFontWeight=Nt.systemFontWeight=Nt.messageFontWeight=t.fontWeight)},"setConf"),hv=o((t,e)=>({fontFamily:t[e+"FontFamily"],fontSize:t[e+"FontSize"],fontWeight:t[e+"FontWeight"]}),"c4ShapeFont"),v5=o(t=>({fontFamily:t.boundaryFontFamily,fontSize:t.boundaryFontSize,fontWeight:t.boundaryFontWeight}),"boundaryFont"),cCe=o(t=>({fontFamily:t.messageFontFamily,fontSize:t.messageFontSize,fontWeight:t.messageFontWeight}),"messageFont");o(Sl,"calcC4ShapeTextWH");LX=o(function(t,e,r){e.x=r.data.startx,e.y=r.data.starty,e.width=r.data.stopx-r.data.startx,e.height=r.data.stopy-r.data.starty,e.label.y=Nt.c4ShapeMargin-35;let n=e.wrap&&Nt.wrap,i=v5(Nt);i.fontSize=i.fontSize+2,i.fontWeight="bold";let a=Cl(e.label.text,i);Sl("label",e,n,i,a),Tl.drawBoundary(t,e,Nt)},"drawBoundary"),DX=o(function(t,e,r,n){let i=0;for(let a of n){i=0;let s=r[a],l=hv(Nt,s.typeC4Shape.text);switch(l.fontSize=l.fontSize-2,s.typeC4Shape.width=Cl("\xAB"+s.typeC4Shape.text+"\xBB",l),s.typeC4Shape.height=l.fontSize+2,s.typeC4Shape.Y=Nt.c4ShapePadding,i=s.typeC4Shape.Y+s.typeC4Shape.height-4,s.image={width:0,height:0,Y:0},s.typeC4Shape.text){case"person":case"external_person":s.image.width=48,s.image.height=48,s.image.Y=i,i=s.image.Y+s.image.height;break}s.sprite&&(s.image.width=48,s.image.height=48,s.image.Y=i,i=s.image.Y+s.image.height);let u=s.wrap&&Nt.wrap,h=Nt.width-Nt.c4ShapePadding*2,f=hv(Nt,s.typeC4Shape.text);if(f.fontSize=f.fontSize+2,f.fontWeight="bold",Sl("label",s,u,f,h),s.label.Y=i+8,i=s.label.Y+s.label.height,s.type&&s.type.text!==""){s.type.text="["+s.type.text+"]";let m=hv(Nt,s.typeC4Shape.text);Sl("type",s,u,m,h),s.type.Y=i+5,i=s.type.Y+s.type.height}else if(s.techn&&s.techn.text!==""){s.techn.text="["+s.techn.text+"]";let m=hv(Nt,s.techn.text);Sl("techn",s,u,m,h),s.techn.Y=i+5,i=s.techn.Y+s.techn.height}let d=i,p=s.label.width;if(s.descr&&s.descr.text!==""){let m=hv(Nt,s.typeC4Shape.text);Sl("descr",s,u,m,h),s.descr.Y=i+20,i=s.descr.Y+s.descr.height,p=Math.max(s.label.width,s.descr.width),d=i-s.descr.textLines*5}p=p+Nt.c4ShapePadding,s.width=Math.max(s.width||Nt.width,p,Nt.width),s.height=Math.max(s.height||Nt.height,d,Nt.height),s.margin=s.margin||Nt.c4ShapeMargin,t.insert(s),Tl.drawC4Shape(e,s,Nt)}t.bumpLastMargin(Nt.c4ShapeMargin)},"drawC4ShapeArray"),ks=class{static{o(this,"Point")}constructor(e,r){this.x=e,this.y=r}},AX=o(function(t,e){let r=t.x,n=t.y,i=e.x,a=e.y,s=r+t.width/2,l=n+t.height/2,u=Math.abs(r-i),h=Math.abs(n-a),f=h/u,d=t.height/t.width,p=null;return n==a&&ri?p=new ks(r,l):r==i&&na&&(p=new ks(s,n)),r>i&&n=f?p=new ks(r,l+f*t.width/2):p=new ks(s-u/h*t.height/2,n+t.height):r=f?p=new ks(r+t.width,l+f*t.width/2):p=new ks(s+u/h*t.height/2,n+t.height):ra?d>=f?p=new ks(r+t.width,l-f*t.width/2):p=new ks(s+t.height/2*u/h,n):r>i&&n>a&&(d>=f?p=new ks(r,l-t.width/2*f):p=new ks(s-t.height/2*u/h,n)),p},"getIntersectPoint"),uCe=o(function(t,e){let r={x:0,y:0};r.x=e.x+e.width/2,r.y=e.y+e.height/2;let n=AX(t,r);r.x=t.x+t.width/2,r.y=t.y+t.height/2;let i=AX(e,r);return{startPoint:n,endPoint:i}},"getIntersectPoints"),hCe=o(function(t,e,r,n){let i=0;for(let a of e){i=i+1;let s=a.wrap&&Nt.wrap,l=cCe(Nt);n.db.getC4Type()==="C4Dynamic"&&(a.label.text=i+": "+a.label.text);let h=Cl(a.label.text,l);Sl("label",a,s,l,h),a.techn&&a.techn.text!==""&&(h=Cl(a.techn.text,l),Sl("techn",a,s,l,h)),a.descr&&a.descr.text!==""&&(h=Cl(a.descr.text,l),Sl("descr",a,s,l,h));let f=r(a.from),d=r(a.to),p=uCe(f,d);a.startPoint=p.startPoint,a.endPoint=p.endPoint}Tl.drawRels(t,e,Nt)},"drawRels");o(RX,"drawInsideBoundary");fCe=o(function(t,e,r,n){Nt=de().c4;let i=de().securityLevel,a;i==="sandbox"&&(a=$e("#i"+e));let s=i==="sandbox"?$e(a.nodes()[0].contentDocument.body):$e("body"),l=n.db;n.db.setWrap(Nt.wrap),_X=l.getC4ShapeInRow(),n9=l.getC4BoundaryInRow(),V.debug(`C:${JSON.stringify(Nt,null,2)}`);let u=i==="sandbox"?s.select(`[id="${e}"]`):$e(`[id="${e}"]`);Tl.insertComputerIcon(u),Tl.insertDatabaseIcon(u),Tl.insertClockIcon(u);let h=new w5(n);h.setData(Nt.diagramMarginX,Nt.diagramMarginX,Nt.diagramMarginY,Nt.diagramMarginY),h.data.widthLimit=screen.availWidth,x5=Nt.diagramMarginX,b5=Nt.diagramMarginY;let f=n.db.getTitle(),d=n.db.getBoundarys("");RX(u,"",h,d,n),Tl.insertArrowHead(u),Tl.insertArrowEnd(u),Tl.insertArrowCrossHead(u),Tl.insertArrowFilledHead(u),hCe(u,n.db.getRels(),n.db.getC4Shape,n),h.data.stopx=x5,h.data.stopy=b5;let p=h.data,g=p.stopy-p.starty+2*Nt.diagramMarginY,v=p.stopx-p.startx+2*Nt.diagramMarginX;f&&u.append("text").text(f).attr("x",(p.stopx-p.startx)/2-4*Nt.diagramMarginX).attr("y",p.starty+Nt.diagramMarginY),Sr(u,g,v,Nt.useMaxWidth);let x=f?60:0;u.attr("viewBox",p.startx-Nt.diagramMarginX+" -"+(Nt.diagramMarginY+x)+" "+v+" "+(g+x)),V.debug("models:",p)},"draw"),a9={drawPersonOrSystemArray:DX,drawBoundary:LX,setConf:i9,draw:fCe}});var dCe,MX,IX=R(()=>{"use strict";dCe=o(t=>`.person { + stroke: ${t.personBorder}; + fill: ${t.personBkg}; + } +`,"getStyles"),MX=dCe});var OX={};hr(OX,{diagram:()=>pCe});var pCe,PX=R(()=>{"use strict";VC();lS();NX();IX();pCe={parser:rz,db:hy,renderer:a9,styles:MX,init:o(({c4:t,wrap:e})=>{a9.setConf(t),hy.setWrap(e)},"init")}});function o9(t){let e=[];for(let r of t){let n=dv.get(r);n?.styles&&(e=[...e,...n.styles??[]].map(i=>i.trim())),n?.textStyles&&(e=[...e,...n.textStyles??[]].map(i=>i.trim()))}return e}var vCe,zX,cm,$h,Es,dv,Cu,l9,c9,T5,s9,Fo,k5,E5,C5,S5,xCe,bCe,wCe,TCe,kCe,ECe,CCe,u9,SCe,ACe,_Ce,GX,LCe,DCe,h9,$X,VX,RCe,UX,NCe,MCe,ICe,OCe,PCe,fv,HX,YX,BCe,FCe,WX,zCe,GCe,$Ce,VCe,UCe,qX,XX,HCe,YCe,WCe,qCe,XCe,jCe,A5,f9=R(()=>{"use strict";Zt();xr();_t();rr();ut();bi();vCe="flowchart-",zX=0,cm=de(),$h=new Map,Es=[],dv=new Map,Cu=[],l9=new Map,c9=new Map,T5=0,s9=!0,E5=[],C5=o(t=>We.sanitizeText(t,cm),"sanitizeText"),S5=o(function(t){for(let e of $h.values())if(e.id===t)return e.domId;return t},"lookUpDomId"),xCe=o(function(t,e,r,n,i,a,s={}){if(!t||t.trim().length===0)return;let l,u=$h.get(t);u===void 0&&(u={id:t,labelType:"text",domId:vCe+t+"-"+zX,styles:[],classes:[]},$h.set(t,u)),zX++,e!==void 0?(cm=de(),l=C5(e.text.trim()),u.labelType=e.type,l.startsWith('"')&&l.endsWith('"')&&(l=l.substring(1,l.length-1)),u.text=l):u.text===void 0&&(u.text=t),r!==void 0&&(u.type=r),n?.forEach(function(h){u.styles.push(h)}),i?.forEach(function(h){u.classes.push(h)}),a!==void 0&&(u.dir=a),u.props===void 0?u.props=s:s!==void 0&&Object.assign(u.props,s)},"addVertex"),bCe=o(function(t,e,r){let a={start:t,end:e,type:void 0,text:"",labelType:"text"};V.info("abc78 Got edge...",a);let s=r.text;if(s!==void 0&&(a.text=C5(s.text.trim()),a.text.startsWith('"')&&a.text.endsWith('"')&&(a.text=a.text.substring(1,a.text.length-1)),a.labelType=s.type),r!==void 0&&(a.type=r.type,a.stroke=r.stroke,a.length=r.length>10?10:r.length),Es.length<(cm.maxEdges??500))V.info("Pushing edge..."),Es.push(a);else throw new Error(`Edge limit exceeded. ${Es.length} edges found, but the limit is ${cm.maxEdges}. + +Initialize mermaid with maxEdges set to a higher number to allow more edges. +You cannot set this config via configuration inside the diagram as it is a secure config. +You have to call mermaid.initialize.`)},"addSingleLink"),wCe=o(function(t,e,r){V.info("addLink",t,e,r);for(let n of t)for(let i of e)bCe(n,i,r)},"addLink"),TCe=o(function(t,e){t.forEach(function(r){r==="default"?Es.defaultInterpolate=e:Es[r].interpolate=e})},"updateLinkInterpolate"),kCe=o(function(t,e){t.forEach(function(r){if(typeof r=="number"&&r>=Es.length)throw new Error(`The index ${r} for linkStyle is out of bounds. Valid indices for linkStyle are between 0 and ${Es.length-1}. (Help: Ensure that the index is within the range of existing edges.)`);r==="default"?Es.defaultStyle=e:(Es[r].style=e,(Es[r]?.style?.length??0)>0&&!Es[r]?.style?.some(n=>n?.startsWith("fill"))&&Es[r]?.style?.push("fill:none"))})},"updateLink"),ECe=o(function(t,e){t.split(",").forEach(function(r){let n=dv.get(r);n===void 0&&(n={id:r,styles:[],textStyles:[]},dv.set(r,n)),e?.forEach(function(i){if(/color/.exec(i)){let a=i.replace("fill","bgFill");n.textStyles.push(a)}n.styles.push(i)})})},"addClass"),CCe=o(function(t){Fo=t,/.*/.exec(Fo)&&(Fo="LR"),/.*v/.exec(Fo)&&(Fo="TB"),Fo==="TD"&&(Fo="TB")},"setDirection"),u9=o(function(t,e){for(let r of t.split(",")){let n=$h.get(r);n&&n.classes.push(e);let i=l9.get(r);i&&i.classes.push(e)}},"setClass"),SCe=o(function(t,e){if(e!==void 0){e=C5(e);for(let r of t.split(","))c9.set(k5==="gen-1"?S5(r):r,e)}},"setTooltip"),ACe=o(function(t,e,r){let n=S5(t);if(de().securityLevel!=="loose"||e===void 0)return;let i=[];if(typeof r=="string"){i=r.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let s=0;s")),i.classed("hover",!0)}).on("mouseout",function(){e.transition().duration(500).style("opacity",0),$e(this).classed("hover",!1)})},"setupToolTips");E5.push(UX);NCe=o(function(t="gen-1"){$h=new Map,dv=new Map,Es=[],E5=[UX],Cu=[],l9=new Map,T5=0,c9=new Map,s9=!0,k5=t,cm=de(),vr()},"clear"),MCe=o(t=>{k5=t||"gen-2"},"setGen"),ICe=o(function(){return"fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;"},"defaultStyle"),OCe=o(function(t,e,r){let n=t.text.trim(),i=r.text;t===r&&/\s/.exec(r.text)&&(n=void 0);function a(h){let f={boolean:{},number:{},string:{}},d=[],p;return{nodeList:h.filter(function(g){let y=typeof g;return g.stmt&&g.stmt==="dir"?(p=g.value,!1):g.trim()===""?!1:y in f?f[y].hasOwnProperty(g)?!1:f[y][g]=!0:d.includes(g)?!1:d.push(g)}),dir:p}}o(a,"uniq");let{nodeList:s,dir:l}=a(e.flat());if(k5==="gen-1")for(let h=0;h2e3)return{result:!1,count:0};if(HX[fv]=e,Cu[e].id===t)return{result:!0,count:0};let n=0,i=1;for(;n=0){let s=YX(t,a);if(s.result)return{result:!0,count:i+s.count};i=i+s.count}n=n+1}return{result:!1,count:i}},"indexNodes2"),BCe=o(function(t){return HX[t]},"getDepthFirstPos"),FCe=o(function(){fv=-1,Cu.length>0&&YX("none",Cu.length-1)},"indexNodes"),WX=o(function(){return Cu},"getSubGraphs"),zCe=o(()=>s9?(s9=!1,!0):!1,"firstGraph"),GCe=o(t=>{let e=t.trim(),r="arrow_open";switch(e[0]){case"<":r="arrow_point",e=e.slice(1);break;case"x":r="arrow_cross",e=e.slice(1);break;case"o":r="arrow_circle",e=e.slice(1);break}let n="normal";return e.includes("=")&&(n="thick"),e.includes(".")&&(n="dotted"),{type:r,stroke:n}},"destructStartLink"),$Ce=o((t,e)=>{let r=e.length,n=0;for(let i=0;i{let e=t.trim(),r=e.slice(0,-1),n="arrow_open";switch(e.slice(-1)){case"x":n="arrow_cross",e.startsWith("x")&&(n="double_"+n,r=r.slice(1));break;case">":n="arrow_point",e.startsWith("<")&&(n="double_"+n,r=r.slice(1));break;case"o":n="arrow_circle",e.startsWith("o")&&(n="double_"+n,r=r.slice(1));break}let i="normal",a=r.length-1;r.startsWith("=")&&(i="thick"),r.startsWith("~")&&(i="invisible");let s=$Ce(".",r);return s&&(i="dotted",a=s),{type:n,stroke:i,length:a}},"destructEndLink"),UCe=o((t,e)=>{let r=VCe(t),n;if(e){if(n=GCe(e),n.stroke!==r.stroke)return{type:"INVALID",stroke:"INVALID"};if(n.type==="arrow_open")n.type=r.type;else{if(n.type!==r.type)return{type:"INVALID",stroke:"INVALID"};n.type="double_"+n.type}return n.type==="double_arrow"&&(n.type="double_arrow_point"),n.length=r.length,n}return r},"destructLink"),qX=o((t,e)=>{for(let r of t)if(r.nodes.includes(e))return!0;return!1},"exists"),XX=o((t,e)=>{let r=[];return t.nodes.forEach((n,i)=>{qX(e,n)||r.push(t.nodes[i])}),{nodes:r}},"makeUniq"),HCe={firstGraph:zCe},YCe=o(t=>t.type==="square"?"squareRect":t.type==="round"?"roundedRect":t.type??"squareRect","getTypeFromVertex"),WCe=o((t,e)=>t.find(r=>r.id===e),"findNode"),qCe=o(t=>{let e="none",r="arrow_point";switch(t){case"arrow_point":case"arrow_circle":case"arrow_cross":r=t;break;case"double_arrow_point":case"double_arrow_circle":case"double_arrow_cross":e=t.replace("double_",""),r=e;break}return{arrowTypeStart:e,arrowTypeEnd:r}},"destructEdgeType"),XCe=o((t,e,r,n,i,a)=>{let s=r.get(t.id),l=n.get(t.id)??!1,u=WCe(e,t.id);u?(u.cssStyles=t.styles,u.cssCompiledStyles=o9(t.classes),u.cssClasses=t.classes.join(" ")):e.push({id:t.id,label:t.text,labelStyle:"",parentId:s,padding:i.flowchart?.padding||8,cssStyles:t.styles,cssCompiledStyles:o9(["default","node",...t.classes]),cssClasses:"default "+t.classes.join(" "),shape:YCe(t),dir:t.dir,domId:t.domId,isGroup:l,look:a,link:t.link,linkTarget:t.linkTarget,tooltip:GX(t.id)})},"addNodeFromVertex");o(o9,"getCompiledStyles");jCe=o(()=>{let t=de(),e=[],r=[],n=WX(),i=new Map,a=new Map;for(let u=n.length-1;u>=0;u--){let h=n[u];h.nodes.length>0&&a.set(h.id,!0);for(let f of h.nodes)i.set(f,h.id)}for(let u=n.length-1;u>=0;u--){let h=n[u];e.push({id:h.id,label:h.title,labelStyle:"",parentId:i.get(h.id),padding:8,cssCompiledStyles:o9(h.classes),cssClasses:h.classes.join(" "),shape:"rect",dir:h.dir,isGroup:!0,look:t.look})}$X().forEach(u=>{XCe(u,e,i,a,t,t.look||"classic")});let l=VX();return l.forEach((u,h)=>{let{arrowTypeStart:f,arrowTypeEnd:d}=qCe(u.type),p=[...l.defaultStyle??[]];u.style&&p.push(...u.style);let m={id:y5(u.start,u.end,{counter:h,prefix:"L"}),start:u.start,end:u.end,type:u.type??"normal",label:u.text,labelpos:"c",thickness:u.stroke,minlen:u.length,classes:u?.stroke==="invisible"?"":"edge-thickness-normal edge-pattern-solid flowchart-link",arrowTypeStart:u?.stroke==="invisible"?"none":f,arrowTypeEnd:u?.stroke==="invisible"?"none":d,arrowheadStyle:"fill: #333",labelStyle:p,style:p,pattern:u.stroke,look:t.look};r.push(m)}),{nodes:e,edges:r,other:{},config:t}},"getData"),A5={defaultConfig:o(()=>_4.flowchart,"defaultConfig"),setAccTitle:kr,getAccTitle:Ar,getAccDescription:Lr,getData:jCe,setAccDescription:_r,addVertex:xCe,lookUpDomId:S5,addLink:wCe,updateLinkInterpolate:TCe,updateLink:kCe,addClass:ECe,setDirection:CCe,setClass:u9,setTooltip:SCe,getTooltip:GX,setClickEvent:LCe,setLink:_Ce,bindFunctions:DCe,getDirection:h9,getVertices:$X,getEdges:VX,getClasses:RCe,clear:NCe,setGen:MCe,defaultStyle:ICe,addSubGraph:OCe,getDepthFirstPos:BCe,indexNodes:FCe,getSubGraphs:WX,destructLink:UCe,lex:HCe,exists:qX,makeUniq:XX,setDiagramTitle:nn,getDiagramTitle:Xr}});var KCe,jX,KX=R(()=>{"use strict";KCe=o(t=>{let e=new Set;for(let r of t)switch(r){case"x":e.add("right"),e.add("left");break;case"y":e.add("up"),e.add("down");break;default:e.add(r);break}return e},"expandAndDeduplicateDirections"),jX=o((t,e,r)=>{let n=KCe(t),i=2,a=e.height+2*r.padding,s=a/i,l=e.width+2*s+r.padding,u=r.padding/2;return n.has("right")&&n.has("left")&&n.has("up")&&n.has("down")?[{x:0,y:0},{x:s,y:0},{x:l/2,y:2*u},{x:l-s,y:0},{x:l,y:0},{x:l,y:-a/3},{x:l+2*u,y:-a/2},{x:l,y:-2*a/3},{x:l,y:-a},{x:l-s,y:-a},{x:l/2,y:-a-2*u},{x:s,y:-a},{x:0,y:-a},{x:0,y:-2*a/3},{x:-2*u,y:-a/2},{x:0,y:-a/3}]:n.has("right")&&n.has("left")&&n.has("up")?[{x:s,y:0},{x:l-s,y:0},{x:l,y:-a/2},{x:l-s,y:-a},{x:s,y:-a},{x:0,y:-a/2}]:n.has("right")&&n.has("left")&&n.has("down")?[{x:0,y:0},{x:s,y:-a},{x:l-s,y:-a},{x:l,y:0}]:n.has("right")&&n.has("up")&&n.has("down")?[{x:0,y:0},{x:l,y:-s},{x:l,y:-a+s},{x:0,y:-a}]:n.has("left")&&n.has("up")&&n.has("down")?[{x:l,y:0},{x:0,y:-s},{x:0,y:-a+s},{x:l,y:-a}]:n.has("right")&&n.has("left")?[{x:s,y:0},{x:s,y:-u},{x:l-s,y:-u},{x:l-s,y:0},{x:l,y:-a/2},{x:l-s,y:-a},{x:l-s,y:-a+u},{x:s,y:-a+u},{x:s,y:-a},{x:0,y:-a/2}]:n.has("up")&&n.has("down")?[{x:l/2,y:0},{x:0,y:-u},{x:s,y:-u},{x:s,y:-a+u},{x:0,y:-a+u},{x:l/2,y:-a},{x:l,y:-a+u},{x:l-s,y:-a+u},{x:l-s,y:-u},{x:l,y:-u}]:n.has("right")&&n.has("up")?[{x:0,y:0},{x:l,y:-s},{x:0,y:-a}]:n.has("right")&&n.has("down")?[{x:0,y:0},{x:l,y:0},{x:0,y:-a}]:n.has("left")&&n.has("up")?[{x:l,y:0},{x:0,y:-s},{x:l,y:-a}]:n.has("left")&&n.has("down")?[{x:l,y:0},{x:0,y:0},{x:l,y:-a}]:n.has("right")?[{x:s,y:-u},{x:s,y:-u},{x:l-s,y:-u},{x:l-s,y:0},{x:l,y:-a/2},{x:l-s,y:-a},{x:l-s,y:-a+u},{x:s,y:-a+u},{x:s,y:-a+u}]:n.has("left")?[{x:s,y:0},{x:s,y:-u},{x:l-s,y:-u},{x:l-s,y:-a+u},{x:s,y:-a+u},{x:s,y:-a},{x:0,y:-a/2}]:n.has("up")?[{x:s,y:-u},{x:s,y:-a+u},{x:0,y:-a+u},{x:l/2,y:-a},{x:l,y:-a+u},{x:l-s,y:-a+u},{x:l-s,y:-u}]:n.has("down")?[{x:l/2,y:0},{x:0,y:-u},{x:s,y:-u},{x:s,y:-a+u},{x:l-s,y:-a+u},{x:l-s,y:-u},{x:l,y:-u}]:[{x:0,y:0}]},"getArrowPoints")});function m9(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function rj(t){Sd=t}function ro(t,e){if(e){if(nj.test(t))return t.replace(QCe,QX)}else if(ij.test(t))return t.replace(ZCe,QX);return t}function t7e(t){return t.replace(e7e,(e,r)=>(r=r.toLowerCase(),r==="colon"?":":r.charAt(0)==="#"?r.charAt(1)==="x"?String.fromCharCode(parseInt(r.substring(2),16)):String.fromCharCode(+r.substring(1)):""))}function ln(t,e){let r=typeof t=="string"?t:t.source;e=e||"";let n={replace:o((i,a)=>{let s=typeof a=="string"?a:a.source;return s=s.replace(r7e,"$1"),r=r.replace(i,s),n},"replace"),getRegex:o(()=>new RegExp(r,e),"getRegex")};return n}function ZX(t){try{t=encodeURI(t).replace(/%25/g,"%")}catch{return null}return t}function JX(t,e){let r=t.replace(/\|/g,(a,s,l)=>{let u=!1,h=s;for(;--h>=0&&l[h]==="\\";)u=!u;return u?"|":" |"}),n=r.split(/ \|/),i=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length{let a=i.match(/^\s+/);if(a===null)return i;let[s]=a;return s.length>=n.length?i.slice(n.length):i}).join(` +`)}function jr(t,e){return Cd.parse(t,e)}var Sd,nj,QCe,ij,ZCe,JCe,QX,e7e,r7e,gv,hm,a7e,s7e,o7e,vv,l7e,aj,sj,g9,c7e,y9,u7e,h7e,D5,v9,f7e,oj,d7e,x9,tj,p7e,m7e,lj,g7e,cj,y7e,xv,v7e,x7e,b7e,w7e,T7e,k7e,E7e,C7e,S7e,L5,A7e,uj,hj,_7e,b9,L7e,d9,D7e,_5,mv,Su,fm,yv,Au,um,p9,Cd,mkt,gkt,ykt,vkt,xkt,bkt,wkt,fj=R(()=>{"use strict";o(m9,"_getDefaults");Sd=m9();o(rj,"changeDefaults");nj=/[&<>"']/,QCe=new RegExp(nj.source,"g"),ij=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,ZCe=new RegExp(ij.source,"g"),JCe={"&":"&","<":"<",">":">",'"':""","'":"'"},QX=o(t=>JCe[t],"getEscapeReplacement");o(ro,"escape$1");e7e=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;o(t7e,"unescape");r7e=/(^|[^\[])\^/g;o(ln,"edit");o(ZX,"cleanUrl");gv={exec:o(()=>null,"exec")};o(JX,"splitCells");o(pv,"rtrim");o(n7e,"findClosingBracket");o(ej,"outputLink");o(i7e,"indentCodeCompensation");hm=class{static{o(this,"_Tokenizer")}options;rules;lexer;constructor(e){this.options=e||Sd}space(e){let r=this.rules.block.newline.exec(e);if(r&&r[0].length>0)return{type:"space",raw:r[0]}}code(e){let r=this.rules.block.code.exec(e);if(r){let n=r[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:r[0],codeBlockStyle:"indented",text:this.options.pedantic?n:pv(n,` +`)}}}fences(e){let r=this.rules.block.fences.exec(e);if(r){let n=r[0],i=i7e(n,r[3]||"");return{type:"code",raw:n,lang:r[2]?r[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):r[2],text:i}}}heading(e){let r=this.rules.block.heading.exec(e);if(r){let n=r[2].trim();if(/#$/.test(n)){let i=pv(n,"#");(this.options.pedantic||!i||/ $/.test(i))&&(n=i.trim())}return{type:"heading",raw:r[0],depth:r[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let r=this.rules.block.hr.exec(e);if(r)return{type:"hr",raw:pv(r[0],` +`)}}blockquote(e){let r=this.rules.block.blockquote.exec(e);if(r){let n=pv(r[0],` +`).split(` +`),i="",a="",s=[];for(;n.length>0;){let l=!1,u=[],h;for(h=0;h/.test(n[h]))u.push(n[h]),l=!0;else if(!l)u.push(n[h]);else break;n=n.slice(h);let f=u.join(` +`),d=f.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,` + $1`).replace(/^ {0,3}>[ \t]?/gm,"");i=i?`${i} +${f}`:f,a=a?`${a} +${d}`:d;let p=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(d,s,!0),this.lexer.state.top=p,n.length===0)break;let m=s[s.length-1];if(m?.type==="code")break;if(m?.type==="blockquote"){let g=m,y=g.raw+` +`+n.join(` +`),v=this.blockquote(y);s[s.length-1]=v,i=i.substring(0,i.length-g.raw.length)+v.raw,a=a.substring(0,a.length-g.text.length)+v.text;break}else if(m?.type==="list"){let g=m,y=g.raw+` +`+n.join(` +`),v=this.list(y);s[s.length-1]=v,i=i.substring(0,i.length-m.raw.length)+v.raw,a=a.substring(0,a.length-g.raw.length)+v.raw,n=y.substring(s[s.length-1].raw.length).split(` +`);continue}}return{type:"blockquote",raw:i,tokens:s,text:a}}}list(e){let r=this.rules.block.list.exec(e);if(r){let n=r[1].trim(),i=n.length>1,a={type:"list",raw:"",ordered:i,start:i?+n.slice(0,-1):"",loose:!1,items:[]};n=i?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=i?n:"[*+-]");let s=new RegExp(`^( {0,3}${n})((?:[ ][^\\n]*)?(?:\\n|$))`),l=!1;for(;e;){let u=!1,h="",f="";if(!(r=s.exec(e))||this.rules.block.hr.test(e))break;h=r[0],e=e.substring(h.length);let d=r[2].split(` +`,1)[0].replace(/^\t+/,x=>" ".repeat(3*x.length)),p=e.split(` +`,1)[0],m=!d.trim(),g=0;if(this.options.pedantic?(g=2,f=d.trimStart()):m?g=r[1].length+1:(g=r[2].search(/[^ ]/),g=g>4?1:g,f=d.slice(g),g+=r[1].length),m&&/^ *$/.test(p)&&(h+=p+` +`,e=e.substring(p.length+1),u=!0),!u){let x=new RegExp(`^ {0,${Math.min(3,g-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),b=new RegExp(`^ {0,${Math.min(3,g-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),w=new RegExp(`^ {0,${Math.min(3,g-1)}}(?:\`\`\`|~~~)`),S=new RegExp(`^ {0,${Math.min(3,g-1)}}#`);for(;e;){let T=e.split(` +`,1)[0];if(p=T,this.options.pedantic&&(p=p.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),w.test(p)||S.test(p)||x.test(p)||b.test(e))break;if(p.search(/[^ ]/)>=g||!p.trim())f+=` +`+p.slice(g);else{if(m||d.search(/[^ ]/)>=4||w.test(d)||S.test(d)||b.test(d))break;f+=` +`+p}!m&&!p.trim()&&(m=!0),h+=T+` +`,e=e.substring(T.length+1),d=p.slice(g)}}a.loose||(l?a.loose=!0:/\n *\n *$/.test(h)&&(l=!0));let y=null,v;this.options.gfm&&(y=/^\[[ xX]\] /.exec(f),y&&(v=y[0]!=="[ ] ",f=f.replace(/^\[[ xX]\] +/,""))),a.items.push({type:"list_item",raw:h,task:!!y,checked:v,loose:!1,text:f,tokens:[]}),a.raw+=h}a.items[a.items.length-1].raw=a.items[a.items.length-1].raw.trimEnd(),a.items[a.items.length-1].text=a.items[a.items.length-1].text.trimEnd(),a.raw=a.raw.trimEnd();for(let u=0;ud.type==="space"),f=h.length>0&&h.some(d=>/\n.*\n/.test(d.raw));a.loose=f}if(a.loose)for(let u=0;u$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",a=r[3]?r[3].substring(1,r[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):r[3];return{type:"def",tag:n,raw:r[0],href:i,title:a}}}table(e){let r=this.rules.block.table.exec(e);if(!r||!/[:|]/.test(r[2]))return;let n=JX(r[1]),i=r[2].replace(/^\||\| *$/g,"").split("|"),a=r[3]&&r[3].trim()?r[3].replace(/\n[ \t]*$/,"").split(` +`):[],s={type:"table",raw:r[0],header:[],align:[],rows:[]};if(n.length===i.length){for(let l of i)/^ *-+: *$/.test(l)?s.align.push("right"):/^ *:-+: *$/.test(l)?s.align.push("center"):/^ *:-+ *$/.test(l)?s.align.push("left"):s.align.push(null);for(let l=0;l({text:u,tokens:this.lexer.inline(u),header:!1,align:s.align[h]})));return s}}lheading(e){let r=this.rules.block.lheading.exec(e);if(r)return{type:"heading",raw:r[0],depth:r[2].charAt(0)==="="?1:2,text:r[1],tokens:this.lexer.inline(r[1])}}paragraph(e){let r=this.rules.block.paragraph.exec(e);if(r){let n=r[1].charAt(r[1].length-1)===` +`?r[1].slice(0,-1):r[1];return{type:"paragraph",raw:r[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let r=this.rules.block.text.exec(e);if(r)return{type:"text",raw:r[0],text:r[0],tokens:this.lexer.inline(r[0])}}escape(e){let r=this.rules.inline.escape.exec(e);if(r)return{type:"escape",raw:r[0],text:ro(r[1])}}tag(e){let r=this.rules.inline.tag.exec(e);if(r)return!this.lexer.state.inLink&&/^/i.test(r[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(r[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(r[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:r[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:r[0]}}link(e){let r=this.rules.inline.link.exec(e);if(r){let n=r[2].trim();if(!this.options.pedantic&&/^$/.test(n))return;let s=pv(n.slice(0,-1),"\\");if((n.length-s.length)%2===0)return}else{let s=n7e(r[2],"()");if(s>-1){let u=(r[0].indexOf("!")===0?5:4)+r[1].length+s;r[2]=r[2].substring(0,s),r[0]=r[0].substring(0,u).trim(),r[3]=""}}let i=r[2],a="";if(this.options.pedantic){let s=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i);s&&(i=s[1],a=s[3])}else a=r[3]?r[3].slice(1,-1):"";return i=i.trim(),/^$/.test(n)?i=i.slice(1):i=i.slice(1,-1)),ej(r,{href:i&&i.replace(this.rules.inline.anyPunctuation,"$1"),title:a&&a.replace(this.rules.inline.anyPunctuation,"$1")},r[0],this.lexer)}}reflink(e,r){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let i=(n[2]||n[1]).replace(/\s+/g," "),a=r[i.toLowerCase()];if(!a){let s=n[0].charAt(0);return{type:"text",raw:s,text:s}}return ej(n,a,n[0],this.lexer)}}emStrong(e,r,n=""){let i=this.rules.inline.emStrongLDelim.exec(e);if(!i||i[3]&&n.match(/[\p{L}\p{N}]/u))return;if(!(i[1]||i[2]||"")||!n||this.rules.inline.punctuation.exec(n)){let s=[...i[0]].length-1,l,u,h=s,f=0,d=i[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(d.lastIndex=0,r=r.slice(-1*e.length+s);(i=d.exec(r))!=null;){if(l=i[1]||i[2]||i[3]||i[4]||i[5]||i[6],!l)continue;if(u=[...l].length,i[3]||i[4]){h+=u;continue}else if((i[5]||i[6])&&s%3&&!((s+u)%3)){f+=u;continue}if(h-=u,h>0)continue;u=Math.min(u,u+h+f);let p=[...i[0]][0].length,m=e.slice(0,s+i.index+p+u);if(Math.min(s,u)%2){let y=m.slice(1,-1);return{type:"em",raw:m,text:y,tokens:this.lexer.inlineTokens(y)}}let g=m.slice(2,-2);return{type:"strong",raw:m,text:g,tokens:this.lexer.inlineTokens(g)}}}}codespan(e){let r=this.rules.inline.code.exec(e);if(r){let n=r[2].replace(/\n/g," "),i=/[^ ]/.test(n),a=/^ /.test(n)&&/ $/.test(n);return i&&a&&(n=n.substring(1,n.length-1)),n=ro(n,!0),{type:"codespan",raw:r[0],text:n}}}br(e){let r=this.rules.inline.br.exec(e);if(r)return{type:"br",raw:r[0]}}del(e){let r=this.rules.inline.del.exec(e);if(r)return{type:"del",raw:r[0],text:r[2],tokens:this.lexer.inlineTokens(r[2])}}autolink(e){let r=this.rules.inline.autolink.exec(e);if(r){let n,i;return r[2]==="@"?(n=ro(r[1]),i="mailto:"+n):(n=ro(r[1]),i=n),{type:"link",raw:r[0],text:n,href:i,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let r;if(r=this.rules.inline.url.exec(e)){let n,i;if(r[2]==="@")n=ro(r[0]),i="mailto:"+n;else{let a;do a=r[0],r[0]=this.rules.inline._backpedal.exec(r[0])?.[0]??"";while(a!==r[0]);n=ro(r[0]),r[1]==="www."?i="http://"+r[0]:i=r[0]}return{type:"link",raw:r[0],text:n,href:i,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let r=this.rules.inline.text.exec(e);if(r){let n;return this.lexer.state.inRawBlock?n=r[0]:n=ro(r[0]),{type:"text",raw:r[0],text:n}}}},a7e=/^(?: *(?:\n|$))+/,s7e=/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,o7e=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,vv=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,l7e=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,aj=/(?:[*+-]|\d{1,9}[.)])/,sj=ln(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,aj).replace(/blockCode/g,/ {4}/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),g9=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,c7e=/^[^\n]+/,y9=/(?!\s*\])(?:\\.|[^\[\]\\])+/,u7e=ln(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",y9).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),h7e=ln(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,aj).getRegex(),D5="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",v9=/|$))/,f7e=ln("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",v9).replace("tag",D5).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),oj=ln(g9).replace("hr",vv).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",D5).getRegex(),d7e=ln(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",oj).getRegex(),x9={blockquote:d7e,code:s7e,def:u7e,fences:o7e,heading:l7e,hr:vv,html:f7e,lheading:sj,list:h7e,newline:a7e,paragraph:oj,table:gv,text:c7e},tj=ln("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",vv).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",D5).getRegex(),p7e={...x9,table:tj,paragraph:ln(g9).replace("hr",vv).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",tj).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",D5).getRegex()},m7e={...x9,html:ln(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",v9).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:gv,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:ln(g9).replace("hr",vv).replace("heading",` *#{1,6} *[^ +]`).replace("lheading",sj).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},lj=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,g7e=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,cj=/^( {2,}|\\)\n(?!\s*$)/,y7e=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\]*?>/g,b7e=ln(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,xv).getRegex(),w7e=ln("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,xv).getRegex(),T7e=ln("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,xv).getRegex(),k7e=ln(/\\([punct])/,"gu").replace(/punct/g,xv).getRegex(),E7e=ln(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),C7e=ln(v9).replace("(?:-->|$)","-->").getRegex(),S7e=ln("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",C7e).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),L5=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,A7e=ln(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",L5).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),uj=ln(/^!?\[(label)\]\[(ref)\]/).replace("label",L5).replace("ref",y9).getRegex(),hj=ln(/^!?\[(ref)\](?:\[\])?/).replace("ref",y9).getRegex(),_7e=ln("reflink|nolink(?!\\()","g").replace("reflink",uj).replace("nolink",hj).getRegex(),b9={_backpedal:gv,anyPunctuation:k7e,autolink:E7e,blockSkip:x7e,br:cj,code:g7e,del:gv,emStrongLDelim:b7e,emStrongRDelimAst:w7e,emStrongRDelimUnd:T7e,escape:lj,link:A7e,nolink:hj,punctuation:v7e,reflink:uj,reflinkSearch:_7e,tag:S7e,text:y7e,url:gv},L7e={...b9,link:ln(/^!?\[(label)\]\((.*?)\)/).replace("label",L5).getRegex(),reflink:ln(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",L5).getRegex()},d9={...b9,escape:ln(lj).replace("])","~|])").getRegex(),url:ln(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\u+" ".repeat(h.length));let i,a,s;for(;e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some(l=>(i=l.call({lexer:this},e,r))?(e=e.substring(i.raw.length),r.push(i),!0):!1))){if(i=this.tokenizer.space(e)){e=e.substring(i.raw.length),i.raw.length===1&&r.length>0?r[r.length-1].raw+=` +`:r.push(i);continue}if(i=this.tokenizer.code(e)){e=e.substring(i.raw.length),a=r[r.length-1],a&&(a.type==="paragraph"||a.type==="text")?(a.raw+=` +`+i.raw,a.text+=` +`+i.text,this.inlineQueue[this.inlineQueue.length-1].src=a.text):r.push(i);continue}if(i=this.tokenizer.fences(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.heading(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.hr(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.blockquote(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.list(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.html(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.def(e)){e=e.substring(i.raw.length),a=r[r.length-1],a&&(a.type==="paragraph"||a.type==="text")?(a.raw+=` +`+i.raw,a.text+=` +`+i.raw,this.inlineQueue[this.inlineQueue.length-1].src=a.text):this.tokens.links[i.tag]||(this.tokens.links[i.tag]={href:i.href,title:i.title});continue}if(i=this.tokenizer.table(e)){e=e.substring(i.raw.length),r.push(i);continue}if(i=this.tokenizer.lheading(e)){e=e.substring(i.raw.length),r.push(i);continue}if(s=e,this.options.extensions&&this.options.extensions.startBlock){let l=1/0,u=e.slice(1),h;this.options.extensions.startBlock.forEach(f=>{h=f.call({lexer:this},u),typeof h=="number"&&h>=0&&(l=Math.min(l,h))}),l<1/0&&l>=0&&(s=e.substring(0,l+1))}if(this.state.top&&(i=this.tokenizer.paragraph(s))){a=r[r.length-1],n&&a?.type==="paragraph"?(a.raw+=` +`+i.raw,a.text+=` +`+i.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=a.text):r.push(i),n=s.length!==e.length,e=e.substring(i.raw.length);continue}if(i=this.tokenizer.text(e)){e=e.substring(i.raw.length),a=r[r.length-1],a&&a.type==="text"?(a.raw+=` +`+i.raw,a.text+=` +`+i.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=a.text):r.push(i);continue}if(e){let l="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(l);break}else throw new Error(l)}}return this.state.top=!0,r}inline(e,r=[]){return this.inlineQueue.push({src:e,tokens:r}),r}inlineTokens(e,r=[]){let n,i,a,s=e,l,u,h;if(this.tokens.links){let f=Object.keys(this.tokens.links);if(f.length>0)for(;(l=this.tokenizer.rules.inline.reflinkSearch.exec(s))!=null;)f.includes(l[0].slice(l[0].lastIndexOf("[")+1,-1))&&(s=s.slice(0,l.index)+"["+"a".repeat(l[0].length-2)+"]"+s.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(l=this.tokenizer.rules.inline.blockSkip.exec(s))!=null;)s=s.slice(0,l.index)+"["+"a".repeat(l[0].length-2)+"]"+s.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;(l=this.tokenizer.rules.inline.anyPunctuation.exec(s))!=null;)s=s.slice(0,l.index)+"++"+s.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;e;)if(u||(h=""),u=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some(f=>(n=f.call({lexer:this},e,r))?(e=e.substring(n.raw.length),r.push(n),!0):!1))){if(n=this.tokenizer.escape(e)){e=e.substring(n.raw.length),r.push(n);continue}if(n=this.tokenizer.tag(e)){e=e.substring(n.raw.length),i=r[r.length-1],i&&n.type==="text"&&i.type==="text"?(i.raw+=n.raw,i.text+=n.text):r.push(n);continue}if(n=this.tokenizer.link(e)){e=e.substring(n.raw.length),r.push(n);continue}if(n=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(n.raw.length),i=r[r.length-1],i&&n.type==="text"&&i.type==="text"?(i.raw+=n.raw,i.text+=n.text):r.push(n);continue}if(n=this.tokenizer.emStrong(e,s,h)){e=e.substring(n.raw.length),r.push(n);continue}if(n=this.tokenizer.codespan(e)){e=e.substring(n.raw.length),r.push(n);continue}if(n=this.tokenizer.br(e)){e=e.substring(n.raw.length),r.push(n);continue}if(n=this.tokenizer.del(e)){e=e.substring(n.raw.length),r.push(n);continue}if(n=this.tokenizer.autolink(e)){e=e.substring(n.raw.length),r.push(n);continue}if(!this.state.inLink&&(n=this.tokenizer.url(e))){e=e.substring(n.raw.length),r.push(n);continue}if(a=e,this.options.extensions&&this.options.extensions.startInline){let f=1/0,d=e.slice(1),p;this.options.extensions.startInline.forEach(m=>{p=m.call({lexer:this},d),typeof p=="number"&&p>=0&&(f=Math.min(f,p))}),f<1/0&&f>=0&&(a=e.substring(0,f+1))}if(n=this.tokenizer.inlineText(a)){e=e.substring(n.raw.length),n.raw.slice(-1)!=="_"&&(h=n.raw.slice(-1)),u=!0,i=r[r.length-1],i&&i.type==="text"?(i.raw+=n.raw,i.text+=n.text):r.push(n);continue}if(e){let f="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(f);break}else throw new Error(f)}}return r}},fm=class{static{o(this,"_Renderer")}options;parser;constructor(e){this.options=e||Sd}space(e){return""}code({text:e,lang:r,escaped:n}){let i=(r||"").match(/^\S*/)?.[0],a=e.replace(/\n$/,"")+` +`;return i?'
'+(n?a:ro(a,!0))+`
+`:"
"+(n?a:ro(a,!0))+`
+`}blockquote({tokens:e}){return`
+${this.parser.parse(e)}
+`}html({text:e}){return e}heading({tokens:e,depth:r}){return`${this.parser.parseInline(e)} +`}hr(e){return`
+`}list(e){let r=e.ordered,n=e.start,i="";for(let l=0;l +`+i+" +`}listitem(e){let r="";if(e.task){let n=this.checkbox({checked:!!e.checked});e.loose?e.tokens.length>0&&e.tokens[0].type==="paragraph"?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&e.tokens[0].tokens[0].type==="text"&&(e.tokens[0].tokens[0].text=n+" "+e.tokens[0].tokens[0].text)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" "}):r+=n+" "}return r+=this.parser.parse(e.tokens,!!e.loose),`
  • ${r}
  • +`}checkbox({checked:e}){return"'}paragraph({tokens:e}){return`

    ${this.parser.parseInline(e)}

    +`}table(e){let r="",n="";for(let a=0;a${i}`),` + +`+r+` +`+i+`
    +`}tablerow({text:e}){return` +${e} +`}tablecell(e){let r=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+r+` +`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${e}`}br(e){return"
    "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:r,tokens:n}){let i=this.parser.parseInline(n),a=ZX(e);if(a===null)return i;e=a;let s='
    ",s}image({href:e,title:r,text:n}){let i=ZX(e);if(i===null)return n;e=i;let a=`${n}{let l=a[s].flat(1/0);n=n.concat(this.walkTokens(l,r))}):a.tokens&&(n=n.concat(this.walkTokens(a.tokens,r)))}}return n}use(...e){let r=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let i={...n};if(i.async=this.defaults.async||i.async||!1,n.extensions&&(n.extensions.forEach(a=>{if(!a.name)throw new Error("extension name required");if("renderer"in a){let s=r.renderers[a.name];s?r.renderers[a.name]=function(...l){let u=a.renderer.apply(this,l);return u===!1&&(u=s.apply(this,l)),u}:r.renderers[a.name]=a.renderer}if("tokenizer"in a){if(!a.level||a.level!=="block"&&a.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let s=r[a.level];s?s.unshift(a.tokenizer):r[a.level]=[a.tokenizer],a.start&&(a.level==="block"?r.startBlock?r.startBlock.push(a.start):r.startBlock=[a.start]:a.level==="inline"&&(r.startInline?r.startInline.push(a.start):r.startInline=[a.start]))}"childTokens"in a&&a.childTokens&&(r.childTokens[a.name]=a.childTokens)}),i.extensions=r),n.renderer){let a=this.defaults.renderer||new fm(this.defaults);for(let s in n.renderer){if(!(s in a))throw new Error(`renderer '${s}' does not exist`);if(["options","parser"].includes(s))continue;let l=s,u=n.renderer[l];n.useNewRenderer||(u=this.#t(u,l,a));let h=a[l];a[l]=(...f)=>{let d=u.apply(a,f);return d===!1&&(d=h.apply(a,f)),d||""}}i.renderer=a}if(n.tokenizer){let a=this.defaults.tokenizer||new hm(this.defaults);for(let s in n.tokenizer){if(!(s in a))throw new Error(`tokenizer '${s}' does not exist`);if(["options","rules","lexer"].includes(s))continue;let l=s,u=n.tokenizer[l],h=a[l];a[l]=(...f)=>{let d=u.apply(a,f);return d===!1&&(d=h.apply(a,f)),d}}i.tokenizer=a}if(n.hooks){let a=this.defaults.hooks||new um;for(let s in n.hooks){if(!(s in a))throw new Error(`hook '${s}' does not exist`);if(s==="options")continue;let l=s,u=n.hooks[l],h=a[l];um.passThroughHooks.has(s)?a[l]=f=>{if(this.defaults.async)return Promise.resolve(u.call(a,f)).then(p=>h.call(a,p));let d=u.call(a,f);return h.call(a,d)}:a[l]=(...f)=>{let d=u.apply(a,f);return d===!1&&(d=h.apply(a,f)),d}}i.hooks=a}if(n.walkTokens){let a=this.defaults.walkTokens,s=n.walkTokens;i.walkTokens=function(l){let u=[];return u.push(s.call(this,l)),a&&(u=u.concat(a.call(this,l))),u}}this.defaults={...this.defaults,...i}}),this}#t(e,r,n){switch(r){case"heading":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,n.parser.parseInline(i.tokens),i.depth,t7e(n.parser.parseInline(i.tokens,n.parser.textRenderer)))};case"code":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.text,i.lang,!!i.escaped)};case"table":return function(i){if(!i.type||i.type!==r)return e.apply(this,arguments);let a="",s="";for(let u=0;u0&&f.tokens[0].type==="paragraph"?(f.tokens[0].text=g+" "+f.tokens[0].text,f.tokens[0].tokens&&f.tokens[0].tokens.length>0&&f.tokens[0].tokens[0].type==="text"&&(f.tokens[0].tokens[0].text=g+" "+f.tokens[0].tokens[0].text)):f.tokens.unshift({type:"text",text:g+" "}):m+=g+" "}m+=this.parser.parse(f.tokens,l),u+=this.listitem({type:"list_item",raw:m,text:m,task:p,checked:!!d,loose:l,tokens:f.tokens})}return e.call(this,u,a,s)};case"html":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.text,i.block)};case"paragraph":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,this.parser.parseInline(i.tokens))};case"escape":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.text)};case"link":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.href,i.title,this.parser.parseInline(i.tokens))};case"image":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.href,i.title,i.text)};case"strong":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,this.parser.parseInline(i.tokens))};case"em":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,this.parser.parseInline(i.tokens))};case"codespan":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.text)};case"del":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,this.parser.parseInline(i.tokens))};case"text":return function(i){return!i.type||i.type!==r?e.apply(this,arguments):e.call(this,i.text)}}return e}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,r){return Su.lex(e,r??this.defaults)}parser(e,r){return Au.parse(e,r??this.defaults)}#e(e,r){return(n,i)=>{let a={...i},s={...this.defaults,...a};this.defaults.async===!0&&a.async===!1&&(s.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),s.async=!0);let l=this.#r(!!s.silent,!!s.async);if(typeof n>"u"||n===null)return l(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(s.hooks&&(s.hooks.options=s),s.async)return Promise.resolve(s.hooks?s.hooks.preprocess(n):n).then(u=>e(u,s)).then(u=>s.hooks?s.hooks.processAllTokens(u):u).then(u=>s.walkTokens?Promise.all(this.walkTokens(u,s.walkTokens)).then(()=>u):u).then(u=>r(u,s)).then(u=>s.hooks?s.hooks.postprocess(u):u).catch(l);try{s.hooks&&(n=s.hooks.preprocess(n));let u=e(n,s);s.hooks&&(u=s.hooks.processAllTokens(u)),s.walkTokens&&this.walkTokens(u,s.walkTokens);let h=r(u,s);return s.hooks&&(h=s.hooks.postprocess(h)),h}catch(u){return l(u)}}}#r(e,r){return n=>{if(n.message+=` +Please report this to https://github.com/markedjs/marked.`,e){let i="

    An error occurred:

    "+ro(n.message+"",!0)+"
    ";return r?Promise.resolve(i):i}if(r)return Promise.reject(n);throw n}}},Cd=new p9;o(jr,"marked");jr.options=jr.setOptions=function(t){return Cd.setOptions(t),jr.defaults=Cd.defaults,rj(jr.defaults),jr};jr.getDefaults=m9;jr.defaults=Sd;jr.use=function(...t){return Cd.use(...t),jr.defaults=Cd.defaults,rj(jr.defaults),jr};jr.walkTokens=function(t,e){return Cd.walkTokens(t,e)};jr.parseInline=Cd.parseInline;jr.Parser=Au;jr.parser=Au.parse;jr.Renderer=fm;jr.TextRenderer=yv;jr.Lexer=Su;jr.lexer=Su.lex;jr.Tokenizer=hm;jr.Hooks=um;jr.parse=jr;mkt=jr.options,gkt=jr.setOptions,ykt=jr.use,vkt=jr.walkTokens,xkt=jr.parseInline,bkt=Au.parse,wkt=Su.lex});function R7e(t,{markdownAutoWrap:e}){let n=t.replace(//g,` +`).replace(/\n{2,}/g,` +`),i=Gb(n);return e===!1?i.replace(/ /g," "):i}function dj(t,e={}){let r=R7e(t,e),n=jr.lexer(r),i=[[]],a=0;function s(l,u="normal"){l.type==="text"?l.text.split(` +`).forEach((f,d)=>{d!==0&&(a++,i.push([])),f.split(" ").forEach(p=>{p&&i[a].push({content:p,type:u})})}):l.type==="strong"||l.type==="em"?l.tokens.forEach(h=>{s(h,l.type)}):l.type==="html"&&i[a].push({content:l.text,type:"normal"})}return o(s,"processNode"),n.forEach(l=>{l.type==="paragraph"?l.tokens?.forEach(u=>{s(u)}):l.type==="html"&&i[a].push({content:l.text,type:"normal"})}),i}function pj(t,{markdownAutoWrap:e}={}){let r=jr.lexer(t);function n(i){return i.type==="text"?e===!1?i.text.replace(/\n */g,"
    ").replace(/ /g," "):i.text.replace(/\n */g,"
    "):i.type==="strong"?`${i.tokens?.map(n).join("")}`:i.type==="em"?`${i.tokens?.map(n).join("")}`:i.type==="paragraph"?`

    ${i.tokens?.map(n).join("")}

    `:i.type==="space"?"":i.type==="html"?`${i.text}`:`Unsupported markdown: ${i.type}`}return o(n,"output"),r.map(n).join("")}var mj=R(()=>{"use strict";fj();zC();o(R7e,"preprocessMarkdown");o(dj,"markdownToLines");o(pj,"markdownToHTML")});function N7e(t){return Intl.Segmenter?[...new Intl.Segmenter().segment(t)].map(e=>e.segment):[...t]}function M7e(t,e){let r=N7e(e.content);return gj(t,[],r,e.type)}function gj(t,e,r,n){if(r.length===0)return[{content:e.join(""),type:n},{content:"",type:n}];let[i,...a]=r,s=[...e,i];return t([{content:s.join(""),type:n}])?gj(t,s,a,n):(e.length===0&&i&&(e.push(i),r.shift()),[{content:e.join(""),type:n},{content:r.join(""),type:n}])}function yj(t,e){if(t.some(({content:r})=>r.includes(` +`)))throw new Error("splitLineToFitWidth does not support newlines in the line");return w9(t,e)}function w9(t,e,r=[],n=[]){if(t.length===0)return n.length>0&&r.push(n),r.length>0?r:[];let i="";t[0].content===" "&&(i=" ",t.shift());let a=t.shift()??{content:" ",type:"normal"},s=[...n];if(i!==""&&s.push({content:i,type:"normal"}),s.push(a),e(s))return w9(t,e,r,s);if(n.length>0)r.push(n),t.unshift(a);else if(a.content){let[l,u]=M7e(e,a);r.push([l]),u.content&&t.unshift(u)}return w9(t,e,r)}var vj=R(()=>{"use strict";o(N7e,"splitTextToChars");o(M7e,"splitWordToFitWidth");o(gj,"splitWordToFitWidthRecursion");o(yj,"splitLineToFitWidth");o(w9,"splitLineToFitWidthRecursion")});function xj(t,e){e&&t.attr("style",e)}async function I7e(t,e,r,n,i=!1){let a=t.append("foreignObject"),s=a.append("xhtml:div"),l=e.label;e.label&&Ni(e.label)&&(l=await yh(e.label.replace(We.lineBreakRegex,` +`),de()));let u=e.isNode?"nodeLabel":"edgeLabel",h=s.append("span");h.html(l),xj(h,e.labelStyle),h.attr("class",`${u} ${n}`),xj(s,e.labelStyle),s.style("display","table-cell"),s.style("white-space","nowrap"),s.style("line-height","1.5"),s.style("max-width",r+"px"),s.style("text-align","center"),s.attr("xmlns","http://www.w3.org/1999/xhtml"),i&&s.attr("class","labelBkg");let f=s.node().getBoundingClientRect();return f.width===r&&(s.style("display","table"),s.style("white-space","break-spaces"),s.style("width",r+"px"),f=s.node().getBoundingClientRect()),a.node()}function T9(t,e,r){return t.append("tspan").attr("class","text-outer-tspan").attr("x",0).attr("y",e*r-.1+"em").attr("dy",r+"em")}function O7e(t,e,r){let n=t.append("text"),i=T9(n,1,e);k9(i,r);let a=i.node().getComputedTextLength();return n.remove(),a}function bj(t,e,r){let n=t.append("text"),i=T9(n,1,e);k9(i,[{content:r,type:"normal"}]);let a=i.node()?.getBoundingClientRect();return a&&n.remove(),a}function P7e(t,e,r,n=!1){let a=e.append("g"),s=a.insert("rect").attr("class","background").attr("style","stroke: none"),l=a.append("text").attr("y","-10.1"),u=0;for(let h of r){let f=o(p=>O7e(a,1.1,p)<=t,"checkWidth"),d=f(h)?[h]:yj(h,f);for(let p of d){let m=T9(l,u,1.1);k9(m,p),u++}}if(n){let h=l.node().getBBox(),f=2;return s.attr("x",-f).attr("y",-f).attr("width",h.width+2*f).attr("height",h.height+2*f),a.node()}else return l.node()}function k9(t,e){t.text(""),e.forEach((r,n)=>{let i=t.append("tspan").attr("font-style",r.type==="em"?"italic":"normal").attr("class","text-inner-tspan").attr("font-weight",r.type==="strong"?"bold":"normal");n===0?i.text(r.content):i.text(" "+r.content)})}function E9(t){return t.replace(/fa[bklrs]?:fa-[\w-]+/g,e=>``)}var ta,Al=R(()=>{"use strict";_t();rr();Zt();ut();mj();xr();vj();o(xj,"applyStyle");o(I7e,"addHtmlSpan");o(T9,"createTspan");o(O7e,"computeWidthOfText");o(bj,"computeDimensionOfText");o(P7e,"createFormattedText");o(k9,"updateTextContentAndStyles");o(E9,"replaceIconSubstring");ta=o(async(t,e="",{style:r="",isTitle:n=!1,classes:i="",useHtmlLabels:a=!0,isNode:s=!0,width:l=200,addSvgBackground:u=!1}={},h)=>{if(V.info("XYZ createText",e,r,n,i,a,s,"addSvgBackground: ",u),a){let f=pj(e,h),d=E9(to(f)),p=e.replace(/\\\\/g,"\\"),m={isNode:s,label:Ni(e)?p:d,labelStyle:r.replace("fill:","color:")};return await I7e(t,m,l,i,u)}else{let f=e.replace(//g,"
    "),d=dj(f.replace("
    ","
    "),h),p=P7e(l,t,d,e?u:!1);if(s){/stroke:/.exec(r)&&(r=r.replace("stroke:","lineColor:"));let m=r.replace(/stroke:[^;]+;?/g,"").replace(/stroke-width:[^;]+;?/g,"").replace(/fill:[^;]+;?/g,"").replace(/color:/g,"fill:");$e(p).attr("style",m)}else{let m=r.replace(/stroke:[^;]+;?/g,"").replace(/stroke-width:[^;]+;?/g,"").replace(/fill:[^;]+;?/g,"").replace(/background:/g,"fill:");$e(p).select("rect").attr("style",m.replace(/background:/g,"fill:"));let g=r.replace(/stroke:[^;]+;?/g,"").replace(/stroke-width:[^;]+;?/g,"").replace(/fill:[^;]+;?/g,"").replace(/color:/g,"fill:");$e(p).select("text").attr("style",g)}return p}},"createText")});function wj(t,e){e&&t.attr("style",e)}function B7e(t){let e=$e(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),r=e.append("xhtml:div"),n=t.label,i=t.isNode?"nodeLabel":"edgeLabel",a=r.append("span");return a.html(n),wj(a,t.labelStyle),a.attr("class",i),wj(r,t.labelStyle),r.style("display","inline-block"),r.style("white-space","nowrap"),r.attr("xmlns","http://www.w3.org/1999/xhtml"),e.node()}var F7e,ra,bv=R(()=>{"use strict";Zt();ut();_t();rr();xr();Al();o(wj,"applyStyle");o(B7e,"addHtmlLabel");F7e=o((t,e,r,n)=>{let i=t||"";if(typeof i=="object"&&(i=i[0]),yr(de().flowchart.htmlLabels)){i=i.replace(/\\n|\n/g,"
    "),V.debug("vertexText"+i);let a={isNode:n,label:E9(to(i)),labelStyle:e.replace("fill:","color:")};return B7e(a)}else{let a=document.createElementNS("http://www.w3.org/2000/svg","text");a.setAttribute("style",e.replace("color:","fill:"));let s=[];typeof i=="string"?s=i.split(/\\n|\n|/gi):Array.isArray(i)?s=i:s=[];for(let l of s){let u=document.createElementNS("http://www.w3.org/2000/svg","tspan");u.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),u.setAttribute("dy","1em"),u.setAttribute("x","0"),r?u.setAttribute("class","title-row"):u.setAttribute("class","row"),u.textContent=l.trim(),a.appendChild(u)}return a}},"createLabel"),ra=F7e});function z7e(t,e){return t.intersect(e)}var Tj,kj=R(()=>{"use strict";o(z7e,"intersectNode");Tj=z7e});function G7e(t,e,r,n){var i=t.x,a=t.y,s=i-n.x,l=a-n.y,u=Math.sqrt(e*e*l*l+r*r*s*s),h=Math.abs(e*r*s/u);n.x{"use strict";o(G7e,"intersectEllipse");R5=G7e});function $7e(t,e,r){return R5(t,e,e,r)}var Ej,Cj=R(()=>{"use strict";C9();o($7e,"intersectCircle");Ej=$7e});function V7e(t,e,r,n){var i,a,s,l,u,h,f,d,p,m,g,y,v,x,b;if(i=e.y-t.y,s=t.x-e.x,u=e.x*t.y-t.x*e.y,p=i*r.x+s*r.y+u,m=i*n.x+s*n.y+u,!(p!==0&&m!==0&&Sj(p,m))&&(a=n.y-r.y,l=r.x-n.x,h=n.x*r.y-r.x*n.y,f=a*t.x+l*t.y+h,d=a*e.x+l*e.y+h,!(f!==0&&d!==0&&Sj(f,d))&&(g=i*l-a*s,g!==0)))return y=Math.abs(g/2),v=s*h-l*u,x=v<0?(v-y)/g:(v+y)/g,v=a*u-i*h,b=v<0?(v-y)/g:(v+y)/g,{x,y:b}}function Sj(t,e){return t*e>0}var Aj,_j=R(()=>{"use strict";o(V7e,"intersectLine");o(Sj,"sameSign");Aj=V7e});function U7e(t,e,r){var n=t.x,i=t.y,a=[],s=Number.POSITIVE_INFINITY,l=Number.POSITIVE_INFINITY;typeof e.forEach=="function"?e.forEach(function(g){s=Math.min(s,g.x),l=Math.min(l,g.y)}):(s=Math.min(s,e.x),l=Math.min(l,e.y));for(var u=n-t.width/2-s,h=i-t.height/2-l,f=0;f1&&a.sort(function(g,y){var v=g.x-r.x,x=g.y-r.y,b=Math.sqrt(v*v+x*x),w=y.x-r.x,S=y.y-r.y,T=Math.sqrt(w*w+S*S);return b{"use strict";_j();Lj=U7e;o(U7e,"intersectPolygon")});var H7e,Ad,S9=R(()=>{"use strict";H7e=o((t,e)=>{var r=t.x,n=t.y,i=e.x-r,a=e.y-n,s=t.width/2,l=t.height/2,u,h;return Math.abs(a)*s>Math.abs(i)*l?(a<0&&(l=-l),u=a===0?0:l*i/a,h=l):(i<0&&(s=-s),u=s,h=i===0?0:s*a/i),{x:r+u,y:n+h}},"intersectRect"),Ad=H7e});var Tn,A9=R(()=>{"use strict";kj();Cj();C9();Dj();S9();Tn={node:Tj,circle:Ej,ellipse:R5,polygon:Lj,rect:Ad}});function _l(t,e,r,n){return t.insert("polygon",":first-child").attr("points",n.map(function(i){return i.x+","+i.y}).join(" ")).attr("class","label-container").attr("transform","translate("+-e/2+","+r/2+")")}var Ti,kn,N5=R(()=>{"use strict";bv();Al();_t();Zt();rr();xr();Ti=o(async(t,e,r,n)=>{let i=de(),a,s=e.useHtmlLabels||yr(i.flowchart.htmlLabels);r?a=r:a="node default";let l=t.insert("g").attr("class",a).attr("id",e.domId||e.id),u=l.insert("g").attr("class","label").attr("style",e.labelStyle),h;e.labelText===void 0?h="":h=typeof e.labelText=="string"?e.labelText:e.labelText[0];let f=u.node(),d;e.labelType==="markdown"?d=ta(u,qr(to(h),i),{useHtmlLabels:s,width:e.width||i.flowchart.wrappingWidth,classes:"markdown-node-label"},i):d=f.appendChild(ra(qr(to(h),i),e.labelStyle,!1,n));let p=d.getBBox(),m=e.padding/2;if(yr(i.flowchart.htmlLabels)){let g=d.children[0],y=$e(d),v=g.getElementsByTagName("img");if(v){let x=h.replace(/]*>/g,"").trim()==="";await Promise.all([...v].map(b=>new Promise(w=>{function S(){if(b.style.display="flex",b.style.flexDirection="column",x){let T=i.fontSize?i.fontSize:window.getComputedStyle(document.body).fontSize,_=parseInt(T,10)*5+"px";b.style.minWidth=_,b.style.maxWidth=_}else b.style.width="100%";w(b)}o(S,"setupImage"),setTimeout(()=>{b.complete&&S()}),b.addEventListener("error",S),b.addEventListener("load",S)})))}p=g.getBoundingClientRect(),y.attr("width",p.width),y.attr("height",p.height)}return s?u.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"):u.attr("transform","translate(0, "+-p.height/2+")"),e.centerLabel&&u.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),u.insert("rect",":first-child"),{shapeSvg:l,bbox:p,halfPadding:m,label:u}},"labelHelper"),kn=o((t,e)=>{let r=e.node().getBBox();t.width=r.width,t.height=r.height},"updateNodeBounds");o(_l,"insertPolygonShape")});var Y7e,Rj,Nj=R(()=>{"use strict";N5();ut();_t();A9();Y7e=o(async(t,e)=>{e.useHtmlLabels||de().flowchart.htmlLabels||(e.centerLabel=!0);let{shapeSvg:n,bbox:i,halfPadding:a}=await Ti(t,e,"node "+e.classes,!0);V.info("Classes = ",e.classes);let s=n.insert("rect",":first-child");return s.attr("rx",e.rx).attr("ry",e.ry).attr("x",-i.width/2-a).attr("y",-i.height/2-a).attr("width",i.width+e.padding).attr("height",i.height+e.padding),kn(e,s),e.intersect=function(l){return Tn.rect(e,l)},n},"note"),Rj=Y7e});function _9(t,e,r,n){let i=[],a=o(l=>{i.push(l,0)},"addBorder"),s=o(l=>{i.push(0,l)},"skipBorder");e.includes("t")?(V.debug("add top border"),a(r)):s(r),e.includes("r")?(V.debug("add right border"),a(n)):s(n),e.includes("b")?(V.debug("add bottom border"),a(r)):s(r),e.includes("l")?(V.debug("add left border"),a(n)):s(n),t.attr("stroke-dasharray",i.join(" "))}var Mj,no,Ij,W7e,q7e,X7e,j7e,K7e,Q7e,Z7e,J7e,eSe,tSe,rSe,nSe,iSe,aSe,sSe,oSe,lSe,cSe,uSe,Oj,hSe,fSe,Pj,dm,pm,Bj,Fj,wv,M5=R(()=>{"use strict";Zt();_t();rr();ut();KX();bv();A9();Nj();N5();Mj=o(t=>t?" "+t:"","formatClass"),no=o((t,e)=>`${e||"node default"}${Mj(t.classes)} ${Mj(t.class)}`,"getClassesFromNode"),Ij=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=i+a,l=[{x:s/2,y:0},{x:s,y:-s/2},{x:s/2,y:-s},{x:0,y:-s/2}];V.info("Question main (Circle)");let u=_l(r,s,s,l);return u.attr("style",e.style),kn(e,u),e.intersect=function(h){return V.warn("Intersect called"),Tn.polygon(e,l,h)},r},"question"),W7e=o((t,e)=>{let r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),n=28,i=[{x:0,y:n/2},{x:n/2,y:0},{x:0,y:-n/2},{x:-n/2,y:0}];return r.insert("polygon",":first-child").attr("points",i.map(function(s){return s.x+","+s.y}).join(" ")).attr("class","state-start").attr("r",7).attr("width",28).attr("height",28),e.width=28,e.height=28,e.intersect=function(s){return Tn.circle(e,14,s)},r},"choice"),q7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=4,a=n.height+e.padding,s=a/i,l=n.width+2*s+e.padding,u=[{x:s,y:0},{x:l-s,y:0},{x:l,y:-a/2},{x:l-s,y:-a},{x:s,y:-a},{x:0,y:-a/2}],h=_l(r,l,a,u);return h.attr("style",e.style),kn(e,h),e.intersect=function(f){return Tn.polygon(e,u,f)},r},"hexagon"),X7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,void 0,!0),i=2,a=n.height+2*e.padding,s=a/i,l=n.width+2*s+e.padding,u=jX(e.directions,n,e),h=_l(r,l,a,u);return h.attr("style",e.style),kn(e,h),e.intersect=function(f){return Tn.polygon(e,u,f)},r},"block_arrow"),j7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:-a/2,y:0},{x:i,y:0},{x:i,y:-a},{x:-a/2,y:-a},{x:0,y:-a/2}];return _l(r,i,a,s).attr("style",e.style),e.width=i+a,e.height=a,e.intersect=function(u){return Tn.polygon(e,s,u)},r},"rect_left_inv_arrow"),K7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:-2*a/6,y:0},{x:i-a/6,y:0},{x:i+2*a/6,y:-a},{x:a/6,y:-a}],l=_l(r,i,a,s);return l.attr("style",e.style),kn(e,l),e.intersect=function(u){return Tn.polygon(e,s,u)},r},"lean_right"),Q7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:2*a/6,y:0},{x:i+a/6,y:0},{x:i-2*a/6,y:-a},{x:-a/6,y:-a}],l=_l(r,i,a,s);return l.attr("style",e.style),kn(e,l),e.intersect=function(u){return Tn.polygon(e,s,u)},r},"lean_left"),Z7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:-2*a/6,y:0},{x:i+2*a/6,y:0},{x:i-a/6,y:-a},{x:a/6,y:-a}],l=_l(r,i,a,s);return l.attr("style",e.style),kn(e,l),e.intersect=function(u){return Tn.polygon(e,s,u)},r},"trapezoid"),J7e=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:a/6,y:0},{x:i-a/6,y:0},{x:i+2*a/6,y:-a},{x:-2*a/6,y:-a}],l=_l(r,i,a,s);return l.attr("style",e.style),kn(e,l),e.intersect=function(u){return Tn.polygon(e,s,u)},r},"inv_trapezoid"),eSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:0,y:0},{x:i+a/2,y:0},{x:i,y:-a/2},{x:i+a/2,y:-a},{x:0,y:-a}],l=_l(r,i,a,s);return l.attr("style",e.style),kn(e,l),e.intersect=function(u){return Tn.polygon(e,s,u)},r},"rect_right_inv_arrow"),tSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=i/2,s=a/(2.5+i/50),l=n.height+s+e.padding,u="M 0,"+s+" a "+a+","+s+" 0,0,0 "+i+" 0 a "+a+","+s+" 0,0,0 "+-i+" 0 l 0,"+l+" a "+a+","+s+" 0,0,0 "+i+" 0 l 0,"+-l,h=r.attr("label-offset-y",s).insert("path",":first-child").attr("style",e.style).attr("d",u).attr("transform","translate("+-i/2+","+-(l/2+s)+")");return kn(e,h),e.intersect=function(f){let d=Tn.rect(e,f),p=d.x-e.x;if(a!=0&&(Math.abs(p)e.height/2-s)){let m=s*s*(1-p*p/(a*a));m!=0&&(m=Math.sqrt(m)),m=s-m,f.y-e.y>0&&(m=-m),d.y+=m}return d},r},"cylinder"),rSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n,halfPadding:i}=await Ti(t,e,"node "+e.classes+" "+e.class,!0),a=r.insert("rect",":first-child"),s=e.positioned?e.width:n.width+e.padding,l=e.positioned?e.height:n.height+e.padding,u=e.positioned?-s/2:-n.width/2-i,h=e.positioned?-l/2:-n.height/2-i;if(a.attr("class","basic label-container").attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",u).attr("y",h).attr("width",s).attr("height",l),e.props){let f=new Set(Object.keys(e.props));e.props.borders&&(_9(a,e.props.borders,s,l),f.delete("borders")),f.forEach(d=>{V.warn(`Unknown node property ${d}`)})}return kn(e,a),e.intersect=function(f){return Tn.rect(e,f)},r},"rect"),nSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n,halfPadding:i}=await Ti(t,e,"node "+e.classes,!0),a=r.insert("rect",":first-child"),s=e.positioned?e.width:n.width+e.padding,l=e.positioned?e.height:n.height+e.padding,u=e.positioned?-s/2:-n.width/2-i,h=e.positioned?-l/2:-n.height/2-i;if(a.attr("class","basic cluster composite label-container").attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",u).attr("y",h).attr("width",s).attr("height",l),e.props){let f=new Set(Object.keys(e.props));e.props.borders&&(_9(a,e.props.borders,s,l),f.delete("borders")),f.forEach(d=>{V.warn(`Unknown node property ${d}`)})}return kn(e,a),e.intersect=function(f){return Tn.rect(e,f)},r},"composite"),iSe=o(async(t,e)=>{let{shapeSvg:r}=await Ti(t,e,"label",!0);V.trace("Classes = ",e.class);let n=r.insert("rect",":first-child"),i=0,a=0;if(n.attr("width",i).attr("height",a),r.attr("class","label edgeLabel"),e.props){let s=new Set(Object.keys(e.props));e.props.borders&&(_9(n,e.props.borders,i,a),s.delete("borders")),s.forEach(l=>{V.warn(`Unknown node property ${l}`)})}return kn(e,n),e.intersect=function(s){return Tn.rect(e,s)},r},"labelRect");o(_9,"applyNodePropertyBorders");aSe=o((t,e)=>{let r;e.classes?r="node "+e.classes:r="node default";let n=t.insert("g").attr("class",r).attr("id",e.domId||e.id),i=n.insert("rect",":first-child"),a=n.insert("line"),s=n.insert("g").attr("class","label"),l=e.labelText.flat?e.labelText.flat():e.labelText,u="";typeof l=="object"?u=l[0]:u=l,V.info("Label text abc79",u,l,typeof l=="object");let h=s.node().appendChild(ra(u,e.labelStyle,!0,!0)),f={width:0,height:0};if(yr(de().flowchart.htmlLabels)){let y=h.children[0],v=$e(h);f=y.getBoundingClientRect(),v.attr("width",f.width),v.attr("height",f.height)}V.info("Text 2",l);let d=l.slice(1,l.length),p=h.getBBox(),m=s.node().appendChild(ra(d.join?d.join("
    "):d,e.labelStyle,!0,!0));if(yr(de().flowchart.htmlLabels)){let y=m.children[0],v=$e(m);f=y.getBoundingClientRect(),v.attr("width",f.width),v.attr("height",f.height)}let g=e.padding/2;return $e(m).attr("transform","translate( "+(f.width>p.width?0:(p.width-f.width)/2)+", "+(p.height+g+5)+")"),$e(h).attr("transform","translate( "+(f.width{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.height+e.padding,a=n.width+i/4+e.padding,s=r.insert("rect",":first-child").attr("style",e.style).attr("rx",i/2).attr("ry",i/2).attr("x",-a/2).attr("y",-i/2).attr("width",a).attr("height",i);return kn(e,s),e.intersect=function(l){return Tn.rect(e,l)},r},"stadium"),oSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n,halfPadding:i}=await Ti(t,e,no(e,void 0),!0),a=r.insert("circle",":first-child");return a.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("r",n.width/2+i).attr("width",n.width+e.padding).attr("height",n.height+e.padding),V.info("Circle main"),kn(e,a),e.intersect=function(s){return V.info("Circle intersect",e,n.width/2+i,s),Tn.circle(e,n.width/2+i,s)},r},"circle"),lSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n,halfPadding:i}=await Ti(t,e,no(e,void 0),!0),a=5,s=r.insert("g",":first-child"),l=s.insert("circle"),u=s.insert("circle");return s.attr("class",e.class),l.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("r",n.width/2+i+a).attr("width",n.width+e.padding+a*2).attr("height",n.height+e.padding+a*2),u.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("r",n.width/2+i).attr("width",n.width+e.padding).attr("height",n.height+e.padding),V.info("DoubleCircle main"),kn(e,l),e.intersect=function(h){return V.info("DoubleCircle intersect",e,n.width/2+i+a,h),Tn.circle(e,n.width/2+i+a,h)},r},"doublecircle"),cSe=o(async(t,e)=>{let{shapeSvg:r,bbox:n}=await Ti(t,e,no(e,void 0),!0),i=n.width+e.padding,a=n.height+e.padding,s=[{x:0,y:0},{x:i,y:0},{x:i,y:-a},{x:0,y:-a},{x:0,y:0},{x:-8,y:0},{x:i+8,y:0},{x:i+8,y:-a},{x:-8,y:-a},{x:-8,y:0}],l=_l(r,i,a,s);return l.attr("style",e.style),kn(e,l),e.intersect=function(u){return Tn.polygon(e,s,u)},r},"subroutine"),uSe=o((t,e)=>{let r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),n=r.insert("circle",":first-child");return n.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),kn(e,n),e.intersect=function(i){return Tn.circle(e,7,i)},r},"start"),Oj=o((t,e,r)=>{let n=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),i=70,a=10;r==="LR"&&(i=10,a=70);let s=n.append("rect").attr("x",-1*i/2).attr("y",-1*a/2).attr("width",i).attr("height",a).attr("class","fork-join");return kn(e,s),e.height=e.height+e.padding/2,e.width=e.width+e.padding/2,e.intersect=function(l){return Tn.rect(e,l)},n},"forkJoin"),hSe=o((t,e)=>{let r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),n=r.insert("circle",":first-child"),i=r.insert("circle",":first-child");return i.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),n.attr("class","state-end").attr("r",5).attr("width",10).attr("height",10),kn(e,i),e.intersect=function(a){return Tn.circle(e,7,a)},r},"end"),fSe=o((t,e)=>{let r=e.padding/2,n=4,i=8,a;e.classes?a="node "+e.classes:a="node default";let s=t.insert("g").attr("class",a).attr("id",e.domId||e.id),l=s.insert("rect",":first-child"),u=s.insert("line"),h=s.insert("line"),f=0,d=n,p=s.insert("g").attr("class","label"),m=0,g=e.classData.annotations?.[0],y=e.classData.annotations[0]?"\xAB"+e.classData.annotations[0]+"\xBB":"",v=p.node().appendChild(ra(y,e.labelStyle,!0,!0)),x=v.getBBox();if(yr(de().flowchart.htmlLabels)){let A=v.children[0],L=$e(v);x=A.getBoundingClientRect(),L.attr("width",x.width),L.attr("height",x.height)}e.classData.annotations[0]&&(d+=x.height+n,f+=x.width);let b=e.classData.label;e.classData.type!==void 0&&e.classData.type!==""&&(de().flowchart.htmlLabels?b+="<"+e.classData.type+">":b+="<"+e.classData.type+">");let w=p.node().appendChild(ra(b,e.labelStyle,!0,!0));$e(w).attr("class","classTitle");let S=w.getBBox();if(yr(de().flowchart.htmlLabels)){let A=w.children[0],L=$e(w);S=A.getBoundingClientRect(),L.attr("width",S.width),L.attr("height",S.height)}d+=S.height+n,S.width>f&&(f=S.width);let T=[];e.classData.members.forEach(A=>{let L=A.getDisplayDetails(),M=L.displayText;de().flowchart.htmlLabels&&(M=M.replace(//g,">"));let N=p.node().appendChild(ra(M,L.cssStyle?L.cssStyle:e.labelStyle,!0,!0)),k=N.getBBox();if(yr(de().flowchart.htmlLabels)){let I=N.children[0],C=$e(N);k=I.getBoundingClientRect(),C.attr("width",k.width),C.attr("height",k.height)}k.width>f&&(f=k.width),d+=k.height+n,T.push(N)}),d+=i;let E=[];if(e.classData.methods.forEach(A=>{let L=A.getDisplayDetails(),M=L.displayText;de().flowchart.htmlLabels&&(M=M.replace(//g,">"));let N=p.node().appendChild(ra(M,L.cssStyle?L.cssStyle:e.labelStyle,!0,!0)),k=N.getBBox();if(yr(de().flowchart.htmlLabels)){let I=N.children[0],C=$e(N);k=I.getBoundingClientRect(),C.attr("width",k.width),C.attr("height",k.height)}k.width>f&&(f=k.width),d+=k.height+n,E.push(N)}),d+=i,g){let A=(f-x.width)/2;$e(v).attr("transform","translate( "+(-1*f/2+A)+", "+-1*d/2+")"),m=x.height+n}let _=(f-S.width)/2;return $e(w).attr("transform","translate( "+(-1*f/2+_)+", "+(-1*d/2+m)+")"),m+=S.height+n,u.attr("class","divider").attr("x1",-f/2-r).attr("x2",f/2+r).attr("y1",-d/2-r+i+m).attr("y2",-d/2-r+i+m),m+=i,T.forEach(A=>{$e(A).attr("transform","translate( "+-f/2+", "+(-1*d/2+m+i/2)+")");let L=A?.getBBox();m+=(L?.height??0)+n}),m+=i,h.attr("class","divider").attr("x1",-f/2-r).attr("x2",f/2+r).attr("y1",-d/2-r+i+m).attr("y2",-d/2-r+i+m),m+=i,E.forEach(A=>{$e(A).attr("transform","translate( "+-f/2+", "+(-1*d/2+m)+")");let L=A?.getBBox();m+=(L?.height??0)+n}),l.attr("style",e.style).attr("class","outer title-state").attr("x",-f/2-r).attr("y",-(d/2)-r).attr("width",f+e.padding).attr("height",d+e.padding),kn(e,l),e.intersect=function(A){return Tn.rect(e,A)},s},"class_box"),Pj={rhombus:Ij,composite:nSe,question:Ij,rect:rSe,labelRect:iSe,rectWithTitle:aSe,choice:W7e,circle:oSe,doublecircle:lSe,stadium:sSe,hexagon:q7e,block_arrow:X7e,rect_left_inv_arrow:j7e,lean_right:K7e,lean_left:Q7e,trapezoid:Z7e,inv_trapezoid:J7e,rect_right_inv_arrow:eSe,cylinder:tSe,start:uSe,end:hSe,note:Rj,subroutine:cSe,fork:Oj,join:Oj,class_box:fSe},dm={},pm=o(async(t,e,r)=>{let n,i;if(e.link){let a;de().securityLevel==="sandbox"?a="_top":e.linkTarget&&(a=e.linkTarget||"_blank"),n=t.insert("svg:a").attr("xlink:href",e.link).attr("target",a),i=await Pj[e.shape](n,e,r)}else i=await Pj[e.shape](t,e,r),n=i;return e.tooltip&&i.attr("title",e.tooltip),e.class&&i.attr("class","node default "+e.class),dm[e.id]=n,e.haveCallback&&dm[e.id].attr("class",dm[e.id].attr("class")+" clickable"),n},"insertNode"),Bj=o((t,e)=>{dm[e.id]=t},"setNodeElem"),Fj=o(()=>{dm={}},"clear"),wv=o(t=>{let e=dm[t.id];V.trace("Transforming node",t.diff,t,"translate("+(t.x-t.width/2-5)+", "+t.width/2+")");let r=8,n=t.diff||0;return t.clusterNode?e.attr("transform","translate("+(t.x+n-t.width/2)+", "+(t.y-t.height/2-r)+")"):e.attr("transform","translate("+t.x+", "+t.y+")"),n},"positionNode")});var I5,L9=R(()=>{"use strict";Zt();M5();I5=o((t,e)=>{let r;return e==="sandbox"&&(r=$e("#i"+t)),(e==="sandbox"?$e(r.nodes()[0].contentDocument.body):$e("body")).select(`[id="${t}"]`)},"getDiagramElement")});var io,_d=R(()=>{"use strict";io=o(({flowchart:t})=>{let e=t?.subGraphTitleMargin?.top??0,r=t?.subGraphTitleMargin?.bottom??0,n=e+r;return{subGraphTitleTopMargin:e,subGraphTitleBottomMargin:r,subGraphTitleTotalMargin:n}},"getSubGraphTitleMargins")});function D9(t,e,r){if(t&&t.length){let[n,i]=e,a=Math.PI/180*r,s=Math.cos(a),l=Math.sin(a);for(let u of t){let[h,f]=u;u[0]=(h-n)*s-(f-i)*l+n,u[1]=(h-n)*l+(f-i)*s+i}}}function dSe(t,e){return t[0]===e[0]&&t[1]===e[1]}function pSe(t,e,r,n=1){let i=r,a=Math.max(e,.1),s=t[0]&&t[0][0]&&typeof t[0][0]=="number"?[t]:t,l=[0,0];if(i)for(let h of s)D9(h,l,i);let u=function(h,f,d){let p=[];for(let b of h){let w=[...b];dSe(w[0],w[w.length-1])||w.push([w[0][0],w[0][1]]),w.length>2&&p.push(w)}let m=[];f=Math.max(f,.1);let g=[];for(let b of p)for(let w=0;wb.yminw.ymin?1:b.xw.x?1:b.ymax===w.ymax?0:(b.ymax-w.ymax)/Math.abs(b.ymax-w.ymax)),!g.length)return m;let y=[],v=g[0].ymin,x=0;for(;y.length||g.length;){if(g.length){let b=-1;for(let w=0;wv);w++)b=w;g.splice(0,b+1).forEach(w=>{y.push({s:v,edge:w})})}if(y=y.filter(b=>!(b.edge.ymax<=v)),y.sort((b,w)=>b.edge.x===w.edge.x?0:(b.edge.x-w.edge.x)/Math.abs(b.edge.x-w.edge.x)),(d!==1||x%f==0)&&y.length>1)for(let b=0;b=y.length)break;let S=y[b].edge,T=y[w].edge;m.push([[Math.round(S.x),v],[Math.round(T.x),v]])}v+=d,y.forEach(b=>{b.edge.x=b.edge.x+d*b.edge.islope}),x++}return m}(s,a,n);if(i){for(let h of s)D9(h,l,-i);(function(h,f,d){let p=[];h.forEach(m=>p.push(...m)),D9(p,f,d)})(u,l,-i)}return u}function Cv(t,e){var r;let n=e.hachureAngle+90,i=e.hachureGap;i<0&&(i=4*e.strokeWidth),i=Math.round(Math.max(i,.1));let a=1;return e.roughness>=1&&(((r=e.randomizer)===null||r===void 0?void 0:r.next())||Math.random())>.7&&(a=i),pSe(t,i,n,a||1)}function U5(t){let e=t[0],r=t[1];return Math.sqrt(Math.pow(e[0]-r[0],2)+Math.pow(e[1]-r[1],2))}function N9(t,e){return t.type===e}function W9(t){let e=[],r=function(s){let l=new Array;for(;s!=="";)if(s.match(/^([ \t\r\n,]+)/))s=s.substr(RegExp.$1.length);else if(s.match(/^([aAcChHlLmMqQsStTvVzZ])/))l[l.length]={type:mSe,text:RegExp.$1},s=s.substr(RegExp.$1.length);else{if(!s.match(/^(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)/))return[];l[l.length]={type:R9,text:`${parseFloat(RegExp.$1)}`},s=s.substr(RegExp.$1.length)}return l[l.length]={type:zj,text:""},l}(t),n="BOD",i=0,a=r[i];for(;!N9(a,zj);){let s=0,l=[];if(n==="BOD"){if(a.text!=="M"&&a.text!=="m")return W9("M0,0"+t);i++,s=O5[a.text],n=a.text}else N9(a,R9)?s=O5[n]:(i++,s=O5[a.text],n=a.text);if(!(i+sf%2?h+r:h+e);a.push({key:"C",data:u}),e=u[4],r=u[5];break}case"Q":a.push({key:"Q",data:[...l]}),e=l[2],r=l[3];break;case"q":{let u=l.map((h,f)=>f%2?h+r:h+e);a.push({key:"Q",data:u}),e=u[2],r=u[3];break}case"A":a.push({key:"A",data:[...l]}),e=l[5],r=l[6];break;case"a":e+=l[5],r+=l[6],a.push({key:"A",data:[l[0],l[1],l[2],l[3],l[4],e,r]});break;case"H":a.push({key:"H",data:[...l]}),e=l[0];break;case"h":e+=l[0],a.push({key:"H",data:[e]});break;case"V":a.push({key:"V",data:[...l]}),r=l[0];break;case"v":r+=l[0],a.push({key:"V",data:[r]});break;case"S":a.push({key:"S",data:[...l]}),e=l[2],r=l[3];break;case"s":{let u=l.map((h,f)=>f%2?h+r:h+e);a.push({key:"S",data:u}),e=u[2],r=u[3];break}case"T":a.push({key:"T",data:[...l]}),e=l[0],r=l[1];break;case"t":e+=l[0],r+=l[1],a.push({key:"T",data:[e,r]});break;case"Z":case"z":a.push({key:"Z",data:[]}),e=n,r=i}return a}function Xj(t){let e=[],r="",n=0,i=0,a=0,s=0,l=0,u=0;for(let{key:h,data:f}of t){switch(h){case"M":e.push({key:"M",data:[...f]}),[n,i]=f,[a,s]=f;break;case"C":e.push({key:"C",data:[...f]}),n=f[4],i=f[5],l=f[2],u=f[3];break;case"L":e.push({key:"L",data:[...f]}),[n,i]=f;break;case"H":n=f[0],e.push({key:"L",data:[n,i]});break;case"V":i=f[0],e.push({key:"L",data:[n,i]});break;case"S":{let d=0,p=0;r==="C"||r==="S"?(d=n+(n-l),p=i+(i-u)):(d=n,p=i),e.push({key:"C",data:[d,p,...f]}),l=f[0],u=f[1],n=f[2],i=f[3];break}case"T":{let[d,p]=f,m=0,g=0;r==="Q"||r==="T"?(m=n+(n-l),g=i+(i-u)):(m=n,g=i);let y=n+2*(m-n)/3,v=i+2*(g-i)/3,x=d+2*(m-d)/3,b=p+2*(g-p)/3;e.push({key:"C",data:[y,v,x,b,d,p]}),l=m,u=g,n=d,i=p;break}case"Q":{let[d,p,m,g]=f,y=n+2*(d-n)/3,v=i+2*(p-i)/3,x=m+2*(d-m)/3,b=g+2*(p-g)/3;e.push({key:"C",data:[y,v,x,b,m,g]}),l=d,u=p,n=m,i=g;break}case"A":{let d=Math.abs(f[0]),p=Math.abs(f[1]),m=f[2],g=f[3],y=f[4],v=f[5],x=f[6];d===0||p===0?(e.push({key:"C",data:[n,i,v,x,v,x]}),n=v,i=x):(n!==v||i!==x)&&(jj(n,i,v,x,d,p,m,g,y).forEach(function(b){e.push({key:"C",data:b})}),n=v,i=x);break}case"Z":e.push({key:"Z",data:[]}),n=a,i=s}r=h}return e}function Tv(t,e,r){return[t*Math.cos(r)-e*Math.sin(r),t*Math.sin(r)+e*Math.cos(r)]}function jj(t,e,r,n,i,a,s,l,u,h){let f=(d=s,Math.PI*d/180);var d;let p=[],m=0,g=0,y=0,v=0;if(h)[m,g,y,v]=h;else{[t,e]=Tv(t,e,-f),[r,n]=Tv(r,n,-f);let I=(t-r)/2,C=(e-n)/2,O=I*I/(i*i)+C*C/(a*a);O>1&&(O=Math.sqrt(O),i*=O,a*=O);let D=i*i,P=a*a,F=D*P-D*C*C-P*I*I,B=D*C*C+P*I*I,$=(l===u?-1:1)*Math.sqrt(Math.abs(F/B));y=$*i*C/a+(t+r)/2,v=$*-a*I/i+(e+n)/2,m=Math.asin(parseFloat(((e-v)/a).toFixed(9))),g=Math.asin(parseFloat(((n-v)/a).toFixed(9))),tg&&(m-=2*Math.PI),!u&&g>m&&(g-=2*Math.PI)}let x=g-m;if(Math.abs(x)>120*Math.PI/180){let I=g,C=r,O=n;g=u&&g>m?m+120*Math.PI/180*1:m+120*Math.PI/180*-1,p=jj(r=y+i*Math.cos(g),n=v+a*Math.sin(g),C,O,i,a,s,0,u,[g,I,y,v])}x=g-m;let b=Math.cos(m),w=Math.sin(m),S=Math.cos(g),T=Math.sin(g),E=Math.tan(x/4),_=4/3*i*E,A=4/3*a*E,L=[t,e],M=[t+_*w,e-A*b],N=[r+_*T,n-A*S],k=[r,n];if(M[0]=2*L[0]-M[0],M[1]=2*L[1]-M[1],h)return[M,N,k].concat(p);{p=[M,N,k].concat(p);let I=[];for(let C=0;C2){let i=[];for(let a=0;a2*Math.PI&&(m=0,g=2*Math.PI);let y=2*Math.PI/u.curveStepCount,v=Math.min(y/2,(g-m)/2),x=Yj(v,h,f,d,p,m,g,1,u);if(!u.disableMultiStroke){let b=Yj(v,h,f,d,p,m,g,1.5,u);x.push(...b)}return s&&(l?x.push(...Vh(h,f,h+d*Math.cos(m),f+p*Math.sin(m),u),...Vh(h,f,h+d*Math.cos(g),f+p*Math.sin(g),u)):x.push({op:"lineTo",data:[h,f]},{op:"lineTo",data:[h+d*Math.cos(m),f+p*Math.sin(m)]})),{type:"path",ops:x}}function Vj(t,e){let r=Xj(qj(W9(t))),n=[],i=[0,0],a=[0,0];for(let{key:s,data:l}of r)switch(s){case"M":a=[l[0],l[1]],i=[l[0],l[1]];break;case"L":n.push(...Vh(a[0],a[1],l[0],l[1],e)),a=[l[0],l[1]];break;case"C":{let[u,h,f,d,p,m]=l;n.push(...vSe(u,h,f,d,p,m,a,e)),a=[p,m];break}case"Z":n.push(...Vh(a[0],a[1],i[0],i[1],e)),a=[i[0],i[1]]}return{type:"path",ops:n}}function M9(t,e){let r=[];for(let n of t)if(n.length){let i=e.maxRandomnessOffset||0,a=n.length;if(a>2){r.push({op:"move",data:[n[0][0]+Yt(i,e),n[0][1]+Yt(i,e)]});for(let s=1;s500?.4:-.0016668*u+1.233334;let f=i.maxRandomnessOffset||0;f*f*100>l&&(f=u/10);let d=f/2,p=.2+.2*Zj(i),m=i.bowing*i.maxRandomnessOffset*(n-e)/200,g=i.bowing*i.maxRandomnessOffset*(t-r)/200;m=Yt(m,i,h),g=Yt(g,i,h);let y=[],v=o(()=>Yt(d,i,h),"M"),x=o(()=>Yt(f,i,h),"k"),b=i.preserveVertices;return a&&(s?y.push({op:"move",data:[t+(b?0:v()),e+(b?0:v())]}):y.push({op:"move",data:[t+(b?0:Yt(f,i,h)),e+(b?0:Yt(f,i,h))]})),s?y.push({op:"bcurveTo",data:[m+t+(r-t)*p+v(),g+e+(n-e)*p+v(),m+t+2*(r-t)*p+v(),g+e+2*(n-e)*p+v(),r+(b?0:v()),n+(b?0:v())]}):y.push({op:"bcurveTo",data:[m+t+(r-t)*p+x(),g+e+(n-e)*p+x(),m+t+2*(r-t)*p+x(),g+e+2*(n-e)*p+x(),r+(b?0:x()),n+(b?0:x())]}),y}function P5(t,e,r){if(!t.length)return[];let n=[];n.push([t[0][0]+Yt(e,r),t[0][1]+Yt(e,r)]),n.push([t[0][0]+Yt(e,r),t[0][1]+Yt(e,r)]);for(let i=1;i3){let a=[],s=1-r.curveTightness;i.push({op:"move",data:[t[1][0],t[1][1]]});for(let l=1;l+21&&i.push(l)):i.push(l),i.push(t[e+3])}else{let u=t[e+0],h=t[e+1],f=t[e+2],d=t[e+3],p=Ld(u,h,.5),m=Ld(h,f,.5),g=Ld(f,d,.5),y=Ld(p,m,.5),v=Ld(m,g,.5),x=Ld(y,v,.5);U9([u,p,y,x],0,r,i),U9([x,v,g,d],0,r,i)}var a,s;return i}function bSe(t,e){return V5(t,0,t.length,e)}function V5(t,e,r,n,i){let a=i||[],s=t[e],l=t[r-1],u=0,h=1;for(let f=e+1;fu&&(u=d,h=f)}return Math.sqrt(u)>n?(V5(t,e,h+1,n,a),V5(t,h,r,n,a)):(a.length||a.push(s),a.push(l)),a}function I9(t,e=.15,r){let n=[],i=(t.length-1)/3;for(let a=0;a0?V5(n,0,n.length,r):n}var Ev,O9,P9,B9,F9,z9,Cs,G9,mSe,R9,zj,O5,gSe,ao,gm,H9,B5,Y9,Jt,ti=R(()=>{"use strict";o(D9,"t");o(dSe,"e");o(pSe,"s");o(Cv,"n");Ev=class{static{o(this,"o")}constructor(e){this.helper=e}fillPolygons(e,r){return this._fillPolygons(e,r)}_fillPolygons(e,r){let n=Cv(e,r);return{type:"fillSketch",ops:this.renderLines(n,r)}}renderLines(e,r){let n=[];for(let i of e)n.push(...this.helper.doubleLineOps(i[0][0],i[0][1],i[1][0],i[1][1],r));return n}};o(U5,"a");O9=class extends Ev{static{o(this,"h")}fillPolygons(e,r){let n=r.hachureGap;n<0&&(n=4*r.strokeWidth),n=Math.max(n,.1);let i=Cv(e,Object.assign({},r,{hachureGap:n})),a=Math.PI/180*r.hachureAngle,s=[],l=.5*n*Math.cos(a),u=.5*n*Math.sin(a);for(let[h,f]of i)U5([h,f])&&s.push([[h[0]-l,h[1]+u],[...f]],[[h[0]+l,h[1]-u],[...f]]);return{type:"fillSketch",ops:this.renderLines(s,r)}}},P9=class extends Ev{static{o(this,"r")}fillPolygons(e,r){let n=this._fillPolygons(e,r),i=Object.assign({},r,{hachureAngle:r.hachureAngle+90}),a=this._fillPolygons(e,i);return n.ops=n.ops.concat(a.ops),n}},B9=class{static{o(this,"i")}constructor(e){this.helper=e}fillPolygons(e,r){let n=Cv(e,r=Object.assign({},r,{hachureAngle:0}));return this.dotsOnLines(n,r)}dotsOnLines(e,r){let n=[],i=r.hachureGap;i<0&&(i=4*r.strokeWidth),i=Math.max(i,.1);let a=r.fillWeight;a<0&&(a=r.strokeWidth/2);let s=i/4;for(let l of e){let u=U5(l),h=u/i,f=Math.ceil(h)-1,d=u-f*i,p=(l[0][0]+l[1][0])/2-i/4,m=Math.min(l[0][1],l[1][1]);for(let g=0;g{let l=U5(s),u=Math.floor(l/(n+i)),h=(l+i-u*(n+i))/2,f=s[0],d=s[1];f[0]>d[0]&&(f=s[1],d=s[0]);let p=Math.atan((d[1]-f[1])/(d[0]-f[0]));for(let m=0;m{let s=U5(a),l=Math.round(s/(2*r)),u=a[0],h=a[1];u[0]>h[0]&&(u=a[1],h=a[0]);let f=Math.atan((h[1]-u[1])/(h[0]-u[0]));for(let d=0;d2*Math.PI&&(_=0,A=2*Math.PI);let L=(A-_)/b.curveStepCount,M=[];for(let N=_;N<=A;N+=L)M.push([w+T*Math.cos(N),S+E*Math.sin(N)]);return M.push([w+T*Math.cos(A),S+E*Math.sin(A)]),M.push([w,S]),mm([M],b)}(e,r,n,i,a,s,h));return h.stroke!==ao&&f.push(d),this._d("arc",f,h)}curve(e,r){let n=this._o(r),i=[],a=Gj(e,n);if(n.fill&&n.fill!==ao)if(n.fillStyle==="solid"){let s=Gj(e,Object.assign(Object.assign({},n),{disableMultiStroke:!0,roughness:n.roughness?n.roughness+n.fillShapeRoughnessGain:0}));i.push({type:"fillPath",ops:this._mergedShape(s.ops)})}else{let s=[],l=e;if(l.length){let u=typeof l[0][0]=="number"?[l]:l;for(let h of u)h.length<3?s.push(...h):h.length===3?s.push(...I9(Wj([h[0],h[0],h[1],h[2]]),10,(1+n.roughness)/2)):s.push(...I9(Wj(h),10,(1+n.roughness)/2))}s.length&&i.push(mm([s],n))}return n.stroke!==ao&&i.push(a),this._d("curve",i,n)}polygon(e,r){let n=this._o(r),i=[],a=F5(e,!0,n);return n.fill&&(n.fillStyle==="solid"?i.push(M9([e],n)):i.push(mm([e],n))),n.stroke!==ao&&i.push(a),this._d("polygon",i,n)}path(e,r){let n=this._o(r),i=[];if(!e)return this._d("path",i,n);e=(e||"").replace(/\n/g," ").replace(/(-\s)/g,"-").replace("/(ss)/g"," ");let a=n.fill&&n.fill!=="transparent"&&n.fill!==ao,s=n.stroke!==ao,l=!!(n.simplification&&n.simplification<1),u=function(f,d,p){let m=Xj(qj(W9(f))),g=[],y=[],v=[0,0],x=[],b=o(()=>{x.length>=4&&y.push(...I9(x,d)),x=[]},"i"),w=o(()=>{b(),y.length&&(g.push(y),y=[])},"c");for(let{key:T,data:E}of m)switch(T){case"M":w(),v=[E[0],E[1]],y.push(v);break;case"L":b(),y.push([E[0],E[1]]);break;case"C":if(!x.length){let _=y.length?y[y.length-1]:v;x.push([_[0],_[1]])}x.push([E[0],E[1]]),x.push([E[2],E[3]]),x.push([E[4],E[5]]);break;case"Z":b(),y.push([v[0],v[1]])}if(w(),!p)return g;let S=[];for(let T of g){let E=bSe(T,p);E.length&&S.push(E)}return S}(e,1,l?4-4*(n.simplification||1):(1+n.roughness)/2),h=Vj(e,n);if(a)if(n.fillStyle==="solid")if(u.length===1){let f=Vj(e,Object.assign(Object.assign({},n),{disableMultiStroke:!0,roughness:n.roughness?n.roughness+n.fillShapeRoughnessGain:0}));i.push({type:"fillPath",ops:this._mergedShape(f.ops)})}else i.push(M9(u,n));else i.push(mm(u,n));return s&&(l?u.forEach(f=>{i.push(F5(f,!1,n))}):i.push(h)),this._d("path",i,n)}opsToPath(e,r){let n="";for(let i of e.ops){let a=typeof r=="number"&&r>=0?i.data.map(s=>+s.toFixed(r)):i.data;switch(i.op){case"move":n+=`M${a[0]} ${a[1]} `;break;case"bcurveTo":n+=`C${a[0]} ${a[1]}, ${a[2]} ${a[3]}, ${a[4]} ${a[5]} `;break;case"lineTo":n+=`L${a[0]} ${a[1]} `}}return n.trim()}toPaths(e){let r=e.sets||[],n=e.options||this.defaultOptions,i=[];for(let a of r){let s=null;switch(a.type){case"path":s={d:this.opsToPath(a),stroke:n.stroke,strokeWidth:n.strokeWidth,fill:ao};break;case"fillPath":s={d:this.opsToPath(a),stroke:ao,strokeWidth:0,fill:n.fill||ao};break;case"fillSketch":s=this.fillSketch(a,n)}s&&i.push(s)}return i}fillSketch(e,r){let n=r.fillWeight;return n<0&&(n=r.strokeWidth/2),{d:this.opsToPath(e),stroke:r.fill||ao,strokeWidth:n,fill:ao}}_mergedShape(e){return e.filter((r,n)=>n===0||r.op!=="move")}},H9=class{static{o(this,"st")}constructor(e,r){this.canvas=e,this.ctx=this.canvas.getContext("2d"),this.gen=new gm(r)}draw(e){let r=e.sets||[],n=e.options||this.getDefaultOptions(),i=this.ctx,a=e.options.fixedDecimalPlaceDigits;for(let s of r)switch(s.type){case"path":i.save(),i.strokeStyle=n.stroke==="none"?"transparent":n.stroke,i.lineWidth=n.strokeWidth,n.strokeLineDash&&i.setLineDash(n.strokeLineDash),n.strokeLineDashOffset&&(i.lineDashOffset=n.strokeLineDashOffset),this._drawToContext(i,s,a),i.restore();break;case"fillPath":{i.save(),i.fillStyle=n.fill||"";let l=e.shape==="curve"||e.shape==="polygon"||e.shape==="path"?"evenodd":"nonzero";this._drawToContext(i,s,a,l),i.restore();break}case"fillSketch":this.fillSketch(i,s,n)}}fillSketch(e,r,n){let i=n.fillWeight;i<0&&(i=n.strokeWidth/2),e.save(),n.fillLineDash&&e.setLineDash(n.fillLineDash),n.fillLineDashOffset&&(e.lineDashOffset=n.fillLineDashOffset),e.strokeStyle=n.fill||"",e.lineWidth=i,this._drawToContext(e,r,n.fixedDecimalPlaceDigits),e.restore()}_drawToContext(e,r,n,i="nonzero"){e.beginPath();for(let a of r.ops){let s=typeof n=="number"&&n>=0?a.data.map(l=>+l.toFixed(n)):a.data;switch(a.op){case"move":e.moveTo(s[0],s[1]);break;case"bcurveTo":e.bezierCurveTo(s[0],s[1],s[2],s[3],s[4],s[5]);break;case"lineTo":e.lineTo(s[0],s[1])}}r.type==="fillPath"?e.fill(i):e.stroke()}get generator(){return this.gen}getDefaultOptions(){return this.gen.defaultOptions}line(e,r,n,i,a){let s=this.gen.line(e,r,n,i,a);return this.draw(s),s}rectangle(e,r,n,i,a){let s=this.gen.rectangle(e,r,n,i,a);return this.draw(s),s}ellipse(e,r,n,i,a){let s=this.gen.ellipse(e,r,n,i,a);return this.draw(s),s}circle(e,r,n,i){let a=this.gen.circle(e,r,n,i);return this.draw(a),a}linearPath(e,r){let n=this.gen.linearPath(e,r);return this.draw(n),n}polygon(e,r){let n=this.gen.polygon(e,r);return this.draw(n),n}arc(e,r,n,i,a,s,l=!1,u){let h=this.gen.arc(e,r,n,i,a,s,l,u);return this.draw(h),h}curve(e,r){let n=this.gen.curve(e,r);return this.draw(n),n}path(e,r){let n=this.gen.path(e,r);return this.draw(n),n}},B5="http://www.w3.org/2000/svg",Y9=class{static{o(this,"ot")}constructor(e,r){this.svg=e,this.gen=new gm(r)}draw(e){let r=e.sets||[],n=e.options||this.getDefaultOptions(),i=this.svg.ownerDocument||window.document,a=i.createElementNS(B5,"g"),s=e.options.fixedDecimalPlaceDigits;for(let l of r){let u=null;switch(l.type){case"path":u=i.createElementNS(B5,"path"),u.setAttribute("d",this.opsToPath(l,s)),u.setAttribute("stroke",n.stroke),u.setAttribute("stroke-width",n.strokeWidth+""),u.setAttribute("fill","none"),n.strokeLineDash&&u.setAttribute("stroke-dasharray",n.strokeLineDash.join(" ").trim()),n.strokeLineDashOffset&&u.setAttribute("stroke-dashoffset",`${n.strokeLineDashOffset}`);break;case"fillPath":u=i.createElementNS(B5,"path"),u.setAttribute("d",this.opsToPath(l,s)),u.setAttribute("stroke","none"),u.setAttribute("stroke-width","0"),u.setAttribute("fill",n.fill||""),e.shape!=="curve"&&e.shape!=="polygon"||u.setAttribute("fill-rule","evenodd");break;case"fillSketch":u=this.fillSketch(i,l,n)}u&&a.appendChild(u)}return a}fillSketch(e,r,n){let i=n.fillWeight;i<0&&(i=n.strokeWidth/2);let a=e.createElementNS(B5,"path");return a.setAttribute("d",this.opsToPath(r,n.fixedDecimalPlaceDigits)),a.setAttribute("stroke",n.fill||""),a.setAttribute("stroke-width",i+""),a.setAttribute("fill","none"),n.fillLineDash&&a.setAttribute("stroke-dasharray",n.fillLineDash.join(" ").trim()),n.fillLineDashOffset&&a.setAttribute("stroke-dashoffset",`${n.fillLineDashOffset}`),a}get generator(){return this.gen}getDefaultOptions(){return this.gen.defaultOptions}opsToPath(e,r){return this.gen.opsToPath(e,r)}line(e,r,n,i,a){let s=this.gen.line(e,r,n,i,a);return this.draw(s)}rectangle(e,r,n,i,a){let s=this.gen.rectangle(e,r,n,i,a);return this.draw(s)}ellipse(e,r,n,i,a){let s=this.gen.ellipse(e,r,n,i,a);return this.draw(s)}circle(e,r,n,i){let a=this.gen.circle(e,r,n,i);return this.draw(a)}linearPath(e,r){let n=this.gen.linearPath(e,r);return this.draw(n)}polygon(e,r){let n=this.gen.polygon(e,r);return this.draw(n)}arc(e,r,n,i,a,s,l=!1,u){let h=this.gen.arc(e,r,n,i,a,s,l,u);return this.draw(h)}curve(e,r){let n=this.gen.curve(e,r);return this.draw(n)}path(e,r){let n=this.gen.path(e,r);return this.draw(n)}},Jt={canvas:o((t,e)=>new H9(t,e),"canvas"),svg:o((t,e)=>new Y9(t,e),"svg"),generator:o(t=>new gm(t),"generator"),newSeed:o(()=>gm.newSeed(),"newSeed")}});var wSe,Dd,q9=R(()=>{"use strict";wSe=o((t,e)=>{var r=t.x,n=t.y,i=e.x-r,a=e.y-n,s=t.width/2,l=t.height/2,u,h;return Math.abs(a)*s>Math.abs(i)*l?(a<0&&(l=-l),u=a===0?0:l*i/a,h=l):(i<0&&(s=-s),u=s,h=i===0?0:s*a/i),{x:r+u,y:n+h}},"intersectRect"),Dd=wSe});function TSe(t,e){e&&t.attr("style",e)}async function kSe(t){let e=$e(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),r=e.append("xhtml:div"),n=t.label;t.label&&Ni(t.label)&&(n=await yh(t.label.replace(We.lineBreakRegex,` +`),de()));let i=t.isNode?"nodeLabel":"edgeLabel";return r.html('"+n+""),TSe(r,t.labelStyle),r.style("display","inline-block"),r.style("padding-right","1px"),r.style("white-space","nowrap"),r.attr("xmlns","http://www.w3.org/1999/xhtml"),e.node()}var ESe,gc,H5=R(()=>{"use strict";Zt();ut();_t();rr();xr();o(TSe,"applyStyle");o(kSe,"addHtmlLabel");ESe=o(async(t,e,r,n)=>{let i=t||"";if(typeof i=="object"&&(i=i[0]),yr(de().flowchart.htmlLabels)){i=i.replace(/\\n|\n/g,"
    "),V.info("vertexText"+i);let a={isNode:n,label:to(i).replace(/fa[blrs]?:fa-[\w-]+/g,l=>``),labelStyle:e&&e.replace("fill:","color:")};return await kSe(a)}else{let a=document.createElementNS("http://www.w3.org/2000/svg","text");a.setAttribute("style",e.replace("color:","fill:"));let s=[];typeof i=="string"?s=i.split(/\\n|\n|/gi):Array.isArray(i)?s=i:s=[];for(let l of s){let u=document.createElementNS("http://www.w3.org/2000/svg","tspan");u.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),u.setAttribute("dy","1em"),u.setAttribute("x","0"),r?u.setAttribute("class","title-row"):u.setAttribute("class","row"),u.textContent=l.trim(),a.appendChild(u)}return a}},"createLabel"),gc=ESe});var _u,Sv=R(()=>{"use strict";_u=o((t,e,r,n,i)=>["M",t+i,e,"H",t+r-i,"A",i,i,0,0,1,t+r,e+i,"V",e+n-i,"A",i,i,0,0,1,t+r-i,e+n,"H",t+i,"A",i,i,0,0,1,t,e+n-i,"V",e+i,"A",i,i,0,0,1,t+i,e,"Z"].join(" "),"createRoundedRectPathD")});var Lu,Jj,CSe,Br,Fr,ki=R(()=>{"use strict";_t();Lu=o(t=>{let{handDrawnSeed:e}=de();return{fill:t,hachureAngle:120,hachureGap:4,fillWeight:2,roughness:.7,stroke:t,seed:e}},"solidStateFill"),Jj=o(t=>{let e=CSe([...t.cssCompiledStyles||[],...t.cssStyles||[]]);return{stylesMap:e,stylesArray:[...e]}},"compileStyles"),CSe=o(t=>{let e=new Map;return t.forEach(r=>{let[n,i]=r.split(":");e.set(n.trim(),i?.trim())}),e},"styles2Map"),Br=o(t=>{let{stylesArray:e}=Jj(t),r=[],n=[],i=[],a=[];return e.forEach(s=>{let l=s[0];l==="color"||l==="font-size"||l==="font-family"||l==="font-weight"||l==="font-style"||l==="text-decoration"||l==="text-align"||l==="text-transform"||l==="line-height"||l==="letter-spacing"||l==="word-spacing"||l==="text-shadow"||l==="text-overflow"||l==="white-space"||l==="word-wrap"||l==="word-break"||l==="overflow-wrap"||l==="hyphens"?r.push(s.join(":")+" !important"):(n.push(s.join(":")+" !important"),l.includes("stroke")&&i.push(s.join(":")+" !important"),l==="fill"&&a.push(s.join(":")+" !important"))}),{labelStyles:r.join(";"),nodeStyles:n.join(";"),stylesArray:e,borderStyles:i,backgroundStyles:a}},"styles2String"),Fr=o((t,e)=>{let{themeVariables:r,handDrawnSeed:n}=de(),{nodeBorder:i,mainBkg:a}=r,{stylesMap:s}=Jj(t);return Object.assign({roughness:.7,fill:s.get("fill")||a,fillStyle:"hachure",fillWeight:4,stroke:s.get("stroke")||i,seed:n,strokeWidth:1.3},e)},"userNodeOverrides")});var eK,SSe,ASe,_Se,LSe,DSe,tK,Y5,rK,X9=R(()=>{"use strict";_t();rr();ut();_d();Zt();ti();Al();q9();H5();Sv();ki();eK=o(async(t,e)=>{V.info("Creating subgraph rect for ",e.id,e);let r=de(),{themeVariables:n,handDrawnSeed:i}=r,{clusterBkg:a,clusterBorder:s}=n,{labelStyles:l,nodeStyles:u,borderStyles:h,backgroundStyles:f}=Br(e),d=t.insert("g").attr("class","cluster "+e.cssClasses).attr("id",e.id).attr("data-look",e.look),p=yr(r.flowchart.htmlLabels),m=d.insert("g").attr("class","cluster-label "),g=await ta(m,e.label,{style:e.labelStyle,useHtmlLabels:p,isNode:!0}),y=g.getBBox();if(yr(r.flowchart.htmlLabels)){let _=g.children[0],A=$e(g);y=_.getBoundingClientRect(),A.attr("width",y.width),A.attr("height",y.height)}let v=e.width<=y.width+e.padding?y.width+e.padding:e.width;e.width<=y.width+e.padding?e.diff=(v-e.width)/2-e.padding:e.diff=-e.padding;let x=e.height,b=e.x-v/2,w=e.y-x/2;V.trace("Data ",e,JSON.stringify(e));let S;if(e.look==="handDrawn"){let _=Jt.svg(d),A=Fr(e,{roughness:.7,fill:a,stroke:s,fillWeight:3,seed:i}),L=_.path(_u(b,w,v,x,0),A);S=d.insert(()=>(V.debug("Rough node insert CXC",L),L),":first-child"),S.select("path:nth-child(2)").attr("style",h.join(";")),S.select("path").attr("style",f.join(";").replace("fill","stroke"))}else S=d.insert("rect",":first-child"),S.attr("style",u).attr("rx",e.rx).attr("ry",e.ry).attr("x",b).attr("y",w).attr("width",v).attr("height",x);let{subGraphTitleTopMargin:T}=io(r);if(m.attr("transform",`translate(${e.x-y.width/2}, ${e.y-e.height/2+T})`),l){let _=m.select("span");_&&_.attr("style",l)}let E=S.node().getBBox();return e.offsetX=0,e.width=E.width,e.height=E.height,e.offsetY=y.height-e.padding/2,e.intersect=function(_){return Dd(e,_)},{cluster:d,labelBBox:y}},"rect"),SSe=o((t,e)=>{let r=t.insert("g").attr("class","note-cluster").attr("id",e.id),n=r.insert("rect",":first-child"),i=0*e.padding,a=i/2;n.attr("rx",e.rx).attr("ry",e.ry).attr("x",e.x-e.width/2-a).attr("y",e.y-e.height/2-a).attr("width",e.width+i).attr("height",e.height+i).attr("fill","none");let s=n.node().getBBox();return e.width=s.width,e.height=s.height,e.intersect=function(l){return Dd(e,l)},{cluster:r,labelBBox:{width:0,height:0}}},"noteGroup"),ASe=o(async(t,e)=>{let r=de(),{themeVariables:n,handDrawnSeed:i}=r,{altBackground:a,compositeBackground:s,compositeTitleBackground:l,nodeBorder:u}=n,h=t.insert("g").attr("class",e.cssClasses).attr("id",e.id).attr("data-id",e.id).attr("data-look",e.look),f=h.insert("g",":first-child"),d=h.insert("g").attr("class","cluster-label"),p=h.append("rect"),m=d.node().appendChild(await gc(e.label,e.labelStyle,void 0,!0)),g=m.getBBox();if(yr(r.flowchart.htmlLabels)){let L=m.children[0],M=$e(m);g=L.getBoundingClientRect(),M.attr("width",g.width),M.attr("height",g.height)}let y=0*e.padding,v=y/2,x=(e.width<=g.width+e.padding?g.width+e.padding:e.width)+y;e.width<=g.width+e.padding?e.diff=(x-e.width)/2-e.padding:e.diff=-e.padding;let b=e.height+y,w=e.height+y-g.height-6,S=e.x-x/2,T=e.y-b/2;e.width=x;let E=e.y-e.height/2-v+g.height+2,_;if(e.look==="handDrawn"){let L=e.cssClasses.includes("statediagram-cluster-alt"),M=Jt.svg(h),N=e.rx||e.ry?M.path(_u(S,T,x,b,10),{roughness:.7,fill:l,fillStyle:"solid",stroke:u,seed:i}):M.rectangle(S,T,x,b,{seed:i});_=h.insert(()=>N,":first-child");let k=M.rectangle(S,E,x,w,{fill:L?a:s,fillStyle:L?"hachure":"solid",stroke:u,seed:i});_=h.insert(()=>N,":first-child"),p=h.insert(()=>k)}else _=f.insert("rect",":first-child"),_.attr("class","outer").attr("x",S).attr("y",T).attr("width",x).attr("height",b).attr("data-look",e.look),p.attr("class","inner").attr("x",S).attr("y",E).attr("width",x).attr("height",w);d.attr("transform",`translate(${e.x-g.width/2}, ${T+1-(yr(r.flowchart.htmlLabels)?0:3)})`);let A=_.node().getBBox();return e.height=A.height,e.offsetX=0,e.offsetY=g.height-e.padding/2,e.labelBBox=g,e.intersect=function(L){return Dd(e,L)},{cluster:h,labelBBox:g}},"roundedWithTitle"),_Se=o((t,e)=>{let r=de(),{themeVariables:n,handDrawnSeed:i}=r,{nodeBorder:a}=n,s=t.insert("g").attr("class",e.cssClasses).attr("id",e.id).attr("data-look",e.look),l=s.insert("g",":first-child"),u=0*e.padding,h=e.width+u;e.diff=-e.padding;let f=e.height+u,d=e.x-h/2,p=e.y-f/2;e.width=h;let m;if(e.look==="handDrawn"){let v=Jt.svg(s).rectangle(d,p,h,f,{fill:"lightgrey",roughness:.5,strokeLineDash:[5],stroke:a,seed:i});m=s.insert(()=>v,":first-child")}else m=l.insert("rect",":first-child"),m.attr("class","divider").attr("x",d).attr("y",p).attr("width",h).attr("height",f).attr("data-look",e.look);let g=m.node().getBBox();return e.height=g.height,e.offsetX=0,e.offsetY=0,e.intersect=function(y){return Dd(e,y)},{cluster:s,labelBBox:{}}},"divider"),LSe=eK,DSe={rect:eK,squareRect:LSe,roundedWithTitle:ASe,noteGroup:SSe,divider:_Se},tK=new Map,Y5=o(async(t,e)=>{let r=e.shape||"rect",n=await DSe[r](t,e);return tK.set(e.id,n),n},"insertCluster"),rK=o(()=>{tK=new Map},"clear")});function W5(t,e){if(t===void 0||e===void 0)return{angle:0,deltaX:0,deltaY:0};t=q5(t),e=q5(e);let[r,n]=[t.x,t.y],[i,a]=[e.x,e.y],s=i-r,l=a-n;return{angle:Math.atan(l/s),deltaX:s,deltaY:l}}var Uh,q5,X5,j9=R(()=>{"use strict";Uh={aggregation:18,extension:18,composition:18,dependency:6,lollipop:13.5,arrow_point:4};o(W5,"calculateDeltaAndAngle");q5=o(t=>Array.isArray(t)?{x:t[0],y:t[1]}:t,"pointTransformer"),X5=o(t=>({x:o(function(e,r,n){let i=0;if(r===0&&Object.hasOwn(Uh,t.arrowTypeStart)){let{angle:a,deltaX:s}=W5(n[0],n[1]);i=Uh[t.arrowTypeStart]*Math.cos(a)*(s>=0?1:-1)}else if(r===n.length-1&&Object.hasOwn(Uh,t.arrowTypeEnd)){let{angle:a,deltaX:s}=W5(n[n.length-1],n[n.length-2]);i=Uh[t.arrowTypeEnd]*Math.cos(a)*(s>=0?1:-1)}return q5(e).x+i},"x"),y:o(function(e,r,n){let i=0;if(r===0&&Object.hasOwn(Uh,t.arrowTypeStart)){let{angle:a,deltaY:s}=W5(n[0],n[1]);i=Uh[t.arrowTypeStart]*Math.abs(Math.sin(a))*(s>=0?1:-1)}else if(r===n.length-1&&Object.hasOwn(Uh,t.arrowTypeEnd)){let{angle:a,deltaY:s}=W5(n[n.length-1],n[n.length-2]);i=Uh[t.arrowTypeEnd]*Math.abs(Math.sin(a))*(s>=0?1:-1)}return q5(e).y+i},"y")}),"getLineFunctionsWithOffset")});var iK,RSe,nK,aK=R(()=>{"use strict";ut();iK=o((t,e,r,n,i)=>{e.arrowTypeStart&&nK(t,"start",e.arrowTypeStart,r,n,i),e.arrowTypeEnd&&nK(t,"end",e.arrowTypeEnd,r,n,i)},"addEdgeMarkers"),RSe={arrow_cross:"cross",arrow_point:"point",arrow_barb:"barb",arrow_circle:"circle",aggregation:"aggregation",extension:"extension",composition:"composition",dependency:"dependency",lollipop:"lollipop"},nK=o((t,e,r,n,i,a)=>{let s=RSe[r];if(!s){V.warn(`Unknown arrow type: ${r}`);return}let l=e==="start"?"Start":"End";t.attr(`marker-${e}`,`url(${n}#${i}_${a}-${s}${l})`)},"addEdgeMarker")});function j5(t,e){de().flowchart.htmlLabels&&t&&(t.style.width=e.length*9+"px",t.style.height="12px")}function ISe(t){let e=[],r=[];for(let n=1;n5&&Math.abs(a.y-i.y)>5||i.y===a.y&&a.x===s.x&&Math.abs(a.x-i.x)>5&&Math.abs(a.y-s.y)>5)&&(e.push(a),r.push(n))}return{cornerPoints:e,cornerPointPositions:r}}var K5,da,lK,Av,Q5,Z5,NSe,MSe,sK,oK,OSe,J5,K9=R(()=>{"use strict";_t();rr();ut();Al();xr();j9();_d();Zt();ti();H5();aK();K5=new Map,da=new Map,lK=o(()=>{K5.clear(),da.clear()},"clear"),Av=o(t=>t?t.reduce((r,n)=>r+";"+n,""):"","getLabelStyles"),Q5=o(async(t,e)=>{let r=yr(de().flowchart.htmlLabels),n=await ta(t,e.label,{style:Av(e.labelStyle),useHtmlLabels:r,addSvgBackground:!0,isNode:!1});V.info("abc82",e,e.labelType);let i=t.insert("g").attr("class","edgeLabel"),a=i.insert("g").attr("class","label");a.node().appendChild(n);let s=n.getBBox();if(r){let u=n.children[0],h=$e(n);s=u.getBoundingClientRect(),h.attr("width",s.width),h.attr("height",s.height)}a.attr("transform","translate("+-s.width/2+", "+-s.height/2+")"),K5.set(e.id,i),e.width=s.width,e.height=s.height;let l;if(e.startLabelLeft){let u=await gc(e.startLabelLeft,Av(e.labelStyle)),h=t.insert("g").attr("class","edgeTerminals"),f=h.insert("g").attr("class","inner");l=f.node().appendChild(u);let d=u.getBBox();f.attr("transform","translate("+-d.width/2+", "+-d.height/2+")"),da.get(e.id)||da.set(e.id,{}),da.get(e.id).startLeft=h,j5(l,e.startLabelLeft)}if(e.startLabelRight){let u=await gc(e.startLabelRight,Av(e.labelStyle)),h=t.insert("g").attr("class","edgeTerminals"),f=h.insert("g").attr("class","inner");l=h.node().appendChild(u),f.node().appendChild(u);let d=u.getBBox();f.attr("transform","translate("+-d.width/2+", "+-d.height/2+")"),da.get(e.id)||da.set(e.id,{}),da.get(e.id).startRight=h,j5(l,e.startLabelRight)}if(e.endLabelLeft){let u=await gc(e.endLabelLeft,Av(e.labelStyle)),h=t.insert("g").attr("class","edgeTerminals"),f=h.insert("g").attr("class","inner");l=f.node().appendChild(u);let d=u.getBBox();f.attr("transform","translate("+-d.width/2+", "+-d.height/2+")"),h.node().appendChild(u),da.get(e.id)||da.set(e.id,{}),da.get(e.id).endLeft=h,j5(l,e.endLabelLeft)}if(e.endLabelRight){let u=await gc(e.endLabelRight,Av(e.labelStyle)),h=t.insert("g").attr("class","edgeTerminals"),f=h.insert("g").attr("class","inner");l=f.node().appendChild(u);let d=u.getBBox();f.attr("transform","translate("+-d.width/2+", "+-d.height/2+")"),h.node().appendChild(u),da.get(e.id)||da.set(e.id,{}),da.get(e.id).endRight=h,j5(l,e.endLabelRight)}return n},"insertEdgeLabel");o(j5,"setTerminalWidth");Z5=o((t,e)=>{V.debug("Moving label abc88 ",t.id,t.label,K5.get(t.id),e);let r=e.updatedPath?e.updatedPath:e.originalPath,n=de(),{subGraphTitleTotalMargin:i}=io(n);if(t.label){let a=K5.get(t.id),s=t.x,l=t.y;if(r){let u=Lt.calcLabelPosition(r);V.debug("Moving label "+t.label+" from (",s,",",l,") to (",u.x,",",u.y,") abc88"),e.updatedPath&&(s=u.x,l=u.y)}a.attr("transform",`translate(${s}, ${l+i/2})`)}if(t.startLabelLeft){let a=da.get(t.id).startLeft,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_left",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}if(t.startLabelRight){let a=da.get(t.id).startRight,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_right",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}if(t.endLabelLeft){let a=da.get(t.id).endLeft,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_left",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}if(t.endLabelRight){let a=da.get(t.id).endRight,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_right",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}},"positionEdgeLabel"),NSe=o((t,e)=>{let r=t.x,n=t.y,i=Math.abs(e.x-r),a=Math.abs(e.y-n),s=t.width/2,l=t.height/2;return i>=s||a>=l},"outsideNode"),MSe=o((t,e,r)=>{V.debug(`intersection calc abc89: + outsidePoint: ${JSON.stringify(e)} + insidePoint : ${JSON.stringify(r)} + node : x:${t.x} y:${t.y} w:${t.width} h:${t.height}`);let n=t.x,i=t.y,a=Math.abs(n-r.x),s=t.width/2,l=r.xMath.abs(n-e.x)*u){let d=r.y{V.warn("abc88 cutPathAtIntersect",t,e);let r=[],n=t[0],i=!1;return t.forEach(a=>{if(V.info("abc88 checking point",a,e),!NSe(e,a)&&!i){let s=MSe(e,n,a);V.debug("abc88 inside",a,n,s),V.debug("abc88 intersection",s,e);let l=!1;r.forEach(u=>{l=l||u.x===s.x&&u.y===s.y}),r.some(u=>u.x===s.x&&u.y===s.y)?V.warn("abc88 no intersect",s,r):r.push(s),i=!0}else V.warn("abc88 outside",a,n),n=a,i||r.push(a)}),V.debug("returning points",r),r},"cutPathAtIntersect");o(ISe,"extractCornerPoints");oK=o(function(t,e,r){let n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),s=r/a;return{x:e.x-s*n,y:e.y-s*i}},"findAdjacentPoint"),OSe=o(function(t){let{cornerPointPositions:e}=ISe(t),r=[];for(let n=0;n10&&Math.abs(a.y-i.y)>=10){V.debug("Corner point fixing",Math.abs(a.x-i.x),Math.abs(a.y-i.y));let m=5;s.x===l.x?p={x:h<0?l.x-m+d:l.x+m-d,y:f<0?l.y-d:l.y+d}:p={x:h<0?l.x-d:l.x+d,y:f<0?l.y-m+d:l.y+m-d}}else V.debug("Corner point skipping fixing",Math.abs(a.x-i.x),Math.abs(a.y-i.y));r.push(p,u)}else r.push(t[n]);return r},"fixCorners"),J5=o(function(t,e,r,n,i,a,s){let{handDrawnSeed:l}=de(),u=e.points,h=!1,f=i;var d=a;d.intersect&&f.intersect&&(u=u.slice(1,e.points.length-1),u.unshift(f.intersect(u[0])),V.debug("Last point APA12",e.start,"-->",e.end,u[u.length-1],d,d.intersect(u[u.length-1])),u.push(d.intersect(u[u.length-1]))),e.toCluster&&(V.info("to cluster abc88",r.get(e.toCluster)),u=sK(e.points,r.get(e.toCluster).node),h=!0),e.fromCluster&&(V.debug("from cluster abc88",r.get(e.fromCluster),JSON.stringify(u,null,2)),u=sK(u.reverse(),r.get(e.fromCluster).node).reverse(),h=!0);let p=u.filter(A=>!Number.isNaN(A.y));p=OSe(p);let m=p[p.length-1];if(p.length>1){m=p[p.length-1];let A=p[p.length-2],L=(m.x-A.x)/2,M=(m.y-A.y)/2,N={x:A.x+L,y:A.y+M};p.splice(-1,0,N)}let g=vs;e.curve&&(g=e.curve);let{x:y,y:v}=X5(e),x=ha().x(y).y(v).curve(g),b;switch(e.thickness){case"normal":b="edge-thickness-normal";break;case"thick":b="edge-thickness-thick";break;case"invisible":b="edge-thickness-invisible";break;default:b="edge-thickness-normal"}switch(e.pattern){case"solid":b+=" edge-pattern-solid";break;case"dotted":b+=" edge-pattern-dotted";break;case"dashed":b+=" edge-pattern-dashed";break;default:b+=" edge-pattern-solid"}let w,S=x(p),T=Array.isArray(e.style)?e.style:[e.style];if(e.look==="handDrawn"){let A=Jt.svg(t);Object.assign([],p);let L=A.path(S,{roughness:.3,seed:l});b+=" transition",w=$e(L).select("path").attr("id",e.id).attr("class"," "+b+(e.classes?" "+e.classes:"")).attr("style",T?T.reduce((N,k)=>N+";"+k,""):"");let M=w.attr("d");w.attr("d",M),t.node().appendChild(w.node())}else w=t.append("path").attr("d",S).attr("id",e.id).attr("class"," "+b+(e.classes?" "+e.classes:"")).attr("style",T?T.reduce((A,L)=>A+";"+L,""):"");let E="";(de().flowchart.arrowMarkerAbsolute||de().state.arrowMarkerAbsolute)&&(E=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,E=E.replace(/\(/g,"\\(").replace(/\)/g,"\\)")),V.info("arrowTypeStart",e.arrowTypeStart),V.info("arrowTypeEnd",e.arrowTypeEnd),iK(w,e,E,s,n);let _={};return h&&(_.updatedPath=u),_.originalPath=e.points,_},"insertEdge")});var PSe,BSe,FSe,zSe,GSe,$Se,VSe,USe,HSe,YSe,WSe,ew,Q9=R(()=>{"use strict";ut();PSe=o((t,e,r,n)=>{e.forEach(i=>{WSe[i](t,r,n)})},"insertMarkers"),BSe=o((t,e,r)=>{V.trace("Making markers for ",r),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionStart").attr("class","marker extension "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionEnd").attr("class","marker extension "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z")},"extension"),FSe=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionStart").attr("class","marker composition "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionEnd").attr("class","marker composition "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"composition"),zSe=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationStart").attr("class","marker aggregation "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationEnd").attr("class","marker aggregation "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"aggregation"),GSe=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyStart").attr("class","marker dependency "+e).attr("refX",6).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyEnd").attr("class","marker dependency "+e).attr("refX",13).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"dependency"),$Se=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopStart").attr("class","marker lollipop "+e).attr("refX",13).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6),t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopEnd").attr("class","marker lollipop "+e).attr("refX",1).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6)},"lollipop"),VSe=o((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-pointEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",8).attr("markerHeight",8).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-pointStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",4.5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",8).attr("markerHeight",8).attr("orient","auto").append("path").attr("d","M 0 5 L 10 10 L 10 0 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"point"),USe=o((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-circleEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",11).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-circleStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",-1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"circle"),HSe=o((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-crossEnd").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",12).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-crossStart").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",-1).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0")},"cross"),YSe=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-barbEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",14).attr("markerUnits","userSpaceOnUse").attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"barb"),WSe={extension:BSe,composition:FSe,aggregation:zSe,dependency:GSe,lollipop:$Se,point:VSe,circle:USe,cross:HSe,barb:YSe},ew=PSe});var zr,ar,En,ri=R(()=>{"use strict";Al();_t();Zt();rr();xr();zr=o(async(t,e,r)=>{let n,i=e.useHtmlLabels||yr(de().flowchart.htmlLabels);r?n=r:n="node default";let a=t.insert("g").attr("class",n).attr("id",e.domId||e.id),s=a.insert("g").attr("class","label").attr("style",e.labelStyle),l;e.label===void 0?l="":l=typeof e.label=="string"?e.label:e.label[0];let u;u=await ta(s,qr(to(l),de()),{useHtmlLabels:i,width:e.width||de().flowchart.wrappingWidth,cssClasses:"markdown-node-label",style:e.labelStyle});let h=u.getBBox(),f=e.padding/2;if(yr(de().flowchart.htmlLabels)){let d=u.children[0],p=$e(u),m=d.getElementsByTagName("img");if(m){let g=l.replace(/]*>/g,"").trim()==="";await Promise.all([...m].map(y=>new Promise(v=>{function x(){if(y.style.display="flex",y.style.flexDirection="column",g){let b=de().fontSize?de().fontSize:window.getComputedStyle(document.body).fontSize,S=parseInt(b,10)*5+"px";y.style.minWidth=S,y.style.maxWidth=S}else y.style.width="100%";v(y)}o(x,"setupImage"),setTimeout(()=>{y.complete&&x()}),y.addEventListener("error",x),y.addEventListener("load",x)})))}h=d.getBoundingClientRect(),p.attr("width",h.width),p.attr("height",h.height)}return i?s.attr("transform","translate("+-h.width/2+", "+-h.height/2+")"):s.attr("transform","translate(0, "+-h.height/2+")"),e.centerLabel&&s.attr("transform","translate("+-h.width/2+", "+-h.height/2+")"),s.insert("rect",":first-child"),{shapeSvg:a,bbox:h,halfPadding:f,label:s}},"labelHelper"),ar=o((t,e)=>{let r=e.node().getBBox();t.width=r.width,t.height=r.height},"updateNodeBounds"),En=o((t,e)=>(t.look==="handDrawn"?"rough-node":"node")+" "+t.cssClasses+" "+(e||""),"getNodeClasses")});function qSe(t,e){return t.intersect(e)}var cK,uK=R(()=>{"use strict";o(qSe,"intersectNode");cK=qSe});function XSe(t,e,r,n){var i=t.x,a=t.y,s=i-n.x,l=a-n.y,u=Math.sqrt(e*e*l*l+r*r*s*s),h=Math.abs(e*r*s/u);n.x{"use strict";o(XSe,"intersectEllipse");tw=XSe});function jSe(t,e,r){return tw(t,e,e,r)}var hK,fK=R(()=>{"use strict";Z9();o(jSe,"intersectCircle");hK=jSe});function KSe(t,e,r,n){var i,a,s,l,u,h,f,d,p,m,g,y,v,x,b;if(i=e.y-t.y,s=t.x-e.x,u=e.x*t.y-t.x*e.y,p=i*r.x+s*r.y+u,m=i*n.x+s*n.y+u,!(p!==0&&m!==0&&dK(p,m))&&(a=n.y-r.y,l=r.x-n.x,h=n.x*r.y-r.x*n.y,f=a*t.x+l*t.y+h,d=a*e.x+l*e.y+h,!(f!==0&&d!==0&&dK(f,d))&&(g=i*l-a*s,g!==0)))return y=Math.abs(g/2),v=s*h-l*u,x=v<0?(v-y)/g:(v+y)/g,v=a*u-i*h,b=v<0?(v-y)/g:(v+y)/g,{x,y:b}}function dK(t,e){return t*e>0}var pK,mK=R(()=>{"use strict";o(KSe,"intersectLine");o(dK,"sameSign");pK=KSe});function QSe(t,e,r){let n=t.x,i=t.y,a=[],s=Number.POSITIVE_INFINITY,l=Number.POSITIVE_INFINITY;typeof e.forEach=="function"?e.forEach(function(f){s=Math.min(s,f.x),l=Math.min(l,f.y)}):(s=Math.min(s,e.x),l=Math.min(l,e.y));let u=n-t.width/2-s,h=i-t.height/2-l;for(let f=0;f1&&a.sort(function(f,d){let p=f.x-r.x,m=f.y-r.y,g=Math.sqrt(p*p+m*m),y=d.x-r.x,v=d.y-r.y,x=Math.sqrt(y*y+v*v);return g{"use strict";mK();o(QSe,"intersectPolygon");gK=QSe});var sr,hi=R(()=>{"use strict";uK();fK();Z9();yK();q9();sr={node:cK,circle:hK,ellipse:tw,polygon:gK,rect:Dd}});var Rd,_v=R(()=>{"use strict";ri();hi();Sv();ki();ti();Rd=o(async(t,e,r)=>{let{labelStyles:n,nodeStyles:i}=Br(e);e.labelStyle=n;let{shapeSvg:a,bbox:s}=await zr(t,e,En(e)),l=Math.max(s.width+r.labelPaddingX*2,e?.width||0),u=Math.max(s.height+r.labelPaddingY*2,e?.height||0),h=-l/2,f=-u/2,d,{rx:p,ry:m}=e,{cssStyles:g}=e;if(r?.rx&&r.ry&&(p=r.rx,m=r.ry),e.look==="handDrawn"){let y=Jt.svg(a),v=Fr(e,{}),x=p||m?y.path(_u(h,f,l,u,p||0),v):y.rectangle(h,f,l,u,v);d=a.insert(()=>x,":first-child"),d.attr("class","basic label-container").attr("style",g)}else d=a.insert("rect",":first-child"),d.attr("class","basic label-container").attr("style",i).attr("rx",p).attr("data-id","abc").attr("data-et","node").attr("ry",m).attr("x",h).attr("y",f).attr("width",l).attr("height",u);return ar(e,d),e.intersect=function(y){return sr.rect(e,y)},a},"drawRect")});var vK,xK=R(()=>{"use strict";_v();vK=o(async(t,e)=>Rd(t,e,{rx:5,ry:5,classes:"flowchart-node"}),"state")});var bK,wK=R(()=>{"use strict";_v();bK=o(async(t,e)=>{let r={rx:5,ry:5,classes:"",labelPaddingX:(e?.padding||0)*1,labelPaddingY:(e?.padding||0)*1};return Rd(t,e,r)},"roundedRect")});var TK,kK=R(()=>{"use strict";_v();TK=o(async(t,e)=>{let r={rx:0,ry:0,classes:"",labelPaddingX:(e?.padding||0)*2,labelPaddingY:(e?.padding||0)*1};return Rd(t,e,r)},"squareRect")});var EK,CK=R(()=>{"use strict";ri();hi();ti();ki();_t();EK=o((t,e)=>{let{themeVariables:r}=de(),{lineColor:n}=r,i=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),a;if(e.look==="handDrawn"){let l=Jt.svg(i).circle(0,0,14,Lu(n));a=i.insert(()=>l)}else a=i.insert("circle",":first-child");return a.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),ar(e,a),e.intersect=function(s){return sr.circle(e,7,s)},i},"stateStart")});var SK,AK=R(()=>{"use strict";ri();hi();ti();ki();_t();SK=o((t,e)=>{let{themeVariables:r}=de(),{lineColor:n}=r,i=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),a,s;if(e.look==="handDrawn"){let l=Jt.svg(i),u=l.circle(0,0,14,{...Lu(n),roughness:.5}),h=l.circle(0,0,5,{...Lu(n),fillStyle:"solid"});a=i.insert(()=>u),s=i.insert(()=>h)}else s=i.insert("circle",":first-child"),a=i.insert("circle",":first-child"),a.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),s.attr("class","state-end").attr("r",5).attr("width",10).attr("height",10);return ar(e,a),e.intersect=function(l){return sr.circle(e,7,l)},i},"stateEnd")});var J9,_K=R(()=>{"use strict";ri();hi();ti();ki();_t();J9=o((t,e,r)=>{let{themeVariables:n}=de(),{lineColor:i}=n,a=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),s=70,l=10;r==="LR"&&(s=10,l=70);let u=-1*s/2,h=-1*l/2,f;if(e.look==="handDrawn"){let y=Jt.svg(a).rectangle(u,h,s,l,Lu(i));f=a.insert(()=>y)}else f=a.append("rect").attr("x",u).attr("y",h).attr("width",s).attr("height",l).attr("class","fork-join");ar(e,f);let d=0,p=0,m=10;return e.height&&(d=e.height),e.width&&(p=e.width),e.padding&&(m=e.padding),e.height=d+m/2,e.width=p+m/2,e.intersect=function(g){return sr.rect(e,g)},a},"forkJoin")});var LK,DK=R(()=>{"use strict";hi();ti();ki();_t();LK=o((t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{themeVariables:i}=de(),{lineColor:a}=i,s=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),l=28,u=[{x:0,y:l/2},{x:l/2,y:0},{x:0,y:-l/2},{x:-l/2,y:0}],h;if(e.look==="handDrawn"){let f=Jt.svg(s),d=u.map(function(m){return[m.x,m.y]}),p=f.polygon(d,Lu(a));h=s.insert(()=>p)}else h=s.insert("polygon",":first-child").attr("points",u.map(function(f){return f.x+","+f.y}).join(" "));return h.attr("class","state-start").attr("r",7).attr("width",28).attr("height",28).attr("style",n),e.width=28,e.height=28,e.intersect=function(f){return sr.circle(e,14,f)},s},"choice")});var RK,NK=R(()=>{"use strict";ut();ri();hi();_t();ti();RK=o(async(t,e)=>{let{themeVariables:r,handDrawnSeed:n}=de(),{noteBorderColor:i,noteBkgColor:a}=r;e.useHtmlLabels||(e.centerLabel=!0);let{shapeSvg:l,bbox:u}=await zr(t,e,"node "+e.cssClasses);V.info("Classes = ",e.cssClasses);let{cssStyles:h}=e,f,d=u.width+e.padding,p=u.height+e.padding,m=-d/2,g=-p/2;if(e.look==="handDrawn"){let v=Jt.svg(l).rectangle(m,g,d,p,{roughness:.7,fill:a,fillWeight:3,seed:n,stroke:i});f=l.insert(()=>v,":first-child"),f.attr("class","basic label-container").attr("style",h)}else f=l.insert("rect",":first-child"),f.attr("rx",e.rx).attr("ry",e.ry).attr("x",m).attr("y",g).attr("width",d).attr("height",p);return ar(e,f),e.intersect=function(y){return sr.rect(e,y)},l},"note")});var MK,IK=R(()=>{"use strict";ri();hi();ki();ti();Sv();MK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.height+e.padding,l=a.width+s/4+e.padding,u,{cssStyles:h}=e;if(e.look==="handDrawn"){let f=Jt.svg(i),d=Fr(e,{}),p=_u(-l/2,-s/2,l,s,s/2),m=f.path(p,d);u=i.insert(()=>m,":first-child"),u.attr("class","basic label-container").attr("style",h)}else u=i.insert("rect",":first-child"),u.attr("class","basic label-container").attr("style",n).attr("rx",s/2).attr("ry",s/2).attr("x",-l/2).attr("y",-s/2).attr("width",l).attr("height",s);return ar(e,u),e.intersect=function(f){return sr.rect(e,f)},i},"stadium")});var OK,PK=R(()=>{"use strict";Zt();rr();ri();H5();hi();ki();ti();_t();Sv();ut();OK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let i;e.cssClasses?i="node "+e.cssClasses:i="node default";let a=t.insert("g").attr("class",i).attr("id",e.domId||e.id),s=a.insert("g"),l=a.insert("g").attr("class","label").attr("style",n),u=e.description,h=e.label,f=l.node().appendChild(await gc(h,e.labelStyle,!0,!0)),d={width:0,height:0};if(yr(de()?.flowchart?.htmlLabels)){let A=f.children[0],L=$e(f);d=A.getBoundingClientRect(),L.attr("width",d.width),L.attr("height",d.height)}V.info("Text 2",u);let p=u||[],m=f.getBBox(),g=l.node().appendChild(await gc(p.join?p.join("
    "):p,e.labelStyle,!0,!0)),y=g.children[0],v=$e(g);d=y.getBoundingClientRect(),v.attr("width",d.width),v.attr("height",d.height);let x=(e.padding||0)/2;$e(g).attr("transform","translate( "+(d.width>m.width?0:(m.width-d.width)/2)+", "+(m.height+x+5)+")"),$e(f).attr("transform","translate( "+(d.width(V.debug("Rough node insert CXC",M),N),":first-child"),E=a.insert(()=>(V.debug("Rough node insert CXC",M),M),":first-child")}else E=s.insert("rect",":first-child"),_=s.insert("line"),E.attr("class","outer title-state").attr("style",n).attr("x",-d.width/2-x).attr("y",-d.height/2-x).attr("width",d.width+(e.padding||0)).attr("height",d.height+(e.padding||0)),_.attr("class","divider").attr("x1",-d.width/2-x).attr("x2",d.width/2+x).attr("y1",-d.height/2-x+m.height+x).attr("y2",-d.height/2-x+m.height+x);return ar(e,E),e.intersect=function(A){return sr.rect(e,A)},a},"rectWithTitle")});function Ma(t,e,r,n){return t.insert("polygon",":first-child").attr("points",n.map(function(i){return i.x+","+i.y}).join(" ")).attr("class","label-container").attr("transform","translate("+-e/2+","+r/2+")")}var Du=R(()=>{"use strict";o(Ma,"insertPolygonShape")});var BK,FK=R(()=>{"use strict";ri();hi();ki();ti();Du();BK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=(e?.padding||0)/2,l=a.width+e.padding,u=a.height+e.padding,h=-a.width/2-s,f=-a.height/2-s,d=[{x:0,y:0},{x:l,y:0},{x:l,y:-u},{x:0,y:-u},{x:0,y:0},{x:-8,y:0},{x:l+8,y:0},{x:l+8,y:-u},{x:-8,y:-u},{x:-8,y:0}];if(e.look==="handDrawn"){let p=Jt.svg(i),m=Fr(e,{}),g=p.rectangle(h-8,f,l+16,u,m),y=p.line(h,f,h,f+u,m),v=p.line(h+l,f,h+l,f+u,m);i.insert(()=>y,":first-child"),i.insert(()=>v,":first-child");let x=i.insert(()=>g,":first-child"),{cssStyles:b}=e;x.attr("class","basic label-container").attr("style",b),ar(e,x)}else{let p=Ma(i,l,u,d);n&&p.attr("style",n),ar(e,p)}return e.intersect=function(p){return sr.polygon(e,d,p)},i},"subroutine")});var ZSe,JSe,eAe,zK,GK=R(()=>{"use strict";ri();hi();ki();ti();ZSe=o((t,e,r,n,i,a)=>[`M${t},${e+a}`,`a${i},${a} 0,0,0 ${r},0`,`a${i},${a} 0,0,0 ${-r},0`,`l0,${n}`,`a${i},${a} 0,0,0 ${r},0`,`l0,${-n}`].join(" "),"createCylinderPathD"),JSe=o((t,e,r,n,i,a)=>[`M${t},${e+a}`,`M${t+r},${e+a}`,`a${i},${a} 0,0,0 ${-r},0`,`l0,${n}`,`a${i},${a} 0,0,0 ${r},0`,`l0,${-n}`].join(" "),"createOuterCylinderPathD"),eAe=o((t,e,r,n,i,a)=>[`M${t-r/2},${-n/2}`,`a${i},${a} 0,0,0 ${r},0`].join(" "),"createInnerCylinderPathD"),zK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=s/2,u=l/(2.5+s/50),h=a.height+u+e.padding,f,{cssStyles:d}=e;if(e.look==="handDrawn"){let p=Jt.svg(i),m=JSe(0,0,s,h,l,u),g=eAe(0,u,s,h,l,u),y=p.path(m,Fr(e,{})),v=p.path(g,Fr(e,{fill:"none"}));f=i.insert(()=>v,":first-child"),f=i.insert(()=>y,":first-child"),f.attr("class","basic label-container"),d&&f.attr("style",d)}else{let p=ZSe(0,0,s,h,l,u);f=i.insert("path",":first-child").attr("d",p).attr("class","basic label-container").attr("style",d).attr("style",n)}return f.attr("label-offset-y",u),f.attr("transform",`translate(${-s/2}, ${-(h/2+u)})`),ar(e,f),e.intersect=function(p){let m=sr.rect(e,p),g=m.x-(e.x??0);if(l!=0&&(Math.abs(g)<(e.width??0)/2||Math.abs(g)==(e.width??0)/2&&Math.abs(m.y-(e.y??0))>(e.height??0)/2-u)){let y=u*u*(1-g*g/(l*l));y>0&&(y=Math.sqrt(y)),y=u-y,p.y-(e.y??0)>0&&(y=-y),m.y+=y}return m},i},"cylinder")});var $K,VK=R(()=>{"use strict";ut();ri();hi();ki();ti();$K=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a,halfPadding:s}=await zr(t,e,En(e)),l=a.width/2+s,u,{cssStyles:h}=e;if(e.look==="handDrawn"){let f=Jt.svg(i),d=Fr(e,{}),p=f.circle(0,0,l*2,d);u=i.insert(()=>p,":first-child"),u.attr("class","basic label-container").attr("style",h)}else u=i.insert("circle",":first-child").attr("class","basic label-container").attr("style",n).attr("r",l).attr("cx",0).attr("cy",0);return ar(e,u),e.intersect=function(f){return V.info("Circle intersect",e,l,f),sr.circle(e,l,f)},i},"circle")});var UK,HK=R(()=>{"use strict";ut();ri();hi();ki();ti();UK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a,halfPadding:s}=await zr(t,e,En(e)),u=a.width/2+s+5,h=a.width/2+s,f,{cssStyles:d}=e;if(e.look==="handDrawn"){let p=Jt.svg(i),m=Fr(e,{roughness:.2,strokeWidth:2.5}),g=Fr(e,{roughness:.2,strokeWidth:1.5}),y=p.circle(0,0,u*2,m),v=p.circle(0,0,h*2,g);f=i.insert("g",":first-child"),f.attr("class",e.cssClasses).attr("style",d),f.node()?.appendChild(y),f.node()?.appendChild(v)}else{f=i.insert("g",":first-child");let p=f.insert("circle",":first-child"),m=f.insert("circle");f.attr("class","basic label-container").attr("style",n),p.attr("class","outer-circle").attr("style",n).attr("r",u).attr("cx",0).attr("cy",0),m.attr("class","inner-circle").attr("style",n).attr("r",h).attr("cx",0).attr("cy",0)}return ar(e,f),e.intersect=function(p){return V.info("DoubleCircle intersect",e,u,p),sr.circle(e,u,p)},i},"doublecircle")});var tAe,YK,WK=R(()=>{"use strict";ri();hi();ki();ti();Du();tAe=o((t,e,r,n)=>[`M${t-n/2},${e}`,`L${t+r},${e}`,`L${t+r},${e-n}`,`L${t-n/2},${e-n}`,`L${t},${e-n/2}`,"Z"].join(" "),"createPolygonPathD"),YK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=a.height+e.padding,u=[{x:-l/2,y:0},{x:s,y:0},{x:s,y:-l},{x:-l/2,y:-l},{x:0,y:-l/2}],h,{cssStyles:f}=e;if(e.look==="handDrawn"){let d=Jt.svg(i),p=Fr(e,{}),m=tAe(0,0,s,l),g=d.path(m,p);h=i.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${l/2})`),f&&h.attr("style",f)}else h=Ma(i,s,l,u);return n&&h.attr("style",n),e.width=s+l,e.height=l,ar(e,h),e.intersect=function(d){return sr.polygon(e,u,d)},i},"rect_left_inv_arrow")});var rAe,qK,XK=R(()=>{"use strict";ut();ri();hi();ki();ti();Du();rAe=o((t,e,r)=>[`M${t+r/2},${e}`,`L${t+r},${e-r/2}`,`L${t+r/2},${e-r}`,`L${t},${e-r/2}`,"Z"].join(" "),"createDecisionBoxPathD"),qK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=a.height+e.padding,u=s+l,h=[{x:u/2,y:0},{x:u,y:-u/2},{x:u/2,y:-u},{x:0,y:-u/2}],f,{cssStyles:d}=e;if(e.look==="handDrawn"){let p=Jt.svg(i),m=Fr(e,{}),g=rAe(0,0,u),y=p.path(g,m);f=i.insert(()=>y,":first-child").attr("transform",`translate(${-u/2}, ${u/2})`),d&&f.attr("style",d)}else f=Ma(i,u,u,h);return n&&f.attr("style",n),ar(e,f),e.intersect=function(p){return V.debug(`APA12 Intersect called SPLIT +point:`,p,` +node: +`,e,` +res:`,sr.polygon(e,h,p)),sr.polygon(e,h,p)},i},"question")});var nAe,jK,KK=R(()=>{"use strict";ri();hi();ki();ti();Du();nAe=o((t,e,r,n,i)=>[`M${t+i},${e}`,`L${t+r-i},${e}`,`L${t+r},${e-n/2}`,`L${t+r-i},${e-n}`,`L${t+i},${e-n}`,`L${t},${e-n/2}`,"Z"].join(" "),"createHexagonPathD"),jK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=4,l=a.height+e.padding,u=l/s,h=a.width+2*u+e.padding,f=[{x:u,y:0},{x:h-u,y:0},{x:h,y:-l/2},{x:h-u,y:-l},{x:u,y:-l},{x:0,y:-l/2}],d,{cssStyles:p}=e;if(e.look==="handDrawn"){let m=Jt.svg(i),g=Fr(e,{}),y=nAe(0,0,h,l,u),v=m.path(y,g);d=i.insert(()=>v,":first-child").attr("transform",`translate(${-h/2}, ${l/2})`),p&&d.attr("style",p)}else d=Ma(i,h,l,f);return n&&d.attr("style",n),e.width=h,e.height=l,ar(e,d),e.intersect=function(m){return sr.polygon(e,f,m)},i},"hexagon")});var iAe,QK,ZK=R(()=>{"use strict";ri();hi();ki();ti();Du();iAe=o((t,e,r,n)=>[`M${t-2*n/6},${e}`,`L${t+r-n/6},${e}`,`L${t+r+2*n/6},${e-n}`,`L${t+n/6},${e-n}`,"Z"].join(" "),"createLeanRightPathD"),QK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=a.height+e.padding,u=[{x:-2*l/6,y:0},{x:s-l/6,y:0},{x:s+2*l/6,y:-l},{x:l/6,y:-l}],h,{cssStyles:f}=e;if(e.look==="handDrawn"){let d=Jt.svg(i),p=Fr(e,{}),m=iAe(0,0,s,l),g=d.path(m,p);h=i.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${l/2})`),f&&h.attr("style",f)}else h=Ma(i,s,l,u);return n&&h.attr("style",n),e.width=s,e.height=l,ar(e,h),e.intersect=function(d){return sr.polygon(e,u,d)},i},"lean_right")});var aAe,JK,eQ=R(()=>{"use strict";ri();hi();ki();ti();Du();aAe=o((t,e,r,n)=>[`M${t+2*n/6},${e}`,`L${t+r+n/6},${e}`,`L${t+r-2*n/6},${e-n}`,`L${t-n/6},${e-n}`,"Z"].join(" "),"createLeanLeftPathD"),JK=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=a.height+e.padding,u=[{x:2*l/6,y:0},{x:s+l/6,y:0},{x:s-2*l/6,y:-l},{x:-l/6,y:-l}],h,{cssStyles:f}=e;if(e.look==="handDrawn"){let d=Jt.svg(i),p=Fr(e,{}),m=aAe(0,0,s,l),g=d.path(m,p);h=i.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${l/2})`),f&&h.attr("style",f)}else h=Ma(i,s,l,u);return n&&h.attr("style",n),e.width=s,e.height=l,ar(e,h),e.intersect=function(d){return sr.polygon(e,u,d)},i},"lean_left")});var sAe,tQ,rQ=R(()=>{"use strict";ri();hi();ki();ti();Du();sAe=o((t,e,r,n)=>[`M${t-2*n/6},${e}`,`L${t+r+2*n/6},${e}`,`L${t+r-n/6},${e-n}`,`L${t+n/6},${e-n}`,"Z"].join(" "),"createTrapezoidPathD"),tQ=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=a.height+e.padding,u=[{x:-2*l/6,y:0},{x:s+2*l/6,y:0},{x:s-l/6,y:-l},{x:l/6,y:-l}],h,{cssStyles:f}=e;if(e.look==="handDrawn"){let d=Jt.svg(i),p=Fr(e,{}),m=sAe(0,0,s,l),g=d.path(m,p);h=i.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${l/2})`),f&&h.attr("style",f)}else h=Ma(i,s,l,u);return n&&h.attr("style",n),e.width=s,e.height=l,ar(e,h),e.intersect=function(d){return sr.polygon(e,u,d)},i},"trapezoid")});var oAe,nQ,iQ=R(()=>{"use strict";ri();hi();ki();ti();Du();oAe=o((t,e,r,n)=>[`M${t+n/6},${e}`,`L${t+r-n/6},${e}`,`L${t+r+2*n/6},${e-n}`,`L${t-2*n/6},${e-n}`,"Z"].join(" "),"createInvertedTrapezoidPathD"),nQ=o(async(t,e)=>{let{labelStyles:r,nodeStyles:n}=Br(e);e.labelStyle=r;let{shapeSvg:i,bbox:a}=await zr(t,e,En(e)),s=a.width+e.padding,l=a.height+e.padding,u=[{x:l/6,y:0},{x:s-l/6,y:0},{x:s+2*l/6,y:-l},{x:-2*l/6,y:-l}],h,{cssStyles:f}=e;if(e.look==="handDrawn"){let d=Jt.svg(i),p=Fr(e,{}),m=oAe(0,0,s,l),g=d.path(m,p);h=i.insert(()=>g,":first-child").attr("transform",`translate(${-s/2}, ${l/2})`),f&&h.attr("style",f)}else h=Ma(i,s,l,u);return n&&h.attr("style",n),e.width=s,e.height=l,ar(e,h),e.intersect=function(d){return sr.polygon(e,u,d)},i},"inv_trapezoid")});var aQ,sQ=R(()=>{"use strict";_v();ri();hi();aQ=o(async(t,e)=>{let{shapeSvg:r}=await zr(t,e,"label"),n=r.insert("rect",":first-child");return n.attr("width",.1).attr("height",.1),r.attr("class","label edgeLabel"),ar(e,n),e.intersect=function(s){return sr.rect(e,s)},r},"labelRect")});var oQ,ym,rw,lQ,cQ,eL,tL=R(()=>{"use strict";ut();xK();wK();kK();CK();AK();_K();DK();NK();IK();PK();_t();FK();GK();VK();HK();WK();XK();KK();ZK();eQ();rQ();iQ();sQ();oQ={state:vK,stateStart:EK,stateEnd:SK,fork:J9,join:J9,choice:LK,note:RK,roundedRect:bK,rectWithTitle:OK,squareRect:TK,stadium:MK,subroutine:BK,cylinder:zK,circle:$K,doublecircle:UK,odd:YK,diamond:qK,hexagon:jK,lean_right:QK,lean_left:JK,trapezoid:tQ,inv_trapezoid:nQ,labelRect:aQ},ym=new Map,rw=o(async(t,e,r)=>{let n,i;if(e.shape==="rect"&&(e.rx&&e.ry?e.shape="roundedRect":e.shape="squareRect"),e.link){let a;de().securityLevel==="sandbox"?a="_top":e.linkTarget&&(a=e.linkTarget||"_blank"),n=t.insert("svg:a").attr("xlink:href",e.link).attr("target",a),i=await oQ[e.shape](n,e,r)}else i=await oQ[e.shape](t,e,r),n=i;return e.tooltip&&i.attr("title",e.tooltip),ym.set(e.id,n),e.haveCallback&&ym.get(e.id).attr("class",ym.get(e.id).attr("class")+" clickable"),n},"insertNode"),lQ=o((t,e)=>{ym.set(e.id,t)},"setNodeElem"),cQ=o(()=>{ym.clear()},"clear"),eL=o(t=>{let e=ym.get(t.id);V.trace("Transforming node",t.diff,t,"translate("+(t.x-t.width/2-5)+", "+t.width/2+")");let r=8,n=t.diff||0;return t.clusterNode?e.attr("transform","translate("+(t.x+n-t.width/2)+", "+(t.y-t.height/2-r)+")"):e.attr("transform","translate("+t.x+", "+t.y+")"),n},"positionNode")});var uQ,hQ=R(()=>{"use strict";qs();rr();ut();X9();K9();Q9();tL();ri();xr();uQ={common:We,getConfig:Or,insertCluster:Y5,insertEdge:J5,insertEdgeLabel:Q5,insertMarkers:ew,insertNode:rw,interpolateToCurve:om,labelHelper:zr,log:V,positionEdgeLabel:Z5}});function cAe(t){return typeof t=="symbol"||Wn(t)&&fa(t)==lAe}var lAe,so,Nd=R(()=>{"use strict";wu();Mo();lAe="[object Symbol]";o(cAe,"isSymbol");so=cAe});function uAe(t,e){for(var r=-1,n=t==null?0:t.length,i=Array(n);++r{"use strict";o(uAe,"arrayMap");Ss=uAe});function pQ(t){if(typeof t=="string")return t;if(wt(t))return Ss(t,pQ)+"";if(so(t))return dQ?dQ.call(t):"";var e=t+"";return e=="0"&&1/t==-hAe?"-0":e}var hAe,fQ,dQ,mQ,gQ=R(()=>{"use strict";vd();Md();Bn();Nd();hAe=1/0,fQ=Ji?Ji.prototype:void 0,dQ=fQ?fQ.toString:void 0;o(pQ,"baseToString");mQ=pQ});function dAe(t){for(var e=t.length;e--&&fAe.test(t.charAt(e)););return e}var fAe,yQ,vQ=R(()=>{"use strict";fAe=/\s/;o(dAe,"trimmedEndIndex");yQ=dAe});function mAe(t){return t&&t.slice(0,yQ(t)+1).replace(pAe,"")}var pAe,xQ,bQ=R(()=>{"use strict";vQ();pAe=/^\s+/;o(mAe,"baseTrim");xQ=mAe});function bAe(t){if(typeof t=="number")return t;if(so(t))return wQ;if(pn(t)){var e=typeof t.valueOf=="function"?t.valueOf():t;t=pn(e)?e+"":e}if(typeof t!="string")return t===0?t:+t;t=xQ(t);var r=yAe.test(t);return r||vAe.test(t)?xAe(t.slice(2),r?2:8):gAe.test(t)?wQ:+t}var wQ,gAe,yAe,vAe,xAe,TQ,kQ=R(()=>{"use strict";bQ();Js();Nd();wQ=NaN,gAe=/^[-+]0x[0-9a-f]+$/i,yAe=/^0b[01]+$/i,vAe=/^0o[0-7]+$/i,xAe=parseInt;o(bAe,"toNumber");TQ=bAe});function TAe(t){if(!t)return t===0?t:0;if(t=TQ(t),t===EQ||t===-EQ){var e=t<0?-1:1;return e*wAe}return t===t?t:0}var EQ,wAe,vm,rL=R(()=>{"use strict";kQ();EQ=1/0,wAe=17976931348623157e292;o(TAe,"toFinite");vm=TAe});function kAe(t){var e=vm(t),r=e%1;return e===e?r?e-r:e:0}var yc,xm=R(()=>{"use strict";rL();o(kAe,"toInteger");yc=kAe});var EAe,nw,CQ=R(()=>{"use strict";Nh();Ro();EAe=xs(Jn,"WeakMap"),nw=EAe});function CAe(){}var qn,nL=R(()=>{"use strict";o(CAe,"noop");qn=CAe});function SAe(t,e){for(var r=-1,n=t==null?0:t.length;++r{"use strict";o(SAe,"arrayEach");iw=SAe});function AAe(t,e,r,n){for(var i=t.length,a=r+(n?1:-1);n?a--:++a{"use strict";o(AAe,"baseFindIndex");aw=AAe});function _Ae(t){return t!==t}var SQ,AQ=R(()=>{"use strict";o(_Ae,"baseIsNaN");SQ=_Ae});function LAe(t,e,r){for(var n=r-1,i=t.length;++n{"use strict";o(LAe,"strictIndexOf");_Q=LAe});function DAe(t,e,r){return e===e?_Q(t,e,r):aw(t,SQ,r)}var bm,sw=R(()=>{"use strict";aL();AQ();LQ();o(DAe,"baseIndexOf");bm=DAe});function RAe(t,e){var r=t==null?0:t.length;return!!r&&bm(t,e,0)>-1}var ow,sL=R(()=>{"use strict";sw();o(RAe,"arrayIncludes");ow=RAe});var NAe,DQ,RQ=R(()=>{"use strict";F_();NAe=s5(Object.keys,Object),DQ=NAe});function OAe(t){if(!fc(t))return DQ(t);var e=[];for(var r in Object(t))IAe.call(t,r)&&r!="constructor"&&e.push(r);return e}var MAe,IAe,wm,lw=R(()=>{"use strict";tm();RQ();MAe=Object.prototype,IAe=MAe.hasOwnProperty;o(OAe,"baseKeys");wm=OAe});function PAe(t){return ei(t)?h5(t):wm(t)}var Dr,vc=R(()=>{"use strict";U_();lw();Io();o(PAe,"keys");Dr=PAe});var BAe,FAe,zAe,pa,NQ=R(()=>{"use strict";am();kd();q_();Io();tm();vc();BAe=Object.prototype,FAe=BAe.hasOwnProperty,zAe=p5(function(t,e){if(fc(e)||ei(e)){Bo(e,Dr(e),t);return}for(var r in e)FAe.call(e,r)&&dc(t,r,e[r])}),pa=zAe});function VAe(t,e){if(wt(t))return!1;var r=typeof t;return r=="number"||r=="symbol"||r=="boolean"||t==null||so(t)?!0:$Ae.test(t)||!GAe.test(t)||e!=null&&t in Object(e)}var GAe,$Ae,Tm,cw=R(()=>{"use strict";Bn();Nd();GAe=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,$Ae=/^\w*$/;o(VAe,"isKey");Tm=VAe});function HAe(t){var e=qp(t,function(n){return r.size===UAe&&r.clear(),n}),r=e.cache;return e}var UAe,MQ,IQ=R(()=>{"use strict";R_();UAe=500;o(HAe,"memoizeCapped");MQ=HAe});var YAe,WAe,qAe,OQ,PQ=R(()=>{"use strict";IQ();YAe=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,WAe=/\\(\\)?/g,qAe=MQ(function(t){var e=[];return t.charCodeAt(0)===46&&e.push(""),t.replace(YAe,function(r,n,i,a){e.push(i?a.replace(WAe,"$1"):n||r)}),e}),OQ=qAe});function XAe(t){return t==null?"":mQ(t)}var uw,oL=R(()=>{"use strict";gQ();o(XAe,"toString");uw=XAe});function jAe(t,e){return wt(t)?t:Tm(t,e)?[t]:OQ(uw(t))}var Hh,Lv=R(()=>{"use strict";Bn();cw();PQ();oL();o(jAe,"castPath");Hh=jAe});function QAe(t){if(typeof t=="string"||so(t))return t;var e=t+"";return e=="0"&&1/t==-KAe?"-0":e}var KAe,xc,km=R(()=>{"use strict";Nd();KAe=1/0;o(QAe,"toKey");xc=QAe});function ZAe(t,e){e=Hh(e,t);for(var r=0,n=e.length;t!=null&&r{"use strict";Lv();km();o(ZAe,"baseGet");Yh=ZAe});function JAe(t,e,r){var n=t==null?void 0:Yh(t,e);return n===void 0?r:n}var BQ,FQ=R(()=>{"use strict";Dv();o(JAe,"get");BQ=JAe});function e8e(t,e){for(var r=-1,n=e.length,i=t.length;++r{"use strict";o(e8e,"arrayPush");Em=e8e});function t8e(t){return wt(t)||kl(t)||!!(zQ&&t&&t[zQ])}var zQ,GQ,$Q=R(()=>{"use strict";vd();rm();Bn();zQ=Ji?Ji.isConcatSpreadable:void 0;o(t8e,"isFlattenable");GQ=t8e});function VQ(t,e,r,n,i){var a=-1,s=t.length;for(r||(r=GQ),i||(i=[]);++a0&&r(l)?e>1?VQ(l,e-1,r,n,i):Em(i,l):n||(i[i.length]=l)}return i}var bc,Cm=R(()=>{"use strict";hw();$Q();o(VQ,"baseFlatten");bc=VQ});function r8e(t){var e=t==null?0:t.length;return e?bc(t,1):[]}var Gr,fw=R(()=>{"use strict";Cm();o(r8e,"flatten");Gr=r8e});function n8e(t){return d5(f5(t,void 0,Gr),t+"")}var UQ,HQ=R(()=>{"use strict";fw();H_();W_();o(n8e,"flatRest");UQ=n8e});function i8e(t,e,r){var n=-1,i=t.length;e<0&&(e=-e>i?0:i+e),r=r>i?i:r,r<0&&(r+=i),i=e>r?0:r-e>>>0,e>>>=0;for(var a=Array(i);++n{"use strict";o(i8e,"baseSlice");dw=i8e});function d8e(t){return f8e.test(t)}var a8e,s8e,o8e,l8e,c8e,u8e,h8e,f8e,YQ,WQ=R(()=>{"use strict";a8e="\\ud800-\\udfff",s8e="\\u0300-\\u036f",o8e="\\ufe20-\\ufe2f",l8e="\\u20d0-\\u20ff",c8e=s8e+o8e+l8e,u8e="\\ufe0e\\ufe0f",h8e="\\u200d",f8e=RegExp("["+h8e+a8e+c8e+u8e+"]");o(d8e,"hasUnicode");YQ=d8e});function p8e(t,e,r,n){var i=-1,a=t==null?0:t.length;for(n&&a&&(r=t[++i]);++i{"use strict";o(p8e,"arrayReduce");qQ=p8e});function m8e(t,e){return t&&Bo(e,Dr(e),t)}var jQ,KQ=R(()=>{"use strict";kd();vc();o(m8e,"baseAssign");jQ=m8e});function g8e(t,e){return t&&Bo(e,bs(e),t)}var QQ,ZQ=R(()=>{"use strict";kd();zh();o(g8e,"baseAssignIn");QQ=g8e});function y8e(t,e){for(var r=-1,n=t==null?0:t.length,i=0,a=[];++r{"use strict";o(y8e,"arrayFilter");Sm=y8e});function v8e(){return[]}var mw,cL=R(()=>{"use strict";o(v8e,"stubArray");mw=v8e});var x8e,b8e,JQ,w8e,Am,gw=R(()=>{"use strict";pw();cL();x8e=Object.prototype,b8e=x8e.propertyIsEnumerable,JQ=Object.getOwnPropertySymbols,w8e=JQ?function(t){return t==null?[]:(t=Object(t),Sm(JQ(t),function(e){return b8e.call(t,e)}))}:mw,Am=w8e});function T8e(t,e){return Bo(t,Am(t),e)}var eZ,tZ=R(()=>{"use strict";kd();gw();o(T8e,"copySymbols");eZ=T8e});var k8e,E8e,yw,uL=R(()=>{"use strict";hw();o5();gw();cL();k8e=Object.getOwnPropertySymbols,E8e=k8e?function(t){for(var e=[];t;)Em(e,Am(t)),t=em(t);return e}:mw,yw=E8e});function C8e(t,e){return Bo(t,yw(t),e)}var rZ,nZ=R(()=>{"use strict";kd();uL();o(C8e,"copySymbolsIn");rZ=C8e});function S8e(t,e,r){var n=e(t);return wt(t)?n:Em(n,r(t))}var vw,hL=R(()=>{"use strict";hw();Bn();o(S8e,"baseGetAllKeys");vw=S8e});function A8e(t){return vw(t,Dr,Am)}var Rv,fL=R(()=>{"use strict";hL();gw();vc();o(A8e,"getAllKeys");Rv=A8e});function _8e(t){return vw(t,bs,yw)}var xw,dL=R(()=>{"use strict";hL();uL();zh();o(_8e,"getAllKeysIn");xw=_8e});var L8e,bw,iZ=R(()=>{"use strict";Nh();Ro();L8e=xs(Jn,"DataView"),bw=L8e});var D8e,ww,aZ=R(()=>{"use strict";Nh();Ro();D8e=xs(Jn,"Promise"),ww=D8e});var R8e,Wh,pL=R(()=>{"use strict";Nh();Ro();R8e=xs(Jn,"Set"),Wh=R8e});var sZ,N8e,oZ,lZ,cZ,uZ,M8e,I8e,O8e,P8e,B8e,Id,oo,Od=R(()=>{"use strict";iZ();J3();aZ();pL();CQ();wu();__();sZ="[object Map]",N8e="[object Object]",oZ="[object Promise]",lZ="[object Set]",cZ="[object WeakMap]",uZ="[object DataView]",M8e=Tu(bw),I8e=Tu(Oh),O8e=Tu(ww),P8e=Tu(Wh),B8e=Tu(nw),Id=fa;(bw&&Id(new bw(new ArrayBuffer(1)))!=uZ||Oh&&Id(new Oh)!=sZ||ww&&Id(ww.resolve())!=oZ||Wh&&Id(new Wh)!=lZ||nw&&Id(new nw)!=cZ)&&(Id=o(function(t){var e=fa(t),r=e==N8e?t.constructor:void 0,n=r?Tu(r):"";if(n)switch(n){case M8e:return uZ;case I8e:return sZ;case O8e:return oZ;case P8e:return lZ;case B8e:return cZ}return e},"getTag"));oo=Id});function G8e(t){var e=t.length,r=new t.constructor(e);return e&&typeof t[0]=="string"&&z8e.call(t,"index")&&(r.index=t.index,r.input=t.input),r}var F8e,z8e,hZ,fZ=R(()=>{"use strict";F8e=Object.prototype,z8e=F8e.hasOwnProperty;o(G8e,"initCloneArray");hZ=G8e});function $8e(t,e){var r=e?Jp(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}var dZ,pZ=R(()=>{"use strict";n5();o($8e,"cloneDataView");dZ=$8e});function U8e(t){var e=new t.constructor(t.source,V8e.exec(t));return e.lastIndex=t.lastIndex,e}var V8e,mZ,gZ=R(()=>{"use strict";V8e=/\w*$/;o(U8e,"cloneRegExp");mZ=U8e});function H8e(t){return vZ?Object(vZ.call(t)):{}}var yZ,vZ,xZ,bZ=R(()=>{"use strict";vd();yZ=Ji?Ji.prototype:void 0,vZ=yZ?yZ.valueOf:void 0;o(H8e,"cloneSymbol");xZ=H8e});function u_e(t,e,r){var n=t.constructor;switch(e){case J8e:return Jp(t);case Y8e:case W8e:return new n(+t);case e_e:return dZ(t,r);case t_e:case r_e:case n_e:case i_e:case a_e:case s_e:case o_e:case l_e:case c_e:return i5(t,r);case q8e:return new n;case X8e:case Q8e:return new n(t);case j8e:return mZ(t);case K8e:return new n;case Z8e:return xZ(t)}}var Y8e,W8e,q8e,X8e,j8e,K8e,Q8e,Z8e,J8e,e_e,t_e,r_e,n_e,i_e,a_e,s_e,o_e,l_e,c_e,wZ,TZ=R(()=>{"use strict";n5();pZ();gZ();bZ();P_();Y8e="[object Boolean]",W8e="[object Date]",q8e="[object Map]",X8e="[object Number]",j8e="[object RegExp]",K8e="[object Set]",Q8e="[object String]",Z8e="[object Symbol]",J8e="[object ArrayBuffer]",e_e="[object DataView]",t_e="[object Float32Array]",r_e="[object Float64Array]",n_e="[object Int8Array]",i_e="[object Int16Array]",a_e="[object Int32Array]",s_e="[object Uint8Array]",o_e="[object Uint8ClampedArray]",l_e="[object Uint16Array]",c_e="[object Uint32Array]";o(u_e,"initCloneByTag");wZ=u_e});function f_e(t){return Wn(t)&&oo(t)==h_e}var h_e,kZ,EZ=R(()=>{"use strict";Od();Mo();h_e="[object Map]";o(f_e,"baseIsMap");kZ=f_e});var CZ,d_e,SZ,AZ=R(()=>{"use strict";EZ();Td();ov();CZ=Po&&Po.isMap,d_e=CZ?Oo(CZ):kZ,SZ=d_e});function m_e(t){return Wn(t)&&oo(t)==p_e}var p_e,_Z,LZ=R(()=>{"use strict";Od();Mo();p_e="[object Set]";o(m_e,"baseIsSet");_Z=m_e});var DZ,g_e,RZ,NZ=R(()=>{"use strict";LZ();Td();ov();DZ=Po&&Po.isSet,g_e=DZ?Oo(DZ):_Z,RZ=g_e});function Tw(t,e,r,n,i,a){var s,l=e&y_e,u=e&v_e,h=e&x_e;if(r&&(s=i?r(t,n,i,a):r(t)),s!==void 0)return s;if(!pn(t))return t;var f=wt(t);if(f){if(s=hZ(t),!l)return a5(t,s)}else{var d=oo(t),p=d==IZ||d==E_e;if(El(t))return r5(t,l);if(d==OZ||d==MZ||p&&!i){if(s=u||p?{}:l5(t),!l)return u?rZ(t,QQ(s,t)):eZ(t,jQ(s,t))}else{if(!Cn[d])return i?t:{};s=wZ(t,d,l)}}a||(a=new uc);var m=a.get(t);if(m)return m;a.set(t,s),RZ(t)?t.forEach(function(v){s.add(Tw(v,e,r,v,t,a))}):SZ(t)&&t.forEach(function(v,x){s.set(x,Tw(v,e,r,x,t,a))});var g=h?u?xw:Rv:u?bs:Dr,y=f?void 0:g(t);return iw(y||t,function(v,x){y&&(x=v,v=t[x]),dc(s,x,Tw(v,e,r,x,t,a))}),s}var y_e,v_e,x_e,MZ,b_e,w_e,T_e,k_e,IZ,E_e,C_e,S_e,OZ,A_e,__e,L_e,D_e,R_e,N_e,M_e,I_e,O_e,P_e,B_e,F_e,z_e,G_e,$_e,V_e,Cn,kw,mL=R(()=>{"use strict";iv();iL();am();KQ();ZQ();I_();B_();tZ();nZ();fL();dL();Od();fZ();TZ();z_();Bn();im();AZ();Js();NZ();vc();zh();y_e=1,v_e=2,x_e=4,MZ="[object Arguments]",b_e="[object Array]",w_e="[object Boolean]",T_e="[object Date]",k_e="[object Error]",IZ="[object Function]",E_e="[object GeneratorFunction]",C_e="[object Map]",S_e="[object Number]",OZ="[object Object]",A_e="[object RegExp]",__e="[object Set]",L_e="[object String]",D_e="[object Symbol]",R_e="[object WeakMap]",N_e="[object ArrayBuffer]",M_e="[object DataView]",I_e="[object Float32Array]",O_e="[object Float64Array]",P_e="[object Int8Array]",B_e="[object Int16Array]",F_e="[object Int32Array]",z_e="[object Uint8Array]",G_e="[object Uint8ClampedArray]",$_e="[object Uint16Array]",V_e="[object Uint32Array]",Cn={};Cn[MZ]=Cn[b_e]=Cn[N_e]=Cn[M_e]=Cn[w_e]=Cn[T_e]=Cn[I_e]=Cn[O_e]=Cn[P_e]=Cn[B_e]=Cn[F_e]=Cn[C_e]=Cn[S_e]=Cn[OZ]=Cn[A_e]=Cn[__e]=Cn[L_e]=Cn[D_e]=Cn[z_e]=Cn[G_e]=Cn[$_e]=Cn[V_e]=!0;Cn[k_e]=Cn[IZ]=Cn[R_e]=!1;o(Tw,"baseClone");kw=Tw});function H_e(t){return kw(t,U_e)}var U_e,Qr,gL=R(()=>{"use strict";mL();U_e=4;o(H_e,"clone");Qr=H_e});function q_e(t){return kw(t,Y_e|W_e)}var Y_e,W_e,yL,PZ=R(()=>{"use strict";mL();Y_e=1,W_e=4;o(q_e,"cloneDeep");yL=q_e});function X_e(t){for(var e=-1,r=t==null?0:t.length,n=0,i=[];++e{"use strict";o(X_e,"compact");wc=X_e});function K_e(t){return this.__data__.set(t,j_e),this}var j_e,FZ,zZ=R(()=>{"use strict";j_e="__lodash_hash_undefined__";o(K_e,"setCacheAdd");FZ=K_e});function Q_e(t){return this.__data__.has(t)}var GZ,$Z=R(()=>{"use strict";o(Q_e,"setCacheHas");GZ=Q_e});function Ew(t){var e=-1,r=t==null?0:t.length;for(this.__data__=new bd;++e{"use strict";e5();zZ();$Z();o(Ew,"SetCache");Ew.prototype.add=Ew.prototype.push=FZ;Ew.prototype.has=GZ;_m=Ew});function Z_e(t,e){for(var r=-1,n=t==null?0:t.length;++r{"use strict";o(Z_e,"arraySome");Sw=Z_e});function J_e(t,e){return t.has(e)}var Lm,Aw=R(()=>{"use strict";o(J_e,"cacheHas");Lm=J_e});function r9e(t,e,r,n,i,a){var s=r&e9e,l=t.length,u=e.length;if(l!=u&&!(s&&u>l))return!1;var h=a.get(t),f=a.get(e);if(h&&f)return h==e&&f==t;var d=-1,p=!0,m=r&t9e?new _m:void 0;for(a.set(t,e),a.set(e,t);++d{"use strict";Cw();vL();Aw();e9e=1,t9e=2;o(r9e,"equalArrays");_w=r9e});function n9e(t){var e=-1,r=Array(t.size);return t.forEach(function(n,i){r[++e]=[i,n]}),r}var VZ,UZ=R(()=>{"use strict";o(n9e,"mapToArray");VZ=n9e});function i9e(t){var e=-1,r=Array(t.size);return t.forEach(function(n){r[++e]=n}),r}var Dm,Lw=R(()=>{"use strict";o(i9e,"setToArray");Dm=i9e});function v9e(t,e,r,n,i,a,s){switch(r){case y9e:if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case g9e:return!(t.byteLength!=e.byteLength||!a(new Zp(t),new Zp(e)));case o9e:case l9e:case h9e:return No(+t,+e);case c9e:return t.name==e.name&&t.message==e.message;case f9e:case p9e:return t==e+"";case u9e:var l=VZ;case d9e:var u=n&a9e;if(l||(l=Dm),t.size!=e.size&&!u)return!1;var h=s.get(t);if(h)return h==e;n|=s9e,s.set(t,e);var f=_w(l(t),l(e),n,i,a,s);return s.delete(t),f;case m9e:if(bL)return bL.call(t)==bL.call(e)}return!1}var a9e,s9e,o9e,l9e,c9e,u9e,h9e,f9e,d9e,p9e,m9e,g9e,y9e,HZ,bL,YZ,WZ=R(()=>{"use strict";vd();O_();xd();xL();UZ();Lw();a9e=1,s9e=2,o9e="[object Boolean]",l9e="[object Date]",c9e="[object Error]",u9e="[object Map]",h9e="[object Number]",f9e="[object RegExp]",d9e="[object Set]",p9e="[object String]",m9e="[object Symbol]",g9e="[object ArrayBuffer]",y9e="[object DataView]",HZ=Ji?Ji.prototype:void 0,bL=HZ?HZ.valueOf:void 0;o(v9e,"equalByTag");YZ=v9e});function T9e(t,e,r,n,i,a){var s=r&x9e,l=Rv(t),u=l.length,h=Rv(e),f=h.length;if(u!=f&&!s)return!1;for(var d=u;d--;){var p=l[d];if(!(s?p in e:w9e.call(e,p)))return!1}var m=a.get(t),g=a.get(e);if(m&&g)return m==e&&g==t;var y=!0;a.set(t,e),a.set(e,t);for(var v=s;++d{"use strict";fL();x9e=1,b9e=Object.prototype,w9e=b9e.hasOwnProperty;o(T9e,"equalObjects");qZ=T9e});function C9e(t,e,r,n,i,a){var s=wt(t),l=wt(e),u=s?KZ:oo(t),h=l?KZ:oo(e);u=u==jZ?Dw:u,h=h==jZ?Dw:h;var f=u==Dw,d=h==Dw,p=u==h;if(p&&El(t)){if(!El(e))return!1;s=!0,f=!1}if(p&&!f)return a||(a=new uc),s||Bh(t)?_w(t,e,r,n,i,a):YZ(t,e,u,r,n,i,a);if(!(r&k9e)){var m=f&&QZ.call(t,"__wrapped__"),g=d&&QZ.call(e,"__wrapped__");if(m||g){var y=m?t.value():t,v=g?e.value():e;return a||(a=new uc),i(y,v,r,n,a)}}return p?(a||(a=new uc),qZ(t,e,r,n,i,a)):!1}var k9e,jZ,KZ,Dw,E9e,QZ,ZZ,JZ=R(()=>{"use strict";iv();xL();WZ();XZ();Od();Bn();im();lv();k9e=1,jZ="[object Arguments]",KZ="[object Array]",Dw="[object Object]",E9e=Object.prototype,QZ=E9e.hasOwnProperty;o(C9e,"baseIsEqualDeep");ZZ=C9e});function eJ(t,e,r,n,i){return t===e?!0:t==null||e==null||!Wn(t)&&!Wn(e)?t!==t&&e!==e:ZZ(t,e,r,n,eJ,i)}var Rw,wL=R(()=>{"use strict";JZ();Mo();o(eJ,"baseIsEqual");Rw=eJ});function _9e(t,e,r,n){var i=r.length,a=i,s=!n;if(t==null)return!a;for(t=Object(t);i--;){var l=r[i];if(s&&l[2]?l[1]!==t[l[0]]:!(l[0]in t))return!1}for(;++i{"use strict";iv();wL();S9e=1,A9e=2;o(_9e,"baseIsMatch");tJ=_9e});function L9e(t){return t===t&&!pn(t)}var Nw,TL=R(()=>{"use strict";Js();o(L9e,"isStrictComparable");Nw=L9e});function D9e(t){for(var e=Dr(t),r=e.length;r--;){var n=e[r],i=t[n];e[r]=[n,i,Nw(i)]}return e}var nJ,iJ=R(()=>{"use strict";TL();vc();o(D9e,"getMatchData");nJ=D9e});function R9e(t,e){return function(r){return r==null?!1:r[t]===e&&(e!==void 0||t in Object(r))}}var Mw,kL=R(()=>{"use strict";o(R9e,"matchesStrictComparable");Mw=R9e});function N9e(t){var e=nJ(t);return e.length==1&&e[0][2]?Mw(e[0][0],e[0][1]):function(r){return r===t||tJ(r,t,e)}}var aJ,sJ=R(()=>{"use strict";rJ();iJ();kL();o(N9e,"baseMatches");aJ=N9e});function M9e(t,e){return t!=null&&e in Object(t)}var oJ,lJ=R(()=>{"use strict";o(M9e,"baseHasIn");oJ=M9e});function I9e(t,e,r){e=Hh(e,t);for(var n=-1,i=e.length,a=!1;++n{"use strict";Lv();rm();Bn();uv();c5();km();o(I9e,"hasPath");Iw=I9e});function O9e(t,e){return t!=null&&Iw(t,e,oJ)}var Ow,CL=R(()=>{"use strict";lJ();EL();o(O9e,"hasIn");Ow=O9e});function F9e(t,e){return Tm(t)&&Nw(e)?Mw(xc(t),e):function(r){var n=BQ(r,t);return n===void 0&&n===e?Ow(r,t):Rw(e,n,P9e|B9e)}}var P9e,B9e,cJ,uJ=R(()=>{"use strict";wL();FQ();CL();cw();TL();kL();km();P9e=1,B9e=2;o(F9e,"baseMatchesProperty");cJ=F9e});function z9e(t){return function(e){return e?.[t]}}var Pw,SL=R(()=>{"use strict";o(z9e,"baseProperty");Pw=z9e});function G9e(t){return function(e){return Yh(e,t)}}var hJ,fJ=R(()=>{"use strict";Dv();o(G9e,"basePropertyDeep");hJ=G9e});function $9e(t){return Tm(t)?Pw(xc(t)):hJ(t)}var dJ,pJ=R(()=>{"use strict";SL();fJ();cw();km();o($9e,"property");dJ=$9e});function V9e(t){return typeof t=="function"?t:t==null?ea:typeof t=="object"?wt(t)?cJ(t[0],t[1]):aJ(t):dJ(t)}var cn,Qa=R(()=>{"use strict";sJ();uJ();Eu();Bn();pJ();o(V9e,"baseIteratee");cn=V9e});function U9e(t,e,r,n){for(var i=-1,a=t==null?0:t.length;++i{"use strict";o(U9e,"arrayAggregator");mJ=U9e});function H9e(t,e){return t&&Qp(t,e,Dr)}var Rm,Bw=R(()=>{"use strict";t5();vc();o(H9e,"baseForOwn");Rm=H9e});function Y9e(t,e){return function(r,n){if(r==null)return r;if(!ei(r))return t(r,n);for(var i=r.length,a=e?i:-1,s=Object(r);(e?a--:++a{"use strict";Io();o(Y9e,"createBaseEach");yJ=Y9e});var W9e,As,qh=R(()=>{"use strict";Bw();vJ();W9e=yJ(Rm),As=W9e});function q9e(t,e,r,n){return As(t,function(i,a,s){e(n,i,r(i),s)}),n}var xJ,bJ=R(()=>{"use strict";qh();o(q9e,"baseAggregator");xJ=q9e});function X9e(t,e){return function(r,n){var i=wt(r)?mJ:xJ,a=e?e():{};return i(r,t,cn(n,2),a)}}var wJ,TJ=R(()=>{"use strict";gJ();bJ();Qa();Bn();o(X9e,"createAggregator");wJ=X9e});var j9e,Fw,kJ=R(()=>{"use strict";Ro();j9e=o(function(){return Jn.Date.now()},"now"),Fw=j9e});var EJ,K9e,Q9e,Xh,CJ=R(()=>{"use strict";sm();xd();Ed();zh();EJ=Object.prototype,K9e=EJ.hasOwnProperty,Q9e=pc(function(t,e){t=Object(t);var r=-1,n=e.length,i=n>2?e[2]:void 0;for(i&&eo(e[0],e[1],i)&&(n=1);++r{"use strict";o(Z9e,"arrayIncludesWith");zw=Z9e});function eLe(t,e,r,n){var i=-1,a=ow,s=!0,l=t.length,u=[],h=e.length;if(!l)return u;r&&(e=Ss(e,Oo(r))),n?(a=zw,s=!1):e.length>=J9e&&(a=Lm,s=!1,e=new _m(e));e:for(;++i{"use strict";Cw();sL();AL();Md();Td();Aw();J9e=200;o(eLe,"baseDifference");SJ=eLe});var tLe,jh,_J=R(()=>{"use strict";AJ();Cm();sm();u5();tLe=pc(function(t,e){return wd(t)?SJ(t,bc(e,1,wd,!0)):[]}),jh=tLe});function rLe(t){var e=t==null?0:t.length;return e?t[e-1]:void 0}var ma,LJ=R(()=>{"use strict";o(rLe,"last");ma=rLe});function nLe(t,e,r){var n=t==null?0:t.length;return n?(e=r||e===void 0?1:yc(e),dw(t,e<0?0:e,n)):[]}var fi,DJ=R(()=>{"use strict";lL();xm();o(nLe,"drop");fi=nLe});function iLe(t,e,r){var n=t==null?0:t.length;return n?(e=r||e===void 0?1:yc(e),e=n-e,dw(t,0,e<0?0:e)):[]}var Ru,RJ=R(()=>{"use strict";lL();xm();o(iLe,"dropRight");Ru=iLe});function aLe(t){return typeof t=="function"?t:ea}var Nm,Gw=R(()=>{"use strict";Eu();o(aLe,"castFunction");Nm=aLe});function sLe(t,e){var r=wt(t)?iw:As;return r(t,Nm(e))}var Ee,$w=R(()=>{"use strict";iL();qh();Gw();Bn();o(sLe,"forEach");Ee=sLe});var NJ=R(()=>{"use strict";$w()});function oLe(t,e){for(var r=-1,n=t==null?0:t.length;++r{"use strict";o(oLe,"arrayEvery");MJ=oLe});function lLe(t,e){var r=!0;return As(t,function(n,i,a){return r=!!e(n,i,a),r}),r}var OJ,PJ=R(()=>{"use strict";qh();o(lLe,"baseEvery");OJ=lLe});function cLe(t,e,r){var n=wt(t)?MJ:OJ;return r&&eo(t,e,r)&&(e=void 0),n(t,cn(e,3))}var Ia,BJ=R(()=>{"use strict";IJ();PJ();Qa();Bn();Ed();o(cLe,"every");Ia=cLe});function uLe(t,e){var r=[];return As(t,function(n,i,a){e(n,i,a)&&r.push(n)}),r}var Vw,_L=R(()=>{"use strict";qh();o(uLe,"baseFilter");Vw=uLe});function hLe(t,e){var r=wt(t)?Sm:Vw;return r(t,cn(e,3))}var $r,LL=R(()=>{"use strict";pw();_L();Qa();Bn();o(hLe,"filter");$r=hLe});function fLe(t){return function(e,r,n){var i=Object(e);if(!ei(e)){var a=cn(r,3);e=Dr(e),r=o(function(l){return a(i[l],l,i)},"predicate")}var s=t(e,r,n);return s>-1?i[a?e[s]:s]:void 0}}var FJ,zJ=R(()=>{"use strict";Qa();Io();vc();o(fLe,"createFind");FJ=fLe});function pLe(t,e,r){var n=t==null?0:t.length;if(!n)return-1;var i=r==null?0:yc(r);return i<0&&(i=dLe(n+i,0)),aw(t,cn(e,3),i)}var dLe,GJ,$J=R(()=>{"use strict";aL();Qa();xm();dLe=Math.max;o(pLe,"findIndex");GJ=pLe});var mLe,Za,VJ=R(()=>{"use strict";zJ();$J();mLe=FJ(GJ),Za=mLe});function gLe(t){return t&&t.length?t[0]:void 0}var na,UJ=R(()=>{"use strict";o(gLe,"head");na=gLe});var HJ=R(()=>{"use strict";UJ()});function yLe(t,e){var r=-1,n=ei(t)?Array(t.length):[];return As(t,function(i,a,s){n[++r]=e(i,a,s)}),n}var Uw,DL=R(()=>{"use strict";qh();Io();o(yLe,"baseMap");Uw=yLe});function vLe(t,e){var r=wt(t)?Ss:Uw;return r(t,cn(e,3))}var qe,Mm=R(()=>{"use strict";Md();Qa();DL();Bn();o(vLe,"map");qe=vLe});function xLe(t,e){return bc(qe(t,e),1)}var ga,RL=R(()=>{"use strict";Cm();Mm();o(xLe,"flatMap");ga=xLe});function bLe(t,e){return t==null?t:Qp(t,Nm(e),bs)}var NL,YJ=R(()=>{"use strict";t5();Gw();zh();o(bLe,"forIn");NL=bLe});function wLe(t,e){return t&&Rm(t,Nm(e))}var ML,WJ=R(()=>{"use strict";Bw();Gw();o(wLe,"forOwn");ML=wLe});var TLe,kLe,ELe,IL,qJ=R(()=>{"use strict";Kp();TJ();TLe=Object.prototype,kLe=TLe.hasOwnProperty,ELe=wJ(function(t,e,r){kLe.call(t,r)?t[r].push(e):hc(t,r,[e])}),IL=ELe});function CLe(t,e){return t>e}var XJ,jJ=R(()=>{"use strict";o(CLe,"baseGt");XJ=CLe});function _Le(t,e){return t!=null&&ALe.call(t,e)}var SLe,ALe,KJ,QJ=R(()=>{"use strict";SLe=Object.prototype,ALe=SLe.hasOwnProperty;o(_Le,"baseHas");KJ=_Le});function LLe(t,e){return t!=null&&Iw(t,e,KJ)}var Xe,ZJ=R(()=>{"use strict";QJ();EL();o(LLe,"has");Xe=LLe});function RLe(t){return typeof t=="string"||!wt(t)&&Wn(t)&&fa(t)==DLe}var DLe,di,Hw=R(()=>{"use strict";wu();Bn();Mo();DLe="[object String]";o(RLe,"isString");di=RLe});function NLe(t,e){return Ss(e,function(r){return t[r]})}var JJ,eee=R(()=>{"use strict";Md();o(NLe,"baseValues");JJ=NLe});function MLe(t){return t==null?[]:JJ(t,Dr(t))}var or,OL=R(()=>{"use strict";eee();vc();o(MLe,"values");or=MLe});function OLe(t,e,r,n){t=ei(t)?t:or(t),r=r&&!n?yc(r):0;var i=t.length;return r<0&&(r=ILe(i+r,0)),di(t)?r<=i&&t.indexOf(e,r)>-1:!!i&&bm(t,e,r)>-1}var ILe,Fn,tee=R(()=>{"use strict";sw();Io();Hw();xm();OL();ILe=Math.max;o(OLe,"includes");Fn=OLe});function BLe(t,e,r){var n=t==null?0:t.length;if(!n)return-1;var i=r==null?0:yc(r);return i<0&&(i=PLe(n+i,0)),bm(t,e,i)}var PLe,Yw,ree=R(()=>{"use strict";sw();xm();PLe=Math.max;o(BLe,"indexOf");Yw=BLe});function VLe(t){if(t==null)return!0;if(ei(t)&&(wt(t)||typeof t=="string"||typeof t.splice=="function"||El(t)||Bh(t)||kl(t)))return!t.length;var e=oo(t);if(e==FLe||e==zLe)return!t.size;if(fc(t))return!wm(t).length;for(var r in t)if($Le.call(t,r))return!1;return!0}var FLe,zLe,GLe,$Le,Qt,Ww=R(()=>{"use strict";lw();Od();rm();Bn();Io();im();tm();lv();FLe="[object Map]",zLe="[object Set]",GLe=Object.prototype,$Le=GLe.hasOwnProperty;o(VLe,"isEmpty");Qt=VLe});function HLe(t){return Wn(t)&&fa(t)==ULe}var ULe,nee,iee=R(()=>{"use strict";wu();Mo();ULe="[object RegExp]";o(HLe,"baseIsRegExp");nee=HLe});var aee,YLe,zo,see=R(()=>{"use strict";iee();Td();ov();aee=Po&&Po.isRegExp,YLe=aee?Oo(aee):nee,zo=YLe});function WLe(t){return t===void 0}var er,oee=R(()=>{"use strict";o(WLe,"isUndefined");er=WLe});function qLe(t,e){return t{"use strict";o(qLe,"baseLt");qw=qLe});function XLe(t,e){var r={};return e=cn(e,3),Rm(t,function(n,i,a){hc(r,i,e(n,i,a))}),r}var Pd,lee=R(()=>{"use strict";Kp();Bw();Qa();o(XLe,"mapValues");Pd=XLe});function jLe(t,e,r){for(var n=-1,i=t.length;++n{"use strict";Nd();o(jLe,"baseExtremum");Im=jLe});function KLe(t){return t&&t.length?Im(t,ea,XJ):void 0}var _s,cee=R(()=>{"use strict";Xw();jJ();Eu();o(KLe,"max");_s=KLe});function QLe(t){return t&&t.length?Im(t,ea,qw):void 0}var Ll,BL=R(()=>{"use strict";Xw();PL();Eu();o(QLe,"min");Ll=QLe});function ZLe(t,e){return t&&t.length?Im(t,cn(e,2),qw):void 0}var Bd,uee=R(()=>{"use strict";Xw();Qa();PL();o(ZLe,"minBy");Bd=ZLe});function eDe(t){if(typeof t!="function")throw new TypeError(JLe);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}var JLe,hee,fee=R(()=>{"use strict";JLe="Expected a function";o(eDe,"negate");hee=eDe});function tDe(t,e,r,n){if(!pn(t))return t;e=Hh(e,t);for(var i=-1,a=e.length,s=a-1,l=t;l!=null&&++i{"use strict";am();Lv();uv();Js();km();o(tDe,"baseSet");dee=tDe});function rDe(t,e,r){for(var n=-1,i=e.length,a={};++n{"use strict";Dv();pee();Lv();o(rDe,"basePickBy");jw=rDe});function nDe(t,e){if(t==null)return{};var r=Ss(xw(t),function(n){return[n]});return e=cn(e),jw(t,r,function(n,i){return e(n,i[0])})}var Ls,mee=R(()=>{"use strict";Md();Qa();FL();dL();o(nDe,"pickBy");Ls=nDe});function iDe(t,e){var r=t.length;for(t.sort(e);r--;)t[r]=t[r].value;return t}var gee,yee=R(()=>{"use strict";o(iDe,"baseSortBy");gee=iDe});function aDe(t,e){if(t!==e){var r=t!==void 0,n=t===null,i=t===t,a=so(t),s=e!==void 0,l=e===null,u=e===e,h=so(e);if(!l&&!h&&!a&&t>e||a&&s&&u&&!l&&!h||n&&s&&u||!r&&u||!i)return 1;if(!n&&!a&&!h&&t{"use strict";Nd();o(aDe,"compareAscending");vee=aDe});function sDe(t,e,r){for(var n=-1,i=t.criteria,a=e.criteria,s=i.length,l=r.length;++n=l)return u;var h=r[n];return u*(h=="desc"?-1:1)}}return t.index-e.index}var bee,wee=R(()=>{"use strict";xee();o(sDe,"compareMultiple");bee=sDe});function oDe(t,e,r){e.length?e=Ss(e,function(a){return wt(a)?function(s){return Yh(s,a.length===1?a[0]:a)}:a}):e=[ea];var n=-1;e=Ss(e,Oo(cn));var i=Uw(t,function(a,s,l){var u=Ss(e,function(h){return h(a)});return{criteria:u,index:++n,value:a}});return gee(i,function(a,s){return bee(a,s,r)})}var Tee,kee=R(()=>{"use strict";Md();Dv();Qa();DL();yee();Td();wee();Eu();Bn();o(oDe,"baseOrderBy");Tee=oDe});var lDe,Eee,Cee=R(()=>{"use strict";SL();lDe=Pw("length"),Eee=lDe});function bDe(t){for(var e=See.lastIndex=0;See.test(t);)++e;return e}var Aee,cDe,uDe,hDe,fDe,dDe,pDe,zL,GL,mDe,_ee,Lee,Dee,gDe,Ree,Nee,yDe,vDe,xDe,See,Mee,Iee=R(()=>{"use strict";Aee="\\ud800-\\udfff",cDe="\\u0300-\\u036f",uDe="\\ufe20-\\ufe2f",hDe="\\u20d0-\\u20ff",fDe=cDe+uDe+hDe,dDe="\\ufe0e\\ufe0f",pDe="["+Aee+"]",zL="["+fDe+"]",GL="\\ud83c[\\udffb-\\udfff]",mDe="(?:"+zL+"|"+GL+")",_ee="[^"+Aee+"]",Lee="(?:\\ud83c[\\udde6-\\uddff]){2}",Dee="[\\ud800-\\udbff][\\udc00-\\udfff]",gDe="\\u200d",Ree=mDe+"?",Nee="["+dDe+"]?",yDe="(?:"+gDe+"(?:"+[_ee,Lee,Dee].join("|")+")"+Nee+Ree+")*",vDe=Nee+Ree+yDe,xDe="(?:"+[_ee+zL+"?",zL,Lee,Dee,pDe].join("|")+")",See=RegExp(GL+"(?="+GL+")|"+xDe+vDe,"g");o(bDe,"unicodeSize");Mee=bDe});function wDe(t){return YQ(t)?Mee(t):Eee(t)}var Oee,Pee=R(()=>{"use strict";Cee();WQ();Iee();o(wDe,"stringSize");Oee=wDe});function TDe(t,e){return jw(t,e,function(r,n){return Ow(t,n)})}var Bee,Fee=R(()=>{"use strict";FL();CL();o(TDe,"basePick");Bee=TDe});var kDe,Fd,zee=R(()=>{"use strict";Fee();HQ();kDe=UQ(function(t,e){return t==null?{}:Bee(t,e)}),Fd=kDe});function SDe(t,e,r,n){for(var i=-1,a=CDe(EDe((e-t)/(r||1)),0),s=Array(a);a--;)s[n?a:++i]=t,t+=r;return s}var EDe,CDe,Gee,$ee=R(()=>{"use strict";EDe=Math.ceil,CDe=Math.max;o(SDe,"baseRange");Gee=SDe});function ADe(t){return function(e,r,n){return n&&typeof n!="number"&&eo(e,r,n)&&(r=n=void 0),e=vm(e),r===void 0?(r=e,e=0):r=vm(r),n=n===void 0?e{"use strict";$ee();Ed();rL();o(ADe,"createRange");Vee=ADe});var _De,Go,Hee=R(()=>{"use strict";Uee();_De=Vee(),Go=_De});function LDe(t,e,r,n,i){return i(t,function(a,s,l){r=n?(n=!1,a):e(r,a,s,l)}),r}var Yee,Wee=R(()=>{"use strict";o(LDe,"baseReduce");Yee=LDe});function DDe(t,e,r){var n=wt(t)?qQ:Yee,i=arguments.length<3;return n(t,cn(e,4),r,i,As)}var Vr,$L=R(()=>{"use strict";XQ();qh();Qa();Wee();Bn();o(DDe,"reduce");Vr=DDe});function RDe(t,e){var r=wt(t)?Sm:Vw;return r(t,hee(cn(e,3)))}var Kh,qee=R(()=>{"use strict";pw();_L();Qa();Bn();fee();o(RDe,"reject");Kh=RDe});function IDe(t){if(t==null)return 0;if(ei(t))return di(t)?Oee(t):t.length;var e=oo(t);return e==NDe||e==MDe?t.size:wm(t).length}var NDe,MDe,VL,Xee=R(()=>{"use strict";lw();Od();Io();Hw();Pee();NDe="[object Map]",MDe="[object Set]";o(IDe,"size");VL=IDe});function ODe(t,e){var r;return As(t,function(n,i,a){return r=e(n,i,a),!r}),!!r}var jee,Kee=R(()=>{"use strict";qh();o(ODe,"baseSome");jee=ODe});function PDe(t,e,r){var n=wt(t)?Sw:jee;return r&&eo(t,e,r)&&(e=void 0),n(t,cn(e,3))}var Nv,Qee=R(()=>{"use strict";vL();Qa();Kee();Bn();Ed();o(PDe,"some");Nv=PDe});var BDe,Tc,Zee=R(()=>{"use strict";Cm();kee();sm();Ed();BDe=pc(function(t,e){if(t==null)return[];var r=e.length;return r>1&&eo(t,e[0],e[1])?e=[]:r>2&&eo(e[0],e[1],e[2])&&(e=[e[0]]),Tee(t,bc(e,1),[])}),Tc=BDe});var FDe,zDe,Jee,ete=R(()=>{"use strict";pL();nL();Lw();FDe=1/0,zDe=Wh&&1/Dm(new Wh([,-0]))[1]==FDe?function(t){return new Wh(t)}:qn,Jee=zDe});function $De(t,e,r){var n=-1,i=ow,a=t.length,s=!0,l=[],u=l;if(r)s=!1,i=zw;else if(a>=GDe){var h=e?null:Jee(t);if(h)return Dm(h);s=!1,i=Lm,u=new _m}else u=e?[]:l;e:for(;++n{"use strict";Cw();sL();AL();Aw();ete();Lw();GDe=200;o($De,"baseUniq");Om=$De});var VDe,UL,tte=R(()=>{"use strict";Cm();sm();Kw();u5();VDe=pc(function(t){return Om(bc(t,1,wd,!0))}),UL=VDe});function UDe(t){return t&&t.length?Om(t):[]}var Pm,rte=R(()=>{"use strict";Kw();o(UDe,"uniq");Pm=UDe});function HDe(t,e){return t&&t.length?Om(t,cn(e,2)):[]}var nte,ite=R(()=>{"use strict";Qa();Kw();o(HDe,"uniqBy");nte=HDe});function WDe(t){var e=++YDe;return uw(t)+e}var YDe,zd,ate=R(()=>{"use strict";oL();YDe=0;o(WDe,"uniqueId");zd=WDe});function qDe(t,e,r){for(var n=-1,i=t.length,a=e.length,s={};++n{"use strict";o(qDe,"baseZipObject");ste=qDe});function XDe(t,e){return ste(t||[],e||[],dc)}var Qw,lte=R(()=>{"use strict";am();ote();o(XDe,"zipObject");Qw=XDe});var Pt=R(()=>{"use strict";NQ();gL();PZ();BZ();Y_();CJ();_J();DJ();RJ();NJ();BJ();LL();VJ();HJ();RL();fw();$w();YJ();WJ();qJ();ZJ();Eu();tee();ree();Bn();Ww();Jy();Js();see();Hw();oee();vc();LJ();Mm();lee();cee();X_();BL();uee();nL();kJ();zee();mee();Hee();$L();qee();Xee();Qee();Zee();tte();rte();ate();OL();lte();});function ute(t,e){t[e]?t[e]++:t[e]=1}function hte(t,e){--t[e]||delete t[e]}function Mv(t,e,r,n){var i=""+e,a=""+r;if(!t&&i>a){var s=i;i=a,a=s}return i+cte+a+cte+(er(n)?jDe:n)}function KDe(t,e,r,n){var i=""+e,a=""+r;if(!t&&i>a){var s=i;i=a,a=s}var l={v:i,w:a};return n&&(l.name=n),l}function HL(t,e){return Mv(t,e.v,e.w,e.name)}var jDe,Gd,cte,lr,Zw=R(()=>{"use strict";Pt();jDe="\0",Gd="\0",cte="",lr=class{static{o(this,"Graph")}constructor(e={}){this._isDirected=Xe(e,"directed")?e.directed:!0,this._isMultigraph=Xe(e,"multigraph")?e.multigraph:!1,this._isCompound=Xe(e,"compound")?e.compound:!1,this._label=void 0,this._defaultNodeLabelFn=ws(void 0),this._defaultEdgeLabelFn=ws(void 0),this._nodes={},this._isCompound&&(this._parent={},this._children={},this._children[Gd]={}),this._in={},this._preds={},this._out={},this._sucs={},this._edgeObjs={},this._edgeLabels={}}isDirected(){return this._isDirected}isMultigraph(){return this._isMultigraph}isCompound(){return this._isCompound}setGraph(e){return this._label=e,this}graph(){return this._label}setDefaultNodeLabel(e){return wi(e)||(e=ws(e)),this._defaultNodeLabelFn=e,this}nodeCount(){return this._nodeCount}nodes(){return Dr(this._nodes)}sources(){var e=this;return $r(this.nodes(),function(r){return Qt(e._in[r])})}sinks(){var e=this;return $r(this.nodes(),function(r){return Qt(e._out[r])})}setNodes(e,r){var n=arguments,i=this;return Ee(e,function(a){n.length>1?i.setNode(a,r):i.setNode(a)}),this}setNode(e,r){return Xe(this._nodes,e)?(arguments.length>1&&(this._nodes[e]=r),this):(this._nodes[e]=arguments.length>1?r:this._defaultNodeLabelFn(e),this._isCompound&&(this._parent[e]=Gd,this._children[e]={},this._children[Gd][e]=!0),this._in[e]={},this._preds[e]={},this._out[e]={},this._sucs[e]={},++this._nodeCount,this)}node(e){return this._nodes[e]}hasNode(e){return Xe(this._nodes,e)}removeNode(e){var r=this;if(Xe(this._nodes,e)){var n=o(function(i){r.removeEdge(r._edgeObjs[i])},"removeEdge");delete this._nodes[e],this._isCompound&&(this._removeFromParentsChildList(e),delete this._parent[e],Ee(this.children(e),function(i){r.setParent(i)}),delete this._children[e]),Ee(Dr(this._in[e]),n),delete this._in[e],delete this._preds[e],Ee(Dr(this._out[e]),n),delete this._out[e],delete this._sucs[e],--this._nodeCount}return this}setParent(e,r){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(er(r))r=Gd;else{r+="";for(var n=r;!er(n);n=this.parent(n))if(n===e)throw new Error("Setting "+r+" as parent of "+e+" would create a cycle");this.setNode(r)}return this.setNode(e),this._removeFromParentsChildList(e),this._parent[e]=r,this._children[r][e]=!0,this}_removeFromParentsChildList(e){delete this._children[this._parent[e]][e]}parent(e){if(this._isCompound){var r=this._parent[e];if(r!==Gd)return r}}children(e){if(er(e)&&(e=Gd),this._isCompound){var r=this._children[e];if(r)return Dr(r)}else{if(e===Gd)return this.nodes();if(this.hasNode(e))return[]}}predecessors(e){var r=this._preds[e];if(r)return Dr(r)}successors(e){var r=this._sucs[e];if(r)return Dr(r)}neighbors(e){var r=this.predecessors(e);if(r)return UL(r,this.successors(e))}isLeaf(e){var r;return this.isDirected()?r=this.successors(e):r=this.neighbors(e),r.length===0}filterNodes(e){var r=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});r.setGraph(this.graph());var n=this;Ee(this._nodes,function(s,l){e(l)&&r.setNode(l,s)}),Ee(this._edgeObjs,function(s){r.hasNode(s.v)&&r.hasNode(s.w)&&r.setEdge(s,n.edge(s))});var i={};function a(s){var l=n.parent(s);return l===void 0||r.hasNode(l)?(i[s]=l,l):l in i?i[l]:a(l)}return o(a,"findParent"),this._isCompound&&Ee(r.nodes(),function(s){r.setParent(s,a(s))}),r}setDefaultEdgeLabel(e){return wi(e)||(e=ws(e)),this._defaultEdgeLabelFn=e,this}edgeCount(){return this._edgeCount}edges(){return or(this._edgeObjs)}setPath(e,r){var n=this,i=arguments;return Vr(e,function(a,s){return i.length>1?n.setEdge(a,s,r):n.setEdge(a,s),s}),this}setEdge(){var e,r,n,i,a=!1,s=arguments[0];typeof s=="object"&&s!==null&&"v"in s?(e=s.v,r=s.w,n=s.name,arguments.length===2&&(i=arguments[1],a=!0)):(e=s,r=arguments[1],n=arguments[3],arguments.length>2&&(i=arguments[2],a=!0)),e=""+e,r=""+r,er(n)||(n=""+n);var l=Mv(this._isDirected,e,r,n);if(Xe(this._edgeLabels,l))return a&&(this._edgeLabels[l]=i),this;if(!er(n)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(e),this.setNode(r),this._edgeLabels[l]=a?i:this._defaultEdgeLabelFn(e,r,n);var u=KDe(this._isDirected,e,r,n);return e=u.v,r=u.w,Object.freeze(u),this._edgeObjs[l]=u,ute(this._preds[r],e),ute(this._sucs[e],r),this._in[r][l]=u,this._out[e][l]=u,this._edgeCount++,this}edge(e,r,n){var i=arguments.length===1?HL(this._isDirected,arguments[0]):Mv(this._isDirected,e,r,n);return this._edgeLabels[i]}hasEdge(e,r,n){var i=arguments.length===1?HL(this._isDirected,arguments[0]):Mv(this._isDirected,e,r,n);return Xe(this._edgeLabels,i)}removeEdge(e,r,n){var i=arguments.length===1?HL(this._isDirected,arguments[0]):Mv(this._isDirected,e,r,n),a=this._edgeObjs[i];return a&&(e=a.v,r=a.w,delete this._edgeLabels[i],delete this._edgeObjs[i],hte(this._preds[r],e),hte(this._sucs[e],r),delete this._in[r][i],delete this._out[e][i],this._edgeCount--),this}inEdges(e,r){var n=this._in[e];if(n){var i=or(n);return r?$r(i,function(a){return a.v===r}):i}}outEdges(e,r){var n=this._out[e];if(n){var i=or(n);return r?$r(i,function(a){return a.w===r}):i}}nodeEdges(e,r){var n=this.inEdges(e,r);if(n)return n.concat(this.outEdges(e,r))}};lr.prototype._nodeCount=0;lr.prototype._edgeCount=0;o(ute,"incrementOrInitEntry");o(hte,"decrementOrRemoveEntry");o(Mv,"edgeArgsToId");o(KDe,"edgeArgsToObj");o(HL,"edgeObjToId")});var ya=R(()=>{"use strict";Zw()});function fte(t){t._prev._next=t._next,t._next._prev=t._prev,delete t._next,delete t._prev}function QDe(t,e){if(t!=="_next"&&t!=="_prev")return e}var Jw,dte=R(()=>{"use strict";Jw=class{static{o(this,"List")}constructor(){var e={};e._next=e._prev=e,this._sentinel=e}dequeue(){var e=this._sentinel,r=e._prev;if(r!==e)return fte(r),r}enqueue(e){var r=this._sentinel;e._prev&&e._next&&fte(e),e._next=r._next,r._next._prev=e,r._next=e,e._prev=r}toString(){for(var e=[],r=this._sentinel,n=r._prev;n!==r;)e.push(JSON.stringify(n,QDe)),n=n._prev;return"["+e.join(", ")+"]"}};o(fte,"unlink");o(QDe,"filterOutLinks")});function pte(t,e){if(t.nodeCount()<=1)return[];var r=eRe(t,e||ZDe),n=JDe(r.graph,r.buckets,r.zeroIdx);return Gr(qe(n,function(i){return t.outEdges(i.v,i.w)}))}function JDe(t,e,r){for(var n=[],i=e[e.length-1],a=e[0],s;t.nodeCount();){for(;s=a.dequeue();)YL(t,e,r,s);for(;s=i.dequeue();)YL(t,e,r,s);if(t.nodeCount()){for(var l=e.length-2;l>0;--l)if(s=e[l].dequeue(),s){n=n.concat(YL(t,e,r,s,!0));break}}}return n}function YL(t,e,r,n,i){var a=i?[]:void 0;return Ee(t.inEdges(n.v),function(s){var l=t.edge(s),u=t.node(s.v);i&&a.push({v:s.v,w:s.w}),u.out-=l,WL(e,r,u)}),Ee(t.outEdges(n.v),function(s){var l=t.edge(s),u=s.w,h=t.node(u);h.in-=l,WL(e,r,h)}),t.removeNode(n.v),a}function eRe(t,e){var r=new lr,n=0,i=0;Ee(t.nodes(),function(l){r.setNode(l,{v:l,in:0,out:0})}),Ee(t.edges(),function(l){var u=r.edge(l.v,l.w)||0,h=e(l),f=u+h;r.setEdge(l.v,l.w,f),i=Math.max(i,r.node(l.v).out+=h),n=Math.max(n,r.node(l.w).in+=h)});var a=Go(i+n+3).map(function(){return new Jw}),s=n+1;return Ee(r.nodes(),function(l){WL(a,s,r.node(l))}),{graph:r,buckets:a,zeroIdx:s}}function WL(t,e,r){r.out?r.in?t[r.out-r.in+e].enqueue(r):t[t.length-1].enqueue(r):t[0].enqueue(r)}var ZDe,mte=R(()=>{"use strict";Pt();ya();dte();ZDe=ws(1);o(pte,"greedyFAS");o(JDe,"doGreedyFAS");o(YL,"removeNode");o(eRe,"buildState");o(WL,"assignBucket")});function gte(t){var e=t.graph().acyclicer==="greedy"?pte(t,r(t)):tRe(t);Ee(e,function(n){var i=t.edge(n);t.removeEdge(n),i.forwardName=n.name,i.reversed=!0,t.setEdge(n.w,n.v,i,zd("rev"))});function r(n){return function(i){return n.edge(i).weight}}o(r,"weightFn")}function tRe(t){var e=[],r={},n={};function i(a){Xe(n,a)||(n[a]=!0,r[a]=!0,Ee(t.outEdges(a),function(s){Xe(r,s.w)?e.push(s):i(s.w)}),delete r[a])}return o(i,"dfs"),Ee(t.nodes(),i),e}function yte(t){Ee(t.edges(),function(e){var r=t.edge(e);if(r.reversed){t.removeEdge(e);var n=r.forwardName;delete r.reversed,delete r.forwardName,t.setEdge(e.w,e.v,r,n)}})}var qL=R(()=>{"use strict";Pt();mte();o(gte,"run");o(tRe,"dfsFAS");o(yte,"undo")});function kc(t,e,r,n){var i;do i=zd(n);while(t.hasNode(i));return r.dummy=e,t.setNode(i,r),i}function xte(t){var e=new lr().setGraph(t.graph());return Ee(t.nodes(),function(r){e.setNode(r,t.node(r))}),Ee(t.edges(),function(r){var n=e.edge(r.v,r.w)||{weight:0,minlen:1},i=t.edge(r);e.setEdge(r.v,r.w,{weight:n.weight+i.weight,minlen:Math.max(n.minlen,i.minlen)})}),e}function eT(t){var e=new lr({multigraph:t.isMultigraph()}).setGraph(t.graph());return Ee(t.nodes(),function(r){t.children(r).length||e.setNode(r,t.node(r))}),Ee(t.edges(),function(r){e.setEdge(r,t.edge(r))}),e}function XL(t,e){var r=t.x,n=t.y,i=e.x-r,a=e.y-n,s=t.width/2,l=t.height/2;if(!i&&!a)throw new Error("Not possible to find intersection inside of the rectangle");var u,h;return Math.abs(a)*s>Math.abs(i)*l?(a<0&&(l=-l),u=l*i/a,h=l):(i<0&&(s=-s),u=s,h=s*a/i),{x:r+u,y:n+h}}function Qh(t){var e=qe(Go(KL(t)+1),function(){return[]});return Ee(t.nodes(),function(r){var n=t.node(r),i=n.rank;er(i)||(e[i][n.order]=r)}),e}function bte(t){var e=Ll(qe(t.nodes(),function(r){return t.node(r).rank}));Ee(t.nodes(),function(r){var n=t.node(r);Xe(n,"rank")&&(n.rank-=e)})}function wte(t){var e=Ll(qe(t.nodes(),function(a){return t.node(a).rank})),r=[];Ee(t.nodes(),function(a){var s=t.node(a).rank-e;r[s]||(r[s]=[]),r[s].push(a)});var n=0,i=t.graph().nodeRankFactor;Ee(r,function(a,s){er(a)&&s%i!==0?--n:n&&Ee(a,function(l){t.node(l).rank+=n})})}function jL(t,e,r,n){var i={width:0,height:0};return arguments.length>=4&&(i.rank=r,i.order=n),kc(t,"border",i,e)}function KL(t){return _s(qe(t.nodes(),function(e){var r=t.node(e).rank;if(!er(r))return r}))}function Tte(t,e){var r={lhs:[],rhs:[]};return Ee(t,function(n){e(n)?r.lhs.push(n):r.rhs.push(n)}),r}function kte(t,e){var r=Fw();try{return e()}finally{console.log(t+" time: "+(Fw()-r)+"ms")}}function Ete(t,e){return e()}var Ec=R(()=>{"use strict";Pt();ya();o(kc,"addDummyNode");o(xte,"simplify");o(eT,"asNonCompoundGraph");o(XL,"intersectRect");o(Qh,"buildLayerMatrix");o(bte,"normalizeRanks");o(wte,"removeEmptyRanks");o(jL,"addBorderNode");o(KL,"maxRank");o(Tte,"partition");o(kte,"time");o(Ete,"notime")});function Ste(t){function e(r){var n=t.children(r),i=t.node(r);if(n.length&&Ee(n,e),Xe(i,"minRank")){i.borderLeft=[],i.borderRight=[];for(var a=i.minRank,s=i.maxRank+1;a{"use strict";Pt();Ec();o(Ste,"addBorderSegments");o(Cte,"addBorderNode")});function Lte(t){var e=t.graph().rankdir.toLowerCase();(e==="lr"||e==="rl")&&Rte(t)}function Dte(t){var e=t.graph().rankdir.toLowerCase();(e==="bt"||e==="rl")&&rRe(t),(e==="lr"||e==="rl")&&(nRe(t),Rte(t))}function Rte(t){Ee(t.nodes(),function(e){_te(t.node(e))}),Ee(t.edges(),function(e){_te(t.edge(e))})}function _te(t){var e=t.width;t.width=t.height,t.height=e}function rRe(t){Ee(t.nodes(),function(e){QL(t.node(e))}),Ee(t.edges(),function(e){var r=t.edge(e);Ee(r.points,QL),Xe(r,"y")&&QL(r)})}function QL(t){t.y=-t.y}function nRe(t){Ee(t.nodes(),function(e){ZL(t.node(e))}),Ee(t.edges(),function(e){var r=t.edge(e);Ee(r.points,ZL),Xe(r,"x")&&ZL(r)})}function ZL(t){var e=t.x;t.x=t.y,t.y=e}var Nte=R(()=>{"use strict";Pt();o(Lte,"adjust");o(Dte,"undo");o(Rte,"swapWidthHeight");o(_te,"swapWidthHeightOne");o(rRe,"reverseY");o(QL,"reverseYOne");o(nRe,"swapXY");o(ZL,"swapXYOne")});function Mte(t){t.graph().dummyChains=[],Ee(t.edges(),function(e){aRe(t,e)})}function aRe(t,e){var r=e.v,n=t.node(r).rank,i=e.w,a=t.node(i).rank,s=e.name,l=t.edge(e),u=l.labelRank;if(a!==n+1){t.removeEdge(e);var h,f,d;for(d=0,++n;n{"use strict";Pt();Ec();o(Mte,"run");o(aRe,"normalizeEdge");o(Ite,"undo")});function Iv(t){var e={};function r(n){var i=t.node(n);if(Xe(e,n))return i.rank;e[n]=!0;var a=Ll(qe(t.outEdges(n),function(s){return r(s.w)-t.edge(s).minlen}));return(a===Number.POSITIVE_INFINITY||a===void 0||a===null)&&(a=0),i.rank=a}o(r,"dfs"),Ee(t.sources(),r)}function $d(t,e){return t.node(e.w).rank-t.node(e.v).rank-t.edge(e).minlen}var tT=R(()=>{"use strict";Pt();o(Iv,"longestPath");o($d,"slack")});function rT(t){var e=new lr({directed:!1}),r=t.nodes()[0],n=t.nodeCount();e.setNode(r,{});for(var i,a;sRe(e,t){"use strict";Pt();ya();tT();o(rT,"feasibleTree");o(sRe,"tightTree");o(oRe,"findMinSlackEdge");o(lRe,"shiftRanks")});var Pte=R(()=>{"use strict"});var tD=R(()=>{"use strict"});var tGt,rD=R(()=>{"use strict";Pt();tD();tGt=ws(1)});var Bte=R(()=>{"use strict";rD()});var nD=R(()=>{"use strict"});var Fte=R(()=>{"use strict";nD()});var fGt,zte=R(()=>{"use strict";Pt();fGt=ws(1)});function iD(t){var e={},r={},n=[];function i(a){if(Xe(r,a))throw new Ov;Xe(e,a)||(r[a]=!0,e[a]=!0,Ee(t.predecessors(a),i),delete r[a],n.push(a))}if(o(i,"visit"),Ee(t.sinks(),i),VL(e)!==t.nodeCount())throw new Ov;return n}function Ov(){}var aD=R(()=>{"use strict";Pt();iD.CycleException=Ov;o(iD,"topsort");o(Ov,"CycleException");Ov.prototype=new Error});var Gte=R(()=>{"use strict";aD()});function nT(t,e,r){wt(e)||(e=[e]);var n=(t.isDirected()?t.successors:t.neighbors).bind(t),i=[],a={};return Ee(e,function(s){if(!t.hasNode(s))throw new Error("Graph does not have node: "+s);$te(t,s,r==="post",a,n,i)}),i}function $te(t,e,r,n,i,a){Xe(n,e)||(n[e]=!0,r||a.push(e),Ee(i(e),function(s){$te(t,s,r,n,i,a)}),r&&a.push(e))}var sD=R(()=>{"use strict";Pt();o(nT,"dfs");o($te,"doDfs")});function oD(t,e){return nT(t,e,"post")}var Vte=R(()=>{"use strict";sD();o(oD,"postorder")});function lD(t,e){return nT(t,e,"pre")}var Ute=R(()=>{"use strict";sD();o(lD,"preorder")});var Hte=R(()=>{"use strict";tD();Zw()});var Yte=R(()=>{"use strict";Pte();rD();Bte();Fte();zte();Gte();Vte();Ute();Hte();nD();aD()});function Jh(t){t=xte(t),Iv(t);var e=rT(t);uD(e),cD(e,t);for(var r,n;r=jte(e);)n=Kte(e,t,r),Qte(e,t,r,n)}function cD(t,e){var r=oD(t,t.nodes());r=r.slice(0,r.length-1),Ee(r,function(n){dRe(t,e,n)})}function dRe(t,e,r){var n=t.node(r),i=n.parent;t.edge(r,i).cutvalue=qte(t,e,r)}function qte(t,e,r){var n=t.node(r),i=n.parent,a=!0,s=e.edge(r,i),l=0;return s||(a=!1,s=e.edge(i,r)),l=s.weight,Ee(e.nodeEdges(r),function(u){var h=u.v===r,f=h?u.w:u.v;if(f!==i){var d=h===a,p=e.edge(u).weight;if(l+=d?p:-p,mRe(t,r,f)){var m=t.edge(r,f).cutvalue;l+=d?-m:m}}}),l}function uD(t,e){arguments.length<2&&(e=t.nodes()[0]),Xte(t,{},1,e)}function Xte(t,e,r,n,i){var a=r,s=t.node(n);return e[n]=!0,Ee(t.neighbors(n),function(l){Xe(e,l)||(r=Xte(t,e,r,l,n))}),s.low=a,s.lim=r++,i?s.parent=i:delete s.parent,r}function jte(t){return Za(t.edges(),function(e){return t.edge(e).cutvalue<0})}function Kte(t,e,r){var n=r.v,i=r.w;e.hasEdge(n,i)||(n=r.w,i=r.v);var a=t.node(n),s=t.node(i),l=a,u=!1;a.lim>s.lim&&(l=s,u=!0);var h=$r(e.edges(),function(f){return u===Wte(t,t.node(f.v),l)&&u!==Wte(t,t.node(f.w),l)});return Bd(h,function(f){return $d(e,f)})}function Qte(t,e,r,n){var i=r.v,a=r.w;t.removeEdge(i,a),t.setEdge(n.v,n.w,{}),uD(t),cD(t,e),pRe(t,e)}function pRe(t,e){var r=Za(t.nodes(),function(i){return!e.node(i).parent}),n=lD(t,r);n=n.slice(1),Ee(n,function(i){var a=t.node(i).parent,s=e.edge(i,a),l=!1;s||(s=e.edge(a,i),l=!0),e.node(i).rank=e.node(a).rank+(l?s.minlen:-s.minlen)})}function mRe(t,e,r){return t.hasEdge(e,r)}function Wte(t,e,r){return r.low<=e.lim&&e.lim<=r.lim}var Zte=R(()=>{"use strict";Pt();Yte();Ec();eD();tT();Jh.initLowLimValues=uD;Jh.initCutValues=cD;Jh.calcCutValue=qte;Jh.leaveEdge=jte;Jh.enterEdge=Kte;Jh.exchangeEdges=Qte;o(Jh,"networkSimplex");o(cD,"initCutValues");o(dRe,"assignCutValue");o(qte,"calcCutValue");o(uD,"initLowLimValues");o(Xte,"dfsAssignLowLim");o(jte,"leaveEdge");o(Kte,"enterEdge");o(Qte,"exchangeEdges");o(pRe,"updateRanks");o(mRe,"isTreeEdge");o(Wte,"isDescendant")});function hD(t){switch(t.graph().ranker){case"network-simplex":Jte(t);break;case"tight-tree":yRe(t);break;case"longest-path":gRe(t);break;default:Jte(t)}}function yRe(t){Iv(t),rT(t)}function Jte(t){Jh(t)}var gRe,fD=R(()=>{"use strict";eD();Zte();tT();o(hD,"rank");gRe=Iv;o(yRe,"tightTreeRanker");o(Jte,"networkSimplexRanker")});function ere(t){var e=kc(t,"root",{},"_root"),r=vRe(t),n=_s(or(r))-1,i=2*n+1;t.graph().nestingRoot=e,Ee(t.edges(),function(s){t.edge(s).minlen*=i});var a=xRe(t)+1;Ee(t.children(),function(s){tre(t,e,i,a,n,r,s)}),t.graph().nodeRankFactor=i}function tre(t,e,r,n,i,a,s){var l=t.children(s);if(!l.length){s!==e&&t.setEdge(e,s,{weight:0,minlen:r});return}var u=jL(t,"_bt"),h=jL(t,"_bb"),f=t.node(s);t.setParent(u,s),f.borderTop=u,t.setParent(h,s),f.borderBottom=h,Ee(l,function(d){tre(t,e,r,n,i,a,d);var p=t.node(d),m=p.borderTop?p.borderTop:d,g=p.borderBottom?p.borderBottom:d,y=p.borderTop?n:2*n,v=m!==g?1:i-a[s]+1;t.setEdge(u,m,{weight:y,minlen:v,nestingEdge:!0}),t.setEdge(g,h,{weight:y,minlen:v,nestingEdge:!0})}),t.parent(s)||t.setEdge(e,u,{weight:0,minlen:i+a[s]})}function vRe(t){var e={};function r(n,i){var a=t.children(n);a&&a.length&&Ee(a,function(s){r(s,i+1)}),e[n]=i}return o(r,"dfs"),Ee(t.children(),function(n){r(n,1)}),e}function xRe(t){return Vr(t.edges(),function(e,r){return e+t.edge(r).weight},0)}function rre(t){var e=t.graph();t.removeNode(e.nestingRoot),delete e.nestingRoot,Ee(t.edges(),function(r){var n=t.edge(r);n.nestingEdge&&t.removeEdge(r)})}var nre=R(()=>{"use strict";Pt();Ec();o(ere,"run");o(tre,"dfs");o(vRe,"treeDepths");o(xRe,"sumWeights");o(rre,"cleanup")});function ire(t,e,r){var n={},i;Ee(r,function(a){for(var s=t.parent(a),l,u;s;){if(l=t.parent(s),l?(u=n[l],n[l]=s):(u=i,i=s),u&&u!==s){e.setEdge(u,s);return}s=l}})}var are=R(()=>{"use strict";Pt();o(ire,"addSubgraphConstraints")});function sre(t,e,r){var n=wRe(t),i=new lr({compound:!0}).setGraph({root:n}).setDefaultNodeLabel(function(a){return t.node(a)});return Ee(t.nodes(),function(a){var s=t.node(a),l=t.parent(a);(s.rank===e||s.minRank<=e&&e<=s.maxRank)&&(i.setNode(a),i.setParent(a,l||n),Ee(t[r](a),function(u){var h=u.v===a?u.w:u.v,f=i.edge(h,a),d=er(f)?0:f.weight;i.setEdge(h,a,{weight:t.edge(u).weight+d})}),Xe(s,"minRank")&&i.setNode(a,{borderLeft:s.borderLeft[e],borderRight:s.borderRight[e]}))}),i}function wRe(t){for(var e;t.hasNode(e=zd("_root")););return e}var ore=R(()=>{"use strict";Pt();ya();o(sre,"buildLayerGraph");o(wRe,"createRootNode")});function lre(t,e){for(var r=0,n=1;n0;)f%2&&(d+=l[f+1]),f=f-1>>1,l[f]+=h.weight;u+=h.weight*d})),u}var cre=R(()=>{"use strict";Pt();o(lre,"crossCount");o(TRe,"twoLayerCrossCount")});function ure(t){var e={},r=$r(t.nodes(),function(l){return!t.children(l).length}),n=_s(qe(r,function(l){return t.node(l).rank})),i=qe(Go(n+1),function(){return[]});function a(l){if(!Xe(e,l)){e[l]=!0;var u=t.node(l);i[u.rank].push(l),Ee(t.successors(l),a)}}o(a,"dfs");var s=Tc(r,function(l){return t.node(l).rank});return Ee(s,a),i}var hre=R(()=>{"use strict";Pt();o(ure,"initOrder")});function fre(t,e){return qe(e,function(r){var n=t.inEdges(r);if(n.length){var i=Vr(n,function(a,s){var l=t.edge(s),u=t.node(s.v);return{sum:a.sum+l.weight*u.order,weight:a.weight+l.weight}},{sum:0,weight:0});return{v:r,barycenter:i.sum/i.weight,weight:i.weight}}else return{v:r}})}var dre=R(()=>{"use strict";Pt();o(fre,"barycenter")});function pre(t,e){var r={};Ee(t,function(i,a){var s=r[i.v]={indegree:0,in:[],out:[],vs:[i.v],i:a};er(i.barycenter)||(s.barycenter=i.barycenter,s.weight=i.weight)}),Ee(e.edges(),function(i){var a=r[i.v],s=r[i.w];!er(a)&&!er(s)&&(s.indegree++,a.out.push(r[i.w]))});var n=$r(r,function(i){return!i.indegree});return kRe(n)}function kRe(t){var e=[];function r(a){return function(s){s.merged||(er(s.barycenter)||er(a.barycenter)||s.barycenter>=a.barycenter)&&ERe(a,s)}}o(r,"handleIn");function n(a){return function(s){s.in.push(a),--s.indegree===0&&t.push(s)}}for(o(n,"handleOut");t.length;){var i=t.pop();e.push(i),Ee(i.in.reverse(),r(i)),Ee(i.out,n(i))}return qe($r(e,function(a){return!a.merged}),function(a){return Fd(a,["vs","i","barycenter","weight"])})}function ERe(t,e){var r=0,n=0;t.weight&&(r+=t.barycenter*t.weight,n+=t.weight),e.weight&&(r+=e.barycenter*e.weight,n+=e.weight),t.vs=e.vs.concat(t.vs),t.barycenter=r/n,t.weight=n,t.i=Math.min(e.i,t.i),e.merged=!0}var mre=R(()=>{"use strict";Pt();o(pre,"resolveConflicts");o(kRe,"doResolveConflicts");o(ERe,"mergeEntries")});function yre(t,e){var r=Tte(t,function(f){return Xe(f,"barycenter")}),n=r.lhs,i=Tc(r.rhs,function(f){return-f.i}),a=[],s=0,l=0,u=0;n.sort(CRe(!!e)),u=gre(a,i,u),Ee(n,function(f){u+=f.vs.length,a.push(f.vs),s+=f.barycenter*f.weight,l+=f.weight,u=gre(a,i,u)});var h={vs:Gr(a)};return l&&(h.barycenter=s/l,h.weight=l),h}function gre(t,e,r){for(var n;e.length&&(n=ma(e)).i<=r;)e.pop(),t.push(n.vs),r++;return r}function CRe(t){return function(e,r){return e.barycenterr.barycenter?1:t?r.i-e.i:e.i-r.i}}var vre=R(()=>{"use strict";Pt();Ec();o(yre,"sort");o(gre,"consumeUnsortable");o(CRe,"compareWithBias")});function dD(t,e,r,n){var i=t.children(e),a=t.node(e),s=a?a.borderLeft:void 0,l=a?a.borderRight:void 0,u={};s&&(i=$r(i,function(g){return g!==s&&g!==l}));var h=fre(t,i);Ee(h,function(g){if(t.children(g.v).length){var y=dD(t,g.v,r,n);u[g.v]=y,Xe(y,"barycenter")&&ARe(g,y)}});var f=pre(h,r);SRe(f,u);var d=yre(f,n);if(s&&(d.vs=Gr([s,d.vs,l]),t.predecessors(s).length)){var p=t.node(t.predecessors(s)[0]),m=t.node(t.predecessors(l)[0]);Xe(d,"barycenter")||(d.barycenter=0,d.weight=0),d.barycenter=(d.barycenter*d.weight+p.order+m.order)/(d.weight+2),d.weight+=2}return d}function SRe(t,e){Ee(t,function(r){r.vs=Gr(r.vs.map(function(n){return e[n]?e[n].vs:n}))})}function ARe(t,e){er(t.barycenter)?(t.barycenter=e.barycenter,t.weight=e.weight):(t.barycenter=(t.barycenter*t.weight+e.barycenter*e.weight)/(t.weight+e.weight),t.weight+=e.weight)}var xre=R(()=>{"use strict";Pt();dre();mre();vre();o(dD,"sortSubgraph");o(SRe,"expandSubgraphs");o(ARe,"mergeBarycenters")});function Tre(t){var e=KL(t),r=bre(t,Go(1,e+1),"inEdges"),n=bre(t,Go(e-1,-1,-1),"outEdges"),i=ure(t);wre(t,i);for(var a=Number.POSITIVE_INFINITY,s,l=0,u=0;u<4;++l,++u){_Re(l%2?r:n,l%4>=2),i=Qh(t);var h=lre(t,i);h{"use strict";Pt();ya();Ec();are();ore();cre();hre();xre();o(Tre,"order");o(bre,"buildLayerGraphs");o(_Re,"sweepLayerGraphs");o(wre,"assignOrder")});function Ere(t){var e=DRe(t);Ee(t.graph().dummyChains,function(r){for(var n=t.node(r),i=n.edgeObj,a=LRe(t,e,i.v,i.w),s=a.path,l=a.lca,u=0,h=s[u],f=!0;r!==i.w;){if(n=t.node(r),f){for(;(h=s[u])!==l&&t.node(h).maxRanks||l>e[u].lim));for(h=u,u=n;(u=t.parent(u))!==h;)a.push(u);return{path:i.concat(a.reverse()),lca:h}}function DRe(t){var e={},r=0;function n(i){var a=r;Ee(t.children(i),n),e[i]={low:a,lim:r++}}return o(n,"dfs"),Ee(t.children(),n),e}var Cre=R(()=>{"use strict";Pt();o(Ere,"parentDummyChains");o(LRe,"findPath");o(DRe,"postorder")});function RRe(t,e){var r={};function n(i,a){var s=0,l=0,u=i.length,h=ma(a);return Ee(a,function(f,d){var p=MRe(t,f),m=p?t.node(p).order:u;(p||f===h)&&(Ee(a.slice(l,d+1),function(g){Ee(t.predecessors(g),function(y){var v=t.node(y),x=v.order;(xh)&&Sre(r,p,f)})})}o(n,"scan");function i(a,s){var l=-1,u,h=0;return Ee(s,function(f,d){if(t.node(f).dummy==="border"){var p=t.predecessors(f);p.length&&(u=t.node(p[0]).order,n(s,h,d,l,u),h=d,l=u)}n(s,h,s.length,u,a.length)}),s}return o(i,"visitLayer"),Vr(e,i),r}function MRe(t,e){if(t.node(e).dummy)return Za(t.predecessors(e),function(r){return t.node(r).dummy})}function Sre(t,e,r){if(e>r){var n=e;e=r,r=n}var i=t[e];i||(t[e]=i={}),i[r]=!0}function IRe(t,e,r){if(e>r){var n=e;e=r,r=n}return Xe(t[e],r)}function ORe(t,e,r,n){var i={},a={},s={};return Ee(e,function(l){Ee(l,function(u,h){i[u]=u,a[u]=u,s[u]=h})}),Ee(e,function(l){var u=-1;Ee(l,function(h){var f=n(h);if(f.length){f=Tc(f,function(y){return s[y]});for(var d=(f.length-1)/2,p=Math.floor(d),m=Math.ceil(d);p<=m;++p){var g=f[p];a[h]===h&&u{"use strict";Pt();ya();Ec();o(RRe,"findType1Conflicts");o(NRe,"findType2Conflicts");o(MRe,"findOtherInnerSegmentNode");o(Sre,"addConflict");o(IRe,"hasConflict");o(ORe,"verticalAlignment");o(PRe,"horizontalCompaction");o(BRe,"buildBlockGraph");o(FRe,"findSmallestWidthAlignment");o(zRe,"alignCoordinates");o(GRe,"balance");o(Are,"positionX");o($Re,"sep");o(VRe,"width")});function Lre(t){t=eT(t),URe(t),ML(Are(t),function(e,r){t.node(r).x=e})}function URe(t){var e=Qh(t),r=t.graph().ranksep,n=0;Ee(e,function(i){var a=_s(qe(i,function(s){return t.node(s).height}));Ee(i,function(s){t.node(s).y=n+a/2}),n+=a+r})}var Dre=R(()=>{"use strict";Pt();Ec();_re();o(Lre,"position");o(URe,"positionY")});function lo(t,e){var r=e&&e.debugTiming?kte:Ete;r("layout",function(){var n=r(" buildLayoutGraph",function(){return eNe(t)});r(" runLayout",function(){HRe(n,r)}),r(" updateInputGraph",function(){YRe(t,n)})})}function HRe(t,e){e(" makeSpaceForEdgeLabels",function(){tNe(t)}),e(" removeSelfEdges",function(){uNe(t)}),e(" acyclic",function(){gte(t)}),e(" nestingGraph.run",function(){ere(t)}),e(" rank",function(){hD(eT(t))}),e(" injectEdgeLabelProxies",function(){rNe(t)}),e(" removeEmptyRanks",function(){wte(t)}),e(" nestingGraph.cleanup",function(){rre(t)}),e(" normalizeRanks",function(){bte(t)}),e(" assignRankMinMax",function(){nNe(t)}),e(" removeEdgeLabelProxies",function(){iNe(t)}),e(" normalize.run",function(){Mte(t)}),e(" parentDummyChains",function(){Ere(t)}),e(" addBorderSegments",function(){Ste(t)}),e(" order",function(){Tre(t)}),e(" insertSelfEdges",function(){hNe(t)}),e(" adjustCoordinateSystem",function(){Lte(t)}),e(" position",function(){Lre(t)}),e(" positionSelfEdges",function(){fNe(t)}),e(" removeBorderNodes",function(){cNe(t)}),e(" normalize.undo",function(){Ite(t)}),e(" fixupEdgeLabelCoords",function(){oNe(t)}),e(" undoCoordinateSystem",function(){Dte(t)}),e(" translateGraph",function(){aNe(t)}),e(" assignNodeIntersects",function(){sNe(t)}),e(" reversePoints",function(){lNe(t)}),e(" acyclic.undo",function(){yte(t)})}function YRe(t,e){Ee(t.nodes(),function(r){var n=t.node(r),i=e.node(r);n&&(n.x=i.x,n.y=i.y,e.children(r).length&&(n.width=i.width,n.height=i.height))}),Ee(t.edges(),function(r){var n=t.edge(r),i=e.edge(r);n.points=i.points,Xe(i,"x")&&(n.x=i.x,n.y=i.y)}),t.graph().width=e.graph().width,t.graph().height=e.graph().height}function eNe(t){var e=new lr({multigraph:!0,compound:!0}),r=mD(t.graph());return e.setGraph(Gh({},qRe,pD(r,WRe),Fd(r,XRe))),Ee(t.nodes(),function(n){var i=mD(t.node(n));e.setNode(n,Xh(pD(i,jRe),KRe)),e.setParent(n,t.parent(n))}),Ee(t.edges(),function(n){var i=mD(t.edge(n));e.setEdge(n,Gh({},ZRe,pD(i,QRe),Fd(i,JRe)))}),e}function tNe(t){var e=t.graph();e.ranksep/=2,Ee(t.edges(),function(r){var n=t.edge(r);n.minlen*=2,n.labelpos.toLowerCase()!=="c"&&(e.rankdir==="TB"||e.rankdir==="BT"?n.width+=n.labeloffset:n.height+=n.labeloffset)})}function rNe(t){Ee(t.edges(),function(e){var r=t.edge(e);if(r.width&&r.height){var n=t.node(e.v),i=t.node(e.w),a={rank:(i.rank-n.rank)/2+n.rank,e};kc(t,"edge-proxy",a,"_ep")}})}function nNe(t){var e=0;Ee(t.nodes(),function(r){var n=t.node(r);n.borderTop&&(n.minRank=t.node(n.borderTop).rank,n.maxRank=t.node(n.borderBottom).rank,e=_s(e,n.maxRank))}),t.graph().maxRank=e}function iNe(t){Ee(t.nodes(),function(e){var r=t.node(e);r.dummy==="edge-proxy"&&(t.edge(r.e).labelRank=r.rank,t.removeNode(e))})}function aNe(t){var e=Number.POSITIVE_INFINITY,r=0,n=Number.POSITIVE_INFINITY,i=0,a=t.graph(),s=a.marginx||0,l=a.marginy||0;function u(h){var f=h.x,d=h.y,p=h.width,m=h.height;e=Math.min(e,f-p/2),r=Math.max(r,f+p/2),n=Math.min(n,d-m/2),i=Math.max(i,d+m/2)}o(u,"getExtremes"),Ee(t.nodes(),function(h){u(t.node(h))}),Ee(t.edges(),function(h){var f=t.edge(h);Xe(f,"x")&&u(f)}),e-=s,n-=l,Ee(t.nodes(),function(h){var f=t.node(h);f.x-=e,f.y-=n}),Ee(t.edges(),function(h){var f=t.edge(h);Ee(f.points,function(d){d.x-=e,d.y-=n}),Xe(f,"x")&&(f.x-=e),Xe(f,"y")&&(f.y-=n)}),a.width=r-e+s,a.height=i-n+l}function sNe(t){Ee(t.edges(),function(e){var r=t.edge(e),n=t.node(e.v),i=t.node(e.w),a,s;r.points?(a=r.points[0],s=r.points[r.points.length-1]):(r.points=[],a=i,s=n),r.points.unshift(XL(n,a)),r.points.push(XL(i,s))})}function oNe(t){Ee(t.edges(),function(e){var r=t.edge(e);if(Xe(r,"x"))switch((r.labelpos==="l"||r.labelpos==="r")&&(r.width-=r.labeloffset),r.labelpos){case"l":r.x-=r.width/2+r.labeloffset;break;case"r":r.x+=r.width/2+r.labeloffset;break}})}function lNe(t){Ee(t.edges(),function(e){var r=t.edge(e);r.reversed&&r.points.reverse()})}function cNe(t){Ee(t.nodes(),function(e){if(t.children(e).length){var r=t.node(e),n=t.node(r.borderTop),i=t.node(r.borderBottom),a=t.node(ma(r.borderLeft)),s=t.node(ma(r.borderRight));r.width=Math.abs(s.x-a.x),r.height=Math.abs(i.y-n.y),r.x=a.x+r.width/2,r.y=n.y+r.height/2}}),Ee(t.nodes(),function(e){t.node(e).dummy==="border"&&t.removeNode(e)})}function uNe(t){Ee(t.edges(),function(e){if(e.v===e.w){var r=t.node(e.v);r.selfEdges||(r.selfEdges=[]),r.selfEdges.push({e,label:t.edge(e)}),t.removeEdge(e)}})}function hNe(t){var e=Qh(t);Ee(e,function(r){var n=0;Ee(r,function(i,a){var s=t.node(i);s.order=a+n,Ee(s.selfEdges,function(l){kc(t,"selfedge",{width:l.label.width,height:l.label.height,rank:s.rank,order:a+ ++n,e:l.e,label:l.label},"_se")}),delete s.selfEdges})})}function fNe(t){Ee(t.nodes(),function(e){var r=t.node(e);if(r.dummy==="selfedge"){var n=t.node(r.e.v),i=n.x+n.width/2,a=n.y,s=r.x-i,l=n.height/2;t.setEdge(r.e,r.label),t.removeNode(e),r.label.points=[{x:i+2*s/3,y:a-l},{x:i+5*s/6,y:a-l},{x:i+s,y:a},{x:i+5*s/6,y:a+l},{x:i+2*s/3,y:a+l}],r.label.x=r.x,r.label.y=r.y}})}function pD(t,e){return Pd(Fd(t,e),Number)}function mD(t){var e={};return Ee(t,function(r,n){e[n.toLowerCase()]=r}),e}var WRe,qRe,XRe,jRe,KRe,QRe,ZRe,JRe,Rre=R(()=>{"use strict";Pt();ya();Ate();Nte();qL();JL();fD();nre();kre();Cre();Dre();Ec();o(lo,"layout");o(HRe,"runLayout");o(YRe,"updateInputGraph");WRe=["nodesep","edgesep","ranksep","marginx","marginy"],qRe={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},XRe=["acyclicer","ranker","rankdir","align"],jRe=["width","height"],KRe={width:0,height:0},QRe=["minlen","weight","width","height","labeloffset"],ZRe={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},JRe=["labelpos"];o(eNe,"buildLayoutGraph");o(tNe,"makeSpaceForEdgeLabels");o(rNe,"injectEdgeLabelProxies");o(nNe,"assignRankMinMax");o(iNe,"removeEdgeLabelProxies");o(aNe,"translateGraph");o(sNe,"assignNodeIntersects");o(oNe,"fixupEdgeLabelCoords");o(lNe,"reversePointsForReversedEdges");o(cNe,"removeBorderNodes");o(uNe,"removeSelfEdges");o(hNe,"insertSelfEdges");o(fNe,"positionSelfEdges");o(pD,"selectNumberAttrs");o(mD,"canonicalize")});var Vd=R(()=>{"use strict";qL();Rre();JL();fD()});function zn(t){var e={options:{directed:t.isDirected(),multigraph:t.isMultigraph(),compound:t.isCompound()},nodes:dNe(t),edges:pNe(t)};return er(t.graph())||(e.value=Qr(t.graph())),e}function dNe(t){return qe(t.nodes(),function(e){var r=t.node(e),n=t.parent(e),i={v:e};return er(r)||(i.value=r),er(n)||(i.parent=n),i})}function pNe(t){return qe(t.edges(),function(e){var r=t.edge(e),n={v:e.v,w:e.w};return er(e.name)||(n.name=e.name),er(r)||(n.value=r),n})}var Pv=R(()=>{"use strict";Pt();Zw();o(zn,"write");o(dNe,"writeNodes");o(pNe,"writeEdges")});var cr,Ud,Mre,Ire,aT,mNe,Ore,Pre,gNe,Bm,Nre,Bre,Fre,zre,Gre,$re=R(()=>{"use strict";ut();ya();Pv();cr=new Map,Ud=new Map,Mre=new Map,Ire=o(()=>{Ud.clear(),Mre.clear(),cr.clear()},"clear"),aT=o((t,e)=>{let r=Ud.get(e)||[];return V.trace("In isDescendant",e," ",t," = ",r.includes(t)),r.includes(t)},"isDescendant"),mNe=o((t,e)=>{let r=Ud.get(e)||[];return V.info("Descendants of ",e," is ",r),V.info("Edge is ",t),t.v===e||t.w===e?!1:r?r.includes(t.v)||aT(t.v,e)||aT(t.w,e)||r.includes(t.w):(V.debug("Tilt, ",e,",not in descendants"),!1)},"edgeInCluster"),Ore=o((t,e,r,n)=>{V.warn("Copying children of ",t,"root",n,"data",e.node(t),n);let i=e.children(t)||[];t!==n&&i.push(t),V.warn("Copying (nodes) clusterId",t,"nodes",i),i.forEach(a=>{if(e.children(a).length>0)Ore(a,e,r,n);else{let s=e.node(a);V.info("cp ",a," to ",n," with parent ",t),r.setNode(a,s),n!==e.parent(a)&&(V.warn("Setting parent",a,e.parent(a)),r.setParent(a,e.parent(a))),t!==n&&a!==t?(V.debug("Setting parent",a,t),r.setParent(a,t)):(V.info("In copy ",t,"root",n,"data",e.node(t),n),V.debug("Not Setting parent for node=",a,"cluster!==rootId",t!==n,"node!==clusterId",a!==t));let l=e.edges(a);V.debug("Copying Edges",l),l.forEach(u=>{V.info("Edge",u);let h=e.edge(u.v,u.w,u.name);V.info("Edge data",h,n);try{mNe(u,n)?(V.info("Copying as ",u.v,u.w,h,u.name),r.setEdge(u.v,u.w,h,u.name),V.info("newGraph edges ",r.edges(),r.edge(r.edges()[0]))):V.info("Skipping copy of edge ",u.v,"-->",u.w," rootId: ",n," clusterId:",t)}catch(f){V.error(f)}})}V.debug("Removing node",a),e.removeNode(a)})},"copy"),Pre=o((t,e)=>{let r=e.children(t),n=[...r];for(let i of r)Mre.set(i,t),n=[...n,...Pre(i,e)];return n},"extractDescendants"),gNe=o((t,e,r)=>{let n=t.edges().filter(u=>u.v===e||u.w===e),i=t.edges().filter(u=>u.v===r||u.w===r),a=n.map(u=>({v:u.v===e?r:u.v,w:u.w===e?e:u.w})),s=i.map(u=>({v:u.v,w:u.w}));return a.filter(u=>s.some(h=>u.v===h.v&&u.w===h.w))},"findCommonEdges"),Bm=o((t,e,r)=>{let n=e.children(t);if(V.trace("Searching children of id ",t,n),n.length<1)return t;let i;for(let a of n){let s=Bm(a,e,r),l=gNe(e,r,s);if(s)if(l.length>0)i=s;else return s}return i},"findNonClusterChild"),Nre=o(t=>!cr.has(t)||!cr.get(t).externalConnections?t:cr.has(t)?cr.get(t).id:t,"getAnchorId"),Bre=o((t,e)=>{if(!t||e>10){V.debug("Opting out, no graph ");return}else V.debug("Opting in, graph ");t.nodes().forEach(function(r){t.children(r).length>0&&(V.warn("Cluster identified",r," Replacement id in edges: ",Bm(r,t,r)),Ud.set(r,Pre(r,t)),cr.set(r,{id:Bm(r,t,r),clusterData:t.node(r)}))}),t.nodes().forEach(function(r){let n=t.children(r),i=t.edges();n.length>0?(V.debug("Cluster identified",r,Ud),i.forEach(a=>{let s=aT(a.v,r),l=aT(a.w,r);s^l&&(V.warn("Edge: ",a," leaves cluster ",r),V.warn("Descendants of XXX ",r,": ",Ud.get(r)),cr.get(r).externalConnections=!0)})):V.debug("Not a cluster ",r,Ud)});for(let r of cr.keys()){let n=cr.get(r).id,i=t.parent(n);i!==r&&cr.has(i)&&!cr.get(i).externalConnections&&(cr.get(r).id=i)}t.edges().forEach(function(r){let n=t.edge(r);V.warn("Edge "+r.v+" -> "+r.w+": "+JSON.stringify(r)),V.warn("Edge "+r.v+" -> "+r.w+": "+JSON.stringify(t.edge(r)));let i=r.v,a=r.w;if(V.warn("Fix XXX",cr,"ids:",r.v,r.w,"Translating: ",cr.get(r.v)," --- ",cr.get(r.w)),cr.get(r.v)||cr.get(r.w)){if(V.warn("Fixing and trying - removing XXX",r.v,r.w,r.name),i=Nre(r.v),a=Nre(r.w),t.removeEdge(r.v,r.w,r.name),i!==r.v){let s=t.parent(i);cr.get(s).externalConnections=!0,n.fromCluster=r.v}if(a!==r.w){let s=t.parent(a);cr.get(s).externalConnections=!0,n.toCluster=r.w}V.warn("Fix Replacing with XXX",i,a,r.name),t.setEdge(i,a,n,r.name)}}),V.warn("Adjusted Graph",zn(t)),Fre(t,0),V.trace(cr)},"adjustClustersAndEdges"),Fre=o((t,e)=>{if(V.warn("extractor - ",e,zn(t),t.children("D")),e>10){V.error("Bailing out");return}let r=t.nodes(),n=!1;for(let i of r){let a=t.children(i);n=n||a.length>0}if(!n){V.debug("Done, no node has children",t.nodes());return}V.debug("Nodes = ",r,e);for(let i of r)if(V.debug("Extracting node",i,cr,cr.has(i)&&!cr.get(i).externalConnections,!t.parent(i),t.node(i),t.children("D")," Depth ",e),!cr.has(i))V.debug("Not a cluster",i,e);else if(!cr.get(i).externalConnections&&t.children(i)&&t.children(i).length>0){V.warn("Cluster without external connections, without a parent and with children",i,e);let s=t.graph().rankdir==="TB"?"LR":"TB";cr.get(i)?.clusterData?.dir&&(s=cr.get(i).clusterData.dir,V.warn("Fixing dir",cr.get(i).clusterData.dir,s));let l=new lr({multigraph:!0,compound:!0}).setGraph({rankdir:s,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});V.warn("Old graph before copy",zn(t)),Ore(i,t,l,i),t.setNode(i,{clusterNode:!0,id:i,clusterData:cr.get(i).clusterData,label:cr.get(i).label,graph:l}),V.warn("New graph after copy node: (",i,")",zn(l)),V.debug("Old graph after copy",zn(t))}else V.warn("Cluster ** ",i," **not meeting the criteria !externalConnections:",!cr.get(i).externalConnections," no parent: ",!t.parent(i)," children ",t.children(i)&&t.children(i).length>0,t.children("D"),e),V.debug(cr);r=t.nodes(),V.warn("New list of nodes",r);for(let i of r){let a=t.node(i);V.warn(" Now next level",i,a),a?.clusterNode&&Fre(a.graph,e+1)}},"extractor"),zre=o((t,e)=>{if(e.length===0)return[];let r=Object.assign([],e);return e.forEach(n=>{let i=t.children(n),a=zre(t,i);r=[...r,...a]}),r},"sorter"),Gre=o(t=>zre(t,t.children()),"sortNodesByHierarchy")});var Ure={};hr(Ure,{render:()=>yNe});var Vre,yNe,Hre=R(()=>{"use strict";Vd();Pv();ya();Q9();ri();$re();tL();X9();K9();ut();_d();_t();Vre=o(async(t,e,r,n,i,a)=>{V.warn("Graph in recursive render:XAX",zn(e),i);let s=e.graph().rankdir;V.trace("Dir in recursive render - dir:",s);let l=t.insert("g").attr("class","root");e.nodes()?V.info("Recursive render XXX",e.nodes()):V.info("No nodes found for",e),e.edges().length>0&&V.info("Recursive edges",e.edge(e.edges()[0]));let u=l.insert("g").attr("class","clusters"),h=l.insert("g").attr("class","edgePaths"),f=l.insert("g").attr("class","edgeLabels"),d=l.insert("g").attr("class","nodes");await Promise.all(e.nodes().map(async function(y){let v=e.node(y);if(i!==void 0){let x=JSON.parse(JSON.stringify(i.clusterData));V.trace(`Setting data for parent cluster XXX + Node.id = `,y,` + data=`,x.height,` +Parent cluster`,i.height),e.setNode(i.id,x),e.parent(y)||(V.trace("Setting parent",y,i.id),e.setParent(y,i.id,x))}if(V.info("(Insert) Node XXX"+y+": "+JSON.stringify(e.node(y))),v?.clusterNode){V.info("Cluster identified XBX",y,v.width,e.node(y));let{ranksep:x,nodesep:b}=e.graph();v.graph.setGraph({...v.graph.graph(),ranksep:x+25,nodesep:b});let w=await Vre(d,v.graph,r,n,e.node(y),a),S=w.elem;ar(v,S),v.diff=w.diff||0,V.info("New compound node after recursive render XAX",y,"width",v.width,"height",v.height),lQ(S,v)}else e.children(y).length>0?(V.trace("Cluster - the non recursive path XBX",y,v.id,v,v.width,"Graph:",e),V.trace(Bm(v.id,e)),cr.set(v.id,{id:Bm(v.id,e),node:v})):(V.trace("Node - the non recursive path XAX",y,d,e.node(y),s),await rw(d,e.node(y),s))})),await o(async()=>{let y=e.edges().map(async function(v){let x=e.edge(v.v,v.w,v.name);V.info("Edge "+v.v+" -> "+v.w+": "+JSON.stringify(v)),V.info("Edge "+v.v+" -> "+v.w+": ",v," ",JSON.stringify(e.edge(v))),V.info("Fix",cr,"ids:",v.v,v.w,"Translating: ",cr.get(v.v),cr.get(v.w)),await Q5(f,x)});await Promise.all(y)},"processEdges")(),V.info("Graph before layout:",JSON.stringify(zn(e))),V.info("############################################# XXX"),V.info("### Layout ### XXX"),V.info("############################################# XXX"),lo(e),V.info("Graph after layout:",JSON.stringify(zn(e)));let m=0,{subGraphTitleTotalMargin:g}=io(a);return await Promise.all(Gre(e).map(async function(y){let v=e.node(y);if(V.info("Position XBX => "+y+": ("+v.x,","+v.y,") width: ",v.width," height: ",v.height),v?.clusterNode)v.y+=g,V.info("A tainted cluster node XBX1",y,v.id,v.width,v.height,v.x,v.y,e.parent(y)),cr.get(v.id).node=v,eL(v);else if(e.children(y).length>0){V.info("A pure cluster node XBX1",y,v.id,v.x,v.y,v.width,v.height,e.parent(y)),v.height+=g,e.node(v.parentId);let x=v?.padding/2||0,b=v?.labelBBox?.height||0,w=b-x||0;V.debug("OffsetY",w,"labelHeight",b,"halfPadding",x),await Y5(u,v),cr.get(v.id).node=v}else{let x=e.node(v.parentId);v.y+=g/2,V.info("A regular node XBX1 - using the padding",v.id,"parent",v.parentId,v.width,v.height,v.x,v.y,"offsetY",v.offsetY,"parent",x,x?.offsetY,v),eL(v)}})),e.edges().forEach(function(y){let v=e.edge(y);V.info("Edge "+y.v+" -> "+y.w+": "+JSON.stringify(v),v),v.points.forEach(S=>S.y+=g/2);let x=e.node(y.v);var b=e.node(y.w);let w=J5(h,v,cr,r,x,b,n);Z5(v,w)}),e.nodes().forEach(function(y){let v=e.node(y);V.info(y,v.type,v.diff),v.isGroup&&(m=v.diff)}),V.warn("Returning from recursive render XAX",l,m),{elem:l,diff:m}},"recursiveRender"),yNe=o(async(t,e)=>{let r=new lr({multigraph:!0,compound:!0}).setGraph({rankdir:t.direction,nodesep:t.config?.nodeSpacing||t.config?.flowchart?.nodeSpacing||t.nodeSpacing,ranksep:t.config?.rankSpacing||t.config?.flowchart?.rankSpacing||t.rankSpacing,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}}),n=e.select("g");ew(n,t.markers,t.type,t.diagramId),cQ(),lK(),rK(),Ire(),t.nodes.forEach(a=>{r.setNode(a.id,{...a}),a.parentId&&r.setParent(a.id,a.parentId)}),V.debug("Edges:",t.edges),t.edges.forEach(a=>{if(a.start===a.end){let s=a.start,l=s+"---"+s+"---1",u=s+"---"+s+"---2",h=r.node(s);r.setNode(l,{domId:l,id:l,parentId:h.parentId,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),r.setParent(l,h.parentId),r.setNode(u,{domId:u,id:u,parentId:h.parentId,labelStyle:"",padding:0,shape:"labelRect",label:"",style:"",width:10,height:10}),r.setParent(u,h.parentId);let f=structuredClone(a),d=structuredClone(a),p=structuredClone(a);f.label="",f.arrowTypeEnd="none",f.id=s+"-cyclic-special-1",d.arrowTypeEnd="none",d.id=s+"-cyclic-special-mid",p.label="",h.isGroup&&(f.fromCluster=s,p.toCluster=s),p.id=s+"-cyclic-special-2",r.setEdge(s,l,f,s+"-cyclic-special-0"),r.setEdge(l,u,d,s+"-cyclic-special-1"),r.setEdge(u,s,p,s+"-cyc{"use strict";hQ();ut();Bv={},gD=o(t=>{for(let e of t)Bv[e.name]=e},"registerLayoutLoaders"),vNe=o(()=>{gD([{name:"dagre",loader:o(async()=>await Promise.resolve().then(()=>(Hre(),Ure)),"loader")}])},"registerDefaultLayoutLoaders");vNe();sT=o(async(t,e)=>{if(!(t.layoutAlgorithm in Bv))throw new Error(`Unknown layout algorithm: ${t.layoutAlgorithm}`);let r=Bv[t.layoutAlgorithm];return(await r.loader()).render(t,e,uQ,{algorithm:r.algorithm})},"render"),Yre=o((t="",{fallback:e="dagre"}={})=>{if(t in Bv)return t;if(e in Bv)return V.warn(`Layout algorithm ${t} is not registered. Using ${e} as fallback.`),e;throw new Error(`Both layout algorithms ${t} and ${e} are not registered.`)},"getRegisteredLayoutAlgorithm")});var lT,xNe,bNe,yD=R(()=>{"use strict";Yn();ut();lT=o((t,e,r,n)=>{t.attr("class",r);let{width:i,height:a,x:s,y:l}=xNe(t,e);Sr(t,a,i,n);let u=bNe(s,l,i,a,e);t.attr("viewBox",u),V.debug(`viewBox configured: ${u} with padding: ${e}`)},"setupViewPortForSVG"),xNe=o((t,e)=>{let r=t.node()?.getBBox()||{width:0,height:0,x:0,y:0};return{width:r.width+e*2,height:r.height+e*2,x:r.x,y:r.y}},"calculateDimensionsWithPadding"),bNe=o((t,e,r,n,i)=>`${t-i} ${e-i} ${r} ${n}`,"createViewBox")});var wNe,TNe,Wre,qre=R(()=>{"use strict";Zt();_t();ut();L9();oT();yD();xr();f9();wNe=o(function(t,e){return e.db.getClasses()},"getClasses"),TNe=o(async function(t,e,r,n){V.info("REF0:"),V.info("Drawing state diagram (v2)",e);let{securityLevel:i,flowchart:a,layout:s}=de(),l;i==="sandbox"&&(l=$e("#i"+e));let u=i==="sandbox"?l.nodes()[0].contentDocument:document;V.debug("Before getData: ");let h=n.db.getData();V.debug("Data: ",h);let f=I5(e,i),d=h9();h.type=n.type,h.layoutAlgorithm=Yre(s),h.layoutAlgorithm==="dagre"&&s==="elk"&&V.warn("flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](https://github.com/mermaid-js/mermaid/releases/tag/v11.0.0) for more details. This diagram will be rendered using `dagre` layout as a fallback."),h.direction=d,h.nodeSpacing=a?.nodeSpacing||50,h.rankSpacing=a?.rankSpacing||50,h.markers=["point","circle","cross"],h.diagramId=e,V.debug("REF1:",h),await sT(h,f);let p=h.config.flowchart?.diagramPadding??8;Lt.insertTitle(f,"flowchartTitleText",a?.titleTopMargin||0,n.db.getDiagramTitle()),lT(f,p,"flowchart",a?.useMaxWidth||!1);for(let m of h.nodes){let g=$e(`#${e} [id="${m.id}"]`);if(!g||!m.link)continue;let y=u.createElementNS("http://www.w3.org/2000/svg","a");y.setAttributeNS("http://www.w3.org/2000/svg","class",m.cssClasses),y.setAttributeNS("http://www.w3.org/2000/svg","rel","noopener"),i==="sandbox"?y.setAttributeNS("http://www.w3.org/2000/svg","target","_top"):m.linkTarget&&y.setAttributeNS("http://www.w3.org/2000/svg","target",m.linkTarget);let v=g.insert(function(){return y},":first-child"),x=g.select(".label-container");x&&v.append(function(){return x.node()});let b=g.select(".label");b&&v.append(function(){return b.node()})}},"draw"),Wre={getClasses:wNe,draw:TNe}});var vD,Xre,jre=R(()=>{"use strict";vD=function(){var t=o(function(qi,ht,At,$t){for(At=At||{},$t=qi.length;$t--;At[qi[$t]]=ht);return At},"o"),e=[1,4],r=[1,3],n=[1,5],i=[1,8,9,10,11,27,34,36,38,42,58,81,82,83,84,85,86,99,102,103,106,108,111,112,113,118,119,120,121],a=[2,2],s=[1,13],l=[1,14],u=[1,15],h=[1,16],f=[1,23],d=[1,25],p=[1,26],m=[1,27],g=[1,49],y=[1,48],v=[1,29],x=[1,30],b=[1,31],w=[1,32],S=[1,33],T=[1,44],E=[1,46],_=[1,42],A=[1,47],L=[1,43],M=[1,50],N=[1,45],k=[1,51],I=[1,52],C=[1,34],O=[1,35],D=[1,36],P=[1,37],F=[1,57],B=[1,8,9,10,11,27,32,34,36,38,42,58,81,82,83,84,85,86,99,102,103,106,108,111,112,113,118,119,120,121],$=[1,61],z=[1,60],Y=[1,62],Q=[8,9,11,73,75],X=[1,88],ie=[1,93],j=[1,92],J=[1,89],Z=[1,85],H=[1,91],q=[1,87],K=[1,94],se=[1,90],ce=[1,95],ue=[1,86],te=[8,9,10,11,73,75],De=[8,9,10,11,44,73,75],oe=[8,9,10,11,29,42,44,46,48,50,52,54,56,58,61,63,65,66,68,73,75,86,99,102,103,106,108,111,112,113],ke=[8,9,11,42,58,73,75,86,99,102,103,106,108,111,112,113],Ie=[42,58,86,99,102,103,106,108,111,112,113],Se=[1,121],Ue=[1,120],Pe=[1,128],_e=[1,142],me=[1,143],W=[1,144],fe=[1,145],ge=[1,130],re=[1,132],he=[1,136],ne=[1,137],ae=[1,138],we=[1,139],Te=[1,140],Ce=[1,141],Ae=[1,146],Ge=[1,147],Me=[1,126],ye=[1,127],He=[1,134],ze=[1,129],Ze=[1,133],gt=[1,131],yt=[8,9,10,11,27,32,34,36,38,42,58,81,82,83,84,85,86,99,102,103,106,108,111,112,113,118,119,120,121],tt=[1,149],Ye=[8,9,11],Je=[8,9,10,11,14,42,58,86,102,103,106,108,111,112,113],Ve=[1,169],je=[1,165],kt=[1,166],at=[1,170],xt=[1,167],it=[1,168],dt=[75,113,116],lt=[8,9,10,11,12,14,27,29,32,42,58,73,81,82,83,84,85,86,87,102,106,108,111,112,113],It=[10,103],mt=[31,47,49,51,53,55,60,62,64,65,67,69,113,114,115],St=[1,235],gr=[1,233],xn=[1,237],jt=[1,231],rn=[1,232],Er=[1,234],Kn=[1,236],hn=[1,238],Qn=[1,255],on=[8,9,11,103],Rn=[8,9,10,11,58,81,102,103,106,107,108,109],Ha={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,graphConfig:4,document:5,line:6,statement:7,SEMI:8,NEWLINE:9,SPACE:10,EOF:11,GRAPH:12,NODIR:13,DIR:14,FirstStmtSeparator:15,ending:16,endToken:17,spaceList:18,spaceListNewline:19,vertexStatement:20,separator:21,styleStatement:22,linkStyleStatement:23,classDefStatement:24,classStatement:25,clickStatement:26,subgraph:27,textNoTags:28,SQS:29,text:30,SQE:31,end:32,direction:33,acc_title:34,acc_title_value:35,acc_descr:36,acc_descr_value:37,acc_descr_multiline_value:38,link:39,node:40,styledVertex:41,AMP:42,vertex:43,STYLE_SEPARATOR:44,idString:45,DOUBLECIRCLESTART:46,DOUBLECIRCLEEND:47,PS:48,PE:49,"(-":50,"-)":51,STADIUMSTART:52,STADIUMEND:53,SUBROUTINESTART:54,SUBROUTINEEND:55,VERTEX_WITH_PROPS_START:56,"NODE_STRING[field]":57,COLON:58,"NODE_STRING[value]":59,PIPE:60,CYLINDERSTART:61,CYLINDEREND:62,DIAMOND_START:63,DIAMOND_STOP:64,TAGEND:65,TRAPSTART:66,TRAPEND:67,INVTRAPSTART:68,INVTRAPEND:69,linkStatement:70,arrowText:71,TESTSTR:72,START_LINK:73,edgeText:74,LINK:75,edgeTextToken:76,STR:77,MD_STR:78,textToken:79,keywords:80,STYLE:81,LINKSTYLE:82,CLASSDEF:83,CLASS:84,CLICK:85,DOWN:86,UP:87,textNoTagsToken:88,stylesOpt:89,"idString[vertex]":90,"idString[class]":91,CALLBACKNAME:92,CALLBACKARGS:93,HREF:94,LINK_TARGET:95,"STR[link]":96,"STR[tooltip]":97,alphaNum:98,DEFAULT:99,numList:100,INTERPOLATE:101,NUM:102,COMMA:103,style:104,styleComponent:105,NODE_STRING:106,UNIT:107,BRKT:108,PCT:109,idStringToken:110,MINUS:111,MULT:112,UNICODE_TEXT:113,TEXT:114,TAGSTART:115,EDGE_TEXT:116,alphaNumToken:117,direction_tb:118,direction_bt:119,direction_rl:120,direction_lr:121,$accept:0,$end:1},terminals_:{2:"error",8:"SEMI",9:"NEWLINE",10:"SPACE",11:"EOF",12:"GRAPH",13:"NODIR",14:"DIR",27:"subgraph",29:"SQS",31:"SQE",32:"end",34:"acc_title",35:"acc_title_value",36:"acc_descr",37:"acc_descr_value",38:"acc_descr_multiline_value",42:"AMP",44:"STYLE_SEPARATOR",46:"DOUBLECIRCLESTART",47:"DOUBLECIRCLEEND",48:"PS",49:"PE",50:"(-",51:"-)",52:"STADIUMSTART",53:"STADIUMEND",54:"SUBROUTINESTART",55:"SUBROUTINEEND",56:"VERTEX_WITH_PROPS_START",57:"NODE_STRING[field]",58:"COLON",59:"NODE_STRING[value]",60:"PIPE",61:"CYLINDERSTART",62:"CYLINDEREND",63:"DIAMOND_START",64:"DIAMOND_STOP",65:"TAGEND",66:"TRAPSTART",67:"TRAPEND",68:"INVTRAPSTART",69:"INVTRAPEND",72:"TESTSTR",73:"START_LINK",75:"LINK",77:"STR",78:"MD_STR",81:"STYLE",82:"LINKSTYLE",83:"CLASSDEF",84:"CLASS",85:"CLICK",86:"DOWN",87:"UP",90:"idString[vertex]",91:"idString[class]",92:"CALLBACKNAME",93:"CALLBACKARGS",94:"HREF",95:"LINK_TARGET",96:"STR[link]",97:"STR[tooltip]",99:"DEFAULT",101:"INTERPOLATE",102:"NUM",103:"COMMA",106:"NODE_STRING",107:"UNIT",108:"BRKT",109:"PCT",111:"MINUS",112:"MULT",113:"UNICODE_TEXT",114:"TEXT",115:"TAGSTART",116:"EDGE_TEXT",118:"direction_tb",119:"direction_bt",120:"direction_rl",121:"direction_lr"},productions_:[0,[3,2],[5,0],[5,2],[6,1],[6,1],[6,1],[6,1],[6,1],[4,2],[4,2],[4,2],[4,3],[16,2],[16,1],[17,1],[17,1],[17,1],[15,1],[15,1],[15,2],[19,2],[19,2],[19,1],[19,1],[18,2],[18,1],[7,2],[7,2],[7,2],[7,2],[7,2],[7,2],[7,9],[7,6],[7,4],[7,1],[7,2],[7,2],[7,1],[21,1],[21,1],[21,1],[20,3],[20,4],[20,2],[20,1],[40,1],[40,5],[41,1],[41,3],[43,4],[43,4],[43,6],[43,4],[43,4],[43,4],[43,8],[43,4],[43,4],[43,4],[43,6],[43,4],[43,4],[43,4],[43,4],[43,4],[43,1],[39,2],[39,3],[39,3],[39,1],[39,3],[74,1],[74,2],[74,1],[74,1],[70,1],[71,3],[30,1],[30,2],[30,1],[30,1],[80,1],[80,1],[80,1],[80,1],[80,1],[80,1],[80,1],[80,1],[80,1],[80,1],[80,1],[28,1],[28,2],[28,1],[28,1],[24,5],[25,5],[26,2],[26,4],[26,3],[26,5],[26,3],[26,5],[26,5],[26,7],[26,2],[26,4],[26,2],[26,4],[26,4],[26,6],[22,5],[23,5],[23,5],[23,9],[23,9],[23,7],[23,7],[100,1],[100,3],[89,1],[89,3],[104,1],[104,2],[105,1],[105,1],[105,1],[105,1],[105,1],[105,1],[105,1],[105,1],[110,1],[110,1],[110,1],[110,1],[110,1],[110,1],[110,1],[110,1],[110,1],[110,1],[110,1],[79,1],[79,1],[79,1],[79,1],[88,1],[88,1],[88,1],[88,1],[88,1],[88,1],[88,1],[88,1],[88,1],[88,1],[88,1],[76,1],[76,1],[117,1],[117,1],[117,1],[117,1],[117,1],[117,1],[117,1],[117,1],[117,1],[117,1],[117,1],[45,1],[45,2],[98,1],[98,2],[33,1],[33,1],[33,1],[33,1]],performAction:o(function(ht,At,$t,rt,Ot,pe,ur){var be=pe.length-1;switch(Ot){case 2:this.$=[];break;case 3:(!Array.isArray(pe[be])||pe[be].length>0)&&pe[be-1].push(pe[be]),this.$=pe[be-1];break;case 4:case 176:this.$=pe[be];break;case 11:rt.setDirection("TB"),this.$="TB";break;case 12:rt.setDirection(pe[be-1]),this.$=pe[be-1];break;case 27:this.$=pe[be-1].nodes;break;case 28:case 29:case 30:case 31:case 32:this.$=[];break;case 33:this.$=rt.addSubGraph(pe[be-6],pe[be-1],pe[be-4]);break;case 34:this.$=rt.addSubGraph(pe[be-3],pe[be-1],pe[be-3]);break;case 35:this.$=rt.addSubGraph(void 0,pe[be-1],void 0);break;case 37:this.$=pe[be].trim(),rt.setAccTitle(this.$);break;case 38:case 39:this.$=pe[be].trim(),rt.setAccDescription(this.$);break;case 43:rt.addLink(pe[be-2].stmt,pe[be],pe[be-1]),this.$={stmt:pe[be],nodes:pe[be].concat(pe[be-2].nodes)};break;case 44:rt.addLink(pe[be-3].stmt,pe[be-1],pe[be-2]),this.$={stmt:pe[be-1],nodes:pe[be-1].concat(pe[be-3].nodes)};break;case 45:this.$={stmt:pe[be-1],nodes:pe[be-1]};break;case 46:this.$={stmt:pe[be],nodes:pe[be]};break;case 47:this.$=[pe[be]];break;case 48:this.$=pe[be-4].concat(pe[be]);break;case 49:this.$=pe[be];break;case 50:this.$=pe[be-2],rt.setClass(pe[be-2],pe[be]);break;case 51:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"square");break;case 52:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"doublecircle");break;case 53:this.$=pe[be-5],rt.addVertex(pe[be-5],pe[be-2],"circle");break;case 54:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"ellipse");break;case 55:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"stadium");break;case 56:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"subroutine");break;case 57:this.$=pe[be-7],rt.addVertex(pe[be-7],pe[be-1],"rect",void 0,void 0,void 0,Object.fromEntries([[pe[be-5],pe[be-3]]]));break;case 58:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"cylinder");break;case 59:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"round");break;case 60:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"diamond");break;case 61:this.$=pe[be-5],rt.addVertex(pe[be-5],pe[be-2],"hexagon");break;case 62:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"odd");break;case 63:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"trapezoid");break;case 64:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"inv_trapezoid");break;case 65:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"lean_right");break;case 66:this.$=pe[be-3],rt.addVertex(pe[be-3],pe[be-1],"lean_left");break;case 67:this.$=pe[be],rt.addVertex(pe[be]);break;case 68:pe[be-1].text=pe[be],this.$=pe[be-1];break;case 69:case 70:pe[be-2].text=pe[be-1],this.$=pe[be-2];break;case 71:this.$=pe[be];break;case 72:var Ir=rt.destructLink(pe[be],pe[be-2]);this.$={type:Ir.type,stroke:Ir.stroke,length:Ir.length,text:pe[be-1]};break;case 73:this.$={text:pe[be],type:"text"};break;case 74:this.$={text:pe[be-1].text+""+pe[be],type:pe[be-1].type};break;case 75:this.$={text:pe[be],type:"string"};break;case 76:this.$={text:pe[be],type:"markdown"};break;case 77:var Ir=rt.destructLink(pe[be]);this.$={type:Ir.type,stroke:Ir.stroke,length:Ir.length};break;case 78:this.$=pe[be-1];break;case 79:this.$={text:pe[be],type:"text"};break;case 80:this.$={text:pe[be-1].text+""+pe[be],type:pe[be-1].type};break;case 81:this.$={text:pe[be],type:"string"};break;case 82:case 97:this.$={text:pe[be],type:"markdown"};break;case 94:this.$={text:pe[be],type:"text"};break;case 95:this.$={text:pe[be-1].text+""+pe[be],type:pe[be-1].type};break;case 96:this.$={text:pe[be],type:"text"};break;case 98:this.$=pe[be-4],rt.addClass(pe[be-2],pe[be]);break;case 99:this.$=pe[be-4],rt.setClass(pe[be-2],pe[be]);break;case 100:case 108:this.$=pe[be-1],rt.setClickEvent(pe[be-1],pe[be]);break;case 101:case 109:this.$=pe[be-3],rt.setClickEvent(pe[be-3],pe[be-2]),rt.setTooltip(pe[be-3],pe[be]);break;case 102:this.$=pe[be-2],rt.setClickEvent(pe[be-2],pe[be-1],pe[be]);break;case 103:this.$=pe[be-4],rt.setClickEvent(pe[be-4],pe[be-3],pe[be-2]),rt.setTooltip(pe[be-4],pe[be]);break;case 104:this.$=pe[be-2],rt.setLink(pe[be-2],pe[be]);break;case 105:this.$=pe[be-4],rt.setLink(pe[be-4],pe[be-2]),rt.setTooltip(pe[be-4],pe[be]);break;case 106:this.$=pe[be-4],rt.setLink(pe[be-4],pe[be-2],pe[be]);break;case 107:this.$=pe[be-6],rt.setLink(pe[be-6],pe[be-4],pe[be]),rt.setTooltip(pe[be-6],pe[be-2]);break;case 110:this.$=pe[be-1],rt.setLink(pe[be-1],pe[be]);break;case 111:this.$=pe[be-3],rt.setLink(pe[be-3],pe[be-2]),rt.setTooltip(pe[be-3],pe[be]);break;case 112:this.$=pe[be-3],rt.setLink(pe[be-3],pe[be-2],pe[be]);break;case 113:this.$=pe[be-5],rt.setLink(pe[be-5],pe[be-4],pe[be]),rt.setTooltip(pe[be-5],pe[be-2]);break;case 114:this.$=pe[be-4],rt.addVertex(pe[be-2],void 0,void 0,pe[be]);break;case 115:this.$=pe[be-4],rt.updateLink([pe[be-2]],pe[be]);break;case 116:this.$=pe[be-4],rt.updateLink(pe[be-2],pe[be]);break;case 117:this.$=pe[be-8],rt.updateLinkInterpolate([pe[be-6]],pe[be-2]),rt.updateLink([pe[be-6]],pe[be]);break;case 118:this.$=pe[be-8],rt.updateLinkInterpolate(pe[be-6],pe[be-2]),rt.updateLink(pe[be-6],pe[be]);break;case 119:this.$=pe[be-6],rt.updateLinkInterpolate([pe[be-4]],pe[be]);break;case 120:this.$=pe[be-6],rt.updateLinkInterpolate(pe[be-4],pe[be]);break;case 121:case 123:this.$=[pe[be]];break;case 122:case 124:pe[be-2].push(pe[be]),this.$=pe[be-2];break;case 126:this.$=pe[be-1]+pe[be];break;case 174:this.$=pe[be];break;case 175:this.$=pe[be-1]+""+pe[be];break;case 177:this.$=pe[be-1]+""+pe[be];break;case 178:this.$={stmt:"dir",value:"TB"};break;case 179:this.$={stmt:"dir",value:"BT"};break;case 180:this.$={stmt:"dir",value:"RL"};break;case 181:this.$={stmt:"dir",value:"LR"};break}},"anonymous"),table:[{3:1,4:2,9:e,10:r,12:n},{1:[3]},t(i,a,{5:6}),{4:7,9:e,10:r,12:n},{4:8,9:e,10:r,12:n},{13:[1,9],14:[1,10]},{1:[2,1],6:11,7:12,8:s,9:l,10:u,11:h,20:17,22:18,23:19,24:20,25:21,26:22,27:f,33:24,34:d,36:p,38:m,40:28,41:38,42:g,43:39,45:40,58:y,81:v,82:x,83:b,84:w,85:S,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I,118:C,119:O,120:D,121:P},t(i,[2,9]),t(i,[2,10]),t(i,[2,11]),{8:[1,54],9:[1,55],10:F,15:53,18:56},t(B,[2,3]),t(B,[2,4]),t(B,[2,5]),t(B,[2,6]),t(B,[2,7]),t(B,[2,8]),{8:$,9:z,11:Y,21:58,39:59,70:63,73:[1,64],75:[1,65]},{8:$,9:z,11:Y,21:66},{8:$,9:z,11:Y,21:67},{8:$,9:z,11:Y,21:68},{8:$,9:z,11:Y,21:69},{8:$,9:z,11:Y,21:70},{8:$,9:z,10:[1,71],11:Y,21:72},t(B,[2,36]),{35:[1,73]},{37:[1,74]},t(B,[2,39]),t(Q,[2,46],{18:75,10:F}),{10:[1,76]},{10:[1,77]},{10:[1,78]},{10:[1,79]},{14:X,42:ie,58:j,77:[1,83],86:J,92:[1,80],94:[1,81],98:82,102:Z,103:H,106:q,108:K,111:se,112:ce,113:ue,117:84},t(B,[2,178]),t(B,[2,179]),t(B,[2,180]),t(B,[2,181]),t(te,[2,47]),t(te,[2,49],{44:[1,96]}),t(De,[2,67],{110:109,29:[1,97],42:g,46:[1,98],48:[1,99],50:[1,100],52:[1,101],54:[1,102],56:[1,103],58:y,61:[1,104],63:[1,105],65:[1,106],66:[1,107],68:[1,108],86:T,99:E,102:_,103:A,106:L,108:M,111:N,112:k,113:I}),t(oe,[2,174]),t(oe,[2,135]),t(oe,[2,136]),t(oe,[2,137]),t(oe,[2,138]),t(oe,[2,139]),t(oe,[2,140]),t(oe,[2,141]),t(oe,[2,142]),t(oe,[2,143]),t(oe,[2,144]),t(oe,[2,145]),t(i,[2,12]),t(i,[2,18]),t(i,[2,19]),{9:[1,110]},t(ke,[2,26],{18:111,10:F}),t(B,[2,27]),{40:112,41:38,42:g,43:39,45:40,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},t(B,[2,40]),t(B,[2,41]),t(B,[2,42]),t(Ie,[2,71],{71:113,60:[1,115],72:[1,114]}),{74:116,76:117,77:[1,118],78:[1,119],113:Se,116:Ue},t([42,58,60,72,86,99,102,103,106,108,111,112,113],[2,77]),t(B,[2,28]),t(B,[2,29]),t(B,[2,30]),t(B,[2,31]),t(B,[2,32]),{10:Pe,12:_e,14:me,27:W,28:122,32:fe,42:ge,58:re,73:he,77:[1,124],78:[1,125],80:135,81:ne,82:ae,83:we,84:Te,85:Ce,86:Ae,87:Ge,88:123,102:Me,106:ye,108:He,111:ze,112:Ze,113:gt},t(yt,a,{5:148}),t(B,[2,37]),t(B,[2,38]),t(Q,[2,45],{42:tt}),{42:g,45:150,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},{99:[1,151],100:152,102:[1,153]},{42:g,45:154,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},{42:g,45:155,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},t(Ye,[2,100],{10:[1,156],93:[1,157]}),{77:[1,158]},t(Ye,[2,108],{117:160,10:[1,159],14:X,42:ie,58:j,86:J,102:Z,103:H,106:q,108:K,111:se,112:ce,113:ue}),t(Ye,[2,110],{10:[1,161]}),t(Je,[2,176]),t(Je,[2,163]),t(Je,[2,164]),t(Je,[2,165]),t(Je,[2,166]),t(Je,[2,167]),t(Je,[2,168]),t(Je,[2,169]),t(Je,[2,170]),t(Je,[2,171]),t(Je,[2,172]),t(Je,[2,173]),{42:g,45:162,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},{30:163,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:171,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:173,48:[1,172],65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:174,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:175,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:176,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{106:[1,177]},{30:178,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:179,63:[1,180],65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:181,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:182,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{30:183,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},t(oe,[2,175]),t(i,[2,20]),t(ke,[2,25]),t(Q,[2,43],{18:184,10:F}),t(Ie,[2,68],{10:[1,185]}),{10:[1,186]},{30:187,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{75:[1,188],76:189,113:Se,116:Ue},t(dt,[2,73]),t(dt,[2,75]),t(dt,[2,76]),t(dt,[2,161]),t(dt,[2,162]),{8:$,9:z,10:Pe,11:Y,12:_e,14:me,21:191,27:W,29:[1,190],32:fe,42:ge,58:re,73:he,80:135,81:ne,82:ae,83:we,84:Te,85:Ce,86:Ae,87:Ge,88:192,102:Me,106:ye,108:He,111:ze,112:Ze,113:gt},t(lt,[2,94]),t(lt,[2,96]),t(lt,[2,97]),t(lt,[2,150]),t(lt,[2,151]),t(lt,[2,152]),t(lt,[2,153]),t(lt,[2,154]),t(lt,[2,155]),t(lt,[2,156]),t(lt,[2,157]),t(lt,[2,158]),t(lt,[2,159]),t(lt,[2,160]),t(lt,[2,83]),t(lt,[2,84]),t(lt,[2,85]),t(lt,[2,86]),t(lt,[2,87]),t(lt,[2,88]),t(lt,[2,89]),t(lt,[2,90]),t(lt,[2,91]),t(lt,[2,92]),t(lt,[2,93]),{6:11,7:12,8:s,9:l,10:u,11:h,20:17,22:18,23:19,24:20,25:21,26:22,27:f,32:[1,193],33:24,34:d,36:p,38:m,40:28,41:38,42:g,43:39,45:40,58:y,81:v,82:x,83:b,84:w,85:S,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I,118:C,119:O,120:D,121:P},{10:F,18:194},{10:[1,195],42:g,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:109,111:N,112:k,113:I},{10:[1,196]},{10:[1,197],103:[1,198]},t(It,[2,121]),{10:[1,199],42:g,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:109,111:N,112:k,113:I},{10:[1,200],42:g,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:109,111:N,112:k,113:I},{77:[1,201]},t(Ye,[2,102],{10:[1,202]}),t(Ye,[2,104],{10:[1,203]}),{77:[1,204]},t(Je,[2,177]),{77:[1,205],95:[1,206]},t(te,[2,50],{110:109,42:g,58:y,86:T,99:E,102:_,103:A,106:L,108:M,111:N,112:k,113:I}),{31:[1,207],65:Ve,79:208,113:at,114:xt,115:it},t(mt,[2,79]),t(mt,[2,81]),t(mt,[2,82]),t(mt,[2,146]),t(mt,[2,147]),t(mt,[2,148]),t(mt,[2,149]),{47:[1,209],65:Ve,79:208,113:at,114:xt,115:it},{30:210,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{49:[1,211],65:Ve,79:208,113:at,114:xt,115:it},{51:[1,212],65:Ve,79:208,113:at,114:xt,115:it},{53:[1,213],65:Ve,79:208,113:at,114:xt,115:it},{55:[1,214],65:Ve,79:208,113:at,114:xt,115:it},{58:[1,215]},{62:[1,216],65:Ve,79:208,113:at,114:xt,115:it},{64:[1,217],65:Ve,79:208,113:at,114:xt,115:it},{30:218,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},{31:[1,219],65:Ve,79:208,113:at,114:xt,115:it},{65:Ve,67:[1,220],69:[1,221],79:208,113:at,114:xt,115:it},{65:Ve,67:[1,223],69:[1,222],79:208,113:at,114:xt,115:it},t(Q,[2,44],{42:tt}),t(Ie,[2,70]),t(Ie,[2,69]),{60:[1,224],65:Ve,79:208,113:at,114:xt,115:it},t(Ie,[2,72]),t(dt,[2,74]),{30:225,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},t(yt,a,{5:226}),t(lt,[2,95]),t(B,[2,35]),{41:227,42:g,43:39,45:40,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},{10:St,58:gr,81:xn,89:228,102:jt,104:229,105:230,106:rn,107:Er,108:Kn,109:hn},{10:St,58:gr,81:xn,89:239,101:[1,240],102:jt,104:229,105:230,106:rn,107:Er,108:Kn,109:hn},{10:St,58:gr,81:xn,89:241,101:[1,242],102:jt,104:229,105:230,106:rn,107:Er,108:Kn,109:hn},{102:[1,243]},{10:St,58:gr,81:xn,89:244,102:jt,104:229,105:230,106:rn,107:Er,108:Kn,109:hn},{42:g,45:245,58:y,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I},t(Ye,[2,101]),{77:[1,246]},{77:[1,247],95:[1,248]},t(Ye,[2,109]),t(Ye,[2,111],{10:[1,249]}),t(Ye,[2,112]),t(De,[2,51]),t(mt,[2,80]),t(De,[2,52]),{49:[1,250],65:Ve,79:208,113:at,114:xt,115:it},t(De,[2,59]),t(De,[2,54]),t(De,[2,55]),t(De,[2,56]),{106:[1,251]},t(De,[2,58]),t(De,[2,60]),{64:[1,252],65:Ve,79:208,113:at,114:xt,115:it},t(De,[2,62]),t(De,[2,63]),t(De,[2,65]),t(De,[2,64]),t(De,[2,66]),t([10,42,58,86,99,102,103,106,108,111,112,113],[2,78]),{31:[1,253],65:Ve,79:208,113:at,114:xt,115:it},{6:11,7:12,8:s,9:l,10:u,11:h,20:17,22:18,23:19,24:20,25:21,26:22,27:f,32:[1,254],33:24,34:d,36:p,38:m,40:28,41:38,42:g,43:39,45:40,58:y,81:v,82:x,83:b,84:w,85:S,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I,118:C,119:O,120:D,121:P},t(te,[2,48]),t(Ye,[2,114],{103:Qn}),t(on,[2,123],{105:256,10:St,58:gr,81:xn,102:jt,106:rn,107:Er,108:Kn,109:hn}),t(Rn,[2,125]),t(Rn,[2,127]),t(Rn,[2,128]),t(Rn,[2,129]),t(Rn,[2,130]),t(Rn,[2,131]),t(Rn,[2,132]),t(Rn,[2,133]),t(Rn,[2,134]),t(Ye,[2,115],{103:Qn}),{10:[1,257]},t(Ye,[2,116],{103:Qn}),{10:[1,258]},t(It,[2,122]),t(Ye,[2,98],{103:Qn}),t(Ye,[2,99],{110:109,42:g,58:y,86:T,99:E,102:_,103:A,106:L,108:M,111:N,112:k,113:I}),t(Ye,[2,103]),t(Ye,[2,105],{10:[1,259]}),t(Ye,[2,106]),{95:[1,260]},{49:[1,261]},{60:[1,262]},{64:[1,263]},{8:$,9:z,11:Y,21:264},t(B,[2,34]),{10:St,58:gr,81:xn,102:jt,104:265,105:230,106:rn,107:Er,108:Kn,109:hn},t(Rn,[2,126]),{14:X,42:ie,58:j,86:J,98:266,102:Z,103:H,106:q,108:K,111:se,112:ce,113:ue,117:84},{14:X,42:ie,58:j,86:J,98:267,102:Z,103:H,106:q,108:K,111:se,112:ce,113:ue,117:84},{95:[1,268]},t(Ye,[2,113]),t(De,[2,53]),{30:269,65:Ve,77:je,78:kt,79:164,113:at,114:xt,115:it},t(De,[2,61]),t(yt,a,{5:270}),t(on,[2,124],{105:256,10:St,58:gr,81:xn,102:jt,106:rn,107:Er,108:Kn,109:hn}),t(Ye,[2,119],{117:160,10:[1,271],14:X,42:ie,58:j,86:J,102:Z,103:H,106:q,108:K,111:se,112:ce,113:ue}),t(Ye,[2,120],{117:160,10:[1,272],14:X,42:ie,58:j,86:J,102:Z,103:H,106:q,108:K,111:se,112:ce,113:ue}),t(Ye,[2,107]),{31:[1,273],65:Ve,79:208,113:at,114:xt,115:it},{6:11,7:12,8:s,9:l,10:u,11:h,20:17,22:18,23:19,24:20,25:21,26:22,27:f,32:[1,274],33:24,34:d,36:p,38:m,40:28,41:38,42:g,43:39,45:40,58:y,81:v,82:x,83:b,84:w,85:S,86:T,99:E,102:_,103:A,106:L,108:M,110:41,111:N,112:k,113:I,118:C,119:O,120:D,121:P},{10:St,58:gr,81:xn,89:275,102:jt,104:229,105:230,106:rn,107:Er,108:Kn,109:hn},{10:St,58:gr,81:xn,89:276,102:jt,104:229,105:230,106:rn,107:Er,108:Kn,109:hn},t(De,[2,57]),t(B,[2,33]),t(Ye,[2,117],{103:Qn}),t(Ye,[2,118],{103:Qn})],defaultActions:{},parseError:o(function(ht,At){if(At.recoverable)this.trace(ht);else{var $t=new Error(ht);throw $t.hash=At,$t}},"parseError"),parse:o(function(ht){var At=this,$t=[0],rt=[],Ot=[null],pe=[],ur=this.table,be="",Ir=0,Xc=0,M1=0,_b=2,I1=1,O1=pe.slice.call(arguments,1),ci=Object.create(this.lexer),ko={yy:{}};for(var ih in this.yy)Object.prototype.hasOwnProperty.call(this.yy,ih)&&(ko.yy[ih]=this.yy[ih]);ci.setInput(ht,ko.yy),ko.yy.lexer=ci,ko.yy.parser=this,typeof ci.yylloc>"u"&&(ci.yylloc={});var Us=ci.yylloc;pe.push(Us);var ah=ci.options&&ci.options.ranges;typeof ko.yy.parseError=="function"?this.parseError=ko.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Lb(La){$t.length=$t.length-2*La,Ot.length=Ot.length-La,pe.length=pe.length-La}o(Lb,"popStack");function P1(){var La;return La=rt.pop()||ci.lex()||I1,typeof La!="number"&&(La instanceof Array&&(rt=La,La=rt.pop()),La=At.symbols_[La]||La),La}o(P1,"lex");for(var sa,jc,Kc,us,_i,Wl,sh={},zf,Hs,B1,Gf;;){if(Kc=$t[$t.length-1],this.defaultActions[Kc]?us=this.defaultActions[Kc]:((sa===null||typeof sa>"u")&&(sa=P1()),us=ur[Kc]&&ur[Kc][sa]),typeof us>"u"||!us.length||!us[0]){var F1="";Gf=[];for(zf in ur[Kc])this.terminals_[zf]&&zf>_b&&Gf.push("'"+this.terminals_[zf]+"'");ci.showPosition?F1="Parse error on line "+(Ir+1)+`: +`+ci.showPosition()+` +Expecting `+Gf.join(", ")+", got '"+(this.terminals_[sa]||sa)+"'":F1="Parse error on line "+(Ir+1)+": Unexpected "+(sa==I1?"end of input":"'"+(this.terminals_[sa]||sa)+"'"),this.parseError(F1,{text:ci.match,token:this.terminals_[sa]||sa,line:ci.yylineno,loc:Us,expected:Gf})}if(us[0]instanceof Array&&us.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Kc+", token: "+sa);switch(us[0]){case 1:$t.push(sa),Ot.push(ci.yytext),pe.push(ci.yylloc),$t.push(us[1]),sa=null,jc?(sa=jc,jc=null):(Xc=ci.yyleng,be=ci.yytext,Ir=ci.yylineno,Us=ci.yylloc,M1>0&&M1--);break;case 2:if(Hs=this.productions_[us[1]][1],sh.$=Ot[Ot.length-Hs],sh._$={first_line:pe[pe.length-(Hs||1)].first_line,last_line:pe[pe.length-1].last_line,first_column:pe[pe.length-(Hs||1)].first_column,last_column:pe[pe.length-1].last_column},ah&&(sh._$.range=[pe[pe.length-(Hs||1)].range[0],pe[pe.length-1].range[1]]),Wl=this.performAction.apply(sh,[be,Xc,Ir,ko.yy,us[1],Ot,pe].concat(O1)),typeof Wl<"u")return Wl;Hs&&($t=$t.slice(0,-1*Hs*2),Ot=Ot.slice(0,-1*Hs),pe=pe.slice(0,-1*Hs)),$t.push(this.productions_[us[1]][0]),Ot.push(sh.$),pe.push(sh._$),B1=ur[$t[$t.length-2]][$t[$t.length-1]],$t.push(B1);break;case 3:return!0}}return!0},"parse")},_a=function(){var qi={EOF:1,parseError:o(function(At,$t){if(this.yy.parser)this.yy.parser.parseError(At,$t);else throw new Error(At)},"parseError"),setInput:o(function(ht,At){return this.yy=At||this.yy||{},this._input=ht,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var ht=this._input[0];this.yytext+=ht,this.yyleng++,this.offset++,this.match+=ht,this.matched+=ht;var At=ht.match(/(?:\r\n?|\n).*/g);return At?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),ht},"input"),unput:o(function(ht){var At=ht.length,$t=ht.split(/(?:\r\n?|\n)/g);this._input=ht+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-At),this.offset-=At;var rt=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),$t.length-1&&(this.yylineno-=$t.length-1);var Ot=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:$t?($t.length===rt.length?this.yylloc.first_column:0)+rt[rt.length-$t.length].length-$t[0].length:this.yylloc.first_column-At},this.options.ranges&&(this.yylloc.range=[Ot[0],Ot[0]+this.yyleng-At]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(ht){this.unput(this.match.slice(ht))},"less"),pastInput:o(function(){var ht=this.matched.substr(0,this.matched.length-this.match.length);return(ht.length>20?"...":"")+ht.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var ht=this.match;return ht.length<20&&(ht+=this._input.substr(0,20-ht.length)),(ht.substr(0,20)+(ht.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var ht=this.pastInput(),At=new Array(ht.length+1).join("-");return ht+this.upcomingInput()+` +`+At+"^"},"showPosition"),test_match:o(function(ht,At){var $t,rt,Ot;if(this.options.backtrack_lexer&&(Ot={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(Ot.yylloc.range=this.yylloc.range.slice(0))),rt=ht[0].match(/(?:\r\n?|\n).*/g),rt&&(this.yylineno+=rt.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:rt?rt[rt.length-1].length-rt[rt.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+ht[0].length},this.yytext+=ht[0],this.match+=ht[0],this.matches=ht,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(ht[0].length),this.matched+=ht[0],$t=this.performAction.call(this,this.yy,this,At,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),$t)return $t;if(this._backtrack){for(var pe in Ot)this[pe]=Ot[pe];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var ht,At,$t,rt;this._more||(this.yytext="",this.match="");for(var Ot=this._currentRules(),pe=0;peAt[0].length)){if(At=$t,rt=pe,this.options.backtrack_lexer){if(ht=this.test_match($t,Ot[pe]),ht!==!1)return ht;if(this._backtrack){At=!1;continue}else return!1}else if(!this.options.flex)break}return At?(ht=this.test_match(At,Ot[rt]),ht!==!1?ht:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var At=this.next();return At||this.lex()},"lex"),begin:o(function(At){this.conditionStack.push(At)},"begin"),popState:o(function(){var At=this.conditionStack.length-1;return At>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(At){return At=this.conditionStack.length-1-Math.abs(At||0),At>=0?this.conditionStack[At]:"INITIAL"},"topState"),pushState:o(function(At){this.begin(At)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:o(function(At,$t,rt,Ot){var pe=Ot;switch(rt){case 0:return this.begin("acc_title"),34;break;case 1:return this.popState(),"acc_title_value";break;case 2:return this.begin("acc_descr"),36;break;case 3:return this.popState(),"acc_descr_value";break;case 4:this.begin("acc_descr_multiline");break;case 5:this.popState();break;case 6:return"acc_descr_multiline_value";case 7:this.begin("callbackname");break;case 8:this.popState();break;case 9:this.popState(),this.begin("callbackargs");break;case 10:return 92;case 11:this.popState();break;case 12:return 93;case 13:return"MD_STR";case 14:this.popState();break;case 15:this.begin("md_string");break;case 16:return"STR";case 17:this.popState();break;case 18:this.pushState("string");break;case 19:return 81;case 20:return 99;case 21:return 82;case 22:return 101;case 23:return 83;case 24:return 84;case 25:return 94;case 26:this.begin("click");break;case 27:this.popState();break;case 28:return 85;case 29:return At.lex.firstGraph()&&this.begin("dir"),12;break;case 30:return At.lex.firstGraph()&&this.begin("dir"),12;break;case 31:return At.lex.firstGraph()&&this.begin("dir"),12;break;case 32:return 27;case 33:return 32;case 34:return 95;case 35:return 95;case 36:return 95;case 37:return 95;case 38:return this.popState(),13;break;case 39:return this.popState(),14;break;case 40:return this.popState(),14;break;case 41:return this.popState(),14;break;case 42:return this.popState(),14;break;case 43:return this.popState(),14;break;case 44:return this.popState(),14;break;case 45:return this.popState(),14;break;case 46:return this.popState(),14;break;case 47:return this.popState(),14;break;case 48:return this.popState(),14;break;case 49:return 118;case 50:return 119;case 51:return 120;case 52:return 121;case 53:return 102;case 54:return 108;case 55:return 44;case 56:return 58;case 57:return 42;case 58:return 8;case 59:return 103;case 60:return 112;case 61:return this.popState(),75;break;case 62:return this.pushState("edgeText"),73;break;case 63:return 116;case 64:return this.popState(),75;break;case 65:return this.pushState("thickEdgeText"),73;break;case 66:return 116;case 67:return this.popState(),75;break;case 68:return this.pushState("dottedEdgeText"),73;break;case 69:return 116;case 70:return 75;case 71:return this.popState(),51;break;case 72:return"TEXT";case 73:return this.pushState("ellipseText"),50;break;case 74:return this.popState(),53;break;case 75:return this.pushState("text"),52;break;case 76:return this.popState(),55;break;case 77:return this.pushState("text"),54;break;case 78:return 56;case 79:return this.pushState("text"),65;break;case 80:return this.popState(),62;break;case 81:return this.pushState("text"),61;break;case 82:return this.popState(),47;break;case 83:return this.pushState("text"),46;break;case 84:return this.popState(),67;break;case 85:return this.popState(),69;break;case 86:return 114;case 87:return this.pushState("trapText"),66;break;case 88:return this.pushState("trapText"),68;break;case 89:return 115;case 90:return 65;case 91:return 87;case 92:return"SEP";case 93:return 86;case 94:return 112;case 95:return 108;case 96:return 42;case 97:return 106;case 98:return 111;case 99:return 113;case 100:return this.popState(),60;break;case 101:return this.pushState("text"),60;break;case 102:return this.popState(),49;break;case 103:return this.pushState("text"),48;break;case 104:return this.popState(),31;break;case 105:return this.pushState("text"),29;break;case 106:return this.popState(),64;break;case 107:return this.pushState("text"),63;break;case 108:return"TEXT";case 109:return"QUOTE";case 110:return 9;case 111:return 10;case 112:return 11}},"anonymous"),rules:[/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:[^`"]+)/,/^(?:[`]["])/,/^(?:["][`])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:["])/,/^(?:style\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\b)/,/^(?:class\b)/,/^(?:href[\s])/,/^(?:click[\s]+)/,/^(?:[\s\n])/,/^(?:[^\s\n]*)/,/^(?:flowchart-elk\b)/,/^(?:graph\b)/,/^(?:flowchart\b)/,/^(?:subgraph\b)/,/^(?:end\b\s*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:(\r?\n)*\s*\n)/,/^(?:\s*LR\b)/,/^(?:\s*RL\b)/,/^(?:\s*TB\b)/,/^(?:\s*BT\b)/,/^(?:\s*TD\b)/,/^(?:\s*BR\b)/,/^(?:\s*<)/,/^(?:\s*>)/,/^(?:\s*\^)/,/^(?:\s*v\b)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:[0-9]+)/,/^(?:#)/,/^(?::::)/,/^(?::)/,/^(?:&)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:[^-]|-(?!-)+)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:[^=]|=(?!))/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:[^\.]|\.(?!))/,/^(?:\s*~~[\~]+\s*)/,/^(?:[-/\)][\)])/,/^(?:[^\(\)\[\]\{\}]|!\)+)/,/^(?:\(-)/,/^(?:\]\))/,/^(?:\(\[)/,/^(?:\]\])/,/^(?:\[\[)/,/^(?:\[\|)/,/^(?:>)/,/^(?:\)\])/,/^(?:\[\()/,/^(?:\)\)\))/,/^(?:\(\(\()/,/^(?:[\\(?=\])][\]])/,/^(?:\/(?=\])\])/,/^(?:\/(?!\])|\\(?!\])|[^\\\[\]\(\)\{\}\/]+)/,/^(?:\[\/)/,/^(?:\[\\)/,/^(?:<)/,/^(?:>)/,/^(?:\^)/,/^(?:\\\|)/,/^(?:v\b)/,/^(?:\*)/,/^(?:#)/,/^(?:&)/,/^(?:([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|-(?=[^\>\-\.])|(?!))+)/,/^(?:-)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\|)/,/^(?:\|)/,/^(?:\))/,/^(?:\()/,/^(?:\])/,/^(?:\[)/,/^(?:(\}))/,/^(?:\{)/,/^(?:[^\[\]\(\)\{\}\|\"]+)/,/^(?:")/,/^(?:(\r?\n)+)/,/^(?:\s)/,/^(?:$)/],conditions:{callbackargs:{rules:[11,12,15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},callbackname:{rules:[8,9,10,15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},href:{rules:[15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},click:{rules:[15,18,27,28,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},dottedEdgeText:{rules:[15,18,67,69,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},thickEdgeText:{rules:[15,18,64,66,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},edgeText:{rules:[15,18,61,63,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},trapText:{rules:[15,18,70,73,75,77,81,83,84,85,86,87,88,101,103,105,107],inclusive:!1},ellipseText:{rules:[15,18,70,71,72,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},text:{rules:[15,18,70,73,74,75,76,77,80,81,82,83,87,88,100,101,102,103,104,105,106,107,108],inclusive:!1},vertex:{rules:[15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},dir:{rules:[15,18,38,39,40,41,42,43,44,45,46,47,48,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},acc_descr_multiline:{rules:[5,6,15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},acc_descr:{rules:[3,15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},acc_title:{rules:[1,15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},md_string:{rules:[13,14,15,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},string:{rules:[15,16,17,18,70,73,75,77,81,83,87,88,101,103,105,107],inclusive:!1},INITIAL:{rules:[0,2,4,7,15,18,19,20,21,22,23,24,25,26,29,30,31,32,33,34,35,36,37,49,50,51,52,53,54,55,56,57,58,59,60,61,62,64,65,67,68,70,73,75,77,78,79,81,83,87,88,89,90,91,92,93,94,95,96,97,98,99,101,103,105,107,109,110,111,112],inclusive:!0}}};return qi}();Ha.lexer=_a;function To(){this.yy={}}return o(To,"Parser"),To.prototype=Ha,Ha.Parser=To,new To}();vD.parser=vD;Xre=vD});var kNe,ENe,Kre,Qre=R(()=>{"use strict";al();kNe=o((t,e)=>{let r=X1,n=r(t,"r"),i=r(t,"g"),a=r(t,"b");return Ws(n,i,a,e)},"fade"),ENe=o(t=>`.label { + font-family: ${t.fontFamily}; + color: ${t.nodeTextColor||t.textColor}; + } + .cluster-label text { + fill: ${t.titleColor}; + } + .cluster-label span { + color: ${t.titleColor}; + } + .cluster-label span p { + background-color: transparent; + } + + .label text,span { + fill: ${t.nodeTextColor||t.textColor}; + color: ${t.nodeTextColor||t.textColor}; + } + + .node rect, + .node circle, + .node ellipse, + .node polygon, + .node path { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; + stroke-width: 1px; + } + .rough-node .label text , .node .label text { + text-anchor: middle; + } + // .flowchart-label .text-outer-tspan { + // text-anchor: middle; + // } + // .flowchart-label .text-inner-tspan { + // text-anchor: start; + // } + + .node .katex path { + fill: #000; + stroke: #000; + stroke-width: 1px; + } + + .node .label { + text-align: center; + } + .node.clickable { + cursor: pointer; + } + + .arrowheadPath { + fill: ${t.arrowheadColor}; + } + + .edgePath .path { + stroke: ${t.lineColor}; + stroke-width: 2.0px; + } + + .flowchart-link { + stroke: ${t.lineColor}; + fill: none; + } + + .edgeLabel { + background-color: ${t.edgeLabelBackground}; + p { + background-color: ${t.edgeLabelBackground}; + } + rect { + opacity: 0.5; + background-color: ${t.edgeLabelBackground}; + fill: ${t.edgeLabelBackground}; + } + text-align: center; + } + + /* For html labels only */ + .labelBkg { + background-color: ${kNe(t.edgeLabelBackground,.5)}; + // background-color: + } + + .cluster rect { + fill: ${t.clusterBkg}; + stroke: ${t.clusterBorder}; + stroke-width: 1px; + } + + .cluster text { + fill: ${t.titleColor}; + } + + .cluster span { + color: ${t.titleColor}; + } + /* .cluster div { + color: ${t.titleColor}; + } */ + + div.mermaidTooltip { + position: absolute; + text-align: center; + max-width: 200px; + padding: 2px; + font-family: ${t.fontFamily}; + font-size: 12px; + background: ${t.tertiaryColor}; + border: 1px solid ${t.border2}; + border-radius: 2px; + pointer-events: none; + z-index: 100; + } + + .flowchartTitleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.textColor}; + } +`,"getStyles"),Kre=ENe});var cT={};hr(cT,{diagram:()=>CNe});var CNe,uT=R(()=>{"use strict";_t();f9();qre();jre();Qre();CNe={parser:Xre,db:A5,renderer:Wre,styles:Kre,init:o(t=>{t.flowchart||(t.flowchart={}),t.layout&&iS({layout:t.layout}),t.flowchart.arrowMarkerAbsolute=t.arrowMarkerAbsolute,iS({flowchart:{arrowMarkerAbsolute:t.arrowMarkerAbsolute}}),A5.clear(),A5.setGen("gen-2")},"init")}});var xD,rne,nne=R(()=>{"use strict";xD=function(){var t=o(function(A,L,M,N){for(M=M||{},N=A.length;N--;M[A[N]]=L);return M},"o"),e=[6,8,10,20,22,24,26,27,28],r=[1,10],n=[1,11],i=[1,12],a=[1,13],s=[1,14],l=[1,15],u=[1,21],h=[1,22],f=[1,23],d=[1,24],p=[1,25],m=[6,8,10,13,15,18,19,20,22,24,26,27,28,41,42,43,44,45],g=[1,34],y=[27,28,46,47],v=[41,42,43,44,45],x=[17,34],b=[1,54],w=[1,53],S=[17,34,36,38],T={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,entityName:11,relSpec:12,":":13,role:14,BLOCK_START:15,attributes:16,BLOCK_STOP:17,SQS:18,SQE:19,title:20,title_value:21,acc_title:22,acc_title_value:23,acc_descr:24,acc_descr_value:25,acc_descr_multiline_value:26,ALPHANUM:27,ENTITY_NAME:28,attribute:29,attributeType:30,attributeName:31,attributeKeyTypeList:32,attributeComment:33,ATTRIBUTE_WORD:34,attributeKeyType:35,COMMA:36,ATTRIBUTE_KEY:37,COMMENT:38,cardinality:39,relType:40,ZERO_OR_ONE:41,ZERO_OR_MORE:42,ONE_OR_MORE:43,ONLY_ONE:44,MD_PARENT:45,NON_IDENTIFYING:46,IDENTIFYING:47,WORD:48,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",8:"SPACE",10:"NEWLINE",13:":",15:"BLOCK_START",17:"BLOCK_STOP",18:"SQS",19:"SQE",20:"title",21:"title_value",22:"acc_title",23:"acc_title_value",24:"acc_descr",25:"acc_descr_value",26:"acc_descr_multiline_value",27:"ALPHANUM",28:"ENTITY_NAME",34:"ATTRIBUTE_WORD",36:"COMMA",37:"ATTRIBUTE_KEY",38:"COMMENT",41:"ZERO_OR_ONE",42:"ZERO_OR_MORE",43:"ONE_OR_MORE",44:"ONLY_ONE",45:"MD_PARENT",46:"NON_IDENTIFYING",47:"IDENTIFYING",48:"WORD"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,5],[9,4],[9,3],[9,1],[9,7],[9,6],[9,4],[9,2],[9,2],[9,2],[9,1],[11,1],[11,1],[16,1],[16,2],[29,2],[29,3],[29,3],[29,4],[30,1],[31,1],[32,1],[32,3],[35,1],[33,1],[12,3],[39,1],[39,1],[39,1],[39,1],[39,1],[40,1],[40,1],[14,1],[14,1],[14,1]],performAction:o(function(L,M,N,k,I,C,O){var D=C.length-1;switch(I){case 1:break;case 2:this.$=[];break;case 3:C[D-1].push(C[D]),this.$=C[D-1];break;case 4:case 5:this.$=C[D];break;case 6:case 7:this.$=[];break;case 8:k.addEntity(C[D-4]),k.addEntity(C[D-2]),k.addRelationship(C[D-4],C[D],C[D-2],C[D-3]);break;case 9:k.addEntity(C[D-3]),k.addAttributes(C[D-3],C[D-1]);break;case 10:k.addEntity(C[D-2]);break;case 11:k.addEntity(C[D]);break;case 12:k.addEntity(C[D-6],C[D-4]),k.addAttributes(C[D-6],C[D-1]);break;case 13:k.addEntity(C[D-5],C[D-3]);break;case 14:k.addEntity(C[D-3],C[D-1]);break;case 15:case 16:this.$=C[D].trim(),k.setAccTitle(this.$);break;case 17:case 18:this.$=C[D].trim(),k.setAccDescription(this.$);break;case 19:case 43:this.$=C[D];break;case 20:case 41:case 42:this.$=C[D].replace(/"/g,"");break;case 21:case 29:this.$=[C[D]];break;case 22:C[D].push(C[D-1]),this.$=C[D];break;case 23:this.$={attributeType:C[D-1],attributeName:C[D]};break;case 24:this.$={attributeType:C[D-2],attributeName:C[D-1],attributeKeyTypeList:C[D]};break;case 25:this.$={attributeType:C[D-2],attributeName:C[D-1],attributeComment:C[D]};break;case 26:this.$={attributeType:C[D-3],attributeName:C[D-2],attributeKeyTypeList:C[D-1],attributeComment:C[D]};break;case 27:case 28:case 31:this.$=C[D];break;case 30:C[D-2].push(C[D]),this.$=C[D-2];break;case 32:this.$=C[D].replace(/"/g,"");break;case 33:this.$={cardA:C[D],relType:C[D-1],cardB:C[D-2]};break;case 34:this.$=k.Cardinality.ZERO_OR_ONE;break;case 35:this.$=k.Cardinality.ZERO_OR_MORE;break;case 36:this.$=k.Cardinality.ONE_OR_MORE;break;case 37:this.$=k.Cardinality.ONLY_ONE;break;case 38:this.$=k.Cardinality.MD_PARENT;break;case 39:this.$=k.Identification.NON_IDENTIFYING;break;case 40:this.$=k.Identification.IDENTIFYING;break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:9,20:r,22:n,24:i,26:a,27:s,28:l},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:16,11:9,20:r,22:n,24:i,26:a,27:s,28:l},t(e,[2,5]),t(e,[2,6]),t(e,[2,11],{12:17,39:20,15:[1,18],18:[1,19],41:u,42:h,43:f,44:d,45:p}),{21:[1,26]},{23:[1,27]},{25:[1,28]},t(e,[2,18]),t(m,[2,19]),t(m,[2,20]),t(e,[2,4]),{11:29,27:s,28:l},{16:30,17:[1,31],29:32,30:33,34:g},{11:35,27:s,28:l},{40:36,46:[1,37],47:[1,38]},t(y,[2,34]),t(y,[2,35]),t(y,[2,36]),t(y,[2,37]),t(y,[2,38]),t(e,[2,15]),t(e,[2,16]),t(e,[2,17]),{13:[1,39]},{17:[1,40]},t(e,[2,10]),{16:41,17:[2,21],29:32,30:33,34:g},{31:42,34:[1,43]},{34:[2,27]},{19:[1,44]},{39:45,41:u,42:h,43:f,44:d,45:p},t(v,[2,39]),t(v,[2,40]),{14:46,27:[1,49],28:[1,48],48:[1,47]},t(e,[2,9]),{17:[2,22]},t(x,[2,23],{32:50,33:51,35:52,37:b,38:w}),t([17,34,37,38],[2,28]),t(e,[2,14],{15:[1,55]}),t([27,28],[2,33]),t(e,[2,8]),t(e,[2,41]),t(e,[2,42]),t(e,[2,43]),t(x,[2,24],{33:56,36:[1,57],38:w}),t(x,[2,25]),t(S,[2,29]),t(x,[2,32]),t(S,[2,31]),{16:58,17:[1,59],29:32,30:33,34:g},t(x,[2,26]),{35:60,37:b},{17:[1,61]},t(e,[2,13]),t(S,[2,30]),t(e,[2,12])],defaultActions:{34:[2,27],41:[2,22]},parseError:o(function(L,M){if(M.recoverable)this.trace(L);else{var N=new Error(L);throw N.hash=M,N}},"parseError"),parse:o(function(L){var M=this,N=[0],k=[],I=[null],C=[],O=this.table,D="",P=0,F=0,B=0,$=2,z=1,Y=C.slice.call(arguments,1),Q=Object.create(this.lexer),X={yy:{}};for(var ie in this.yy)Object.prototype.hasOwnProperty.call(this.yy,ie)&&(X.yy[ie]=this.yy[ie]);Q.setInput(L,X.yy),X.yy.lexer=Q,X.yy.parser=this,typeof Q.yylloc>"u"&&(Q.yylloc={});var j=Q.yylloc;C.push(j);var J=Q.options&&Q.options.ranges;typeof X.yy.parseError=="function"?this.parseError=X.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Z(Pe){N.length=N.length-2*Pe,I.length=I.length-Pe,C.length=C.length-Pe}o(Z,"popStack");function H(){var Pe;return Pe=k.pop()||Q.lex()||z,typeof Pe!="number"&&(Pe instanceof Array&&(k=Pe,Pe=k.pop()),Pe=M.symbols_[Pe]||Pe),Pe}o(H,"lex");for(var q,K,se,ce,ue,te,De={},oe,ke,Ie,Se;;){if(se=N[N.length-1],this.defaultActions[se]?ce=this.defaultActions[se]:((q===null||typeof q>"u")&&(q=H()),ce=O[se]&&O[se][q]),typeof ce>"u"||!ce.length||!ce[0]){var Ue="";Se=[];for(oe in O[se])this.terminals_[oe]&&oe>$&&Se.push("'"+this.terminals_[oe]+"'");Q.showPosition?Ue="Parse error on line "+(P+1)+`: +`+Q.showPosition()+` +Expecting `+Se.join(", ")+", got '"+(this.terminals_[q]||q)+"'":Ue="Parse error on line "+(P+1)+": Unexpected "+(q==z?"end of input":"'"+(this.terminals_[q]||q)+"'"),this.parseError(Ue,{text:Q.match,token:this.terminals_[q]||q,line:Q.yylineno,loc:j,expected:Se})}if(ce[0]instanceof Array&&ce.length>1)throw new Error("Parse Error: multiple actions possible at state: "+se+", token: "+q);switch(ce[0]){case 1:N.push(q),I.push(Q.yytext),C.push(Q.yylloc),N.push(ce[1]),q=null,K?(q=K,K=null):(F=Q.yyleng,D=Q.yytext,P=Q.yylineno,j=Q.yylloc,B>0&&B--);break;case 2:if(ke=this.productions_[ce[1]][1],De.$=I[I.length-ke],De._$={first_line:C[C.length-(ke||1)].first_line,last_line:C[C.length-1].last_line,first_column:C[C.length-(ke||1)].first_column,last_column:C[C.length-1].last_column},J&&(De._$.range=[C[C.length-(ke||1)].range[0],C[C.length-1].range[1]]),te=this.performAction.apply(De,[D,F,P,X.yy,ce[1],I,C].concat(Y)),typeof te<"u")return te;ke&&(N=N.slice(0,-1*ke*2),I=I.slice(0,-1*ke),C=C.slice(0,-1*ke)),N.push(this.productions_[ce[1]][0]),I.push(De.$),C.push(De._$),Ie=O[N[N.length-2]][N[N.length-1]],N.push(Ie);break;case 3:return!0}}return!0},"parse")},E=function(){var A={EOF:1,parseError:o(function(M,N){if(this.yy.parser)this.yy.parser.parseError(M,N);else throw new Error(M)},"parseError"),setInput:o(function(L,M){return this.yy=M||this.yy||{},this._input=L,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var L=this._input[0];this.yytext+=L,this.yyleng++,this.offset++,this.match+=L,this.matched+=L;var M=L.match(/(?:\r\n?|\n).*/g);return M?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),L},"input"),unput:o(function(L){var M=L.length,N=L.split(/(?:\r\n?|\n)/g);this._input=L+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-M),this.offset-=M;var k=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),N.length-1&&(this.yylineno-=N.length-1);var I=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:N?(N.length===k.length?this.yylloc.first_column:0)+k[k.length-N.length].length-N[0].length:this.yylloc.first_column-M},this.options.ranges&&(this.yylloc.range=[I[0],I[0]+this.yyleng-M]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(L){this.unput(this.match.slice(L))},"less"),pastInput:o(function(){var L=this.matched.substr(0,this.matched.length-this.match.length);return(L.length>20?"...":"")+L.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var L=this.match;return L.length<20&&(L+=this._input.substr(0,20-L.length)),(L.substr(0,20)+(L.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var L=this.pastInput(),M=new Array(L.length+1).join("-");return L+this.upcomingInput()+` +`+M+"^"},"showPosition"),test_match:o(function(L,M){var N,k,I;if(this.options.backtrack_lexer&&(I={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(I.yylloc.range=this.yylloc.range.slice(0))),k=L[0].match(/(?:\r\n?|\n).*/g),k&&(this.yylineno+=k.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:k?k[k.length-1].length-k[k.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+L[0].length},this.yytext+=L[0],this.match+=L[0],this.matches=L,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(L[0].length),this.matched+=L[0],N=this.performAction.call(this,this.yy,this,M,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),N)return N;if(this._backtrack){for(var C in I)this[C]=I[C];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var L,M,N,k;this._more||(this.yytext="",this.match="");for(var I=this._currentRules(),C=0;CM[0].length)){if(M=N,k=C,this.options.backtrack_lexer){if(L=this.test_match(N,I[C]),L!==!1)return L;if(this._backtrack){M=!1;continue}else return!1}else if(!this.options.flex)break}return M?(L=this.test_match(M,I[k]),L!==!1?L:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var M=this.next();return M||this.lex()},"lex"),begin:o(function(M){this.conditionStack.push(M)},"begin"),popState:o(function(){var M=this.conditionStack.length-1;return M>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(M){return M=this.conditionStack.length-1-Math.abs(M||0),M>=0?this.conditionStack[M]:"INITIAL"},"topState"),pushState:o(function(M){this.begin(M)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(M,N,k,I){var C=I;switch(k){case 0:return this.begin("acc_title"),22;break;case 1:return this.popState(),"acc_title_value";break;case 2:return this.begin("acc_descr"),24;break;case 3:return this.popState(),"acc_descr_value";break;case 4:this.begin("acc_descr_multiline");break;case 5:this.popState();break;case 6:return"acc_descr_multiline_value";case 7:return 10;case 8:break;case 9:return 8;case 10:return 28;case 11:return 48;case 12:return 4;case 13:return this.begin("block"),15;break;case 14:return 36;case 15:break;case 16:return 37;case 17:return 34;case 18:return 34;case 19:return 38;case 20:break;case 21:return this.popState(),17;break;case 22:return N.yytext[0];case 23:return 18;case 24:return 19;case 25:return 41;case 26:return 43;case 27:return 43;case 28:return 43;case 29:return 41;case 30:return 41;case 31:return 42;case 32:return 42;case 33:return 42;case 34:return 42;case 35:return 42;case 36:return 43;case 37:return 42;case 38:return 43;case 39:return 44;case 40:return 44;case 41:return 44;case 42:return 44;case 43:return 41;case 44:return 42;case 45:return 43;case 46:return 45;case 47:return 46;case 48:return 47;case 49:return 47;case 50:return 46;case 51:return 46;case 52:return 46;case 53:return 27;case 54:return N.yytext[0];case 55:return 6}},"anonymous"),rules:[/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:[\s]+)/i,/^(?:"[^"%\r\n\v\b\\]+")/i,/^(?:"[^"]*")/i,/^(?:erDiagram\b)/i,/^(?:\{)/i,/^(?:,)/i,/^(?:\s+)/i,/^(?:\b((?:PK)|(?:FK)|(?:UK))\b)/i,/^(?:(.*?)[~](.*?)*[~])/i,/^(?:[\*A-Za-z_][A-Za-z0-9\-_\[\]\(\)]*)/i,/^(?:"[^"]*")/i,/^(?:[\n]+)/i,/^(?:\})/i,/^(?:.)/i,/^(?:\[)/i,/^(?:\])/i,/^(?:one or zero\b)/i,/^(?:one or more\b)/i,/^(?:one or many\b)/i,/^(?:1\+)/i,/^(?:\|o\b)/i,/^(?:zero or one\b)/i,/^(?:zero or more\b)/i,/^(?:zero or many\b)/i,/^(?:0\+)/i,/^(?:\}o\b)/i,/^(?:many\(0\))/i,/^(?:many\(1\))/i,/^(?:many\b)/i,/^(?:\}\|)/i,/^(?:one\b)/i,/^(?:only one\b)/i,/^(?:1\b)/i,/^(?:\|\|)/i,/^(?:o\|)/i,/^(?:o\{)/i,/^(?:\|\{)/i,/^(?:\s*u\b)/i,/^(?:\.\.)/i,/^(?:--)/i,/^(?:to\b)/i,/^(?:optionally to\b)/i,/^(?:\.-)/i,/^(?:-\.)/i,/^(?:[A-Za-z_][A-Za-z0-9\-_]*)/i,/^(?:.)/i,/^(?:$)/i],conditions:{acc_descr_multiline:{rules:[5,6],inclusive:!1},acc_descr:{rules:[3],inclusive:!1},acc_title:{rules:[1],inclusive:!1},block:{rules:[14,15,16,17,18,19,20,21,22],inclusive:!1},INITIAL:{rules:[0,2,4,7,8,9,10,11,12,13,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55],inclusive:!0}}};return A}();T.lexer=E;function _(){this.yy={}}return o(_,"Parser"),_.prototype=T,T.Parser=_,new _}();xD.parser=xD;rne=xD});var Hd,bD,NNe,MNe,ine,INe,ONe,PNe,BNe,FNe,ane,sne=R(()=>{"use strict";ut();_t();bi();Hd=new Map,bD=[],NNe={ZERO_OR_ONE:"ZERO_OR_ONE",ZERO_OR_MORE:"ZERO_OR_MORE",ONE_OR_MORE:"ONE_OR_MORE",ONLY_ONE:"ONLY_ONE",MD_PARENT:"MD_PARENT"},MNe={NON_IDENTIFYING:"NON_IDENTIFYING",IDENTIFYING:"IDENTIFYING"},ine=o(function(t,e=void 0){return Hd.has(t)?!Hd.get(t).alias&&e&&(Hd.get(t).alias=e,V.info(`Add alias '${e}' to entity '${t}'`)):(Hd.set(t,{attributes:[],alias:e}),V.info("Added new entity :",t)),Hd.get(t)},"addEntity"),INe=o(()=>Hd,"getEntities"),ONe=o(function(t,e){let r=ine(t),n;for(n=e.length-1;n>=0;n--)r.attributes.push(e[n]),V.debug("Added attribute ",e[n].attributeName)},"addAttributes"),PNe=o(function(t,e,r,n){let i={entityA:t,roleA:e,entityB:r,relSpec:n};bD.push(i),V.debug("Added new relationship :",i)},"addRelationship"),BNe=o(()=>bD,"getRelationships"),FNe=o(function(){Hd=new Map,bD=[],vr()},"clear"),ane={Cardinality:NNe,Identification:MNe,getConfig:o(()=>de().er,"getConfig"),addEntity:ine,addAttributes:ONe,getEntities:INe,addRelationship:PNe,getRelationships:BNe,clear:FNe,setAccTitle:kr,getAccTitle:Ar,setAccDescription:_r,getAccDescription:Lr,setDiagramTitle:nn,getDiagramTitle:Xr}});var Dl,zNe,$o,one=R(()=>{"use strict";Dl={ONLY_ONE_START:"ONLY_ONE_START",ONLY_ONE_END:"ONLY_ONE_END",ZERO_OR_ONE_START:"ZERO_OR_ONE_START",ZERO_OR_ONE_END:"ZERO_OR_ONE_END",ONE_OR_MORE_START:"ONE_OR_MORE_START",ONE_OR_MORE_END:"ONE_OR_MORE_END",ZERO_OR_MORE_START:"ZERO_OR_MORE_START",ZERO_OR_MORE_END:"ZERO_OR_MORE_END",MD_PARENT_END:"MD_PARENT_END",MD_PARENT_START:"MD_PARENT_START"},zNe=o(function(t,e){let r;t.append("defs").append("marker").attr("id",Dl.MD_PARENT_START).attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",Dl.MD_PARENT_END).attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",Dl.ONLY_ONE_START).attr("refX",0).attr("refY",9).attr("markerWidth",18).attr("markerHeight",18).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M9,0 L9,18 M15,0 L15,18"),t.append("defs").append("marker").attr("id",Dl.ONLY_ONE_END).attr("refX",18).attr("refY",9).attr("markerWidth",18).attr("markerHeight",18).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M3,0 L3,18 M9,0 L9,18"),r=t.append("defs").append("marker").attr("id",Dl.ZERO_OR_ONE_START).attr("refX",0).attr("refY",9).attr("markerWidth",30).attr("markerHeight",18).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",21).attr("cy",9).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M9,0 L9,18"),r=t.append("defs").append("marker").attr("id",Dl.ZERO_OR_ONE_END).attr("refX",30).attr("refY",9).attr("markerWidth",30).attr("markerHeight",18).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",9).attr("cy",9).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M21,0 L21,18"),t.append("defs").append("marker").attr("id",Dl.ONE_OR_MORE_START).attr("refX",18).attr("refY",18).attr("markerWidth",45).attr("markerHeight",36).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M0,18 Q 18,0 36,18 Q 18,36 0,18 M42,9 L42,27"),t.append("defs").append("marker").attr("id",Dl.ONE_OR_MORE_END).attr("refX",27).attr("refY",18).attr("markerWidth",45).attr("markerHeight",36).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M3,9 L3,27 M9,18 Q27,0 45,18 Q27,36 9,18"),r=t.append("defs").append("marker").attr("id",Dl.ZERO_OR_MORE_START).attr("refX",18).attr("refY",18).attr("markerWidth",57).attr("markerHeight",36).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",48).attr("cy",18).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M0,18 Q18,0 36,18 Q18,36 0,18"),r=t.append("defs").append("marker").attr("id",Dl.ZERO_OR_MORE_END).attr("refX",39).attr("refY",18).attr("markerWidth",57).attr("markerHeight",36).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",9).attr("cy",18).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M21,18 Q39,0 57,18 Q39,36 21,18")},"insertMarkers"),$o={ERMarkers:Dl,insertMarkers:zNe}});var lne,cne=R(()=>{"use strict";lne=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i});function GNe(t){return typeof t=="string"&&lne.test(t)}var une,hne=R(()=>{"use strict";cne();o(GNe,"validate");une=GNe});function fne(t,e=0){return va[t[e+0]]+va[t[e+1]]+va[t[e+2]]+va[t[e+3]]+"-"+va[t[e+4]]+va[t[e+5]]+"-"+va[t[e+6]]+va[t[e+7]]+"-"+va[t[e+8]]+va[t[e+9]]+"-"+va[t[e+10]]+va[t[e+11]]+va[t[e+12]]+va[t[e+13]]+va[t[e+14]]+va[t[e+15]]}var va,dne=R(()=>{"use strict";va=[];for(let t=0;t<256;++t)va.push((t+256).toString(16).slice(1));o(fne,"unsafeStringify")});function $Ne(t){if(!une(t))throw TypeError("Invalid UUID");let e,r=new Uint8Array(16);return r[0]=(e=parseInt(t.slice(0,8),16))>>>24,r[1]=e>>>16&255,r[2]=e>>>8&255,r[3]=e&255,r[4]=(e=parseInt(t.slice(9,13),16))>>>8,r[5]=e&255,r[6]=(e=parseInt(t.slice(14,18),16))>>>8,r[7]=e&255,r[8]=(e=parseInt(t.slice(19,23),16))>>>8,r[9]=e&255,r[10]=(e=parseInt(t.slice(24,36),16))/1099511627776&255,r[11]=e/4294967296&255,r[12]=e>>>24&255,r[13]=e>>>16&255,r[14]=e>>>8&255,r[15]=e&255,r}var pne,mne=R(()=>{"use strict";hne();o($Ne,"parse");pne=$Ne});function VNe(t){t=unescape(encodeURIComponent(t));let e=[];for(let r=0;r{"use strict";dne();mne();o(VNe,"stringToBytes");UNe="6ba7b810-9dad-11d1-80b4-00c04fd430c8",HNe="6ba7b811-9dad-11d1-80b4-00c04fd430c8";o(wD,"v35")});function YNe(t,e,r,n){switch(t){case 0:return e&r^~e&n;case 1:return e^r^n;case 2:return e&r^e&n^r&n;case 3:return e^r^n}}function TD(t,e){return t<>>32-e}function WNe(t){let e=[1518500249,1859775393,2400959708,3395469782],r=[1732584193,4023233417,2562383102,271733878,3285377520];if(typeof t=="string"){let s=unescape(encodeURIComponent(t));t=[];for(let l=0;l>>0;p=d,d=f,f=TD(h,30)>>>0,h=u,u=y}r[0]=r[0]+u>>>0,r[1]=r[1]+h>>>0,r[2]=r[2]+f>>>0,r[3]=r[3]+d>>>0,r[4]=r[4]+p>>>0}return[r[0]>>24&255,r[0]>>16&255,r[0]>>8&255,r[0]&255,r[1]>>24&255,r[1]>>16&255,r[1]>>8&255,r[1]&255,r[2]>>24&255,r[2]>>16&255,r[2]>>8&255,r[2]&255,r[3]>>24&255,r[3]>>16&255,r[3]>>8&255,r[3]&255,r[4]>>24&255,r[4]>>16&255,r[4]>>8&255,r[4]&255]}var yne,vne=R(()=>{"use strict";o(YNe,"f");o(TD,"ROTL");o(WNe,"sha1");yne=WNe});var qNe,kD,xne=R(()=>{"use strict";gne();vne();qNe=wD("v5",80,yne),kD=qNe});var bne=R(()=>{"use strict";xne()});function nMe(t="",e=""){let r=t.replace(XNe,"");return`${Tne(e)}${Tne(r)}${kD(t,rMe)}`}function Tne(t=""){return t.length>0?`${t}-`:""}var XNe,Ii,Fv,jNe,KNe,QNe,ZNe,kne,JNe,wne,eMe,tMe,rMe,Ene,Cne=R(()=>{"use strict";ya();Zt();Vd();_t();ut();xr();one();Yn();rr();bne();XNe=/[^\dA-Za-z](\W)*/g,Ii={},Fv=new Map,jNe=o(function(t){let e=Object.keys(t);for(let r of e)Ii[r]=t[r]},"setConf"),KNe=o((t,e,r)=>{let n=Ii.entityPadding/3,i=Ii.entityPadding/3,a=Ii.fontSize*.85,s=e.node().getBBox(),l=[],u=!1,h=!1,f=0,d=0,p=0,m=0,g=s.height+n*2,y=1;r.forEach(w=>{w.attributeKeyTypeList!==void 0&&w.attributeKeyTypeList.length>0&&(u=!0),w.attributeComment!==void 0&&(h=!0)}),r.forEach(w=>{let S=`${e.node().id}-attr-${y}`,T=0,E=gh(w.attributeType),_=t.append("text").classed("er entityLabel",!0).attr("id",`${S}-type`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",de().fontFamily).style("font-size",a+"px").text(E),A=t.append("text").classed("er entityLabel",!0).attr("id",`${S}-name`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",de().fontFamily).style("font-size",a+"px").text(w.attributeName),L={};L.tn=_,L.nn=A;let M=_.node().getBBox(),N=A.node().getBBox();if(f=Math.max(f,M.width),d=Math.max(d,N.width),T=Math.max(M.height,N.height),u){let k=w.attributeKeyTypeList!==void 0?w.attributeKeyTypeList.join(","):"",I=t.append("text").classed("er entityLabel",!0).attr("id",`${S}-key`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",de().fontFamily).style("font-size",a+"px").text(k);L.kn=I;let C=I.node().getBBox();p=Math.max(p,C.width),T=Math.max(T,C.height)}if(h){let k=t.append("text").classed("er entityLabel",!0).attr("id",`${S}-comment`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",de().fontFamily).style("font-size",a+"px").text(w.attributeComment||"");L.cn=k;let I=k.node().getBBox();m=Math.max(m,I.width),T=Math.max(T,I.height)}L.height=T,l.push(L),g+=T+n*2,y+=1});let v=4;u&&(v+=2),h&&(v+=2);let x=f+d+p+m,b={width:Math.max(Ii.minEntityWidth,Math.max(s.width+Ii.entityPadding*2,x+i*v)),height:r.length>0?g:Math.max(Ii.minEntityHeight,s.height+Ii.entityPadding*2)};if(r.length>0){let w=Math.max(0,(b.width-x-i*v)/(v/2));e.attr("transform","translate("+b.width/2+","+(n+s.height/2)+")");let S=s.height+n*2,T="attributeBoxOdd";l.forEach(E=>{let _=S+n+E.height/2;E.tn.attr("transform","translate("+i+","+_+")");let A=t.insert("rect","#"+E.tn.node().id).classed(`er ${T}`,!0).attr("x",0).attr("y",S).attr("width",f+i*2+w).attr("height",E.height+n*2),L=parseFloat(A.attr("x"))+parseFloat(A.attr("width"));E.nn.attr("transform","translate("+(L+i)+","+_+")");let M=t.insert("rect","#"+E.nn.node().id).classed(`er ${T}`,!0).attr("x",L).attr("y",S).attr("width",d+i*2+w).attr("height",E.height+n*2),N=parseFloat(M.attr("x"))+parseFloat(M.attr("width"));if(u){E.kn.attr("transform","translate("+(N+i)+","+_+")");let k=t.insert("rect","#"+E.kn.node().id).classed(`er ${T}`,!0).attr("x",N).attr("y",S).attr("width",p+i*2+w).attr("height",E.height+n*2);N=parseFloat(k.attr("x"))+parseFloat(k.attr("width"))}h&&(E.cn.attr("transform","translate("+(N+i)+","+_+")"),t.insert("rect","#"+E.cn.node().id).classed(`er ${T}`,"true").attr("x",N).attr("y",S).attr("width",m+i*2+w).attr("height",E.height+n*2)),S+=E.height+n*2,T=T==="attributeBoxOdd"?"attributeBoxEven":"attributeBoxOdd"})}else b.height=Math.max(Ii.minEntityHeight,g),e.attr("transform","translate("+b.width/2+","+b.height/2+")");return b},"drawAttributes"),QNe=o(function(t,e,r){let n=[...e.keys()],i;return n.forEach(function(a){let s=nMe(a,"entity");Fv.set(a,s);let l=t.append("g").attr("id",s);i=i===void 0?s:i;let u="text-"+s,h=l.append("text").classed("er entityLabel",!0).attr("id",u).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","middle").style("font-family",de().fontFamily).style("font-size",Ii.fontSize+"px").text(e.get(a).alias??a),{width:f,height:d}=KNe(l,h,e.get(a).attributes),m=l.insert("rect","#"+u).classed("er entityBox",!0).attr("x",0).attr("y",0).attr("width",f).attr("height",d).node().getBBox();r.setNode(s,{width:m.width,height:m.height,shape:"rect",id:s})}),i},"drawEntities"),ZNe=o(function(t,e){e.nodes().forEach(function(r){r!==void 0&&e.node(r)!==void 0&&t.select("#"+r).attr("transform","translate("+(e.node(r).x-e.node(r).width/2)+","+(e.node(r).y-e.node(r).height/2)+" )")})},"adjustEntities"),kne=o(function(t){return(t.entityA+t.roleA+t.entityB).replace(/\s/g,"")},"getEdgeName"),JNe=o(function(t,e){return t.forEach(function(r){e.setEdge(Fv.get(r.entityA),Fv.get(r.entityB),{relationship:r},kne(r))}),t},"addRelationships"),wne=0,eMe=o(function(t,e,r,n,i){wne++;let a=r.edge(Fv.get(e.entityA),Fv.get(e.entityB),kne(e)),s=ha().x(function(y){return y.x}).y(function(y){return y.y}).curve(vs),l=t.insert("path","#"+n).classed("er relationshipLine",!0).attr("d",s(a.points)).style("stroke",Ii.stroke).style("fill","none");e.relSpec.relType===i.db.Identification.NON_IDENTIFYING&&l.attr("stroke-dasharray","8,8");let u="";switch(Ii.arrowMarkerAbsolute&&(u=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,u=u.replace(/\(/g,"\\("),u=u.replace(/\)/g,"\\)")),e.relSpec.cardA){case i.db.Cardinality.ZERO_OR_ONE:l.attr("marker-end","url("+u+"#"+$o.ERMarkers.ZERO_OR_ONE_END+")");break;case i.db.Cardinality.ZERO_OR_MORE:l.attr("marker-end","url("+u+"#"+$o.ERMarkers.ZERO_OR_MORE_END+")");break;case i.db.Cardinality.ONE_OR_MORE:l.attr("marker-end","url("+u+"#"+$o.ERMarkers.ONE_OR_MORE_END+")");break;case i.db.Cardinality.ONLY_ONE:l.attr("marker-end","url("+u+"#"+$o.ERMarkers.ONLY_ONE_END+")");break;case i.db.Cardinality.MD_PARENT:l.attr("marker-end","url("+u+"#"+$o.ERMarkers.MD_PARENT_END+")");break}switch(e.relSpec.cardB){case i.db.Cardinality.ZERO_OR_ONE:l.attr("marker-start","url("+u+"#"+$o.ERMarkers.ZERO_OR_ONE_START+")");break;case i.db.Cardinality.ZERO_OR_MORE:l.attr("marker-start","url("+u+"#"+$o.ERMarkers.ZERO_OR_MORE_START+")");break;case i.db.Cardinality.ONE_OR_MORE:l.attr("marker-start","url("+u+"#"+$o.ERMarkers.ONE_OR_MORE_START+")");break;case i.db.Cardinality.ONLY_ONE:l.attr("marker-start","url("+u+"#"+$o.ERMarkers.ONLY_ONE_START+")");break;case i.db.Cardinality.MD_PARENT:l.attr("marker-start","url("+u+"#"+$o.ERMarkers.MD_PARENT_START+")");break}let h=l.node().getTotalLength(),f=l.node().getPointAtLength(h*.5),d="rel"+wne,p=e.roleA.split(/
    /g),m=t.append("text").classed("er relationshipLabel",!0).attr("id",d).attr("x",f.x).attr("y",f.y).style("text-anchor","middle").style("dominant-baseline","middle").style("font-family",de().fontFamily).style("font-size",Ii.fontSize+"px");if(p.length==1)m.text(e.roleA);else{let y=-(p.length-1)*.5;p.forEach((v,x)=>{m.append("tspan").attr("x",f.x).attr("dy",`${x===0?y:1}em`).text(v)})}let g=m.node().getBBox();t.insert("rect","#"+d).classed("er relationshipLabelBox",!0).attr("x",f.x-g.width/2).attr("y",f.y-g.height/2).attr("width",g.width).attr("height",g.height)},"drawRelationshipFromLayout"),tMe=o(function(t,e,r,n){Ii=de().er,V.info("Drawing ER diagram");let i=de().securityLevel,a;i==="sandbox"&&(a=$e("#i"+e));let l=(i==="sandbox"?$e(a.nodes()[0].contentDocument.body):$e("body")).select(`[id='${e}']`);$o.insertMarkers(l,Ii);let u;u=new lr({multigraph:!0,directed:!0,compound:!1}).setGraph({rankdir:Ii.layoutDirection,marginx:20,marginy:20,nodesep:100,edgesep:100,ranksep:100}).setDefaultEdgeLabel(function(){return{}});let h=QNe(l,n.db.getEntities(),u),f=JNe(n.db.getRelationships(),u);lo(u),ZNe(l,u),f.forEach(function(y){eMe(l,y,u,h,n)});let d=Ii.diagramPadding;Lt.insertTitle(l,"entityTitleText",Ii.titleTopMargin,n.db.getDiagramTitle());let p=l.node().getBBox(),m=p.width+d*2,g=p.height+d*2;Sr(l,g,m,Ii.useMaxWidth),l.attr("viewBox",`${p.x-d} ${p.y-d} ${m} ${g}`)},"draw"),rMe="28e9f9db-3c8d-5aa5-9faf-44286ae5937c";o(nMe,"generateId");o(Tne,"strWithHyphen");Ene={setConf:jNe,draw:tMe}});var iMe,Sne,Ane=R(()=>{"use strict";iMe=o(t=>` + .entityBox { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; + } + + .attributeBoxOdd { + fill: ${t.attributeBackgroundColorOdd}; + stroke: ${t.nodeBorder}; + } + + .attributeBoxEven { + fill: ${t.attributeBackgroundColorEven}; + stroke: ${t.nodeBorder}; + } + + .relationshipLabelBox { + fill: ${t.tertiaryColor}; + opacity: 0.7; + background-color: ${t.tertiaryColor}; + rect { + opacity: 0.5; + } + } + + .relationshipLine { + stroke: ${t.lineColor}; + } + + .entityTitleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.textColor}; + } + #MD_PARENT_START { + fill: #f5f5f5 !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; + } + #MD_PARENT_END { + fill: #f5f5f5 !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; + } + +`,"getStyles"),Sne=iMe});var _ne={};hr(_ne,{diagram:()=>aMe});var aMe,Lne=R(()=>{"use strict";nne();sne();Cne();Ane();aMe={parser:rne,db:ane,renderer:Ene,styles:Sne}});function Xn(t){return typeof t=="object"&&t!==null&&typeof t.$type=="string"}function xa(t){return typeof t=="object"&&t!==null&&typeof t.$refText=="string"}function ED(t){return typeof t=="object"&&t!==null&&typeof t.name=="string"&&typeof t.type=="string"&&typeof t.path=="string"}function Wd(t){return typeof t=="object"&&t!==null&&Xn(t.container)&&xa(t.reference)&&typeof t.message=="string"}function co(t){return typeof t=="object"&&t!==null&&Array.isArray(t.content)}function ef(t){return typeof t=="object"&&t!==null&&typeof t.tokenType=="object"}function zv(t){return co(t)&&typeof t.fullText=="string"}var Yd,Vo=R(()=>{"use strict";o(Xn,"isAstNode");o(xa,"isReference");o(ED,"isAstNodeDescription");o(Wd,"isLinkingError");Yd=class{static{o(this,"AbstractAstReflection")}constructor(){this.subtypes={},this.allSubtypes={}}isInstance(e,r){return Xn(e)&&this.isSubtype(e.$type,r)}isSubtype(e,r){if(e===r)return!0;let n=this.subtypes[e];n||(n=this.subtypes[e]={});let i=n[r];if(i!==void 0)return i;{let a=this.computeIsSubtype(e,r);return n[r]=a,a}}getAllSubTypes(e){let r=this.allSubtypes[e];if(r)return r;{let n=this.getAllTypes(),i=[];for(let a of n)this.isSubtype(a,e)&&i.push(a);return this.allSubtypes[e]=i,i}}};o(co,"isCompositeCstNode");o(ef,"isLeafCstNode");o(zv,"isRootCstNode")});function cMe(t){return typeof t=="string"?t:typeof t>"u"?"undefined":typeof t.toString=="function"?t.toString():Object.prototype.toString.call(t)}function hT(t){return!!t&&typeof t[Symbol.iterator]=="function"}function Kr(...t){if(t.length===1){let e=t[0];if(e instanceof uo)return e;if(hT(e))return new uo(()=>e[Symbol.iterator](),r=>r.next());if(typeof e.length=="number")return new uo(()=>({index:0}),r=>r.index1?new uo(()=>({collIndex:0,arrIndex:0}),e=>{do{if(e.iterator){let r=e.iterator.next();if(!r.done)return r;e.iterator=void 0}if(e.array){if(e.arrIndex{"use strict";uo=class t{static{o(this,"StreamImpl")}constructor(e,r){this.startFn=e,this.nextFn=r}iterator(){let e={state:this.startFn(),next:o(()=>this.nextFn(e.state),"next"),[Symbol.iterator]:()=>e};return e}[Symbol.iterator](){return this.iterator()}isEmpty(){return!!this.iterator().next().done}count(){let e=this.iterator(),r=0,n=e.next();for(;!n.done;)r++,n=e.next();return r}toArray(){let e=[],r=this.iterator(),n;do n=r.next(),n.value!==void 0&&e.push(n.value);while(!n.done);return e}toSet(){return new Set(this)}toMap(e,r){let n=this.map(i=>[e?e(i):i,r?r(i):i]);return new Map(n)}toString(){return this.join()}concat(e){let r=e[Symbol.iterator]();return new t(()=>({first:this.startFn(),firstDone:!1}),n=>{let i;if(!n.firstDone){do if(i=this.nextFn(n.first),!i.done)return i;while(!i.done);n.firstDone=!0}do if(i=r.next(),!i.done)return i;while(!i.done);return Ja})}join(e=","){let r=this.iterator(),n="",i,a=!1;do i=r.next(),i.done||(a&&(n+=e),n+=cMe(i.value)),a=!0;while(!i.done);return n}indexOf(e,r=0){let n=this.iterator(),i=0,a=n.next();for(;!a.done;){if(i>=r&&a.value===e)return i;a=n.next(),i++}return-1}every(e){let r=this.iterator(),n=r.next();for(;!n.done;){if(!e(n.value))return!1;n=r.next()}return!0}some(e){let r=this.iterator(),n=r.next();for(;!n.done;){if(e(n.value))return!0;n=r.next()}return!1}forEach(e){let r=this.iterator(),n=0,i=r.next();for(;!i.done;)e(i.value,n),i=r.next(),n++}map(e){return new t(this.startFn,r=>{let{done:n,value:i}=this.nextFn(r);return n?Ja:{done:!1,value:e(i)}})}filter(e){return new t(this.startFn,r=>{let n;do if(n=this.nextFn(r),!n.done&&e(n.value))return n;while(!n.done);return Ja})}nonNullable(){return this.filter(e=>e!=null)}reduce(e,r){let n=this.iterator(),i=r,a=n.next();for(;!a.done;)i===void 0?i=a.value:i=e(i,a.value),a=n.next();return i}reduceRight(e,r){return this.recursiveReduce(this.iterator(),e,r)}recursiveReduce(e,r,n){let i=e.next();if(i.done)return n;let a=this.recursiveReduce(e,r,n);return a===void 0?i.value:r(a,i.value)}find(e){let r=this.iterator(),n=r.next();for(;!n.done;){if(e(n.value))return n.value;n=r.next()}}findIndex(e){let r=this.iterator(),n=0,i=r.next();for(;!i.done;){if(e(i.value))return n;i=r.next(),n++}return-1}includes(e){let r=this.iterator(),n=r.next();for(;!n.done;){if(n.value===e)return!0;n=r.next()}return!1}flatMap(e){return new t(()=>({this:this.startFn()}),r=>{do{if(r.iterator){let a=r.iterator.next();if(a.done)r.iterator=void 0;else return a}let{done:n,value:i}=this.nextFn(r.this);if(!n){let a=e(i);if(hT(a))r.iterator=a[Symbol.iterator]();else return{done:!1,value:a}}}while(r.iterator);return Ja})}flat(e){if(e===void 0&&(e=1),e<=0)return this;let r=e>1?this.flat(e-1):this;return new t(()=>({this:r.startFn()}),n=>{do{if(n.iterator){let s=n.iterator.next();if(s.done)n.iterator=void 0;else return s}let{done:i,value:a}=r.nextFn(n.this);if(!i)if(hT(a))n.iterator=a[Symbol.iterator]();else return{done:!1,value:a}}while(n.iterator);return Ja})}head(){let r=this.iterator().next();if(!r.done)return r.value}tail(e=1){return new t(()=>{let r=this.startFn();for(let n=0;n({size:0,state:this.startFn()}),r=>(r.size++,r.size>e?Ja:this.nextFn(r.state)))}distinct(e){let r=new Set;return this.filter(n=>{let i=e?e(n):n;return r.has(i)?!1:(r.add(i),!0)})}exclude(e,r){let n=new Set;for(let i of e){let a=r?r(i):i;n.add(a)}return this.filter(i=>{let a=r?r(i):i;return!n.has(a)})}};o(cMe,"toString");o(hT,"isIterable");Gv=new uo(()=>{},()=>Ja),Ja=Object.freeze({done:!0,value:void 0});o(Kr,"stream");Cc=class extends uo{static{o(this,"TreeStreamImpl")}constructor(e,r,n){super(()=>({iterators:n?.includeRoot?[[e][Symbol.iterator]()]:[r(e)[Symbol.iterator]()],pruned:!1}),i=>{for(i.pruned&&(i.iterators.pop(),i.pruned=!1);i.iterators.length>0;){let s=i.iterators[i.iterators.length-1].next();if(s.done)i.iterators.pop();else return i.iterators.push(r(s.value)[Symbol.iterator]()),s}return Ja})}iterator(){let e={state:this.startFn(),next:o(()=>this.nextFn(e.state),"next"),prune:o(()=>{e.state.pruned=!0},"prune"),[Symbol.iterator]:()=>e};return e}};(function(t){function e(a){return a.reduce((s,l)=>s+l,0)}o(e,"sum"),t.sum=e;function r(a){return a.reduce((s,l)=>s*l,0)}o(r,"product"),t.product=r;function n(a){return a.reduce((s,l)=>Math.min(s,l))}o(n,"min"),t.min=n;function i(a){return a.reduce((s,l)=>Math.max(s,l))}o(i,"max"),t.max=i})(Fm||(Fm={}))});var dT={};hr(dT,{DefaultNameRegexp:()=>fT,RangeComparison:()=>Mu,compareRange:()=>Mne,findCommentNode:()=>_D,findDeclarationNodeAtOffset:()=>hMe,findLeafNodeAtOffset:()=>LD,findLeafNodeBeforeOffset:()=>Ine,flattenCst:()=>uMe,getInteriorNodes:()=>pMe,getNextNode:()=>fMe,getPreviousNode:()=>Pne,getStartlineNode:()=>dMe,inRange:()=>AD,isChildNode:()=>SD,isCommentNode:()=>CD,streamCst:()=>qd,toDocumentSegment:()=>Xd,tokenToRange:()=>zm});function qd(t){return new Cc(t,e=>co(e)?e.content:[],{includeRoot:!0})}function uMe(t){return qd(t).filter(ef)}function SD(t,e){for(;t.container;)if(t=t.container,t===e)return!0;return!1}function zm(t){return{start:{character:t.startColumn-1,line:t.startLine-1},end:{character:t.endColumn,line:t.endLine-1}}}function Xd(t){if(!t)return;let{offset:e,end:r,range:n}=t;return{range:n,offset:e,end:r,length:r-e}}function Mne(t,e){if(t.end.linee.end.line||t.start.line===e.end.line&&t.start.character>e.end.character)return Mu.After;let r=t.start.line>e.start.line||t.start.line===e.start.line&&t.start.character>=e.start.character,n=t.end.lineMu.After}function hMe(t,e,r=fT){if(t){if(e>0){let n=e-t.offset,i=t.text.charAt(n);r.test(i)||e--}return LD(t,e)}}function _D(t,e){if(t){let r=Pne(t,!0);if(r&&CD(r,e))return r;if(zv(t)){let n=t.content.findIndex(i=>!i.hidden);for(let i=n-1;i>=0;i--){let a=t.content[i];if(CD(a,e))return a}}}}function CD(t,e){return ef(t)&&e.includes(t.tokenType.name)}function LD(t,e){if(ef(t))return t;if(co(t)){let r=One(t,e,!1);if(r)return LD(r,e)}}function Ine(t,e){if(ef(t))return t;if(co(t)){let r=One(t,e,!0);if(r)return Ine(r,e)}}function One(t,e,r){let n=0,i=t.content.length-1,a;for(;n<=i;){let s=Math.floor((n+i)/2),l=t.content[s];if(l.offset<=e&&l.end>e)return l;l.end<=e?(a=r?l:void 0,n=s+1):i=s-1}return a}function Pne(t,e=!0){for(;t.container;){let r=t.container,n=r.content.indexOf(t);for(;n>0;){n--;let i=r.content[n];if(e||!i.hidden)return i}t=r}}function fMe(t,e=!0){for(;t.container;){let r=t.container,n=r.content.indexOf(t),i=r.content.length-1;for(;n{"use strict";Vo();Ds();o(qd,"streamCst");o(uMe,"flattenCst");o(SD,"isChildNode");o(zm,"tokenToRange");o(Xd,"toDocumentSegment");(function(t){t[t.Before=0]="Before",t[t.After=1]="After",t[t.OverlapFront=2]="OverlapFront",t[t.OverlapBack=3]="OverlapBack",t[t.Inside=4]="Inside"})(Mu||(Mu={}));o(Mne,"compareRange");o(AD,"inRange");fT=/^[\w\p{L}]$/u;o(hMe,"findDeclarationNodeAtOffset");o(_D,"findCommentNode");o(CD,"isCommentNode");o(LD,"findLeafNodeAtOffset");o(Ine,"findLeafNodeBeforeOffset");o(One,"binarySearch");o(Pne,"getPreviousNode");o(fMe,"getNextNode");o(dMe,"getStartlineNode");o(pMe,"getInteriorNodes");o(mMe,"getCommonParent");o(Nne,"getParentChain")});function tf(t){throw new Error("Error! The input value was not handled.")}var jd,pT=R(()=>{"use strict";jd=class extends Error{static{o(this,"ErrorWithLocation")}constructor(e,r){super(e?`${r} at ${e.range.start.line}:${e.range.start.character}`:r)}};o(tf,"assertUnreachable")});var Yv={};hr(Yv,{AbstractElement:()=>RD,AbstractRule:()=>$v,AbstractType:()=>Vv,Action:()=>aR,Alternatives:()=>sR,ArrayLiteral:()=>ND,ArrayType:()=>MD,Assignment:()=>oR,BooleanLiteral:()=>OD,CharacterRange:()=>lR,Condition:()=>mT,Conjunction:()=>BD,CrossReference:()=>uR,Disjunction:()=>zD,EndOfFile:()=>hR,Grammar:()=>$D,GrammarImport:()=>Fne,Group:()=>dR,InferredType:()=>VD,Interface:()=>UD,Keyword:()=>pR,LangiumGrammarAstReflection:()=>Gm,LangiumGrammarTerminals:()=>gMe,NamedArgument:()=>zne,NegatedToken:()=>mR,Negation:()=>HD,NumberLiteral:()=>WD,Parameter:()=>qD,ParameterReference:()=>XD,ParserRule:()=>KD,ReferenceType:()=>QD,RegexToken:()=>yR,ReturnType:()=>Gne,RuleCall:()=>xR,SimpleType:()=>eR,StringLiteral:()=>tR,TerminalAlternatives:()=>bR,TerminalGroup:()=>TR,TerminalRule:()=>yT,TerminalRuleCall:()=>ER,Type:()=>rR,TypeAttribute:()=>$ne,TypeDefinition:()=>DD,UnionType:()=>nR,UnorderedGroup:()=>CR,UntilToken:()=>SR,ValueLiteral:()=>gT,Wildcard:()=>_R,isAbstractElement:()=>Uv,isAbstractRule:()=>yMe,isAbstractType:()=>vMe,isAction:()=>Iu,isAlternatives:()=>wT,isArrayLiteral:()=>kMe,isArrayType:()=>ID,isAssignment:()=>Nl,isBooleanLiteral:()=>PD,isCharacterRange:()=>cR,isCondition:()=>xMe,isConjunction:()=>FD,isCrossReference:()=>Kd,isDisjunction:()=>GD,isEndOfFile:()=>fR,isFeatureName:()=>bMe,isGrammar:()=>EMe,isGrammarImport:()=>CMe,isGroup:()=>rf,isInferredType:()=>vT,isInterface:()=>xT,isKeyword:()=>Ho,isNamedArgument:()=>SMe,isNegatedToken:()=>gR,isNegation:()=>YD,isNumberLiteral:()=>AMe,isParameter:()=>_Me,isParameterReference:()=>jD,isParserRule:()=>Oa,isPrimitiveType:()=>Bne,isReferenceType:()=>ZD,isRegexToken:()=>vR,isReturnType:()=>JD,isRuleCall:()=>Ml,isSimpleType:()=>bT,isStringLiteral:()=>LMe,isTerminalAlternatives:()=>wR,isTerminalGroup:()=>kR,isTerminalRule:()=>Uo,isTerminalRuleCall:()=>TT,isType:()=>Hv,isTypeAttribute:()=>DMe,isTypeDefinition:()=>wMe,isUnionType:()=>iR,isUnorderedGroup:()=>kT,isUntilToken:()=>AR,isValueLiteral:()=>TMe,isWildcard:()=>LR,reflection:()=>Kt});function yMe(t){return Kt.isInstance(t,$v)}function vMe(t){return Kt.isInstance(t,Vv)}function xMe(t){return Kt.isInstance(t,mT)}function bMe(t){return Bne(t)||t==="current"||t==="entry"||t==="extends"||t==="false"||t==="fragment"||t==="grammar"||t==="hidden"||t==="import"||t==="interface"||t==="returns"||t==="terminal"||t==="true"||t==="type"||t==="infer"||t==="infers"||t==="with"||typeof t=="string"&&/\^?[_a-zA-Z][\w_]*/.test(t)}function Bne(t){return t==="string"||t==="number"||t==="boolean"||t==="Date"||t==="bigint"}function wMe(t){return Kt.isInstance(t,DD)}function TMe(t){return Kt.isInstance(t,gT)}function Uv(t){return Kt.isInstance(t,RD)}function kMe(t){return Kt.isInstance(t,ND)}function ID(t){return Kt.isInstance(t,MD)}function PD(t){return Kt.isInstance(t,OD)}function FD(t){return Kt.isInstance(t,BD)}function GD(t){return Kt.isInstance(t,zD)}function EMe(t){return Kt.isInstance(t,$D)}function CMe(t){return Kt.isInstance(t,Fne)}function vT(t){return Kt.isInstance(t,VD)}function xT(t){return Kt.isInstance(t,UD)}function SMe(t){return Kt.isInstance(t,zne)}function YD(t){return Kt.isInstance(t,HD)}function AMe(t){return Kt.isInstance(t,WD)}function _Me(t){return Kt.isInstance(t,qD)}function jD(t){return Kt.isInstance(t,XD)}function Oa(t){return Kt.isInstance(t,KD)}function ZD(t){return Kt.isInstance(t,QD)}function JD(t){return Kt.isInstance(t,Gne)}function bT(t){return Kt.isInstance(t,eR)}function LMe(t){return Kt.isInstance(t,tR)}function Uo(t){return Kt.isInstance(t,yT)}function Hv(t){return Kt.isInstance(t,rR)}function DMe(t){return Kt.isInstance(t,$ne)}function iR(t){return Kt.isInstance(t,nR)}function Iu(t){return Kt.isInstance(t,aR)}function wT(t){return Kt.isInstance(t,sR)}function Nl(t){return Kt.isInstance(t,oR)}function cR(t){return Kt.isInstance(t,lR)}function Kd(t){return Kt.isInstance(t,uR)}function fR(t){return Kt.isInstance(t,hR)}function rf(t){return Kt.isInstance(t,dR)}function Ho(t){return Kt.isInstance(t,pR)}function gR(t){return Kt.isInstance(t,mR)}function vR(t){return Kt.isInstance(t,yR)}function Ml(t){return Kt.isInstance(t,xR)}function wR(t){return Kt.isInstance(t,bR)}function kR(t){return Kt.isInstance(t,TR)}function TT(t){return Kt.isInstance(t,ER)}function kT(t){return Kt.isInstance(t,CR)}function AR(t){return Kt.isInstance(t,SR)}function LR(t){return Kt.isInstance(t,_R)}var gMe,$v,Vv,mT,DD,gT,RD,ND,MD,OD,BD,zD,$D,Fne,VD,UD,zne,HD,WD,qD,XD,KD,QD,Gne,eR,tR,yT,rR,$ne,nR,aR,sR,oR,lR,uR,hR,dR,pR,mR,yR,xR,bR,TR,ER,CR,SR,_R,Gm,Kt,Sc=R(()=>{"use strict";Vo();gMe={ID:/\^?[_a-zA-Z][\w_]*/,STRING:/"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/,NUMBER:/NaN|-?((\d*\.\d+|\d+)([Ee][+-]?\d+)?|Infinity)/,RegexLiteral:/\/(?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\/[a-z]*/,WS:/\s+/,ML_COMMENT:/\/\*[\s\S]*?\*\//,SL_COMMENT:/\/\/[^\n\r]*/},$v="AbstractRule";o(yMe,"isAbstractRule");Vv="AbstractType";o(vMe,"isAbstractType");mT="Condition";o(xMe,"isCondition");o(bMe,"isFeatureName");o(Bne,"isPrimitiveType");DD="TypeDefinition";o(wMe,"isTypeDefinition");gT="ValueLiteral";o(TMe,"isValueLiteral");RD="AbstractElement";o(Uv,"isAbstractElement");ND="ArrayLiteral";o(kMe,"isArrayLiteral");MD="ArrayType";o(ID,"isArrayType");OD="BooleanLiteral";o(PD,"isBooleanLiteral");BD="Conjunction";o(FD,"isConjunction");zD="Disjunction";o(GD,"isDisjunction");$D="Grammar";o(EMe,"isGrammar");Fne="GrammarImport";o(CMe,"isGrammarImport");VD="InferredType";o(vT,"isInferredType");UD="Interface";o(xT,"isInterface");zne="NamedArgument";o(SMe,"isNamedArgument");HD="Negation";o(YD,"isNegation");WD="NumberLiteral";o(AMe,"isNumberLiteral");qD="Parameter";o(_Me,"isParameter");XD="ParameterReference";o(jD,"isParameterReference");KD="ParserRule";o(Oa,"isParserRule");QD="ReferenceType";o(ZD,"isReferenceType");Gne="ReturnType";o(JD,"isReturnType");eR="SimpleType";o(bT,"isSimpleType");tR="StringLiteral";o(LMe,"isStringLiteral");yT="TerminalRule";o(Uo,"isTerminalRule");rR="Type";o(Hv,"isType");$ne="TypeAttribute";o(DMe,"isTypeAttribute");nR="UnionType";o(iR,"isUnionType");aR="Action";o(Iu,"isAction");sR="Alternatives";o(wT,"isAlternatives");oR="Assignment";o(Nl,"isAssignment");lR="CharacterRange";o(cR,"isCharacterRange");uR="CrossReference";o(Kd,"isCrossReference");hR="EndOfFile";o(fR,"isEndOfFile");dR="Group";o(rf,"isGroup");pR="Keyword";o(Ho,"isKeyword");mR="NegatedToken";o(gR,"isNegatedToken");yR="RegexToken";o(vR,"isRegexToken");xR="RuleCall";o(Ml,"isRuleCall");bR="TerminalAlternatives";o(wR,"isTerminalAlternatives");TR="TerminalGroup";o(kR,"isTerminalGroup");ER="TerminalRuleCall";o(TT,"isTerminalRuleCall");CR="UnorderedGroup";o(kT,"isUnorderedGroup");SR="UntilToken";o(AR,"isUntilToken");_R="Wildcard";o(LR,"isWildcard");Gm=class extends Yd{static{o(this,"LangiumGrammarAstReflection")}getAllTypes(){return["AbstractElement","AbstractRule","AbstractType","Action","Alternatives","ArrayLiteral","ArrayType","Assignment","BooleanLiteral","CharacterRange","Condition","Conjunction","CrossReference","Disjunction","EndOfFile","Grammar","GrammarImport","Group","InferredType","Interface","Keyword","NamedArgument","NegatedToken","Negation","NumberLiteral","Parameter","ParameterReference","ParserRule","ReferenceType","RegexToken","ReturnType","RuleCall","SimpleType","StringLiteral","TerminalAlternatives","TerminalGroup","TerminalRule","TerminalRuleCall","Type","TypeAttribute","TypeDefinition","UnionType","UnorderedGroup","UntilToken","ValueLiteral","Wildcard"]}computeIsSubtype(e,r){switch(e){case aR:case sR:case oR:case lR:case uR:case hR:case dR:case pR:case mR:case yR:case xR:case bR:case TR:case ER:case CR:case SR:case _R:return this.isSubtype(RD,r);case ND:case WD:case tR:return this.isSubtype(gT,r);case MD:case QD:case eR:case nR:return this.isSubtype(DD,r);case OD:return this.isSubtype(mT,r)||this.isSubtype(gT,r);case BD:case zD:case HD:case XD:return this.isSubtype(mT,r);case VD:case UD:case rR:return this.isSubtype(Vv,r);case KD:return this.isSubtype($v,r)||this.isSubtype(Vv,r);case yT:return this.isSubtype($v,r);default:return!1}}getReferenceType(e){let r=`${e.container.$type}:${e.property}`;switch(r){case"Action:type":case"CrossReference:type":case"Interface:superTypes":case"ParserRule:returnType":case"SimpleType:typeRef":return Vv;case"Grammar:hiddenTokens":case"ParserRule:hiddenTokens":case"RuleCall:rule":return $v;case"Grammar:usedGrammars":return $D;case"NamedArgument:parameter":case"ParameterReference:parameter":return qD;case"TerminalRuleCall:rule":return yT;default:throw new Error(`${r} is not a valid reference id.`)}}getTypeMetaData(e){switch(e){case"AbstractElement":return{name:"AbstractElement",properties:[{name:"cardinality"},{name:"lookahead"}]};case"ArrayLiteral":return{name:"ArrayLiteral",properties:[{name:"elements",defaultValue:[]}]};case"ArrayType":return{name:"ArrayType",properties:[{name:"elementType"}]};case"BooleanLiteral":return{name:"BooleanLiteral",properties:[{name:"true",defaultValue:!1}]};case"Conjunction":return{name:"Conjunction",properties:[{name:"left"},{name:"right"}]};case"Disjunction":return{name:"Disjunction",properties:[{name:"left"},{name:"right"}]};case"Grammar":return{name:"Grammar",properties:[{name:"definesHiddenTokens",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"imports",defaultValue:[]},{name:"interfaces",defaultValue:[]},{name:"isDeclared",defaultValue:!1},{name:"name"},{name:"rules",defaultValue:[]},{name:"types",defaultValue:[]},{name:"usedGrammars",defaultValue:[]}]};case"GrammarImport":return{name:"GrammarImport",properties:[{name:"path"}]};case"InferredType":return{name:"InferredType",properties:[{name:"name"}]};case"Interface":return{name:"Interface",properties:[{name:"attributes",defaultValue:[]},{name:"name"},{name:"superTypes",defaultValue:[]}]};case"NamedArgument":return{name:"NamedArgument",properties:[{name:"calledByName",defaultValue:!1},{name:"parameter"},{name:"value"}]};case"Negation":return{name:"Negation",properties:[{name:"value"}]};case"NumberLiteral":return{name:"NumberLiteral",properties:[{name:"value"}]};case"Parameter":return{name:"Parameter",properties:[{name:"name"}]};case"ParameterReference":return{name:"ParameterReference",properties:[{name:"parameter"}]};case"ParserRule":return{name:"ParserRule",properties:[{name:"dataType"},{name:"definesHiddenTokens",defaultValue:!1},{name:"definition"},{name:"entry",defaultValue:!1},{name:"fragment",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"inferredType"},{name:"name"},{name:"parameters",defaultValue:[]},{name:"returnType"},{name:"wildcard",defaultValue:!1}]};case"ReferenceType":return{name:"ReferenceType",properties:[{name:"referenceType"}]};case"ReturnType":return{name:"ReturnType",properties:[{name:"name"}]};case"SimpleType":return{name:"SimpleType",properties:[{name:"primitiveType"},{name:"stringType"},{name:"typeRef"}]};case"StringLiteral":return{name:"StringLiteral",properties:[{name:"value"}]};case"TerminalRule":return{name:"TerminalRule",properties:[{name:"definition"},{name:"fragment",defaultValue:!1},{name:"hidden",defaultValue:!1},{name:"name"},{name:"type"}]};case"Type":return{name:"Type",properties:[{name:"name"},{name:"type"}]};case"TypeAttribute":return{name:"TypeAttribute",properties:[{name:"defaultValue"},{name:"isOptional",defaultValue:!1},{name:"name"},{name:"type"}]};case"UnionType":return{name:"UnionType",properties:[{name:"types",defaultValue:[]}]};case"Action":return{name:"Action",properties:[{name:"cardinality"},{name:"feature"},{name:"inferredType"},{name:"lookahead"},{name:"operator"},{name:"type"}]};case"Alternatives":return{name:"Alternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"Assignment":return{name:"Assignment",properties:[{name:"cardinality"},{name:"feature"},{name:"lookahead"},{name:"operator"},{name:"terminal"}]};case"CharacterRange":return{name:"CharacterRange",properties:[{name:"cardinality"},{name:"left"},{name:"lookahead"},{name:"right"}]};case"CrossReference":return{name:"CrossReference",properties:[{name:"cardinality"},{name:"deprecatedSyntax",defaultValue:!1},{name:"lookahead"},{name:"terminal"},{name:"type"}]};case"EndOfFile":return{name:"EndOfFile",properties:[{name:"cardinality"},{name:"lookahead"}]};case"Group":return{name:"Group",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"guardCondition"},{name:"lookahead"}]};case"Keyword":return{name:"Keyword",properties:[{name:"cardinality"},{name:"lookahead"},{name:"value"}]};case"NegatedToken":return{name:"NegatedToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"RegexToken":return{name:"RegexToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"regex"}]};case"RuleCall":return{name:"RuleCall",properties:[{name:"arguments",defaultValue:[]},{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"TerminalAlternatives":return{name:"TerminalAlternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalGroup":return{name:"TerminalGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalRuleCall":return{name:"TerminalRuleCall",properties:[{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"UnorderedGroup":return{name:"UnorderedGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"UntilToken":return{name:"UntilToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"Wildcard":return{name:"Wildcard",properties:[{name:"cardinality"},{name:"lookahead"}]};default:return{name:e,properties:[]}}}},Kt=new Gm});var CT={};hr(CT,{assignMandatoryProperties:()=>NR,copyAstNode:()=>RR,findLocalReferences:()=>NMe,findRootNode:()=>Vne,getContainerOfType:()=>Qd,getDocument:()=>Oi,hasContainerOfType:()=>RMe,linkContentToContainer:()=>ET,streamAllContents:()=>Ac,streamAst:()=>Yo,streamContents:()=>Wv,streamReferences:()=>$m});function ET(t){for(let[e,r]of Object.entries(t))e.startsWith("$")||(Array.isArray(r)?r.forEach((n,i)=>{Xn(n)&&(n.$container=t,n.$containerProperty=e,n.$containerIndex=i)}):Xn(r)&&(r.$container=t,r.$containerProperty=e))}function Qd(t,e){let r=t;for(;r;){if(e(r))return r;r=r.$container}}function RMe(t,e){let r=t;for(;r;){if(e(r))return!0;r=r.$container}return!1}function Oi(t){let r=Vne(t).$document;if(!r)throw new Error("AST node has no document.");return r}function Vne(t){for(;t.$container;)t=t.$container;return t}function Wv(t,e){if(!t)throw new Error("Node must be an AstNode.");let r=e?.range;return new uo(()=>({keys:Object.keys(t),keyIndex:0,arrayIndex:0}),n=>{for(;n.keyIndexWv(r,e))}function Yo(t,e){if(t){if(e?.range&&!DR(t,e.range))return new Cc(t,()=>[])}else throw new Error("Root node must be an AstNode.");return new Cc(t,r=>Wv(r,e),{includeRoot:!0})}function DR(t,e){var r;if(!e)return!0;let n=(r=t.$cstNode)===null||r===void 0?void 0:r.range;return n?AD(n,e):!1}function $m(t){return new uo(()=>({keys:Object.keys(t),keyIndex:0,arrayIndex:0}),e=>{for(;e.keyIndex{$m(n).forEach(i=>{i.reference.ref===t&&r.push(i.reference)})}),Kr(r)}function NR(t,e){let r=t.getTypeMetaData(e.$type),n=e;for(let i of r.properties)i.defaultValue!==void 0&&n[i.name]===void 0&&(n[i.name]=Une(i.defaultValue))}function Une(t){return Array.isArray(t)?[...t.map(Une)]:t}function RR(t,e){let r={$type:t.$type};for(let[n,i]of Object.entries(t))if(!n.startsWith("$"))if(Xn(i))r[n]=RR(i,e);else if(xa(i))r[n]=e(r,n,i.$refNode,i.$refText);else if(Array.isArray(i)){let a=[];for(let s of i)Xn(s)?a.push(RR(s,e)):xa(s)?a.push(e(r,n,s.$refNode,s.$refText)):a.push(s);r[n]=a}else r[n]=i;return ET(r),r}var es=R(()=>{"use strict";Vo();Ds();Rl();o(ET,"linkContentToContainer");o(Qd,"getContainerOfType");o(RMe,"hasContainerOfType");o(Oi,"getDocument");o(Vne,"findRootNode");o(Wv,"streamContents");o(Ac,"streamAllContents");o(Yo,"streamAst");o(DR,"isAstNodeInRange");o($m,"streamReferences");o(NMe,"findLocalReferences");o(NR,"assignMandatoryProperties");o(Une,"copyDefaultValue");o(RR,"copyAstNode")});function qt(t){return t.charCodeAt(0)}function ST(t,e){Array.isArray(t)?t.forEach(function(r){e.push(r)}):e.push(t)}function Vm(t,e){if(t[e]===!0)throw"duplicate flag "+e;let r=t[e];t[e]=!0}function Zd(t){if(t===void 0)throw Error("Internal Error - Should never get here!");return!0}function qv(){throw Error("Internal Error - Should never get here!")}function MR(t){return t.type==="Character"}var IR=R(()=>{"use strict";o(qt,"cc");o(ST,"insertToSet");o(Vm,"addFlag");o(Zd,"ASSERT_EXISTS");o(qv,"ASSERT_NEVER_REACH_HERE");o(MR,"isCharacter")});var Xv,jv,OR,Hne=R(()=>{"use strict";IR();Xv=[];for(let t=qt("0");t<=qt("9");t++)Xv.push(t);jv=[qt("_")].concat(Xv);for(let t=qt("a");t<=qt("z");t++)jv.push(t);for(let t=qt("A");t<=qt("Z");t++)jv.push(t);OR=[qt(" "),qt("\f"),qt(` +`),qt("\r"),qt(" "),qt("\v"),qt(" "),qt("\xA0"),qt("\u1680"),qt("\u2000"),qt("\u2001"),qt("\u2002"),qt("\u2003"),qt("\u2004"),qt("\u2005"),qt("\u2006"),qt("\u2007"),qt("\u2008"),qt("\u2009"),qt("\u200A"),qt("\u2028"),qt("\u2029"),qt("\u202F"),qt("\u205F"),qt("\u3000"),qt("\uFEFF")]});var MMe,AT,IMe,Jd,Yne=R(()=>{"use strict";IR();Hne();MMe=/[0-9a-fA-F]/,AT=/[0-9]/,IMe=/[1-9]/,Jd=class{static{o(this,"RegExpParser")}constructor(){this.idx=0,this.input="",this.groupIdx=0}saveState(){return{idx:this.idx,input:this.input,groupIdx:this.groupIdx}}restoreState(e){this.idx=e.idx,this.input=e.input,this.groupIdx=e.groupIdx}pattern(e){this.idx=0,this.input=e,this.groupIdx=0,this.consumeChar("/");let r=this.disjunction();this.consumeChar("/");let n={type:"Flags",loc:{begin:this.idx,end:e.length},global:!1,ignoreCase:!1,multiLine:!1,unicode:!1,sticky:!1};for(;this.isRegExpFlag();)switch(this.popChar()){case"g":Vm(n,"global");break;case"i":Vm(n,"ignoreCase");break;case"m":Vm(n,"multiLine");break;case"u":Vm(n,"unicode");break;case"y":Vm(n,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:n,value:r,loc:this.loc(0)}}disjunction(){let e=[],r=this.idx;for(e.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),e.push(this.alternative());return{type:"Disjunction",value:e,loc:this.loc(r)}}alternative(){let e=[],r=this.idx;for(;this.isTerm();)e.push(this.term());return{type:"Alternative",value:e,loc:this.loc(r)}}term(){return this.isAssertion()?this.assertion():this.atom()}assertion(){let e=this.idx;switch(this.popChar()){case"^":return{type:"StartAnchor",loc:this.loc(e)};case"$":return{type:"EndAnchor",loc:this.loc(e)};case"\\":switch(this.popChar()){case"b":return{type:"WordBoundary",loc:this.loc(e)};case"B":return{type:"NonWordBoundary",loc:this.loc(e)}}throw Error("Invalid Assertion Escape");case"(":this.consumeChar("?");let r;switch(this.popChar()){case"=":r="Lookahead";break;case"!":r="NegativeLookahead";break}Zd(r);let n=this.disjunction();return this.consumeChar(")"),{type:r,value:n,loc:this.loc(e)}}return qv()}quantifier(e=!1){let r,n=this.idx;switch(this.popChar()){case"*":r={atLeast:0,atMost:1/0};break;case"+":r={atLeast:1,atMost:1/0};break;case"?":r={atLeast:0,atMost:1};break;case"{":let i=this.integerIncludingZero();switch(this.popChar()){case"}":r={atLeast:i,atMost:i};break;case",":let a;this.isDigit()?(a=this.integerIncludingZero(),r={atLeast:i,atMost:a}):r={atLeast:i,atMost:1/0},this.consumeChar("}");break}if(e===!0&&r===void 0)return;Zd(r);break}if(!(e===!0&&r===void 0)&&Zd(r))return this.peekChar(0)==="?"?(this.consumeChar("?"),r.greedy=!1):r.greedy=!0,r.type="Quantifier",r.loc=this.loc(n),r}atom(){let e,r=this.idx;switch(this.peekChar()){case".":e=this.dotAll();break;case"\\":e=this.atomEscape();break;case"[":e=this.characterClass();break;case"(":e=this.group();break}return e===void 0&&this.isPatternCharacter()&&(e=this.patternCharacter()),Zd(e)?(e.loc=this.loc(r),this.isQuantifier()&&(e.quantifier=this.quantifier()),e):qv()}dotAll(){return this.consumeChar("."),{type:"Set",complement:!0,value:[qt(` +`),qt("\r"),qt("\u2028"),qt("\u2029")]}}atomEscape(){switch(this.consumeChar("\\"),this.peekChar()){case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":return this.decimalEscapeAtom();case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}}decimalEscapeAtom(){return{type:"GroupBackReference",value:this.positiveInteger()}}characterClassEscape(){let e,r=!1;switch(this.popChar()){case"d":e=Xv;break;case"D":e=Xv,r=!0;break;case"s":e=OR;break;case"S":e=OR,r=!0;break;case"w":e=jv;break;case"W":e=jv,r=!0;break}return Zd(e)?{type:"Set",value:e,complement:r}:qv()}controlEscapeAtom(){let e;switch(this.popChar()){case"f":e=qt("\f");break;case"n":e=qt(` +`);break;case"r":e=qt("\r");break;case"t":e=qt(" ");break;case"v":e=qt("\v");break}return Zd(e)?{type:"Character",value:e}:qv()}controlLetterEscapeAtom(){this.consumeChar("c");let e=this.popChar();if(/[a-zA-Z]/.test(e)===!1)throw Error("Invalid ");return{type:"Character",value:e.toUpperCase().charCodeAt(0)-64}}nulCharacterAtom(){return this.consumeChar("0"),{type:"Character",value:qt("\0")}}hexEscapeSequenceAtom(){return this.consumeChar("x"),this.parseHexDigits(2)}regExpUnicodeEscapeSequenceAtom(){return this.consumeChar("u"),this.parseHexDigits(4)}identityEscapeAtom(){let e=this.popChar();return{type:"Character",value:qt(e)}}classPatternCharacterAtom(){switch(this.peekChar()){case` +`:case"\r":case"\u2028":case"\u2029":case"\\":case"]":throw Error("TBD");default:let e=this.popChar();return{type:"Character",value:qt(e)}}}characterClass(){let e=[],r=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),r=!0);this.isClassAtom();){let n=this.classAtom(),i=n.type==="Character";if(MR(n)&&this.isRangeDash()){this.consumeChar("-");let a=this.classAtom(),s=a.type==="Character";if(MR(a)){if(a.value=this.input.length)throw Error("Unexpected end of input");this.idx++}loc(e){return{begin:e,end:this.idx}}}});var _c,Wne=R(()=>{"use strict";_c=class{static{o(this,"BaseRegExpVisitor")}visitChildren(e){for(let r in e){let n=e[r];e.hasOwnProperty(r)&&(n.type!==void 0?this.visit(n):Array.isArray(n)&&n.forEach(i=>{this.visit(i)},this))}}visit(e){switch(e.type){case"Pattern":this.visitPattern(e);break;case"Flags":this.visitFlags(e);break;case"Disjunction":this.visitDisjunction(e);break;case"Alternative":this.visitAlternative(e);break;case"StartAnchor":this.visitStartAnchor(e);break;case"EndAnchor":this.visitEndAnchor(e);break;case"WordBoundary":this.visitWordBoundary(e);break;case"NonWordBoundary":this.visitNonWordBoundary(e);break;case"Lookahead":this.visitLookahead(e);break;case"NegativeLookahead":this.visitNegativeLookahead(e);break;case"Character":this.visitCharacter(e);break;case"Set":this.visitSet(e);break;case"Group":this.visitGroup(e);break;case"GroupBackReference":this.visitGroupBackReference(e);break;case"Quantifier":this.visitQuantifier(e);break}this.visitChildren(e)}visitPattern(e){}visitFlags(e){}visitDisjunction(e){}visitAlternative(e){}visitStartAnchor(e){}visitEndAnchor(e){}visitWordBoundary(e){}visitNonWordBoundary(e){}visitLookahead(e){}visitNegativeLookahead(e){}visitCharacter(e){}visitSet(e){}visitGroup(e){}visitGroupBackReference(e){}visitQuantifier(e){}}});var Kv=R(()=>{"use strict";Yne();Wne()});var LT={};hr(LT,{NEWLINE_REGEXP:()=>BR,escapeRegExp:()=>t0,getCaseInsensitivePattern:()=>zR,getTerminalParts:()=>OMe,isMultilineComment:()=>FR,isWhitespace:()=>_T,partialMatches:()=>GR,partialRegExp:()=>Xne});function OMe(t){try{typeof t!="string"&&(t=t.source),t=`/${t}/`;let e=qne.pattern(t),r=[];for(let n of e.value.value)e0.reset(t),e0.visit(n),r.push({start:e0.startRegexp,end:e0.endRegex});return r}catch{return[]}}function FR(t){try{return typeof t=="string"&&(t=new RegExp(t)),t=t.toString(),e0.reset(t),e0.visit(qne.pattern(t)),e0.multiline}catch{return!1}}function _T(t){return(typeof t=="string"?new RegExp(t):t).test(" ")}function t0(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function zR(t){return Array.prototype.map.call(t,e=>/\w/.test(e)?`[${e.toLowerCase()}${e.toUpperCase()}]`:t0(e)).join("")}function GR(t,e){let r=Xne(t),n=e.match(r);return!!n&&n[0].length>0}function Xne(t){typeof t=="string"&&(t=new RegExp(t));let e=t,r=t.source,n=0;function i(){let a="",s;function l(h){a+=r.substr(n,h),n+=h}o(l,"appendRaw");function u(h){a+="(?:"+r.substr(n,h)+"|$)",n+=h}for(o(u,"appendOptional");n",n)-n+1);break;default:u(2);break}break;case"[":s=/\[(?:\\.|.)*?\]/g,s.lastIndex=n,s=s.exec(r)||[],u(s[0].length);break;case"|":case"^":case"$":case"*":case"+":case"?":l(1);break;case"{":s=/\{\d+,?\d*\}/g,s.lastIndex=n,s=s.exec(r),s?l(s[0].length):u(1);break;case"(":if(r[n+1]==="?")switch(r[n+2]){case":":a+="(?:",n+=3,a+=i()+"|$)";break;case"=":a+="(?=",n+=3,a+=i()+")";break;case"!":s=n,n+=3,i(),a+=r.substr(s,n-s);break;case"<":switch(r[n+3]){case"=":case"!":s=n,n+=4,i(),a+=r.substr(s,n-s);break;default:l(r.indexOf(">",n)-n+1),a+=i()+"|$)";break}break}else l(1),a+=i()+"|$)";break;case")":return++n,a;default:u(1);break}return a}return o(i,"process"),new RegExp(i(),t.flags)}var BR,qne,PR,e0,Um=R(()=>{"use strict";Kv();BR=/\r?\n/gm,qne=new Jd,PR=class extends _c{static{o(this,"TerminalRegExpVisitor")}constructor(){super(...arguments),this.isStarting=!0,this.endRegexpStack=[],this.multiline=!1}get endRegex(){return this.endRegexpStack.join("")}reset(e){this.multiline=!1,this.regex=e,this.startRegexp="",this.isStarting=!0,this.endRegexpStack=[]}visitGroup(e){e.quantifier&&(this.isStarting=!1,this.endRegexpStack=[])}visitCharacter(e){let r=String.fromCharCode(e.value);if(!this.multiline&&r===` +`&&(this.multiline=!0),e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{let n=t0(r);this.endRegexpStack.push(n),this.isStarting&&(this.startRegexp+=n)}}visitSet(e){if(!this.multiline){let r=this.regex.substring(e.loc.begin,e.loc.end),n=new RegExp(r);this.multiline=!!` +`.match(n)}if(e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{let r=this.regex.substring(e.loc.begin,e.loc.end);this.endRegexpStack.push(r),this.isStarting&&(this.startRegexp+=r)}}visitChildren(e){e.type==="Group"&&e.quantifier||super.visitChildren(e)}},e0=new PR;o(OMe,"getTerminalParts");o(FR,"isMultilineComment");o(_T,"isWhitespace");o(t0,"escapeRegExp");o(zR,"getCaseInsensitivePattern");o(GR,"partialMatches");o(Xne,"partialRegExp")});var RT={};hr(RT,{findAssignment:()=>jR,findNameAssignment:()=>DT,findNodeForKeyword:()=>qR,findNodeForProperty:()=>Zv,findNodesForKeyword:()=>PMe,findNodesForKeywordInternal:()=>XR,findNodesForProperty:()=>YR,getActionAtElement:()=>Jne,getActionType:()=>tie,getAllReachableRules:()=>Qv,getCrossReferenceTerminal:()=>UR,getEntryRule:()=>jne,getExplicitRuleType:()=>KR,getHiddenRules:()=>Kne,getRuleType:()=>QR,getTypeName:()=>r0,isArrayCardinality:()=>FMe,isArrayOperator:()=>zMe,isCommentTerminal:()=>HR,isDataType:()=>GMe,isDataTypeRule:()=>Jv,isOptionalCardinality:()=>BMe,terminalRegex:()=>Hm});function jne(t){return t.rules.find(e=>Oa(e)&&e.entry)}function Kne(t){return t.rules.filter(e=>Uo(e)&&e.hidden)}function Qv(t,e){let r=new Set,n=jne(t);if(!n)return new Set(t.rules);let i=[n].concat(Kne(t));for(let s of i)Qne(s,r,e);let a=new Set;for(let s of t.rules)(r.has(s.name)||Uo(s)&&s.hidden)&&a.add(s);return a}function Qne(t,e,r){e.add(t.name),Ac(t).forEach(n=>{if(Ml(n)||r&&TT(n)){let i=n.rule.ref;i&&!e.has(i.name)&&Qne(i,e,r)}})}function UR(t){if(t.terminal)return t.terminal;if(t.type.ref){let e=DT(t.type.ref);return e?.terminal}}function HR(t){return t.hidden&&!Hm(t).test(" ")}function YR(t,e){return!t||!e?[]:WR(t,e,t.astNode,!0)}function Zv(t,e,r){if(!t||!e)return;let n=WR(t,e,t.astNode,!0);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}function WR(t,e,r,n){if(!n){let i=Qd(t.grammarSource,Nl);if(i&&i.feature===e)return[t]}return co(t)&&t.astNode===r?t.content.flatMap(i=>WR(i,e,r,!1)):[]}function PMe(t,e){return t?XR(t,e,t?.astNode):[]}function qR(t,e,r){if(!t)return;let n=XR(t,e,t?.astNode);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}function XR(t,e,r){if(t.astNode!==r)return[];if(Ho(t.grammarSource)&&t.grammarSource.value===e)return[t];let n=qd(t).iterator(),i,a=[];do if(i=n.next(),!i.done){let s=i.value;s.astNode===r?Ho(s.grammarSource)&&s.grammarSource.value===e&&a.push(s):n.prune()}while(!i.done);return a}function jR(t){var e;let r=t.astNode;for(;r===((e=t.container)===null||e===void 0?void 0:e.astNode);){let n=Qd(t.grammarSource,Nl);if(n)return n;t=t.container}}function DT(t){let e=t;return vT(e)&&(Iu(e.$container)?e=e.$container.$container:Oa(e.$container)?e=e.$container:tf(e.$container)),Zne(t,e,new Map)}function Zne(t,e,r){var n;function i(a,s){let l;return Qd(a,Nl)||(l=Zne(s,s,r)),r.set(t,l),l}if(o(i,"go"),r.has(t))return r.get(t);r.set(t,void 0);for(let a of Ac(e)){if(Nl(a)&&a.feature.toLowerCase()==="name")return r.set(t,a),a;if(Ml(a)&&Oa(a.rule.ref))return i(a,a.rule.ref);if(bT(a)&&(!((n=a.typeRef)===null||n===void 0)&&n.ref))return i(a,a.typeRef.ref)}}function Jne(t){let e=t.$container;if(rf(e)){let r=e.elements,n=r.indexOf(t);for(let i=n-1;i>=0;i--){let a=r[i];if(Iu(a))return a;{let s=Ac(r[i]).find(Iu);if(s)return s}}}if(Uv(e))return Jne(e)}function BMe(t,e){return t==="?"||t==="*"||rf(e)&&!!e.guardCondition}function FMe(t){return t==="*"||t==="+"}function zMe(t){return t==="+="}function Jv(t){return eie(t,new Set)}function eie(t,e){if(e.has(t))return!0;e.add(t);for(let r of Ac(t))if(Ml(r)){if(!r.rule.ref||Oa(r.rule.ref)&&!eie(r.rule.ref,e))return!1}else{if(Nl(r))return!1;if(Iu(r))return!1}return!!t.definition}function GMe(t){return VR(t.type,new Set)}function VR(t,e){if(e.has(t))return!0;if(e.add(t),ID(t))return!1;if(ZD(t))return!1;if(iR(t))return t.types.every(r=>VR(r,e));if(bT(t)){if(t.primitiveType!==void 0)return!0;if(t.stringType!==void 0)return!0;if(t.typeRef!==void 0){let r=t.typeRef.ref;return Hv(r)?VR(r.type,e):!1}else return!1}else return!1}function KR(t){if(t.inferredType)return t.inferredType.name;if(t.dataType)return t.dataType;if(t.returnType){let e=t.returnType.ref;if(e){if(Oa(e))return e.name;if(xT(e)||Hv(e))return e.name}}}function r0(t){var e;if(Oa(t))return Jv(t)?t.name:(e=KR(t))!==null&&e!==void 0?e:t.name;if(xT(t)||Hv(t)||JD(t))return t.name;if(Iu(t)){let r=tie(t);if(r)return r}else if(vT(t))return t.name;throw new Error("Cannot get name of Unknown Type")}function tie(t){var e;if(t.inferredType)return t.inferredType.name;if(!((e=t.type)===null||e===void 0)&&e.ref)return r0(t.type.ref)}function QR(t){var e,r,n;return Uo(t)?(r=(e=t.type)===null||e===void 0?void 0:e.name)!==null&&r!==void 0?r:"string":Jv(t)?t.name:(n=KR(t))!==null&&n!==void 0?n:t.name}function Hm(t){let e={s:!1,i:!1,u:!1},r=Ym(t.definition,e),n=Object.entries(e).filter(([,i])=>i).map(([i])=>i).join("");return new RegExp(r,n)}function Ym(t,e){if(wR(t))return $Me(t);if(kR(t))return VMe(t);if(cR(t))return YMe(t);if(TT(t)){let r=t.rule.ref;if(!r)throw new Error("Missing rule reference.");return Ou(Ym(r.definition),{cardinality:t.cardinality,lookahead:t.lookahead})}else{if(gR(t))return HMe(t);if(AR(t))return UMe(t);if(vR(t)){let r=t.regex.lastIndexOf("/"),n=t.regex.substring(1,r),i=t.regex.substring(r+1);return e&&(e.i=i.includes("i"),e.s=i.includes("s"),e.u=i.includes("u")),Ou(n,{cardinality:t.cardinality,lookahead:t.lookahead,wrap:!1})}else{if(LR(t))return Ou(ZR,{cardinality:t.cardinality,lookahead:t.lookahead});throw new Error(`Invalid terminal element: ${t?.$type}`)}}}function $Me(t){return Ou(t.elements.map(e=>Ym(e)).join("|"),{cardinality:t.cardinality,lookahead:t.lookahead})}function VMe(t){return Ou(t.elements.map(e=>Ym(e)).join(""),{cardinality:t.cardinality,lookahead:t.lookahead})}function UMe(t){return Ou(`${ZR}*?${Ym(t.terminal)}`,{cardinality:t.cardinality,lookahead:t.lookahead})}function HMe(t){return Ou(`(?!${Ym(t.terminal)})${ZR}*?`,{cardinality:t.cardinality,lookahead:t.lookahead})}function YMe(t){return t.right?Ou(`[${$R(t.left)}-${$R(t.right)}]`,{cardinality:t.cardinality,lookahead:t.lookahead,wrap:!1}):Ou($R(t.left),{cardinality:t.cardinality,lookahead:t.lookahead,wrap:!1})}function $R(t){return t0(t.value)}function Ou(t,e){var r;return(e.wrap!==!1||e.lookahead)&&(t=`(${(r=e.lookahead)!==null&&r!==void 0?r:""}${t})`),e.cardinality?`${t}${e.cardinality}`:t}var ZR,Il=R(()=>{"use strict";pT();Sc();Vo();es();Rl();Um();o(jne,"getEntryRule");o(Kne,"getHiddenRules");o(Qv,"getAllReachableRules");o(Qne,"ruleDfs");o(UR,"getCrossReferenceTerminal");o(HR,"isCommentTerminal");o(YR,"findNodesForProperty");o(Zv,"findNodeForProperty");o(WR,"findNodesForPropertyInternal");o(PMe,"findNodesForKeyword");o(qR,"findNodeForKeyword");o(XR,"findNodesForKeywordInternal");o(jR,"findAssignment");o(DT,"findNameAssignment");o(Zne,"findNameAssignmentInternal");o(Jne,"getActionAtElement");o(BMe,"isOptionalCardinality");o(FMe,"isArrayCardinality");o(zMe,"isArrayOperator");o(Jv,"isDataTypeRule");o(eie,"isDataTypeRuleInternal");o(GMe,"isDataType");o(VR,"isDataTypeInternal");o(KR,"getExplicitRuleType");o(r0,"getTypeName");o(tie,"getActionType");o(QR,"getRuleType");o(Hm,"terminalRegex");ZR=/[\s\S]/.source;o(Ym,"abstractElementToRegex");o($Me,"terminalAlternativesToRegex");o(VMe,"terminalGroupToRegex");o(UMe,"untilTokenToRegex");o(HMe,"negateTokenToRegex");o(YMe,"characterRangeToRegex");o($R,"keywordToRegex");o(Ou,"withCardinality")});function JR(t){let e=[],r=t.Grammar;for(let n of r.rules)Uo(n)&&HR(n)&&FR(Hm(n))&&e.push(n.name);return{multilineCommentRules:e,nameRegexp:fT}}var eN=R(()=>{"use strict";Rl();Il();Um();Sc();o(JR,"createGrammarConfig")});var tN=R(()=>{"use strict"});function Wm(t){console&&console.error&&console.error(`Error: ${t}`)}function e2(t){console&&console.warn&&console.warn(`Warning: ${t}`)}var rie=R(()=>{"use strict";o(Wm,"PRINT_ERROR");o(e2,"PRINT_WARNING")});function t2(t){let e=new Date().getTime(),r=t();return{time:new Date().getTime()-e,value:r}}var nie=R(()=>{"use strict";o(t2,"timer")});function r2(t){function e(){}o(e,"FakeConstructor"),e.prototype=t;let r=new e;function n(){return typeof r.bar}return o(n,"fakeAccess"),n(),n(),t;(0,eval)(t)}var iie=R(()=>{"use strict";o(r2,"toFastProperties")});var qm=R(()=>{"use strict";rie();nie();iie()});function WMe(t){return qMe(t)?t.LABEL:t.name}function qMe(t){return di(t.LABEL)&&t.LABEL!==""}function NT(t){return qe(t,Xm)}function Xm(t){function e(r){return qe(r,Xm)}if(o(e,"convertDefinition"),t instanceof Zr){let r={type:"NonTerminal",name:t.nonTerminalName,idx:t.idx};return di(t.label)&&(r.label=t.label),r}else{if(t instanceof Sn)return{type:"Alternative",definition:e(t.definition)};if(t instanceof Jr)return{type:"Option",idx:t.idx,definition:e(t.definition)};if(t instanceof An)return{type:"RepetitionMandatory",idx:t.idx,definition:e(t.definition)};if(t instanceof _n)return{type:"RepetitionMandatoryWithSeparator",idx:t.idx,separator:Xm(new fr({terminalType:t.separator})),definition:e(t.definition)};if(t instanceof mn)return{type:"RepetitionWithSeparator",idx:t.idx,separator:Xm(new fr({terminalType:t.separator})),definition:e(t.definition)};if(t instanceof br)return{type:"Repetition",idx:t.idx,definition:e(t.definition)};if(t instanceof gn)return{type:"Alternation",idx:t.idx,definition:e(t.definition)};if(t instanceof fr){let r={type:"Terminal",name:t.terminalType.name,label:WMe(t.terminalType),idx:t.idx};di(t.label)&&(r.terminalLabel=t.label);let n=t.terminalType.PATTERN;return t.terminalType.PATTERN&&(r.pattern=zo(n)?n.source:n),r}else{if(t instanceof ts)return{type:"Rule",name:t.name,orgText:t.orgText,definition:e(t.definition)};throw Error("non exhaustive match")}}}var ho,Zr,ts,Sn,Jr,An,_n,br,mn,gn,fr,MT=R(()=>{"use strict";Pt();o(WMe,"tokenLabel");o(qMe,"hasTokenLabel");ho=class{static{o(this,"AbstractProduction")}get definition(){return this._definition}set definition(e){this._definition=e}constructor(e){this._definition=e}accept(e){e.visit(this),Ee(this.definition,r=>{r.accept(e)})}},Zr=class extends ho{static{o(this,"NonTerminal")}constructor(e){super([]),this.idx=1,pa(this,Ls(e,r=>r!==void 0))}set definition(e){}get definition(){return this.referencedRule!==void 0?this.referencedRule.definition:[]}accept(e){e.visit(this)}},ts=class extends ho{static{o(this,"Rule")}constructor(e){super(e.definition),this.orgText="",pa(this,Ls(e,r=>r!==void 0))}},Sn=class extends ho{static{o(this,"Alternative")}constructor(e){super(e.definition),this.ignoreAmbiguities=!1,pa(this,Ls(e,r=>r!==void 0))}},Jr=class extends ho{static{o(this,"Option")}constructor(e){super(e.definition),this.idx=1,pa(this,Ls(e,r=>r!==void 0))}},An=class extends ho{static{o(this,"RepetitionMandatory")}constructor(e){super(e.definition),this.idx=1,pa(this,Ls(e,r=>r!==void 0))}},_n=class extends ho{static{o(this,"RepetitionMandatoryWithSeparator")}constructor(e){super(e.definition),this.idx=1,pa(this,Ls(e,r=>r!==void 0))}},br=class extends ho{static{o(this,"Repetition")}constructor(e){super(e.definition),this.idx=1,pa(this,Ls(e,r=>r!==void 0))}},mn=class extends ho{static{o(this,"RepetitionWithSeparator")}constructor(e){super(e.definition),this.idx=1,pa(this,Ls(e,r=>r!==void 0))}},gn=class extends ho{static{o(this,"Alternation")}get definition(){return this._definition}set definition(e){this._definition=e}constructor(e){super(e.definition),this.idx=1,this.ignoreAmbiguities=!1,this.hasPredicates=!1,pa(this,Ls(e,r=>r!==void 0))}},fr=class{static{o(this,"Terminal")}constructor(e){this.idx=1,pa(this,Ls(e,r=>r!==void 0))}accept(e){e.visit(this)}};o(NT,"serializeGrammar");o(Xm,"serializeProduction")});var rs,aie=R(()=>{"use strict";MT();rs=class{static{o(this,"GAstVisitor")}visit(e){let r=e;switch(r.constructor){case Zr:return this.visitNonTerminal(r);case Sn:return this.visitAlternative(r);case Jr:return this.visitOption(r);case An:return this.visitRepetitionMandatory(r);case _n:return this.visitRepetitionMandatoryWithSeparator(r);case mn:return this.visitRepetitionWithSeparator(r);case br:return this.visitRepetition(r);case gn:return this.visitAlternation(r);case fr:return this.visitTerminal(r);case ts:return this.visitRule(r);default:throw Error("non exhaustive match")}}visitNonTerminal(e){}visitAlternative(e){}visitOption(e){}visitRepetition(e){}visitRepetitionMandatory(e){}visitRepetitionMandatoryWithSeparator(e){}visitRepetitionWithSeparator(e){}visitAlternation(e){}visitTerminal(e){}visitRule(e){}}});function rN(t){return t instanceof Sn||t instanceof Jr||t instanceof br||t instanceof An||t instanceof _n||t instanceof mn||t instanceof fr||t instanceof ts}function n0(t,e=[]){return t instanceof Jr||t instanceof br||t instanceof mn?!0:t instanceof gn?Nv(t.definition,n=>n0(n,e)):t instanceof Zr&&Fn(e,t)?!1:t instanceof ho?(t instanceof Zr&&e.push(t),Ia(t.definition,n=>n0(n,e))):!1}function nN(t){return t instanceof gn}function Rs(t){if(t instanceof Zr)return"SUBRULE";if(t instanceof Jr)return"OPTION";if(t instanceof gn)return"OR";if(t instanceof An)return"AT_LEAST_ONE";if(t instanceof _n)return"AT_LEAST_ONE_SEP";if(t instanceof mn)return"MANY_SEP";if(t instanceof br)return"MANY";if(t instanceof fr)return"CONSUME";throw Error("non exhaustive match")}var sie=R(()=>{"use strict";Pt();MT();o(rN,"isSequenceProd");o(n0,"isOptionalProd");o(nN,"isBranchingProd");o(Rs,"getProductionDslName")});var ns=R(()=>{"use strict";MT();aie();sie()});function oie(t,e,r){return[new Jr({definition:[new fr({terminalType:t.separator})].concat(t.definition)})].concat(e,r)}var Pu,IT=R(()=>{"use strict";Pt();ns();Pu=class{static{o(this,"RestWalker")}walk(e,r=[]){Ee(e.definition,(n,i)=>{let a=fi(e.definition,i+1);if(n instanceof Zr)this.walkProdRef(n,a,r);else if(n instanceof fr)this.walkTerminal(n,a,r);else if(n instanceof Sn)this.walkFlat(n,a,r);else if(n instanceof Jr)this.walkOption(n,a,r);else if(n instanceof An)this.walkAtLeastOne(n,a,r);else if(n instanceof _n)this.walkAtLeastOneSep(n,a,r);else if(n instanceof mn)this.walkManySep(n,a,r);else if(n instanceof br)this.walkMany(n,a,r);else if(n instanceof gn)this.walkOr(n,a,r);else throw Error("non exhaustive match")})}walkTerminal(e,r,n){}walkProdRef(e,r,n){}walkFlat(e,r,n){let i=r.concat(n);this.walk(e,i)}walkOption(e,r,n){let i=r.concat(n);this.walk(e,i)}walkAtLeastOne(e,r,n){let i=[new Jr({definition:e.definition})].concat(r,n);this.walk(e,i)}walkAtLeastOneSep(e,r,n){let i=oie(e,r,n);this.walk(e,i)}walkMany(e,r,n){let i=[new Jr({definition:e.definition})].concat(r,n);this.walk(e,i)}walkManySep(e,r,n){let i=oie(e,r,n);this.walk(e,i)}walkOr(e,r,n){let i=r.concat(n);Ee(e.definition,a=>{let s=new Sn({definition:[a]});this.walk(s,i)})}};o(oie,"restForRepetitionWithSeparator")});function i0(t){if(t instanceof Zr)return i0(t.referencedRule);if(t instanceof fr)return KMe(t);if(rN(t))return XMe(t);if(nN(t))return jMe(t);throw Error("non exhaustive match")}function XMe(t){let e=[],r=t.definition,n=0,i=r.length>n,a,s=!0;for(;i&&s;)a=r[n],s=n0(a),e=e.concat(i0(a)),n=n+1,i=r.length>n;return Pm(e)}function jMe(t){let e=qe(t.definition,r=>i0(r));return Pm(Gr(e))}function KMe(t){return[t.terminalType]}var iN=R(()=>{"use strict";Pt();ns();o(i0,"first");o(XMe,"firstForSequence");o(jMe,"firstForBranching");o(KMe,"firstForTerminal")});var OT,aN=R(()=>{"use strict";OT="_~IN~_"});function lie(t){let e={};return Ee(t,r=>{let n=new sN(r).startWalking();pa(e,n)}),e}function QMe(t,e){return t.name+e+OT}var sN,cie=R(()=>{"use strict";IT();iN();Pt();aN();ns();sN=class extends Pu{static{o(this,"ResyncFollowsWalker")}constructor(e){super(),this.topProd=e,this.follows={}}startWalking(){return this.walk(this.topProd),this.follows}walkTerminal(e,r,n){}walkProdRef(e,r,n){let i=QMe(e.referencedRule,e.idx)+this.topProd.name,a=r.concat(n),s=new Sn({definition:a}),l=i0(s);this.follows[i]=l}};o(lie,"computeAllProdsFollows");o(QMe,"buildBetweenProdsFollowPrefix")});function jm(t){let e=t.toString();if(PT.hasOwnProperty(e))return PT[e];{let r=ZMe.pattern(e);return PT[e]=r,r}}function uie(){PT={}}var PT,ZMe,BT=R(()=>{"use strict";Kv();PT={},ZMe=new Jd;o(jm,"getRegExpAst");o(uie,"clearRegExpParserCache")});function die(t,e=!1){try{let r=jm(t);return oN(r.value,{},r.flags.ignoreCase)}catch(r){if(r.message===fie)e&&e2(`${n2} Unable to optimize: < ${t.toString()} > + Complement Sets cannot be automatically optimized. + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.`);else{let n="";e&&(n=` + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),Wm(`${n2} + Failed parsing: < ${t.toString()} > + Using the @chevrotain/regexp-to-ast library + Please open an issue at: https://github.com/chevrotain/chevrotain/issues`+n)}}return[]}function oN(t,e,r){switch(t.type){case"Disjunction":for(let i=0;i{if(typeof u=="number")FT(u,e,r);else{let h=u;if(r===!0)for(let f=h.from;f<=h.to;f++)FT(f,e,r);else{for(let f=h.from;f<=h.to&&f=Km){let f=h.from>=Km?h.from:Km,d=h.to,p=Lc(f),m=Lc(d);for(let g=p;g<=m;g++)e[g]=g}}}});break;case"Group":oN(s.value,e,r);break;default:throw Error("Non Exhaustive Match")}let l=s.quantifier!==void 0&&s.quantifier.atLeast===0;if(s.type==="Group"&&lN(s)===!1||s.type!=="Group"&&l===!1)break}break;default:throw Error("non exhaustive match!")}return or(e)}function FT(t,e,r){let n=Lc(t);e[n]=n,r===!0&&JMe(t,e)}function JMe(t,e){let r=String.fromCharCode(t),n=r.toUpperCase();if(n!==r){let i=Lc(n.charCodeAt(0));e[i]=i}else{let i=r.toLowerCase();if(i!==r){let a=Lc(i.charCodeAt(0));e[a]=a}}}function hie(t,e){return Za(t.value,r=>{if(typeof r=="number")return Fn(e,r);{let n=r;return Za(e,i=>n.from<=i&&i<=n.to)!==void 0}})}function lN(t){let e=t.quantifier;return e&&e.atLeast===0?!0:t.value?wt(t.value)?Ia(t.value,lN):lN(t.value):!1}function zT(t,e){if(e instanceof RegExp){let r=jm(e),n=new cN(t);return n.visit(r),n.found}else return Za(e,r=>Fn(t,r.charCodeAt(0)))!==void 0}var fie,n2,cN,pie=R(()=>{"use strict";Kv();Pt();qm();BT();uN();fie="Complement Sets are not supported for first char optimization",n2=`Unable to use "first char" lexer optimizations: +`;o(die,"getOptimizedStartCodesIndices");o(oN,"firstCharOptimizedIndices");o(FT,"addOptimizedIdxToResult");o(JMe,"handleIgnoreCase");o(hie,"findCode");o(lN,"isWholeOptional");cN=class extends _c{static{o(this,"CharCodeFinder")}constructor(e){super(),this.targetCharCodes=e,this.found=!1}visitChildren(e){if(this.found!==!0){switch(e.type){case"Lookahead":this.visitLookahead(e);return;case"NegativeLookahead":this.visitNegativeLookahead(e);return}super.visitChildren(e)}}visitCharacter(e){Fn(this.targetCharCodes,e.value)&&(this.found=!0)}visitSet(e){e.complement?hie(e,this.targetCharCodes)===void 0&&(this.found=!0):hie(e,this.targetCharCodes)!==void 0&&(this.found=!0)}};o(zT,"canMatchCharCode")});function yie(t,e){e=Xh(e,{useSticky:fN,debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",` +`],tracer:o((b,w)=>w(),"tracer")});let r=e.tracer;r("initCharCodeToOptimizedIndexMap",()=>{yIe()});let n;r("Reject Lexer.NA",()=>{n=Kh(t,b=>b[a0]===ni.NA)});let i=!1,a;r("Transform Patterns",()=>{i=!1,a=qe(n,b=>{let w=b[a0];if(zo(w)){let S=w.source;return S.length===1&&S!=="^"&&S!=="$"&&S!=="."&&!w.ignoreCase?S:S.length===2&&S[0]==="\\"&&!Fn(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],S[1])?S[1]:e.useSticky?gie(w):mie(w)}else{if(wi(w))return i=!0,{exec:w};if(typeof w=="object")return i=!0,w;if(typeof w=="string"){if(w.length===1)return w;{let S=w.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),T=new RegExp(S);return e.useSticky?gie(T):mie(T)}}else throw Error("non exhaustive match")}})});let s,l,u,h,f;r("misc mapping",()=>{s=qe(n,b=>b.tokenTypeIdx),l=qe(n,b=>{let w=b.GROUP;if(w!==ni.SKIPPED){if(di(w))return w;if(er(w))return!1;throw Error("non exhaustive match")}}),u=qe(n,b=>{let w=b.LONGER_ALT;if(w)return wt(w)?qe(w,T=>Yw(n,T)):[Yw(n,w)]}),h=qe(n,b=>b.PUSH_MODE),f=qe(n,b=>Xe(b,"POP_MODE"))});let d;r("Line Terminator Handling",()=>{let b=Cie(e.lineTerminatorCharacters);d=qe(n,w=>!1),e.positionTracking!=="onlyOffset"&&(d=qe(n,w=>Xe(w,"LINE_BREAKS")?!!w.LINE_BREAKS:Eie(w,b)===!1&&zT(b,w.PATTERN)))});let p,m,g,y;r("Misc Mapping #2",()=>{p=qe(n,Tie),m=qe(a,mIe),g=Vr(n,(b,w)=>{let S=w.GROUP;return di(S)&&S!==ni.SKIPPED&&(b[S]=[]),b},{}),y=qe(a,(b,w)=>({pattern:a[w],longerAlt:u[w],canLineTerminator:d[w],isCustom:p[w],short:m[w],group:l[w],push:h[w],pop:f[w],tokenTypeIdx:s[w],tokenType:n[w]}))});let v=!0,x=[];return e.safeMode||r("First Char Optimization",()=>{x=Vr(n,(b,w,S)=>{if(typeof w.PATTERN=="string"){let T=w.PATTERN.charCodeAt(0),E=Lc(T);hN(b,E,y[S])}else if(wt(w.START_CHARS_HINT)){let T;Ee(w.START_CHARS_HINT,E=>{let _=typeof E=="string"?E.charCodeAt(0):E,A=Lc(_);T!==A&&(T=A,hN(b,A,y[S]))})}else if(zo(w.PATTERN))if(w.PATTERN.unicode)v=!1,e.ensureOptimizations&&Wm(`${n2} Unable to analyze < ${w.PATTERN.toString()} > pattern. + The regexp unicode flag is not currently supported by the regexp-to-ast library. + This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNICODE_OPTIMIZE`);else{let T=die(w.PATTERN,e.ensureOptimizations);Qt(T)&&(v=!1),Ee(T,E=>{hN(b,E,y[S])})}else e.ensureOptimizations&&Wm(`${n2} TokenType: <${w.name}> is using a custom token pattern without providing parameter. + This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),v=!1;return b},[])}),{emptyGroups:g,patternIdxToConfig:y,charCodeToPatternIdxToConfig:x,hasCustom:i,canBeOptimized:v}}function vie(t,e){let r=[],n=tIe(t);r=r.concat(n.errors);let i=rIe(n.valid),a=i.valid;return r=r.concat(i.errors),r=r.concat(eIe(a)),r=r.concat(uIe(a)),r=r.concat(hIe(a,e)),r=r.concat(fIe(a)),r}function eIe(t){let e=[],r=$r(t,n=>zo(n[a0]));return e=e.concat(iIe(r)),e=e.concat(oIe(r)),e=e.concat(lIe(r)),e=e.concat(cIe(r)),e=e.concat(aIe(r)),e}function tIe(t){let e=$r(t,i=>!Xe(i,a0)),r=qe(e,i=>({message:"Token Type: ->"+i.name+"<- missing static 'PATTERN' property",type:Gn.MISSING_PATTERN,tokenTypes:[i]})),n=jh(t,e);return{errors:r,valid:n}}function rIe(t){let e=$r(t,i=>{let a=i[a0];return!zo(a)&&!wi(a)&&!Xe(a,"exec")&&!di(a)}),r=qe(e,i=>({message:"Token Type: ->"+i.name+"<- static 'PATTERN' can only be a RegExp, a Function matching the {CustomPatternMatcherFunc} type or an Object matching the {ICustomPattern} interface.",type:Gn.INVALID_PATTERN,tokenTypes:[i]})),n=jh(t,e);return{errors:r,valid:n}}function iIe(t){class e extends _c{static{o(this,"EndAnchorFinder")}constructor(){super(...arguments),this.found=!1}visitEndAnchor(a){this.found=!0}}let r=$r(t,i=>{let a=i.PATTERN;try{let s=jm(a),l=new e;return l.visit(s),l.found}catch{return nIe.test(a.source)}});return qe(r,i=>({message:`Unexpected RegExp Anchor Error: + Token Type: ->`+i.name+`<- static 'PATTERN' cannot contain end of input anchor '$' + See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:Gn.EOI_ANCHOR_FOUND,tokenTypes:[i]}))}function aIe(t){let e=$r(t,n=>n.PATTERN.test(""));return qe(e,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' must not match an empty string",type:Gn.EMPTY_MATCH_PATTERN,tokenTypes:[n]}))}function oIe(t){class e extends _c{static{o(this,"StartAnchorFinder")}constructor(){super(...arguments),this.found=!1}visitStartAnchor(a){this.found=!0}}let r=$r(t,i=>{let a=i.PATTERN;try{let s=jm(a),l=new e;return l.visit(s),l.found}catch{return sIe.test(a.source)}});return qe(r,i=>({message:`Unexpected RegExp Anchor Error: + Token Type: ->`+i.name+`<- static 'PATTERN' cannot contain start of input anchor '^' + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:Gn.SOI_ANCHOR_FOUND,tokenTypes:[i]}))}function lIe(t){let e=$r(t,n=>{let i=n[a0];return i instanceof RegExp&&(i.multiline||i.global)});return qe(e,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:Gn.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[n]}))}function cIe(t){let e=[],r=qe(t,a=>Vr(t,(s,l)=>(a.PATTERN.source===l.PATTERN.source&&!Fn(e,l)&&l.PATTERN!==ni.NA&&(e.push(l),s.push(l)),s),[]));r=wc(r);let n=$r(r,a=>a.length>1);return qe(n,a=>{let s=qe(a,u=>u.name);return{message:`The same RegExp pattern ->${na(a).PATTERN}<-has been used in all of the following Token Types: ${s.join(", ")} <-`,type:Gn.DUPLICATE_PATTERNS_FOUND,tokenTypes:a}})}function uIe(t){let e=$r(t,n=>{if(!Xe(n,"GROUP"))return!1;let i=n.GROUP;return i!==ni.SKIPPED&&i!==ni.NA&&!di(i)});return qe(e,n=>({message:"Token Type: ->"+n.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:Gn.INVALID_GROUP_TYPE_FOUND,tokenTypes:[n]}))}function hIe(t,e){let r=$r(t,i=>i.PUSH_MODE!==void 0&&!Fn(e,i.PUSH_MODE));return qe(r,i=>({message:`Token Type: ->${i.name}<- static 'PUSH_MODE' value cannot refer to a Lexer Mode ->${i.PUSH_MODE}<-which does not exist`,type:Gn.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[i]}))}function fIe(t){let e=[],r=Vr(t,(n,i,a)=>{let s=i.PATTERN;return s===ni.NA||(di(s)?n.push({str:s,idx:a,tokenType:i}):zo(s)&&pIe(s)&&n.push({str:s.source,idx:a,tokenType:i})),n},[]);return Ee(t,(n,i)=>{Ee(r,({str:a,idx:s,tokenType:l})=>{if(i${l.name}<- can never be matched. +Because it appears AFTER the Token Type ->${n.name}<-in the lexer's definition. +See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;e.push({message:u,type:Gn.UNREACHABLE_PATTERN,tokenTypes:[n,l]})}})}),e}function dIe(t,e){if(zo(e)){let r=e.exec(t);return r!==null&&r.index===0}else{if(wi(e))return e(t,0,[],{});if(Xe(e,"exec"))return e.exec(t,0,[],{});if(typeof e=="string")return e===t;throw Error("non exhaustive match")}}function pIe(t){return Za([".","\\","[","]","|","^","$","(",")","?","*","+","{"],r=>t.source.indexOf(r)!==-1)===void 0}function mie(t){let e=t.ignoreCase?"i":"";return new RegExp(`^(?:${t.source})`,e)}function gie(t){let e=t.ignoreCase?"iy":"y";return new RegExp(`${t.source}`,e)}function xie(t,e,r){let n=[];return Xe(t,Qm)||n.push({message:"A MultiMode Lexer cannot be initialized without a <"+Qm+`> property in its definition +`,type:Gn.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),Xe(t,GT)||n.push({message:"A MultiMode Lexer cannot be initialized without a <"+GT+`> property in its definition +`,type:Gn.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),Xe(t,GT)&&Xe(t,Qm)&&!Xe(t.modes,t.defaultMode)&&n.push({message:`A MultiMode Lexer cannot be initialized with a ${Qm}: <${t.defaultMode}>which does not exist +`,type:Gn.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),Xe(t,GT)&&Ee(t.modes,(i,a)=>{Ee(i,(s,l)=>{if(er(s))n.push({message:`A Lexer cannot be initialized using an undefined Token Type. Mode:<${a}> at index: <${l}> +`,type:Gn.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED});else if(Xe(s,"LONGER_ALT")){let u=wt(s.LONGER_ALT)?s.LONGER_ALT:[s.LONGER_ALT];Ee(u,h=>{!er(h)&&!Fn(i,h)&&n.push({message:`A MultiMode Lexer cannot be initialized with a longer_alt <${h.name}> on token <${s.name}> outside of mode <${a}> +`,type:Gn.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE})})}})}),n}function bie(t,e,r){let n=[],i=!1,a=wc(Gr(or(t.modes))),s=Kh(a,u=>u[a0]===ni.NA),l=Cie(r);return e&&Ee(s,u=>{let h=Eie(u,l);if(h!==!1){let d={message:gIe(u,h),type:h.issue,tokenType:u};n.push(d)}else Xe(u,"LINE_BREAKS")?u.LINE_BREAKS===!0&&(i=!0):zT(l,u.PATTERN)&&(i=!0)}),e&&!i&&n.push({message:`Warning: No LINE_BREAKS Found. + This Lexer has been defined to track line and column information, + But none of the Token Types can be identified as matching a line terminator. + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#LINE_BREAKS + for details.`,type:Gn.NO_LINE_BREAKS_FLAGS}),n}function wie(t){let e={},r=Dr(t);return Ee(r,n=>{let i=t[n];if(wt(i))e[n]=[];else throw Error("non exhaustive match")}),e}function Tie(t){let e=t.PATTERN;if(zo(e))return!1;if(wi(e))return!0;if(Xe(e,"exec"))return!0;if(di(e))return!1;throw Error("non exhaustive match")}function mIe(t){return di(t)&&t.length===1?t.charCodeAt(0):!1}function Eie(t,e){if(Xe(t,"LINE_BREAKS"))return!1;if(zo(t.PATTERN)){try{zT(e,t.PATTERN)}catch(r){return{issue:Gn.IDENTIFY_TERMINATOR,errMsg:r.message}}return!1}else{if(di(t.PATTERN))return!1;if(Tie(t))return{issue:Gn.CUSTOM_LINE_BREAK};throw Error("non exhaustive match")}}function gIe(t,e){if(e.issue===Gn.IDENTIFY_TERMINATOR)return`Warning: unable to identify line terminator usage in pattern. + The problem is in the <${t.name}> Token Type + Root cause: ${e.errMsg}. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR`;if(e.issue===Gn.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the option. + The problem is in the <${t.name}> Token Type + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK`;throw Error("non exhaustive match")}function Cie(t){return qe(t,r=>di(r)?r.charCodeAt(0):r)}function hN(t,e,r){t[e]===void 0?t[e]=[r]:t[e].push(r)}function Lc(t){return t255?255+~~(t/255):t}}var a0,Qm,GT,fN,nIe,sIe,kie,Km,$T,uN=R(()=>{"use strict";Kv();i2();Pt();qm();pie();BT();a0="PATTERN",Qm="defaultMode",GT="modes",fN=typeof new RegExp("(?:)").sticky=="boolean";o(yie,"analyzeTokenTypes");o(vie,"validatePatterns");o(eIe,"validateRegExpPattern");o(tIe,"findMissingPatterns");o(rIe,"findInvalidPatterns");nIe=/[^\\][$]/;o(iIe,"findEndOfInputAnchor");o(aIe,"findEmptyMatchRegExps");sIe=/[^\\[][\^]|^\^/;o(oIe,"findStartOfInputAnchor");o(lIe,"findUnsupportedFlags");o(cIe,"findDuplicatePatterns");o(uIe,"findInvalidGroupType");o(hIe,"findModesThatDoNotExist");o(fIe,"findUnreachablePatterns");o(dIe,"testTokenType");o(pIe,"noMetaChar");o(mie,"addStartOfInput");o(gie,"addStickyFlag");o(xie,"performRuntimeChecks");o(bie,"performWarningRuntimeChecks");o(wie,"cloneEmptyGroups");o(Tie,"isCustomPattern");o(mIe,"isShortPattern");kie={test:o(function(t){let e=t.length;for(let r=this.lastIndex;r{r.isParent=r.categoryMatches.length>0})}function vIe(t){let e=Qr(t),r=t,n=!0;for(;n;){r=wc(Gr(qe(r,a=>a.CATEGORIES)));let i=jh(r,e);e=e.concat(i),Qt(i)?n=!1:r=i}return e}function xIe(t){Ee(t,e=>{dN(e)||(_ie[Sie]=e,e.tokenTypeIdx=Sie++),Aie(e)&&!wt(e.CATEGORIES)&&(e.CATEGORIES=[e.CATEGORIES]),Aie(e)||(e.CATEGORIES=[]),TIe(e)||(e.categoryMatches=[]),kIe(e)||(e.categoryMatchesMap={})})}function bIe(t){Ee(t,e=>{e.categoryMatches=[],Ee(e.categoryMatchesMap,(r,n)=>{e.categoryMatches.push(_ie[n].tokenTypeIdx)})})}function wIe(t){Ee(t,e=>{Lie([],e)})}function Lie(t,e){Ee(t,r=>{e.categoryMatchesMap[r.tokenTypeIdx]=!0}),Ee(e.CATEGORIES,r=>{let n=t.concat(e);Fn(n,r)||Lie(n,r)})}function dN(t){return Xe(t,"tokenTypeIdx")}function Aie(t){return Xe(t,"CATEGORIES")}function TIe(t){return Xe(t,"categoryMatches")}function kIe(t){return Xe(t,"categoryMatchesMap")}function Die(t){return Xe(t,"tokenTypeIdx")}var Sie,_ie,s0=R(()=>{"use strict";Pt();o(Bu,"tokenStructuredMatcher");o(Zm,"tokenStructuredMatcherNoCategories");Sie=1,_ie={};o(Fu,"augmentTokenTypes");o(vIe,"expandCategories");o(xIe,"assignTokenDefaultProps");o(bIe,"assignCategoriesTokensProp");o(wIe,"assignCategoriesMapProp");o(Lie,"singleAssignCategoriesToksMap");o(dN,"hasShortKeyProperty");o(Aie,"hasCategoriesProperty");o(TIe,"hasExtendingTokensTypesProperty");o(kIe,"hasExtendingTokensTypesMapProperty");o(Die,"isTokenType")});var pN,mN=R(()=>{"use strict";pN={buildUnableToPopLexerModeMessage(t){return`Unable to pop Lexer Mode after encountering Token ->${t.image}<- The Mode Stack is empty`},buildUnexpectedCharactersMessage(t,e,r,n,i){return`unexpected character: ->${t.charAt(e)}<- at offset: ${e}, skipped ${r} characters.`}}});var Gn,a2,ni,i2=R(()=>{"use strict";uN();Pt();qm();s0();mN();BT();(function(t){t[t.MISSING_PATTERN=0]="MISSING_PATTERN",t[t.INVALID_PATTERN=1]="INVALID_PATTERN",t[t.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",t[t.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",t[t.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",t[t.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",t[t.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",t[t.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",t[t.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",t[t.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",t[t.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",t[t.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",t[t.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",t[t.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",t[t.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",t[t.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",t[t.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK",t[t.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE=17]="MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE"})(Gn||(Gn={}));a2={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[` +`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:pN,traceInitPerf:!1,skipValidations:!1,recoveryEnabled:!0};Object.freeze(a2);ni=class{static{o(this,"Lexer")}constructor(e,r=a2){if(this.lexerDefinition=e,this.lexerDefinitionErrors=[],this.lexerDefinitionWarning=[],this.patternIdxToConfig={},this.charCodeToPatternIdxToConfig={},this.modes=[],this.emptyGroups={},this.trackStartLines=!0,this.trackEndLines=!0,this.hasCustom=!1,this.canModeBeOptimized={},this.TRACE_INIT=(i,a)=>{if(this.traceInitPerf===!0){this.traceInitIndent++;let s=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <${i}>`);let{time:l,value:u}=t2(a),h=l>10?console.warn:console.log;return this.traceInitIndent time: ${l}ms`),this.traceInitIndent--,u}else return a()},typeof r=="boolean")throw Error(`The second argument to the Lexer constructor is now an ILexerConfig Object. +a boolean 2nd argument is no longer supported`);this.config=pa({},a2,r);let n=this.config.traceInitPerf;n===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof n=="number"&&(this.traceInitMaxIdent=n,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",()=>{let i,a=!0;this.TRACE_INIT("Lexer Config handling",()=>{if(this.config.lineTerminatorsPattern===a2.lineTerminatorsPattern)this.config.lineTerminatorsPattern=kie;else if(this.config.lineTerminatorCharacters===a2.lineTerminatorCharacters)throw Error(`Error: Missing property on the Lexer config. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(r.safeMode&&r.ensureOptimizations)throw Error('"safeMode" and "ensureOptimizations" flags are mutually exclusive.');this.trackStartLines=/full|onlyStart/i.test(this.config.positionTracking),this.trackEndLines=/full/i.test(this.config.positionTracking),wt(e)?i={modes:{defaultMode:Qr(e)},defaultMode:Qm}:(a=!1,i=Qr(e))}),this.config.skipValidations===!1&&(this.TRACE_INIT("performRuntimeChecks",()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(xie(i,this.trackStartLines,this.config.lineTerminatorCharacters))}),this.TRACE_INIT("performWarningRuntimeChecks",()=>{this.lexerDefinitionWarning=this.lexerDefinitionWarning.concat(bie(i,this.trackStartLines,this.config.lineTerminatorCharacters))})),i.modes=i.modes?i.modes:{},Ee(i.modes,(l,u)=>{i.modes[u]=Kh(l,h=>er(h))});let s=Dr(i.modes);if(Ee(i.modes,(l,u)=>{this.TRACE_INIT(`Mode: <${u}> processing`,()=>{if(this.modes.push(u),this.config.skipValidations===!1&&this.TRACE_INIT("validatePatterns",()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(vie(l,s))}),Qt(this.lexerDefinitionErrors)){Fu(l);let h;this.TRACE_INIT("analyzeTokenTypes",()=>{h=yie(l,{lineTerminatorCharacters:this.config.lineTerminatorCharacters,positionTracking:r.positionTracking,ensureOptimizations:r.ensureOptimizations,safeMode:r.safeMode,tracer:this.TRACE_INIT})}),this.patternIdxToConfig[u]=h.patternIdxToConfig,this.charCodeToPatternIdxToConfig[u]=h.charCodeToPatternIdxToConfig,this.emptyGroups=pa({},this.emptyGroups,h.emptyGroups),this.hasCustom=h.hasCustom||this.hasCustom,this.canModeBeOptimized[u]=h.canBeOptimized}})}),this.defaultMode=i.defaultMode,!Qt(this.lexerDefinitionErrors)&&!this.config.deferDefinitionErrorsHandling){let u=qe(this.lexerDefinitionErrors,h=>h.message).join(`----------------------- +`);throw new Error(`Errors detected in definition of Lexer: +`+u)}Ee(this.lexerDefinitionWarning,l=>{e2(l.message)}),this.TRACE_INIT("Choosing sub-methods implementations",()=>{if(fN?(this.chopInput=ea,this.match=this.matchWithTest):(this.updateLastIndex=qn,this.match=this.matchWithExec),a&&(this.handleModes=qn),this.trackStartLines===!1&&(this.computeNewColumn=ea),this.trackEndLines===!1&&(this.updateTokenEndLineColumnLocation=qn),/full/i.test(this.config.positionTracking))this.createTokenInstance=this.createFullToken;else if(/onlyStart/i.test(this.config.positionTracking))this.createTokenInstance=this.createStartOnlyToken;else if(/onlyOffset/i.test(this.config.positionTracking))this.createTokenInstance=this.createOffsetOnlyToken;else throw Error(`Invalid config option: "${this.config.positionTracking}"`);this.hasCustom?(this.addToken=this.addTokenUsingPush,this.handlePayload=this.handlePayloadWithCustom):(this.addToken=this.addTokenUsingMemberAccess,this.handlePayload=this.handlePayloadNoCustom)}),this.TRACE_INIT("Failed Optimization Warnings",()=>{let l=Vr(this.canModeBeOptimized,(u,h,f)=>(h===!1&&u.push(f),u),[]);if(r.ensureOptimizations&&!Qt(l))throw Error(`Lexer Modes: < ${l.join(", ")} > cannot be optimized. + Disable the "ensureOptimizations" lexer config flag to silently ignore this and run the lexer in an un-optimized mode. + Or inspect the console log for details on how to resolve these issues.`)}),this.TRACE_INIT("clearRegExpParserCache",()=>{uie()}),this.TRACE_INIT("toFastProperties",()=>{r2(this)})})}tokenize(e,r=this.defaultMode){if(!Qt(this.lexerDefinitionErrors)){let i=qe(this.lexerDefinitionErrors,a=>a.message).join(`----------------------- +`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer: +`+i)}return this.tokenizeInternal(e,r)}tokenizeInternal(e,r){let n,i,a,s,l,u,h,f,d,p,m,g,y,v,x,b,w=e,S=w.length,T=0,E=0,_=this.hasCustom?0:Math.floor(e.length/10),A=new Array(_),L=[],M=this.trackStartLines?1:void 0,N=this.trackStartLines?1:void 0,k=wie(this.emptyGroups),I=this.trackStartLines,C=this.config.lineTerminatorsPattern,O=0,D=[],P=[],F=[],B=[];Object.freeze(B);let $;function z(){return D}o(z,"getPossiblePatternsSlow");function Y(J){let Z=Lc(J),H=P[Z];return H===void 0?B:H}o(Y,"getPossiblePatternsOptimized");let Q=o(J=>{if(F.length===1&&J.tokenType.PUSH_MODE===void 0){let Z=this.config.errorMessageProvider.buildUnableToPopLexerModeMessage(J);L.push({offset:J.startOffset,line:J.startLine,column:J.startColumn,length:J.image.length,message:Z})}else{F.pop();let Z=ma(F);D=this.patternIdxToConfig[Z],P=this.charCodeToPatternIdxToConfig[Z],O=D.length;let H=this.canModeBeOptimized[Z]&&this.config.safeMode===!1;P&&H?$=Y:$=z}},"pop_mode");function X(J){F.push(J),P=this.charCodeToPatternIdxToConfig[J],D=this.patternIdxToConfig[J],O=D.length,O=D.length;let Z=this.canModeBeOptimized[J]&&this.config.safeMode===!1;P&&Z?$=Y:$=z}o(X,"push_mode"),X.call(this,r);let ie,j=this.config.recoveryEnabled;for(;Tu.length){u=s,h=f,ie=ce;break}}}break}}if(u!==null){if(d=u.length,p=ie.group,p!==void 0&&(m=ie.tokenTypeIdx,g=this.createTokenInstance(u,T,m,ie.tokenType,M,N,d),this.handlePayload(g,h),p===!1?E=this.addToken(A,E,g):k[p].push(g)),e=this.chopInput(e,d),T=T+d,N=this.computeNewColumn(N,d),I===!0&&ie.canLineTerminator===!0){let q=0,K,se;C.lastIndex=0;do K=C.test(u),K===!0&&(se=C.lastIndex-1,q++);while(K===!0);q!==0&&(M=M+q,N=d-se,this.updateTokenEndLineColumnLocation(g,p,se,q,M,N,d))}this.handleModes(ie,Q,X,g)}else{let q=T,K=M,se=N,ce=j===!1;for(;ce===!1&&T{"use strict";Pt();i2();s0();o(zu,"tokenLabel");o(gN,"hasTokenLabel");EIe="parent",Rie="categories",Nie="label",Mie="group",Iie="push_mode",Oie="pop_mode",Pie="longer_alt",Bie="line_breaks",Fie="start_chars_hint";o(VT,"createToken");o(CIe,"createTokenInternal");fo=VT({name:"EOF",pattern:ni.NA});Fu([fo]);o(o0,"createTokenInstance");o(s2,"tokenMatcher")});var Gu,zie,Ol,Jm=R(()=>{"use strict";l0();Pt();ns();Gu={buildMismatchTokenMessage({expected:t,actual:e,previous:r,ruleName:n}){return`Expecting ${gN(t)?`--> ${zu(t)} <--`:`token of type --> ${t.name} <--`} but found --> '${e.image}' <--`},buildNotAllInputParsedMessage({firstRedundant:t,ruleName:e}){return"Redundant input, expecting EOF but found: "+t.image},buildNoViableAltMessage({expectedPathsPerAlt:t,actual:e,previous:r,customUserDescription:n,ruleName:i}){let a="Expecting: ",l=` +but found: '`+na(e).image+"'";if(n)return a+n+l;{let u=Vr(t,(p,m)=>p.concat(m),[]),h=qe(u,p=>`[${qe(p,m=>zu(m)).join(", ")}]`),d=`one of these possible Token sequences: +${qe(h,(p,m)=>` ${m+1}. ${p}`).join(` +`)}`;return a+d+l}},buildEarlyExitMessage({expectedIterationPaths:t,actual:e,customUserDescription:r,ruleName:n}){let i="Expecting: ",s=` +but found: '`+na(e).image+"'";if(r)return i+r+s;{let u=`expecting at least one iteration which starts with one of these possible Token sequences:: + <${qe(t,h=>`[${qe(h,f=>zu(f)).join(",")}]`).join(" ,")}>`;return i+u+s}}};Object.freeze(Gu);zie={buildRuleNotFoundError(t,e){return"Invalid grammar, reference to a rule which is not defined: ->"+e.nonTerminalName+`<- +inside top level rule: ->`+t.name+"<-"}},Ol={buildDuplicateFoundError(t,e){function r(f){return f instanceof fr?f.terminalType.name:f instanceof Zr?f.nonTerminalName:""}o(r,"getExtraProductionArgument");let n=t.name,i=na(e),a=i.idx,s=Rs(i),l=r(i),u=a>0,h=`->${s}${u?a:""}<- ${l?`with argument: ->${l}<-`:""} + appears more than once (${e.length} times) in the top level rule: ->${n}<-. + For further details see: https://chevrotain.io/docs/FAQ.html#NUMERICAL_SUFFIXES + `;return h=h.replace(/[ \t]+/g," "),h=h.replace(/\s\s+/g,` +`),h},buildNamespaceConflictError(t){return`Namespace conflict found in grammar. +The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <${t.name}>. +To resolve this make sure each Terminal and Non-Terminal names are unique +This is easy to accomplish by using the convention that Terminal names start with an uppercase letter +and Non-Terminal names start with a lower case letter.`},buildAlternationPrefixAmbiguityError(t){let e=qe(t.prefixPath,i=>zu(i)).join(", "),r=t.alternation.idx===0?"":t.alternation.idx;return`Ambiguous alternatives: <${t.ambiguityIndices.join(" ,")}> due to common lookahead prefix +in inside <${t.topLevelRule.name}> Rule, +<${e}> may appears as a prefix path in all these alternatives. +See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#COMMON_PREFIX +For Further details.`},buildAlternationAmbiguityError(t){let e=qe(t.prefixPath,i=>zu(i)).join(", "),r=t.alternation.idx===0?"":t.alternation.idx,n=`Ambiguous Alternatives Detected: <${t.ambiguityIndices.join(" ,")}> in inside <${t.topLevelRule.name}> Rule, +<${e}> may appears as a prefix path in all these alternatives. +`;return n=n+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES +For Further details.`,n},buildEmptyRepetitionError(t){let e=Rs(t.repetition);return t.repetition.idx!==0&&(e+=t.repetition.idx),`The repetition <${e}> within Rule <${t.topLevelRule.name}> can never consume any tokens. +This could lead to an infinite loop.`},buildTokenNameError(t){return"deprecated"},buildEmptyAlternationError(t){return`Ambiguous empty alternative: <${t.emptyChoiceIdx+1}> in inside <${t.topLevelRule.name}> Rule. +Only the last alternative may be an empty alternative.`},buildTooManyAlternativesError(t){return`An Alternation cannot have more than 256 alternatives: + inside <${t.topLevelRule.name}> Rule. + has ${t.alternation.definition.length+1} alternatives.`},buildLeftRecursionError(t){let e=t.topLevelRule.name,r=qe(t.leftRecursionPath,a=>a.name),n=`${e} --> ${r.concat([e]).join(" --> ")}`;return`Left Recursion found in grammar. +rule: <${e}> can be invoked from itself (directly or indirectly) +without consuming any Tokens. The grammar path that causes this is: + ${n} + To fix this refactor your grammar to remove the left recursion. +see: https://en.wikipedia.org/wiki/LL_parser#Left_factoring.`},buildInvalidRuleNameError(t){return"deprecated"},buildDuplicateRuleNameError(t){let e;return t.topLevelRule instanceof ts?e=t.topLevelRule.name:e=t.topLevelRule,`Duplicate definition, rule: ->${e}<- is already defined in the grammar: ->${t.grammarName}<-`}}});function Gie(t,e){let r=new yN(t,e);return r.resolveRefs(),r.errors}var yN,$ie=R(()=>{"use strict";Ns();Pt();ns();o(Gie,"resolveGrammar");yN=class extends rs{static{o(this,"GastRefResolverVisitor")}constructor(e,r){super(),this.nameToTopRule=e,this.errMsgProvider=r,this.errors=[]}resolveRefs(){Ee(or(this.nameToTopRule),e=>{this.currTopLevel=e,e.accept(this)})}visitNonTerminal(e){let r=this.nameToTopRule[e.nonTerminalName];if(r)e.referencedRule=r;else{let n=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,e);this.errors.push({message:n,type:Pi.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:e.nonTerminalName})}}}});function WT(t,e,r=[]){r=Qr(r);let n=[],i=0;function a(l){return l.concat(fi(t,i+1))}o(a,"remainingPathWith");function s(l){let u=WT(a(l),e,r);return n.concat(u)}for(o(s,"getAlternativesForProd");r.length{Qt(u.definition)===!1&&(n=s(u.definition))}),n;if(l instanceof fr)r.push(l.terminalType);else throw Error("non exhaustive match")}i++}return n.push({partialPath:r,suffixDef:fi(t,i)}),n}function qT(t,e,r,n){let i="EXIT_NONE_TERMINAL",a=[i],s="EXIT_ALTERNATIVE",l=!1,u=e.length,h=u-n-1,f=[],d=[];for(d.push({idx:-1,def:t,ruleStack:[],occurrenceStack:[]});!Qt(d);){let p=d.pop();if(p===s){l&&ma(d).idx<=h&&d.pop();continue}let m=p.def,g=p.idx,y=p.ruleStack,v=p.occurrenceStack;if(Qt(m))continue;let x=m[0];if(x===i){let b={idx:g,def:fi(m),ruleStack:Ru(y),occurrenceStack:Ru(v)};d.push(b)}else if(x instanceof fr)if(g=0;b--){let w=x.definition[b],S={idx:g,def:w.definition.concat(fi(m)),ruleStack:y,occurrenceStack:v};d.push(S),d.push(s)}else if(x instanceof Sn)d.push({idx:g,def:x.definition.concat(fi(m)),ruleStack:y,occurrenceStack:v});else if(x instanceof ts)d.push(SIe(x,g,y,v));else throw Error("non exhaustive match")}return f}function SIe(t,e,r,n){let i=Qr(r);i.push(t.name);let a=Qr(n);return a.push(1),{idx:e,def:t.definition,ruleStack:i,occurrenceStack:a}}var vN,UT,eg,HT,o2,YT,l2,c2=R(()=>{"use strict";Pt();iN();IT();ns();vN=class extends Pu{static{o(this,"AbstractNextPossibleTokensWalker")}constructor(e,r){super(),this.topProd=e,this.path=r,this.possibleTokTypes=[],this.nextProductionName="",this.nextProductionOccurrence=0,this.found=!1,this.isAtEndOfPath=!1}startWalking(){if(this.found=!1,this.path.ruleStack[0]!==this.topProd.name)throw Error("The path does not start with the walker's top Rule!");return this.ruleStack=Qr(this.path.ruleStack).reverse(),this.occurrenceStack=Qr(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes}walk(e,r=[]){this.found||super.walk(e,r)}walkProdRef(e,r,n){if(e.referencedRule.name===this.nextProductionName&&e.idx===this.nextProductionOccurrence){let i=r.concat(n);this.updateExpectedNext(),this.walk(e.referencedRule,i)}}updateExpectedNext(){Qt(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())}},UT=class extends vN{static{o(this,"NextAfterTokenWalker")}constructor(e,r){super(e,r),this.path=r,this.nextTerminalName="",this.nextTerminalOccurrence=0,this.nextTerminalName=this.path.lastTok.name,this.nextTerminalOccurrence=this.path.lastTokOccurrence}walkTerminal(e,r,n){if(this.isAtEndOfPath&&e.terminalType.name===this.nextTerminalName&&e.idx===this.nextTerminalOccurrence&&!this.found){let i=r.concat(n),a=new Sn({definition:i});this.possibleTokTypes=i0(a),this.found=!0}}},eg=class extends Pu{static{o(this,"AbstractNextTerminalAfterProductionWalker")}constructor(e,r){super(),this.topRule=e,this.occurrence=r,this.result={token:void 0,occurrence:void 0,isEndOfRule:void 0}}startWalking(){return this.walk(this.topRule),this.result}},HT=class extends eg{static{o(this,"NextTerminalAfterManyWalker")}walkMany(e,r,n){if(e.idx===this.occurrence){let i=na(r.concat(n));this.result.isEndOfRule=i===void 0,i instanceof fr&&(this.result.token=i.terminalType,this.result.occurrence=i.idx)}else super.walkMany(e,r,n)}},o2=class extends eg{static{o(this,"NextTerminalAfterManySepWalker")}walkManySep(e,r,n){if(e.idx===this.occurrence){let i=na(r.concat(n));this.result.isEndOfRule=i===void 0,i instanceof fr&&(this.result.token=i.terminalType,this.result.occurrence=i.idx)}else super.walkManySep(e,r,n)}},YT=class extends eg{static{o(this,"NextTerminalAfterAtLeastOneWalker")}walkAtLeastOne(e,r,n){if(e.idx===this.occurrence){let i=na(r.concat(n));this.result.isEndOfRule=i===void 0,i instanceof fr&&(this.result.token=i.terminalType,this.result.occurrence=i.idx)}else super.walkAtLeastOne(e,r,n)}},l2=class extends eg{static{o(this,"NextTerminalAfterAtLeastOneSepWalker")}walkAtLeastOneSep(e,r,n){if(e.idx===this.occurrence){let i=na(r.concat(n));this.result.isEndOfRule=i===void 0,i instanceof fr&&(this.result.token=i.terminalType,this.result.occurrence=i.idx)}else super.walkAtLeastOneSep(e,r,n)}};o(WT,"possiblePathsFrom");o(qT,"nextPossibleTokensAfter");o(SIe,"expandTopLevelRule")});function u2(t){if(t instanceof Jr||t==="Option")return $n.OPTION;if(t instanceof br||t==="Repetition")return $n.REPETITION;if(t instanceof An||t==="RepetitionMandatory")return $n.REPETITION_MANDATORY;if(t instanceof _n||t==="RepetitionMandatoryWithSeparator")return $n.REPETITION_MANDATORY_WITH_SEPARATOR;if(t instanceof mn||t==="RepetitionWithSeparator")return $n.REPETITION_WITH_SEPARATOR;if(t instanceof gn||t==="Alternation")return $n.ALTERNATION;throw Error("non exhaustive match")}function jT(t){let{occurrence:e,rule:r,prodType:n,maxLookahead:i}=t,a=u2(n);return a===$n.ALTERNATION?tg(e,r,i):rg(e,r,a,i)}function Uie(t,e,r,n,i,a){let s=tg(t,e,r),l=jie(s)?Zm:Bu;return a(s,n,l,i)}function Hie(t,e,r,n,i,a){let s=rg(t,e,i,r),l=jie(s)?Zm:Bu;return a(s[0],l,n)}function Yie(t,e,r,n){let i=t.length,a=Ia(t,s=>Ia(s,l=>l.length===1));if(e)return function(s){let l=qe(s,u=>u.GATE);for(let u=0;uGr(u)),l=Vr(s,(u,h,f)=>(Ee(h,d=>{Xe(u,d.tokenTypeIdx)||(u[d.tokenTypeIdx]=f),Ee(d.categoryMatches,p=>{Xe(u,p)||(u[p]=f)})}),u),{});return function(){let u=this.LA(1);return l[u.tokenTypeIdx]}}else return function(){for(let s=0;sa.length===1),i=t.length;if(n&&!r){let a=Gr(t);if(a.length===1&&Qt(a[0].categoryMatches)){let l=a[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===l}}else{let s=Vr(a,(l,u,h)=>(l[u.tokenTypeIdx]=!0,Ee(u.categoryMatches,f=>{l[f]=!0}),l),[]);return function(){let l=this.LA(1);return s[l.tokenTypeIdx]===!0}}}else return function(){e:for(let a=0;aWT([s],1)),n=Vie(r.length),i=qe(r,s=>{let l={};return Ee(s,u=>{let h=xN(u.partialPath);Ee(h,f=>{l[f]=!0})}),l}),a=r;for(let s=1;s<=e;s++){let l=a;a=Vie(l.length);for(let u=0;u{let x=xN(v.partialPath);Ee(x,b=>{i[u][b]=!0})})}}}}return n}function tg(t,e,r,n){let i=new XT(t,$n.ALTERNATION,n);return e.accept(i),qie(i.result,r)}function rg(t,e,r,n){let i=new XT(t,r);e.accept(i);let a=i.result,l=new bN(e,t,r).startWalking(),u=new Sn({definition:a}),h=new Sn({definition:l});return qie([u,h],n)}function KT(t,e){e:for(let r=0;r{let i=e[n];return r===i||i.categoryMatchesMap[r.tokenTypeIdx]})}function jie(t){return Ia(t,e=>Ia(e,r=>Ia(r,n=>Qt(n.categoryMatches))))}var $n,bN,XT,ng=R(()=>{"use strict";Pt();c2();IT();s0();ns();(function(t){t[t.OPTION=0]="OPTION",t[t.REPETITION=1]="REPETITION",t[t.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",t[t.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",t[t.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",t[t.ALTERNATION=5]="ALTERNATION"})($n||($n={}));o(u2,"getProdType");o(jT,"getLookaheadPaths");o(Uie,"buildLookaheadFuncForOr");o(Hie,"buildLookaheadFuncForOptionalProd");o(Yie,"buildAlternativesLookAheadFunc");o(Wie,"buildSingleAlternativeLookaheadFunction");bN=class extends Pu{static{o(this,"RestDefinitionFinderWalker")}constructor(e,r,n){super(),this.topProd=e,this.targetOccurrence=r,this.targetProdType=n}startWalking(){return this.walk(this.topProd),this.restDef}checkIsTarget(e,r,n,i){return e.idx===this.targetOccurrence&&this.targetProdType===r?(this.restDef=n.concat(i),!0):!1}walkOption(e,r,n){this.checkIsTarget(e,$n.OPTION,r,n)||super.walkOption(e,r,n)}walkAtLeastOne(e,r,n){this.checkIsTarget(e,$n.REPETITION_MANDATORY,r,n)||super.walkOption(e,r,n)}walkAtLeastOneSep(e,r,n){this.checkIsTarget(e,$n.REPETITION_MANDATORY_WITH_SEPARATOR,r,n)||super.walkOption(e,r,n)}walkMany(e,r,n){this.checkIsTarget(e,$n.REPETITION,r,n)||super.walkOption(e,r,n)}walkManySep(e,r,n){this.checkIsTarget(e,$n.REPETITION_WITH_SEPARATOR,r,n)||super.walkOption(e,r,n)}},XT=class extends rs{static{o(this,"InsideDefinitionFinderVisitor")}constructor(e,r,n){super(),this.targetOccurrence=e,this.targetProdType=r,this.targetRef=n,this.result=[]}checkIsTarget(e,r){e.idx===this.targetOccurrence&&this.targetProdType===r&&(this.targetRef===void 0||e===this.targetRef)&&(this.result=e.definition)}visitOption(e){this.checkIsTarget(e,$n.OPTION)}visitRepetition(e){this.checkIsTarget(e,$n.REPETITION)}visitRepetitionMandatory(e){this.checkIsTarget(e,$n.REPETITION_MANDATORY)}visitRepetitionMandatoryWithSeparator(e){this.checkIsTarget(e,$n.REPETITION_MANDATORY_WITH_SEPARATOR)}visitRepetitionWithSeparator(e){this.checkIsTarget(e,$n.REPETITION_WITH_SEPARATOR)}visitAlternation(e){this.checkIsTarget(e,$n.ALTERNATION)}};o(Vie,"initializeArrayOfArrays");o(xN,"pathToHashKeys");o(AIe,"isUniquePrefixHash");o(qie,"lookAheadSequenceFromAlternatives");o(tg,"getLookaheadPathsForOr");o(rg,"getLookaheadPathsForOptionalProd");o(KT,"containsPath");o(Xie,"isStrictPrefixOfPath");o(jie,"areTokenCategoriesNotUsed")});function Kie(t){let e=t.lookaheadStrategy.validate({rules:t.rules,tokenTypes:t.tokenTypes,grammarName:t.grammarName});return qe(e,r=>Object.assign({type:Pi.CUSTOM_LOOKAHEAD_VALIDATION},r))}function Qie(t,e,r,n){let i=ga(t,u=>_Ie(u,r)),a=IIe(t,e,r),s=ga(t,u=>RIe(u,r)),l=ga(t,u=>DIe(u,t,n,r));return i.concat(a,s,l)}function _Ie(t,e){let r=new wN;t.accept(r);let n=r.allProductions,i=IL(n,LIe),a=Ls(i,l=>l.length>1);return qe(or(a),l=>{let u=na(l),h=e.buildDuplicateFoundError(t,l),f=Rs(u),d={message:h,type:Pi.DUPLICATE_PRODUCTIONS,ruleName:t.name,dslName:f,occurrence:u.idx},p=Zie(u);return p&&(d.parameter=p),d})}function LIe(t){return`${Rs(t)}_#_${t.idx}_#_${Zie(t)}`}function Zie(t){return t instanceof fr?t.terminalType.name:t instanceof Zr?t.nonTerminalName:""}function DIe(t,e,r,n){let i=[];if(Vr(e,(s,l)=>l.name===t.name?s+1:s,0)>1){let s=n.buildDuplicateRuleNameError({topLevelRule:t,grammarName:r});i.push({message:s,type:Pi.DUPLICATE_RULE_NAME,ruleName:t.name})}return i}function Jie(t,e,r){let n=[],i;return Fn(e,t)||(i=`Invalid rule override, rule: ->${t}<- cannot be overridden in the grammar: ->${r}<-as it is not defined in any of the super grammars `,n.push({message:i,type:Pi.INVALID_RULE_OVERRIDE,ruleName:t})),n}function kN(t,e,r,n=[]){let i=[],a=QT(e.definition);if(Qt(a))return[];{let s=t.name;Fn(a,t)&&i.push({message:r.buildLeftRecursionError({topLevelRule:t,leftRecursionPath:n}),type:Pi.LEFT_RECURSION,ruleName:s});let u=jh(a,n.concat([t])),h=ga(u,f=>{let d=Qr(n);return d.push(f),kN(t,f,r,d)});return i.concat(h)}}function QT(t){let e=[];if(Qt(t))return e;let r=na(t);if(r instanceof Zr)e.push(r.referencedRule);else if(r instanceof Sn||r instanceof Jr||r instanceof An||r instanceof _n||r instanceof mn||r instanceof br)e=e.concat(QT(r.definition));else if(r instanceof gn)e=Gr(qe(r.definition,a=>QT(a.definition)));else if(!(r instanceof fr))throw Error("non exhaustive match");let n=n0(r),i=t.length>1;if(n&&i){let a=fi(t);return e.concat(QT(a))}else return e}function eae(t,e){let r=new h2;t.accept(r);let n=r.alternations;return ga(n,a=>{let s=Ru(a.definition);return ga(s,(l,u)=>{let h=qT([l],[],Bu,1);return Qt(h)?[{message:e.buildEmptyAlternationError({topLevelRule:t,alternation:a,emptyChoiceIdx:u}),type:Pi.NONE_LAST_EMPTY_ALT,ruleName:t.name,occurrence:a.idx,alternative:u+1}]:[]})})}function tae(t,e,r){let n=new h2;t.accept(n);let i=n.alternations;return i=Kh(i,s=>s.ignoreAmbiguities===!0),ga(i,s=>{let l=s.idx,u=s.maxLookahead||e,h=tg(l,t,u,s),f=NIe(h,s,t,r),d=MIe(h,s,t,r);return f.concat(d)})}function RIe(t,e){let r=new h2;t.accept(r);let n=r.alternations;return ga(n,a=>a.definition.length>255?[{message:e.buildTooManyAlternativesError({topLevelRule:t,alternation:a}),type:Pi.TOO_MANY_ALTS,ruleName:t.name,occurrence:a.idx}]:[])}function rae(t,e,r){let n=[];return Ee(t,i=>{let a=new TN;i.accept(a);let s=a.allProductions;Ee(s,l=>{let u=u2(l),h=l.maxLookahead||e,f=l.idx,p=rg(f,i,u,h)[0];if(Qt(Gr(p))){let m=r.buildEmptyRepetitionError({topLevelRule:i,repetition:l});n.push({message:m,type:Pi.NO_NON_EMPTY_LOOKAHEAD,ruleName:i.name})}})}),n}function NIe(t,e,r,n){let i=[],a=Vr(t,(l,u,h)=>(e.definition[h].ignoreAmbiguities===!0||Ee(u,f=>{let d=[h];Ee(t,(p,m)=>{h!==m&&KT(p,f)&&e.definition[m].ignoreAmbiguities!==!0&&d.push(m)}),d.length>1&&!KT(i,f)&&(i.push(f),l.push({alts:d,path:f}))}),l),[]);return qe(a,l=>{let u=qe(l.alts,f=>f+1);return{message:n.buildAlternationAmbiguityError({topLevelRule:r,alternation:e,ambiguityIndices:u,prefixPath:l.path}),type:Pi.AMBIGUOUS_ALTS,ruleName:r.name,occurrence:e.idx,alternatives:l.alts}})}function MIe(t,e,r,n){let i=Vr(t,(s,l,u)=>{let h=qe(l,f=>({idx:u,path:f}));return s.concat(h)},[]);return wc(ga(i,s=>{if(e.definition[s.idx].ignoreAmbiguities===!0)return[];let u=s.idx,h=s.path,f=$r(i,p=>e.definition[p.idx].ignoreAmbiguities!==!0&&p.idx{let m=[p.idx+1,u+1],g=e.idx===0?"":e.idx;return{message:n.buildAlternationPrefixAmbiguityError({topLevelRule:r,alternation:e,ambiguityIndices:m,prefixPath:p.path}),type:Pi.AMBIGUOUS_PREFIX_ALTS,ruleName:r.name,occurrence:g,alternatives:m}})}))}function IIe(t,e,r){let n=[],i=qe(e,a=>a.name);return Ee(t,a=>{let s=a.name;if(Fn(i,s)){let l=r.buildNamespaceConflictError(a);n.push({message:l,type:Pi.CONFLICT_TOKENS_RULES_NAMESPACE,ruleName:s})}}),n}var wN,h2,TN,f2=R(()=>{"use strict";Pt();Ns();ns();ng();c2();s0();o(Kie,"validateLookahead");o(Qie,"validateGrammar");o(_Ie,"validateDuplicateProductions");o(LIe,"identifyProductionForDuplicates");o(Zie,"getExtraProductionArgument");wN=class extends rs{static{o(this,"OccurrenceValidationCollector")}constructor(){super(...arguments),this.allProductions=[]}visitNonTerminal(e){this.allProductions.push(e)}visitOption(e){this.allProductions.push(e)}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}visitAlternation(e){this.allProductions.push(e)}visitTerminal(e){this.allProductions.push(e)}};o(DIe,"validateRuleDoesNotAlreadyExist");o(Jie,"validateRuleIsOverridden");o(kN,"validateNoLeftRecursion");o(QT,"getFirstNoneTerminal");h2=class extends rs{static{o(this,"OrCollector")}constructor(){super(...arguments),this.alternations=[]}visitAlternation(e){this.alternations.push(e)}};o(eae,"validateEmptyOrAlternative");o(tae,"validateAmbiguousAlternationAlternatives");TN=class extends rs{static{o(this,"RepetitionCollector")}constructor(){super(...arguments),this.allProductions=[]}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}};o(RIe,"validateTooManyAlts");o(rae,"validateSomeNonEmptyLookaheadPath");o(NIe,"checkAlternativesAmbiguities");o(MIe,"checkPrefixAlternativesAmbiguities");o(IIe,"checkTerminalAndNoneTerminalsNameSpace")});function nae(t){let e=Xh(t,{errMsgProvider:zie}),r={};return Ee(t.rules,n=>{r[n.name]=n}),Gie(r,e.errMsgProvider)}function iae(t){return t=Xh(t,{errMsgProvider:Ol}),Qie(t.rules,t.tokenTypes,t.errMsgProvider,t.grammarName)}var aae=R(()=>{"use strict";Pt();$ie();f2();Jm();o(nae,"resolveGrammar");o(iae,"validateGrammar")});function nf(t){return Fn(uae,t.name)}var sae,oae,lae,cae,uae,ig,c0,d2,p2,m2,ag=R(()=>{"use strict";Pt();sae="MismatchedTokenException",oae="NoViableAltException",lae="EarlyExitException",cae="NotAllInputParsedException",uae=[sae,oae,lae,cae];Object.freeze(uae);o(nf,"isRecognitionException");ig=class extends Error{static{o(this,"RecognitionException")}constructor(e,r){super(e),this.token=r,this.resyncedTokens=[],Object.setPrototypeOf(this,new.target.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},c0=class extends ig{static{o(this,"MismatchedTokenException")}constructor(e,r,n){super(e,r),this.previousToken=n,this.name=sae}},d2=class extends ig{static{o(this,"NoViableAltException")}constructor(e,r,n){super(e,r),this.previousToken=n,this.name=oae}},p2=class extends ig{static{o(this,"NotAllInputParsedException")}constructor(e,r){super(e,r),this.name=cae}},m2=class extends ig{static{o(this,"EarlyExitException")}constructor(e,r,n){super(e,r),this.previousToken=n,this.name=lae}}});function OIe(t,e,r,n,i,a,s){let l=this.getKeyForAutomaticLookahead(n,i),u=this.firstAfterRepMap[l];if(u===void 0){let p=this.getCurrRuleFullName(),m=this.getGAstProductions()[p];u=new a(m,i).startWalking(),this.firstAfterRepMap[l]=u}let h=u.token,f=u.occurrence,d=u.isEndOfRule;this.RULE_STACK.length===1&&d&&h===void 0&&(h=fo,f=1),!(h===void 0||f===void 0)&&this.shouldInRepetitionRecoveryBeTried(h,f,s)&&this.tryInRepetitionRecovery(t,e,r,h)}var EN,SN,CN,ZT,AN=R(()=>{"use strict";l0();Pt();ag();aN();Ns();EN={},SN="InRuleRecoveryException",CN=class extends Error{static{o(this,"InRuleRecoveryException")}constructor(e){super(e),this.name=SN}},ZT=class{static{o(this,"Recoverable")}initRecoverable(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=Xe(e,"recoveryEnabled")?e.recoveryEnabled:is.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=OIe)}getTokenToInsert(e){let r=o0(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return r.isInsertedInRecovery=!0,r}canTokenTypeBeInsertedInRecovery(e){return!0}canTokenTypeBeDeletedInRecovery(e){return!0}tryInRepetitionRecovery(e,r,n,i){let a=this.findReSyncTokenType(),s=this.exportLexerState(),l=[],u=!1,h=this.LA(1),f=this.LA(1),d=o(()=>{let p=this.LA(0),m=this.errorMessageProvider.buildMismatchTokenMessage({expected:i,actual:h,previous:p,ruleName:this.getCurrRuleFullName()}),g=new c0(m,h,this.LA(0));g.resyncedTokens=Ru(l),this.SAVE_ERROR(g)},"generateErrorMessage");for(;!u;)if(this.tokenMatcher(f,i)){d();return}else if(n.call(this)){d(),e.apply(this,r);return}else this.tokenMatcher(f,a)?u=!0:(f=this.SKIP_TOKEN(),this.addToResyncTokens(f,l));this.importLexerState(s)}shouldInRepetitionRecoveryBeTried(e,r,n){return!(n===!1||this.tokenMatcher(this.LA(1),e)||this.isBackTracking()||this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,r)))}getFollowsForInRuleRecovery(e,r){let n=this.getCurrentGrammarPath(e,r);return this.getNextPossibleTokenTypes(n)}tryInRuleRecovery(e,r){if(this.canRecoverWithSingleTokenInsertion(e,r))return this.getTokenToInsert(e);if(this.canRecoverWithSingleTokenDeletion(e)){let n=this.SKIP_TOKEN();return this.consumeToken(),n}throw new CN("sad sad panda")}canPerformInRuleRecovery(e,r){return this.canRecoverWithSingleTokenInsertion(e,r)||this.canRecoverWithSingleTokenDeletion(e)}canRecoverWithSingleTokenInsertion(e,r){if(!this.canTokenTypeBeInsertedInRecovery(e)||Qt(r))return!1;let n=this.LA(1);return Za(r,a=>this.tokenMatcher(n,a))!==void 0}canRecoverWithSingleTokenDeletion(e){return this.canTokenTypeBeDeletedInRecovery(e)?this.tokenMatcher(this.LA(2),e):!1}isInCurrentRuleReSyncSet(e){let r=this.getCurrFollowKey(),n=this.getFollowSetFromFollowKey(r);return Fn(n,e)}findReSyncTokenType(){let e=this.flattenFollowSet(),r=this.LA(1),n=2;for(;;){let i=Za(e,a=>s2(r,a));if(i!==void 0)return i;r=this.LA(n),n++}}getCurrFollowKey(){if(this.RULE_STACK.length===1)return EN;let e=this.getLastExplicitRuleShortName(),r=this.getLastExplicitRuleOccurrenceIndex(),n=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:r,inRule:this.shortRuleNameToFullName(n)}}buildFullFollowKeyStack(){let e=this.RULE_STACK,r=this.RULE_OCCURRENCE_STACK;return qe(e,(n,i)=>i===0?EN:{ruleName:this.shortRuleNameToFullName(n),idxInCallingRule:r[i],inRule:this.shortRuleNameToFullName(e[i-1])})}flattenFollowSet(){let e=qe(this.buildFullFollowKeyStack(),r=>this.getFollowSetFromFollowKey(r));return Gr(e)}getFollowSetFromFollowKey(e){if(e===EN)return[fo];let r=e.ruleName+e.idxInCallingRule+OT+e.inRule;return this.resyncFollows[r]}addToResyncTokens(e,r){return this.tokenMatcher(e,fo)||r.push(e),r}reSyncTo(e){let r=[],n=this.LA(1);for(;this.tokenMatcher(n,e)===!1;)n=this.SKIP_TOKEN(),this.addToResyncTokens(n,r);return Ru(r)}attemptInRepetitionRecovery(e,r,n,i,a,s,l){}getCurrentGrammarPath(e,r){let n=this.getHumanReadableRuleStack(),i=Qr(this.RULE_OCCURRENCE_STACK);return{ruleStack:n,occurrenceStack:i,lastTok:e,lastTokOccurrence:r}}getHumanReadableRuleStack(){return qe(this.RULE_STACK,e=>this.shortRuleNameToFullName(e))}};o(OIe,"attemptInRepetitionRecovery")});function JT(t,e,r){return r|e|t}var ek=R(()=>{"use strict";o(JT,"getKeyForAutomaticLookahead")});var $u,_N=R(()=>{"use strict";Pt();Jm();Ns();f2();ng();$u=class{static{o(this,"LLkLookaheadStrategy")}constructor(e){var r;this.maxLookahead=(r=e?.maxLookahead)!==null&&r!==void 0?r:is.maxLookahead}validate(e){let r=this.validateNoLeftRecursion(e.rules);if(Qt(r)){let n=this.validateEmptyOrAlternatives(e.rules),i=this.validateAmbiguousAlternationAlternatives(e.rules,this.maxLookahead),a=this.validateSomeNonEmptyLookaheadPath(e.rules,this.maxLookahead);return[...r,...n,...i,...a]}return r}validateNoLeftRecursion(e){return ga(e,r=>kN(r,r,Ol))}validateEmptyOrAlternatives(e){return ga(e,r=>eae(r,Ol))}validateAmbiguousAlternationAlternatives(e,r){return ga(e,n=>tae(n,r,Ol))}validateSomeNonEmptyLookaheadPath(e,r){return rae(e,r,Ol)}buildLookaheadForAlternation(e){return Uie(e.prodOccurrence,e.rule,e.maxLookahead,e.hasPredicates,e.dynamicTokensEnabled,Yie)}buildLookaheadForOptional(e){return Hie(e.prodOccurrence,e.rule,e.maxLookahead,e.dynamicTokensEnabled,u2(e.prodType),Wie)}}});function PIe(t){tk.reset(),t.accept(tk);let e=tk.dslMethods;return tk.reset(),e}var rk,LN,tk,hae=R(()=>{"use strict";Pt();Ns();ek();ns();_N();rk=class{static{o(this,"LooksAhead")}initLooksAhead(e){this.dynamicTokensEnabled=Xe(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:is.dynamicTokensEnabled,this.maxLookahead=Xe(e,"maxLookahead")?e.maxLookahead:is.maxLookahead,this.lookaheadStrategy=Xe(e,"lookaheadStrategy")?e.lookaheadStrategy:new $u({maxLookahead:this.maxLookahead}),this.lookAheadFuncsCache=new Map}preComputeLookaheadFunctions(e){Ee(e,r=>{this.TRACE_INIT(`${r.name} Rule Lookahead`,()=>{let{alternation:n,repetition:i,option:a,repetitionMandatory:s,repetitionMandatoryWithSeparator:l,repetitionWithSeparator:u}=PIe(r);Ee(n,h=>{let f=h.idx===0?"":h.idx;this.TRACE_INIT(`${Rs(h)}${f}`,()=>{let d=this.lookaheadStrategy.buildLookaheadForAlternation({prodOccurrence:h.idx,rule:r,maxLookahead:h.maxLookahead||this.maxLookahead,hasPredicates:h.hasPredicates,dynamicTokensEnabled:this.dynamicTokensEnabled}),p=JT(this.fullRuleNameToShort[r.name],256,h.idx);this.setLaFuncCache(p,d)})}),Ee(i,h=>{this.computeLookaheadFunc(r,h.idx,768,"Repetition",h.maxLookahead,Rs(h))}),Ee(a,h=>{this.computeLookaheadFunc(r,h.idx,512,"Option",h.maxLookahead,Rs(h))}),Ee(s,h=>{this.computeLookaheadFunc(r,h.idx,1024,"RepetitionMandatory",h.maxLookahead,Rs(h))}),Ee(l,h=>{this.computeLookaheadFunc(r,h.idx,1536,"RepetitionMandatoryWithSeparator",h.maxLookahead,Rs(h))}),Ee(u,h=>{this.computeLookaheadFunc(r,h.idx,1280,"RepetitionWithSeparator",h.maxLookahead,Rs(h))})})})}computeLookaheadFunc(e,r,n,i,a,s){this.TRACE_INIT(`${s}${r===0?"":r}`,()=>{let l=this.lookaheadStrategy.buildLookaheadForOptional({prodOccurrence:r,rule:e,maxLookahead:a||this.maxLookahead,dynamicTokensEnabled:this.dynamicTokensEnabled,prodType:i}),u=JT(this.fullRuleNameToShort[e.name],n,r);this.setLaFuncCache(u,l)})}getKeyForAutomaticLookahead(e,r){let n=this.getLastExplicitRuleShortName();return JT(n,e,r)}getLaFuncFromCache(e){return this.lookAheadFuncsCache.get(e)}setLaFuncCache(e,r){this.lookAheadFuncsCache.set(e,r)}},LN=class extends rs{static{o(this,"DslMethodsCollectorVisitor")}constructor(){super(...arguments),this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}reset(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}visitOption(e){this.dslMethods.option.push(e)}visitRepetitionWithSeparator(e){this.dslMethods.repetitionWithSeparator.push(e)}visitRepetitionMandatory(e){this.dslMethods.repetitionMandatory.push(e)}visitRepetitionMandatoryWithSeparator(e){this.dslMethods.repetitionMandatoryWithSeparator.push(e)}visitRepetition(e){this.dslMethods.repetition.push(e)}visitAlternation(e){this.dslMethods.alternation.push(e)}},tk=new LN;o(PIe,"collectMethods")});function NN(t,e){isNaN(t.startOffset)===!0?(t.startOffset=e.startOffset,t.endOffset=e.endOffset):t.endOffset{"use strict";o(NN,"setNodeLocationOnlyOffset");o(MN,"setNodeLocationFull");o(fae,"addTerminalToCst");o(dae,"addNoneTerminalToCst")});function IN(t,e){Object.defineProperty(t,BIe,{enumerable:!1,configurable:!0,writable:!1,value:e})}var BIe,mae=R(()=>{"use strict";BIe="name";o(IN,"defineNameProp")});function FIe(t,e){let r=Dr(t),n=r.length;for(let i=0;is.msg);throw Error(`Errors Detected in CST Visitor <${this.constructor.name}>: + ${a.join(` + +`).replace(/\n/g,` + `)}`)}},"validateVisitor")};return r.prototype=n,r.prototype.constructor=r,r._RULE_NAMES=e,r}function yae(t,e,r){let n=o(function(){},"derivedConstructor");IN(n,t+"BaseSemanticsWithDefaults");let i=Object.create(r.prototype);return Ee(e,a=>{i[a]=FIe}),n.prototype=i,n.prototype.constructor=n,n}function zIe(t,e){return GIe(t,e)}function GIe(t,e){let r=$r(e,i=>wi(t[i])===!1),n=qe(r,i=>({msg:`Missing visitor method: <${i}> on ${t.constructor.name} CST Visitor.`,type:ON.MISSING_METHOD,methodName:i}));return wc(n)}var ON,vae=R(()=>{"use strict";Pt();mae();o(FIe,"defaultVisit");o(gae,"createBaseSemanticVisitorConstructor");o(yae,"createBaseVisitorConstructorWithDefaults");(function(t){t[t.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",t[t.MISSING_METHOD=1]="MISSING_METHOD"})(ON||(ON={}));o(zIe,"validateVisitor");o(GIe,"validateMissingCstMethods")});var sk,xae=R(()=>{"use strict";pae();Pt();vae();Ns();sk=class{static{o(this,"TreeBuilder")}initTreeBuilder(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=Xe(e,"nodeLocationTracking")?e.nodeLocationTracking:is.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=qn,this.cstFinallyStateUpdate=qn,this.cstPostTerminal=qn,this.cstPostNonTerminal=qn,this.cstPostRule=qn;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=MN,this.setNodeLocationFromNode=MN,this.cstPostRule=qn,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=qn,this.setNodeLocationFromNode=qn,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=NN,this.setNodeLocationFromNode=NN,this.cstPostRule=qn,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=qn,this.setNodeLocationFromNode=qn,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=qn,this.setNodeLocationFromNode=qn,this.cstPostRule=qn,this.setInitialNodeLocation=qn;else throw Error(`Invalid config option: "${e.nodeLocationTracking}"`)}setInitialNodeLocationOnlyOffsetRecovery(e){e.location={startOffset:NaN,endOffset:NaN}}setInitialNodeLocationOnlyOffsetRegular(e){e.location={startOffset:this.LA(1).startOffset,endOffset:NaN}}setInitialNodeLocationFullRecovery(e){e.location={startOffset:NaN,startLine:NaN,startColumn:NaN,endOffset:NaN,endLine:NaN,endColumn:NaN}}setInitialNodeLocationFullRegular(e){let r=this.LA(1);e.location={startOffset:r.startOffset,startLine:r.startLine,startColumn:r.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}}cstInvocationStateUpdate(e){let r={name:e,children:Object.create(null)};this.setInitialNodeLocation(r),this.CST_STACK.push(r)}cstFinallyStateUpdate(){this.CST_STACK.pop()}cstPostRuleFull(e){let r=this.LA(0),n=e.location;n.startOffset<=r.startOffset?(n.endOffset=r.endOffset,n.endLine=r.endLine,n.endColumn=r.endColumn):(n.startOffset=NaN,n.startLine=NaN,n.startColumn=NaN)}cstPostRuleOnlyOffset(e){let r=this.LA(0),n=e.location;n.startOffset<=r.startOffset?n.endOffset=r.endOffset:n.startOffset=NaN}cstPostTerminal(e,r){let n=this.CST_STACK[this.CST_STACK.length-1];fae(n,r,e),this.setNodeLocationFromToken(n.location,r)}cstPostNonTerminal(e,r){let n=this.CST_STACK[this.CST_STACK.length-1];dae(n,r,e),this.setNodeLocationFromNode(n.location,e.location)}getBaseCstVisitorConstructor(){if(er(this.baseCstVisitorConstructor)){let e=gae(this.className,Dr(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor}getBaseCstVisitorConstructorWithDefaults(){if(er(this.baseCstVisitorWithDefaultsConstructor)){let e=yae(this.className,Dr(this.gastProductionsCache),this.getBaseCstVisitorConstructor());return this.baseCstVisitorWithDefaultsConstructor=e,e}return this.baseCstVisitorWithDefaultsConstructor}getLastExplicitRuleShortName(){let e=this.RULE_STACK;return e[e.length-1]}getPreviousExplicitRuleShortName(){let e=this.RULE_STACK;return e[e.length-2]}getLastExplicitRuleOccurrenceIndex(){let e=this.RULE_OCCURRENCE_STACK;return e[e.length-1]}}});var ok,bae=R(()=>{"use strict";Ns();ok=class{static{o(this,"LexerAdapter")}initLexerAdapter(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1}set input(e){if(this.selfAnalysisDone!==!0)throw Error("Missing invocation at the end of the Parser's constructor.");this.reset(),this.tokVector=e,this.tokVectorLength=e.length}get input(){return this.tokVector}SKIP_TOKEN(){return this.currIdx<=this.tokVector.length-2?(this.consumeToken(),this.LA(1)):sg}LA(e){let r=this.currIdx+e;return r<0||this.tokVectorLength<=r?sg:this.tokVector[r]}consumeToken(){this.currIdx++}exportLexerState(){return this.currIdx}importLexerState(e){this.currIdx=e}resetLexerState(){this.currIdx=-1}moveToTerminatedState(){this.currIdx=this.tokVector.length-1}getLexerPosition(){return this.exportLexerState()}}});var lk,wae=R(()=>{"use strict";Pt();ag();Ns();Jm();f2();ns();lk=class{static{o(this,"RecognizerApi")}ACTION(e){return e.call(this)}consume(e,r,n){return this.consumeInternal(r,e,n)}subrule(e,r,n){return this.subruleInternal(r,e,n)}option(e,r){return this.optionInternal(r,e)}or(e,r){return this.orInternal(r,e)}many(e,r){return this.manyInternal(e,r)}atLeastOne(e,r){return this.atLeastOneInternal(e,r)}CONSUME(e,r){return this.consumeInternal(e,0,r)}CONSUME1(e,r){return this.consumeInternal(e,1,r)}CONSUME2(e,r){return this.consumeInternal(e,2,r)}CONSUME3(e,r){return this.consumeInternal(e,3,r)}CONSUME4(e,r){return this.consumeInternal(e,4,r)}CONSUME5(e,r){return this.consumeInternal(e,5,r)}CONSUME6(e,r){return this.consumeInternal(e,6,r)}CONSUME7(e,r){return this.consumeInternal(e,7,r)}CONSUME8(e,r){return this.consumeInternal(e,8,r)}CONSUME9(e,r){return this.consumeInternal(e,9,r)}SUBRULE(e,r){return this.subruleInternal(e,0,r)}SUBRULE1(e,r){return this.subruleInternal(e,1,r)}SUBRULE2(e,r){return this.subruleInternal(e,2,r)}SUBRULE3(e,r){return this.subruleInternal(e,3,r)}SUBRULE4(e,r){return this.subruleInternal(e,4,r)}SUBRULE5(e,r){return this.subruleInternal(e,5,r)}SUBRULE6(e,r){return this.subruleInternal(e,6,r)}SUBRULE7(e,r){return this.subruleInternal(e,7,r)}SUBRULE8(e,r){return this.subruleInternal(e,8,r)}SUBRULE9(e,r){return this.subruleInternal(e,9,r)}OPTION(e){return this.optionInternal(e,0)}OPTION1(e){return this.optionInternal(e,1)}OPTION2(e){return this.optionInternal(e,2)}OPTION3(e){return this.optionInternal(e,3)}OPTION4(e){return this.optionInternal(e,4)}OPTION5(e){return this.optionInternal(e,5)}OPTION6(e){return this.optionInternal(e,6)}OPTION7(e){return this.optionInternal(e,7)}OPTION8(e){return this.optionInternal(e,8)}OPTION9(e){return this.optionInternal(e,9)}OR(e){return this.orInternal(e,0)}OR1(e){return this.orInternal(e,1)}OR2(e){return this.orInternal(e,2)}OR3(e){return this.orInternal(e,3)}OR4(e){return this.orInternal(e,4)}OR5(e){return this.orInternal(e,5)}OR6(e){return this.orInternal(e,6)}OR7(e){return this.orInternal(e,7)}OR8(e){return this.orInternal(e,8)}OR9(e){return this.orInternal(e,9)}MANY(e){this.manyInternal(0,e)}MANY1(e){this.manyInternal(1,e)}MANY2(e){this.manyInternal(2,e)}MANY3(e){this.manyInternal(3,e)}MANY4(e){this.manyInternal(4,e)}MANY5(e){this.manyInternal(5,e)}MANY6(e){this.manyInternal(6,e)}MANY7(e){this.manyInternal(7,e)}MANY8(e){this.manyInternal(8,e)}MANY9(e){this.manyInternal(9,e)}MANY_SEP(e){this.manySepFirstInternal(0,e)}MANY_SEP1(e){this.manySepFirstInternal(1,e)}MANY_SEP2(e){this.manySepFirstInternal(2,e)}MANY_SEP3(e){this.manySepFirstInternal(3,e)}MANY_SEP4(e){this.manySepFirstInternal(4,e)}MANY_SEP5(e){this.manySepFirstInternal(5,e)}MANY_SEP6(e){this.manySepFirstInternal(6,e)}MANY_SEP7(e){this.manySepFirstInternal(7,e)}MANY_SEP8(e){this.manySepFirstInternal(8,e)}MANY_SEP9(e){this.manySepFirstInternal(9,e)}AT_LEAST_ONE(e){this.atLeastOneInternal(0,e)}AT_LEAST_ONE1(e){return this.atLeastOneInternal(1,e)}AT_LEAST_ONE2(e){this.atLeastOneInternal(2,e)}AT_LEAST_ONE3(e){this.atLeastOneInternal(3,e)}AT_LEAST_ONE4(e){this.atLeastOneInternal(4,e)}AT_LEAST_ONE5(e){this.atLeastOneInternal(5,e)}AT_LEAST_ONE6(e){this.atLeastOneInternal(6,e)}AT_LEAST_ONE7(e){this.atLeastOneInternal(7,e)}AT_LEAST_ONE8(e){this.atLeastOneInternal(8,e)}AT_LEAST_ONE9(e){this.atLeastOneInternal(9,e)}AT_LEAST_ONE_SEP(e){this.atLeastOneSepFirstInternal(0,e)}AT_LEAST_ONE_SEP1(e){this.atLeastOneSepFirstInternal(1,e)}AT_LEAST_ONE_SEP2(e){this.atLeastOneSepFirstInternal(2,e)}AT_LEAST_ONE_SEP3(e){this.atLeastOneSepFirstInternal(3,e)}AT_LEAST_ONE_SEP4(e){this.atLeastOneSepFirstInternal(4,e)}AT_LEAST_ONE_SEP5(e){this.atLeastOneSepFirstInternal(5,e)}AT_LEAST_ONE_SEP6(e){this.atLeastOneSepFirstInternal(6,e)}AT_LEAST_ONE_SEP7(e){this.atLeastOneSepFirstInternal(7,e)}AT_LEAST_ONE_SEP8(e){this.atLeastOneSepFirstInternal(8,e)}AT_LEAST_ONE_SEP9(e){this.atLeastOneSepFirstInternal(9,e)}RULE(e,r,n=og){if(Fn(this.definedRulesNames,e)){let s={message:Ol.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),type:Pi.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(s)}this.definedRulesNames.push(e);let i=this.defineRule(e,r,n);return this[e]=i,i}OVERRIDE_RULE(e,r,n=og){let i=Jie(e,this.definedRulesNames,this.className);this.definitionErrors=this.definitionErrors.concat(i);let a=this.defineRule(e,r,n);return this[e]=a,a}BACKTRACK(e,r){return function(){this.isBackTrackingStack.push(1);let n=this.saveRecogState();try{return e.apply(this,r),!0}catch(i){if(nf(i))return!1;throw i}finally{this.reloadRecogState(n),this.isBackTrackingStack.pop()}}}getGAstProductions(){return this.gastProductionsCache}getSerializedGastProductions(){return NT(or(this.gastProductionsCache))}}});var ck,Tae=R(()=>{"use strict";Pt();ek();ag();ng();c2();Ns();AN();l0();s0();ck=class{static{o(this,"RecognizerEngine")}initRecognizerEngine(e,r){if(this.className=this.constructor.name,this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=Zm,this.subruleIdx=0,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},Xe(r,"serializedGrammar"))throw Error(`The Parser's configuration can no longer contain a property. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0 + For Further details.`);if(wt(e)){if(Qt(e))throw Error(`A Token Vocabulary cannot be empty. + Note that the first argument for the parser constructor + is no longer a Token vector (since v4.0).`);if(typeof e[0].startOffset=="number")throw Error(`The Parser constructor no longer accepts a token vector as the first argument. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_4-0-0 + For Further details.`)}if(wt(e))this.tokensMap=Vr(e,(a,s)=>(a[s.name]=s,a),{});else if(Xe(e,"modes")&&Ia(Gr(or(e.modes)),Die)){let a=Gr(or(e.modes)),s=Pm(a);this.tokensMap=Vr(s,(l,u)=>(l[u.name]=u,l),{})}else if(pn(e))this.tokensMap=Qr(e);else throw new Error(" argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=fo;let n=Xe(e,"modes")?Gr(or(e.modes)):or(e),i=Ia(n,a=>Qt(a.categoryMatches));this.tokenMatcher=i?Zm:Bu,Fu(or(this.tokensMap))}defineRule(e,r,n){if(this.selfAnalysisDone)throw Error(`Grammar rule <${e}> may not be defined after the 'performSelfAnalysis' method has been called' +Make sure that all grammar rule definitions are done before 'performSelfAnalysis' is called.`);let i=Xe(n,"resyncEnabled")?n.resyncEnabled:og.resyncEnabled,a=Xe(n,"recoveryValueFunc")?n.recoveryValueFunc:og.recoveryValueFunc,s=this.ruleShortNameIdx<<12;this.ruleShortNameIdx++,this.shortRuleNameToFull[s]=e,this.fullRuleNameToShort[e]=s;let l;return this.outputCst===!0?l=o(function(...f){try{this.ruleInvocationStateUpdate(s,e,this.subruleIdx),r.apply(this,f);let d=this.CST_STACK[this.CST_STACK.length-1];return this.cstPostRule(d),d}catch(d){return this.invokeRuleCatch(d,i,a)}finally{this.ruleFinallyStateUpdate()}},"invokeRuleWithTry"):l=o(function(...f){try{return this.ruleInvocationStateUpdate(s,e,this.subruleIdx),r.apply(this,f)}catch(d){return this.invokeRuleCatch(d,i,a)}finally{this.ruleFinallyStateUpdate()}},"invokeRuleWithTryCst"),Object.assign(l,{ruleName:e,originalGrammarAction:r})}invokeRuleCatch(e,r,n){let i=this.RULE_STACK.length===1,a=r&&!this.isBackTracking()&&this.recoveryEnabled;if(nf(e)){let s=e;if(a){let l=this.findReSyncTokenType();if(this.isInCurrentRuleReSyncSet(l))if(s.resyncedTokens=this.reSyncTo(l),this.outputCst){let u=this.CST_STACK[this.CST_STACK.length-1];return u.recoveredNode=!0,u}else return n(e);else{if(this.outputCst){let u=this.CST_STACK[this.CST_STACK.length-1];u.recoveredNode=!0,s.partialCstResult=u}throw s}}else{if(i)return this.moveToTerminatedState(),n(e);throw s}}else throw e}optionInternal(e,r){let n=this.getKeyForAutomaticLookahead(512,r);return this.optionInternalLogic(e,r,n)}optionInternalLogic(e,r,n){let i=this.getLaFuncFromCache(n),a;if(typeof e!="function"){a=e.DEF;let s=e.GATE;if(s!==void 0){let l=i;i=o(()=>s.call(this)&&l.call(this),"lookAheadFunc")}}else a=e;if(i.call(this)===!0)return a.call(this)}atLeastOneInternal(e,r){let n=this.getKeyForAutomaticLookahead(1024,e);return this.atLeastOneInternalLogic(e,r,n)}atLeastOneInternalLogic(e,r,n){let i=this.getLaFuncFromCache(n),a;if(typeof r!="function"){a=r.DEF;let s=r.GATE;if(s!==void 0){let l=i;i=o(()=>s.call(this)&&l.call(this),"lookAheadFunc")}}else a=r;if(i.call(this)===!0){let s=this.doSingleRepetition(a);for(;i.call(this)===!0&&s===!0;)s=this.doSingleRepetition(a)}else throw this.raiseEarlyExitException(e,$n.REPETITION_MANDATORY,r.ERR_MSG);this.attemptInRepetitionRecovery(this.atLeastOneInternal,[e,r],i,1024,e,YT)}atLeastOneSepFirstInternal(e,r){let n=this.getKeyForAutomaticLookahead(1536,e);this.atLeastOneSepFirstInternalLogic(e,r,n)}atLeastOneSepFirstInternalLogic(e,r,n){let i=r.DEF,a=r.SEP;if(this.getLaFuncFromCache(n).call(this)===!0){i.call(this);let l=o(()=>this.tokenMatcher(this.LA(1),a),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),a)===!0;)this.CONSUME(a),i.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,a,l,i,l2],l,1536,e,l2)}else throw this.raiseEarlyExitException(e,$n.REPETITION_MANDATORY_WITH_SEPARATOR,r.ERR_MSG)}manyInternal(e,r){let n=this.getKeyForAutomaticLookahead(768,e);return this.manyInternalLogic(e,r,n)}manyInternalLogic(e,r,n){let i=this.getLaFuncFromCache(n),a;if(typeof r!="function"){a=r.DEF;let l=r.GATE;if(l!==void 0){let u=i;i=o(()=>l.call(this)&&u.call(this),"lookaheadFunction")}}else a=r;let s=!0;for(;i.call(this)===!0&&s===!0;)s=this.doSingleRepetition(a);this.attemptInRepetitionRecovery(this.manyInternal,[e,r],i,768,e,HT,s)}manySepFirstInternal(e,r){let n=this.getKeyForAutomaticLookahead(1280,e);this.manySepFirstInternalLogic(e,r,n)}manySepFirstInternalLogic(e,r,n){let i=r.DEF,a=r.SEP;if(this.getLaFuncFromCache(n).call(this)===!0){i.call(this);let l=o(()=>this.tokenMatcher(this.LA(1),a),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),a)===!0;)this.CONSUME(a),i.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,a,l,i,o2],l,1280,e,o2)}}repetitionSepSecondInternal(e,r,n,i,a){for(;n();)this.CONSUME(r),i.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,r,n,i,a],n,1536,e,a)}doSingleRepetition(e){let r=this.getLexerPosition();return e.call(this),this.getLexerPosition()>r}orInternal(e,r){let n=this.getKeyForAutomaticLookahead(256,r),i=wt(e)?e:e.DEF,s=this.getLaFuncFromCache(n).call(this,i);if(s!==void 0)return i[s].ALT.call(this);this.raiseNoAltException(r,e.ERR_MSG)}ruleFinallyStateUpdate(){if(this.RULE_STACK.pop(),this.RULE_OCCURRENCE_STACK.pop(),this.cstFinallyStateUpdate(),this.RULE_STACK.length===0&&this.isAtEndOfInput()===!1){let e=this.LA(1),r=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new p2(r,e))}}subruleInternal(e,r,n){let i;try{let a=n!==void 0?n.ARGS:void 0;return this.subruleIdx=r,i=e.apply(this,a),this.cstPostNonTerminal(i,n!==void 0&&n.LABEL!==void 0?n.LABEL:e.ruleName),i}catch(a){throw this.subruleInternalError(a,n,e.ruleName)}}subruleInternalError(e,r,n){throw nf(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstResult,r!==void 0&&r.LABEL!==void 0?r.LABEL:n),delete e.partialCstResult),e}consumeInternal(e,r,n){let i;try{let a=this.LA(1);this.tokenMatcher(a,e)===!0?(this.consumeToken(),i=a):this.consumeInternalError(e,a,n)}catch(a){i=this.consumeInternalRecovery(e,r,a)}return this.cstPostTerminal(n!==void 0&&n.LABEL!==void 0?n.LABEL:e.name,i),i}consumeInternalError(e,r,n){let i,a=this.LA(0);throw n!==void 0&&n.ERR_MSG?i=n.ERR_MSG:i=this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:r,previous:a,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new c0(i,r,a))}consumeInternalRecovery(e,r,n){if(this.recoveryEnabled&&n.name==="MismatchedTokenException"&&!this.isBackTracking()){let i=this.getFollowsForInRuleRecovery(e,r);try{return this.tryInRuleRecovery(e,i)}catch(a){throw a.name===SN?n:a}}else throw n}saveRecogState(){let e=this.errors,r=Qr(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:r,CST_STACK:this.CST_STACK}}reloadRecogState(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK}ruleInvocationStateUpdate(e,r,n){this.RULE_OCCURRENCE_STACK.push(n),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(r)}isBackTracking(){return this.isBackTrackingStack.length!==0}getCurrRuleFullName(){let e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]}shortRuleNameToFullName(e){return this.shortRuleNameToFull[e]}isAtEndOfInput(){return this.tokenMatcher(this.LA(1),fo)}reset(){this.resetLexerState(),this.subruleIdx=0,this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]}}});var uk,kae=R(()=>{"use strict";ag();Pt();ng();Ns();uk=class{static{o(this,"ErrorHandler")}initErrorHandler(e){this._errors=[],this.errorMessageProvider=Xe(e,"errorMessageProvider")?e.errorMessageProvider:is.errorMessageProvider}SAVE_ERROR(e){if(nf(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:Qr(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")}get errors(){return Qr(this._errors)}set errors(e){this._errors=e}raiseEarlyExitException(e,r,n){let i=this.getCurrRuleFullName(),a=this.getGAstProductions()[i],l=rg(e,a,r,this.maxLookahead)[0],u=[];for(let f=1;f<=this.maxLookahead;f++)u.push(this.LA(f));let h=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:l,actual:u,previous:this.LA(0),customUserDescription:n,ruleName:i});throw this.SAVE_ERROR(new m2(h,this.LA(1),this.LA(0)))}raiseNoAltException(e,r){let n=this.getCurrRuleFullName(),i=this.getGAstProductions()[n],a=tg(e,i,this.maxLookahead),s=[];for(let h=1;h<=this.maxLookahead;h++)s.push(this.LA(h));let l=this.LA(0),u=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:a,actual:s,previous:l,customUserDescription:r,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new d2(u,this.LA(1),l))}}});var hk,Eae=R(()=>{"use strict";c2();Pt();hk=class{static{o(this,"ContentAssist")}initContentAssist(){}computeContentAssist(e,r){let n=this.gastProductionsCache[e];if(er(n))throw Error(`Rule ->${e}<- does not exist in this grammar.`);return qT([n],r,this.tokenMatcher,this.maxLookahead)}getNextPossibleTokenTypes(e){let r=na(e.ruleStack),i=this.getGAstProductions()[r];return new UT(i,e).startWalking()}}});function y2(t,e,r,n=!1){dk(r);let i=ma(this.recordingProdStack),a=wi(e)?e:e.DEF,s=new t({definition:[],idx:r});return n&&(s.separator=e.SEP),Xe(e,"MAX_LOOKAHEAD")&&(s.maxLookahead=e.MAX_LOOKAHEAD),this.recordingProdStack.push(s),a.call(this),i.definition.push(s),this.recordingProdStack.pop(),pk}function UIe(t,e){dk(e);let r=ma(this.recordingProdStack),n=wt(t)===!1,i=n===!1?t:t.DEF,a=new gn({definition:[],idx:e,ignoreAmbiguities:n&&t.IGNORE_AMBIGUITIES===!0});Xe(t,"MAX_LOOKAHEAD")&&(a.maxLookahead=t.MAX_LOOKAHEAD);let s=Nv(i,l=>wi(l.GATE));return a.hasPredicates=s,r.definition.push(a),Ee(i,l=>{let u=new Sn({definition:[]});a.definition.push(u),Xe(l,"IGNORE_AMBIGUITIES")?u.ignoreAmbiguities=l.IGNORE_AMBIGUITIES:Xe(l,"GATE")&&(u.ignoreAmbiguities=!0),this.recordingProdStack.push(u),l.ALT.call(this),this.recordingProdStack.pop()}),pk}function Aae(t){return t===0?"":`${t}`}function dk(t){if(t<0||t>Sae){let e=new Error(`Invalid DSL Method idx value: <${t}> + Idx value must be a none negative value smaller than ${Sae+1}`);throw e.KNOWN_RECORDER_ERROR=!0,e}}var pk,Cae,Sae,_ae,Lae,VIe,fk,Dae=R(()=>{"use strict";Pt();ns();i2();s0();l0();Ns();ek();pk={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(pk);Cae=!0,Sae=Math.pow(2,8)-1,_ae=VT({name:"RECORDING_PHASE_TOKEN",pattern:ni.NA});Fu([_ae]);Lae=o0(_ae,`This IToken indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze(Lae);VIe={name:`This CSTNode indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},fk=class{static{o(this,"GastRecorder")}initGastRecorder(e){this.recordingProdStack=[],this.RECORDING_PHASE=!1}enableRecording(){this.RECORDING_PHASE=!0,this.TRACE_INIT("Enable Recording",()=>{for(let e=0;e<10;e++){let r=e>0?e:"";this[`CONSUME${r}`]=function(n,i){return this.consumeInternalRecord(n,e,i)},this[`SUBRULE${r}`]=function(n,i){return this.subruleInternalRecord(n,e,i)},this[`OPTION${r}`]=function(n){return this.optionInternalRecord(n,e)},this[`OR${r}`]=function(n){return this.orInternalRecord(n,e)},this[`MANY${r}`]=function(n){this.manyInternalRecord(e,n)},this[`MANY_SEP${r}`]=function(n){this.manySepFirstInternalRecord(e,n)},this[`AT_LEAST_ONE${r}`]=function(n){this.atLeastOneInternalRecord(e,n)},this[`AT_LEAST_ONE_SEP${r}`]=function(n){this.atLeastOneSepFirstInternalRecord(e,n)}}this.consume=function(e,r,n){return this.consumeInternalRecord(r,e,n)},this.subrule=function(e,r,n){return this.subruleInternalRecord(r,e,n)},this.option=function(e,r){return this.optionInternalRecord(r,e)},this.or=function(e,r){return this.orInternalRecord(r,e)},this.many=function(e,r){this.manyInternalRecord(e,r)},this.atLeastOne=function(e,r){this.atLeastOneInternalRecord(e,r)},this.ACTION=this.ACTION_RECORD,this.BACKTRACK=this.BACKTRACK_RECORD,this.LA=this.LA_RECORD})}disableRecording(){this.RECORDING_PHASE=!1,this.TRACE_INIT("Deleting Recording methods",()=>{let e=this;for(let r=0;r<10;r++){let n=r>0?r:"";delete e[`CONSUME${n}`],delete e[`SUBRULE${n}`],delete e[`OPTION${n}`],delete e[`OR${n}`],delete e[`MANY${n}`],delete e[`MANY_SEP${n}`],delete e[`AT_LEAST_ONE${n}`],delete e[`AT_LEAST_ONE_SEP${n}`]}delete e.consume,delete e.subrule,delete e.option,delete e.or,delete e.many,delete e.atLeastOne,delete e.ACTION,delete e.BACKTRACK,delete e.LA})}ACTION_RECORD(e){}BACKTRACK_RECORD(e,r){return()=>!0}LA_RECORD(e){return sg}topLevelRuleRecord(e,r){try{let n=new ts({definition:[],name:e});return n.name=e,this.recordingProdStack.push(n),r.call(this),this.recordingProdStack.pop(),n}catch(n){if(n.KNOWN_RECORDER_ERROR!==!0)try{n.message=n.message+` + This error was thrown during the "grammar recording phase" For more info see: + https://chevrotain.io/docs/guide/internals.html#grammar-recording`}catch{throw n}throw n}}optionInternalRecord(e,r){return y2.call(this,Jr,e,r)}atLeastOneInternalRecord(e,r){y2.call(this,An,r,e)}atLeastOneSepFirstInternalRecord(e,r){y2.call(this,_n,r,e,Cae)}manyInternalRecord(e,r){y2.call(this,br,r,e)}manySepFirstInternalRecord(e,r){y2.call(this,mn,r,e,Cae)}orInternalRecord(e,r){return UIe.call(this,e,r)}subruleInternalRecord(e,r,n){if(dk(r),!e||Xe(e,"ruleName")===!1){let l=new Error(` argument is invalid expecting a Parser method reference but got: <${JSON.stringify(e)}> + inside top level rule: <${this.recordingProdStack[0].name}>`);throw l.KNOWN_RECORDER_ERROR=!0,l}let i=ma(this.recordingProdStack),a=e.ruleName,s=new Zr({idx:r,nonTerminalName:a,label:n?.LABEL,referencedRule:void 0});return i.definition.push(s),this.outputCst?VIe:pk}consumeInternalRecord(e,r,n){if(dk(r),!dN(e)){let s=new Error(` argument is invalid expecting a TokenType reference but got: <${JSON.stringify(e)}> + inside top level rule: <${this.recordingProdStack[0].name}>`);throw s.KNOWN_RECORDER_ERROR=!0,s}let i=ma(this.recordingProdStack),a=new fr({idx:r,terminalType:e,label:n?.LABEL});return i.definition.push(a),Lae}};o(y2,"recordProd");o(UIe,"recordOrProd");o(Aae,"getIdxSuffix");o(dk,"assertMethodIdxIsValid")});var mk,Rae=R(()=>{"use strict";Pt();qm();Ns();mk=class{static{o(this,"PerformanceTracer")}initPerformanceTracer(e){if(Xe(e,"traceInitPerf")){let r=e.traceInitPerf,n=typeof r=="number";this.traceInitMaxIdent=n?r:1/0,this.traceInitPerf=n?r>0:r}else this.traceInitMaxIdent=0,this.traceInitPerf=is.traceInitPerf;this.traceInitIndent=-1}TRACE_INIT(e,r){if(this.traceInitPerf===!0){this.traceInitIndent++;let n=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <${e}>`);let{time:i,value:a}=t2(r),s=i>10?console.warn:console.log;return this.traceInitIndent time: ${i}ms`),this.traceInitIndent--,a}else return r()}}});function Nae(t,e){e.forEach(r=>{let n=r.prototype;Object.getOwnPropertyNames(n).forEach(i=>{if(i==="constructor")return;let a=Object.getOwnPropertyDescriptor(n,i);a&&(a.get||a.set)?Object.defineProperty(t.prototype,i,a):t.prototype[i]=r.prototype[i]})})}var Mae=R(()=>{"use strict";o(Nae,"applyMixins")});function gk(t=void 0){return function(){return t}}var sg,is,og,Pi,v2,x2,Ns=R(()=>{"use strict";Pt();qm();cie();l0();Jm();aae();AN();hae();xae();bae();wae();Tae();kae();Eae();Dae();Rae();Mae();f2();sg=o0(fo,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(sg);is=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:Gu,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1}),og=Object.freeze({recoveryValueFunc:o(()=>{},"recoveryValueFunc"),resyncEnabled:!0});(function(t){t[t.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",t[t.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",t[t.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",t[t.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",t[t.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",t[t.LEFT_RECURSION=5]="LEFT_RECURSION",t[t.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",t[t.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",t[t.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",t[t.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",t[t.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",t[t.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",t[t.TOO_MANY_ALTS=12]="TOO_MANY_ALTS",t[t.CUSTOM_LOOKAHEAD_VALIDATION=13]="CUSTOM_LOOKAHEAD_VALIDATION"})(Pi||(Pi={}));o(gk,"EMPTY_ALT");v2=class t{static{o(this,"Parser")}static performSelfAnalysis(e){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")}performSelfAnalysis(){this.TRACE_INIT("performSelfAnalysis",()=>{let e;this.selfAnalysisDone=!0;let r=this.className;this.TRACE_INIT("toFastProps",()=>{r2(this)}),this.TRACE_INIT("Grammar Recording",()=>{try{this.enableRecording(),Ee(this.definedRulesNames,i=>{let s=this[i].originalGrammarAction,l;this.TRACE_INIT(`${i} Rule`,()=>{l=this.topLevelRuleRecord(i,s)}),this.gastProductionsCache[i]=l})}finally{this.disableRecording()}});let n=[];if(this.TRACE_INIT("Grammar Resolving",()=>{n=nae({rules:or(this.gastProductionsCache)}),this.definitionErrors=this.definitionErrors.concat(n)}),this.TRACE_INIT("Grammar Validations",()=>{if(Qt(n)&&this.skipValidations===!1){let i=iae({rules:or(this.gastProductionsCache),tokenTypes:or(this.tokensMap),errMsgProvider:Ol,grammarName:r}),a=Kie({lookaheadStrategy:this.lookaheadStrategy,rules:or(this.gastProductionsCache),tokenTypes:or(this.tokensMap),grammarName:r});this.definitionErrors=this.definitionErrors.concat(i,a)}}),Qt(this.definitionErrors)&&(this.recoveryEnabled&&this.TRACE_INIT("computeAllProdsFollows",()=>{let i=lie(or(this.gastProductionsCache));this.resyncFollows=i}),this.TRACE_INIT("ComputeLookaheadFunctions",()=>{var i,a;(a=(i=this.lookaheadStrategy).initialize)===null||a===void 0||a.call(i,{rules:or(this.gastProductionsCache)}),this.preComputeLookaheadFunctions(or(this.gastProductionsCache))})),!t.DEFER_DEFINITION_ERRORS_HANDLING&&!Qt(this.definitionErrors))throw e=qe(this.definitionErrors,i=>i.message),new Error(`Parser Definition Errors detected: + ${e.join(` +------------------------------- +`)}`)})}constructor(e,r){this.definitionErrors=[],this.selfAnalysisDone=!1;let n=this;if(n.initErrorHandler(r),n.initLexerAdapter(),n.initLooksAhead(r),n.initRecognizerEngine(e,r),n.initRecoverable(r),n.initTreeBuilder(r),n.initContentAssist(),n.initGastRecorder(r),n.initPerformanceTracer(r),Xe(r,"ignoredIssues"))throw new Error(`The IParserConfig property has been deprecated. + Please use the flag on the relevant DSL method instead. + See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES + For further details.`);this.skipValidations=Xe(r,"skipValidations")?r.skipValidations:is.skipValidations}};v2.DEFER_DEFINITION_ERRORS_HANDLING=!1;Nae(v2,[ZT,rk,sk,ok,ck,lk,uk,hk,fk,mk]);x2=class extends v2{static{o(this,"EmbeddedActionsParser")}constructor(e,r=is){let n=Qr(r);n.outputCst=!1,super(e,n)}}});var Iae=R(()=>{"use strict";ns()});var Oae=R(()=>{"use strict"});var Pae=R(()=>{"use strict";Iae();Oae()});var Bae=R(()=>{"use strict";tN()});var u0=R(()=>{"use strict";tN();Ns();i2();l0();ng();_N();Jm();ag();mN();ns();ns();Pae();Bae()});function h0(t,e,r){return`${t.name}_${e}_${r}`}function $ae(t){let e={decisionMap:{},decisionStates:[],ruleToStartState:new Map,ruleToStopState:new Map,states:[]};KIe(e,t);let r=t.length;for(let n=0;nVae(t,e,s));return hg(t,e,n,r,...i)}function rOe(t,e,r){let n=ia(t,e,r,{type:af});sf(t,n);let i=hg(t,e,n,r,f0(t,e,r));return nOe(t,e,r,i)}function f0(t,e,r){let n=$r(qe(r.definition,i=>Vae(t,e,i)),i=>i!==void 0);return n.length===1?n[0]:n.length===0?void 0:aOe(t,n)}function Uae(t,e,r,n,i){let a=n.left,s=n.right,l=ia(t,e,r,{type:jIe});sf(t,l);let u=ia(t,e,r,{type:Gae});return a.loopback=l,u.loopback=l,t.decisionMap[h0(e,i?"RepetitionMandatoryWithSeparator":"RepetitionMandatory",r.idx)]=l,Ei(s,l),i===void 0?(Ei(l,a),Ei(l,u)):(Ei(l,u),Ei(l,i.left),Ei(i.right,a)),{left:a,right:u}}function Hae(t,e,r,n,i){let a=n.left,s=n.right,l=ia(t,e,r,{type:XIe});sf(t,l);let u=ia(t,e,r,{type:Gae}),h=ia(t,e,r,{type:qIe});return l.loopback=h,u.loopback=h,Ei(l,a),Ei(l,u),Ei(s,h),i!==void 0?(Ei(h,u),Ei(h,i.left),Ei(i.right,a)):Ei(h,l),t.decisionMap[h0(e,i?"RepetitionWithSeparator":"Repetition",r.idx)]=l,{left:l,right:u}}function nOe(t,e,r,n){let i=n.left,a=n.right;return Ei(i,a),t.decisionMap[h0(e,"Option",r.idx)]=i,n}function sf(t,e){return t.decisionStates.push(e),e.decision=t.decisionStates.length-1,e.decision}function hg(t,e,r,n,...i){let a=ia(t,e,n,{type:WIe,start:r});r.end=a;for(let l of i)l!==void 0?(Ei(r,l.left),Ei(l.right,a)):Ei(r,a);let s={left:r,right:a};return t.decisionMap[h0(e,iOe(n),n.idx)]=r,s}function iOe(t){if(t instanceof gn)return"Alternation";if(t instanceof Jr)return"Option";if(t instanceof br)return"Repetition";if(t instanceof mn)return"RepetitionWithSeparator";if(t instanceof An)return"RepetitionMandatory";if(t instanceof _n)return"RepetitionMandatoryWithSeparator";throw new Error("Invalid production type encountered")}function aOe(t,e){let r=e.length;for(let a=0;a{"use strict";Mm();LL();u0();o(h0,"buildATNKey");af=1,YIe=2,Fae=4,zae=5,ug=7,WIe=8,qIe=9,XIe=10,jIe=11,Gae=12,b2=class{static{o(this,"AbstractTransition")}constructor(e){this.target=e}isEpsilon(){return!1}},lg=class extends b2{static{o(this,"AtomTransition")}constructor(e,r){super(e),this.tokenType=r}},w2=class extends b2{static{o(this,"EpsilonTransition")}constructor(e){super(e)}isEpsilon(){return!0}},cg=class extends b2{static{o(this,"RuleTransition")}constructor(e,r,n){super(e),this.rule=r,this.followState=n}isEpsilon(){return!0}};o($ae,"createATN");o(KIe,"createRuleStartAndStopATNStates");o(Vae,"atom");o(QIe,"repetition");o(ZIe,"repetitionSep");o(JIe,"repetitionMandatory");o(eOe,"repetitionMandatorySep");o(tOe,"alternation");o(rOe,"option");o(f0,"block");o(Uae,"plus");o(Hae,"star");o(nOe,"optional");o(sf,"defineDecisionState");o(hg,"makeAlts");o(iOe,"getProdType");o(aOe,"makeBlock");o(BN,"tokenRef");o(sOe,"ruleRef");o(oOe,"buildRuleHandle");o(Ei,"epsilon");o(ia,"newState");o(FN,"addTransition");o(lOe,"removeState")});function zN(t,e=!0){return`${e?`a${t.alt}`:""}s${t.state.stateNumber}:${t.stack.map(r=>r.stateNumber.toString()).join("_")}`}var T2,fg,Wae=R(()=>{"use strict";Mm();T2={},fg=class{static{o(this,"ATNConfigSet")}constructor(){this.map={},this.configs=[]}get size(){return this.configs.length}finalize(){this.map={}}add(e){let r=zN(e);r in this.map||(this.map[r]=this.configs.length,this.configs.push(e))}get elements(){return this.configs}get alts(){return qe(this.configs,e=>e.alt)}get key(){let e="";for(let r in this.map)e+=r+":";return e}};o(zN,"getATNConfigKey")});function cOe(t,e){let r={};return n=>{let i=n.toString(),a=r[i];return a!==void 0||(a={atnStartState:t,decision:e,states:{}},r[i]=a),a}}function Xae(t,e=!0){let r=new Set;for(let n of t){let i=new Set;for(let a of n){if(a===void 0){if(e)break;return!1}let s=[a.tokenTypeIdx].concat(a.categoryMatches);for(let l of s)if(r.has(l)){if(!i.has(l))return!1}else r.add(l),i.add(l)}}return!0}function uOe(t){let e=t.decisionStates.length,r=Array(e);for(let n=0;nzu(i)).join(", "),r=t.production.idx===0?"":t.production.idx,n=`Ambiguous Alternatives Detected: <${t.ambiguityIndices.join(", ")}> in <${mOe(t.production)}${r}> inside <${t.topLevelRule.name}> Rule, +<${e}> may appears as a prefix path in all these alternatives. +`;return n=n+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES +For Further details.`,n}function mOe(t){if(t instanceof Zr)return"SUBRULE";if(t instanceof Jr)return"OPTION";if(t instanceof gn)return"OR";if(t instanceof An)return"AT_LEAST_ONE";if(t instanceof _n)return"AT_LEAST_ONE_SEP";if(t instanceof mn)return"MANY_SEP";if(t instanceof br)return"MANY";if(t instanceof fr)return"CONSUME";throw Error("non exhaustive match")}function gOe(t,e,r){let n=ga(e.configs.elements,a=>a.state.transitions),i=nte(n.filter(a=>a instanceof lg).map(a=>a.tokenType),a=>a.tokenTypeIdx);return{actualToken:r,possibleTokenTypes:i,tokenPath:t}}function yOe(t,e){return t.edges[e.tokenTypeIdx]}function vOe(t,e,r){let n=new fg,i=[];for(let s of t.elements){if(r.is(s.alt)===!1)continue;if(s.state.type===ug){i.push(s);continue}let l=s.state.transitions.length;for(let u=0;u0&&!kOe(a))for(let s of i)a.add(s);return a}function xOe(t,e){if(t instanceof lg&&s2(e,t.tokenType))return t.target}function bOe(t,e){let r;for(let n of t.elements)if(e.is(n.alt)===!0){if(r===void 0)r=n.alt;else if(r!==n.alt)return}return r}function Kae(t){return{configs:t,edges:{},isAcceptState:!1,prediction:-1}}function jae(t,e,r,n){return n=Qae(t,n),e.edges[r.tokenTypeIdx]=n,n}function Qae(t,e){if(e===T2)return e;let r=e.configs.key,n=t.states[r];return n!==void 0?n:(e.configs.finalize(),t.states[r]=e,e)}function wOe(t){let e=new fg,r=t.transitions.length;for(let n=0;n0){let i=[...t.stack],s={state:i.pop(),alt:t.alt,stack:i};vk(s,e)}else e.add(t);return}r.epsilonOnlyTransitions||e.add(t);let n=r.transitions.length;for(let i=0;i1)return!0;return!1}function _Oe(t){for(let e of Array.from(t.values()))if(Object.keys(e).length===1)return!0;return!1}var yk,qae,k2,Zae=R(()=>{"use strict";u0();Yae();Wae();BL();RL();ite();Mm();fw();$w();Ww();$L();o(cOe,"createDFACache");yk=class{static{o(this,"PredicateSet")}constructor(){this.predicates=[]}is(e){return e>=this.predicates.length||this.predicates[e]}set(e,r){this.predicates[e]=r}toString(){let e="",r=this.predicates.length;for(let n=0;nconsole.log(n)}initialize(e){this.atn=$ae(e.rules),this.dfas=uOe(this.atn)}validateAmbiguousAlternationAlternatives(){return[]}validateEmptyOrAlternatives(){return[]}buildLookaheadForAlternation(e){let{prodOccurrence:r,rule:n,hasPredicates:i,dynamicTokensEnabled:a}=e,s=this.dfas,l=this.logging,u=h0(n,"Alternation",r),f=this.atn.decisionMap[u].decision,d=qe(jT({maxLookahead:1,occurrence:r,prodType:"Alternation",rule:n}),p=>qe(p,m=>m[0]));if(Xae(d,!1)&&!a){let p=Vr(d,(m,g,y)=>(Ee(g,v=>{v&&(m[v.tokenTypeIdx]=y,Ee(v.categoryMatches,x=>{m[x]=y}))}),m),{});return i?function(m){var g;let y=this.LA(1),v=p[y.tokenTypeIdx];if(m!==void 0&&v!==void 0){let x=(g=m[v])===null||g===void 0?void 0:g.GATE;if(x!==void 0&&x.call(this)===!1)return}return v}:function(){let m=this.LA(1);return p[m.tokenTypeIdx]}}else return i?function(p){let m=new yk,g=p===void 0?0:p.length;for(let v=0;vqe(p,m=>m[0]));if(Xae(d)&&d[0][0]&&!a){let p=d[0],m=Gr(p);if(m.length===1&&Qt(m[0].categoryMatches)){let y=m[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===y}}else{let g=Vr(m,(y,v)=>(v!==void 0&&(y[v.tokenTypeIdx]=!0,Ee(v.categoryMatches,x=>{y[x]=!0})),y),{});return function(){let y=this.LA(1);return g[y.tokenTypeIdx]===!0}}}return function(){let p=GN.call(this,s,f,qae,l);return typeof p=="object"?!1:p===0}}};o(Xae,"isLL1Sequence");o(uOe,"initATNSimulator");o(GN,"adaptivePredict");o(hOe,"performLookahead");o(fOe,"computeLookaheadTarget");o(dOe,"reportLookaheadAmbiguity");o(pOe,"buildAmbiguityError");o(mOe,"getProductionDslName");o(gOe,"buildAdaptivePredictError");o(yOe,"getExistingTargetState");o(vOe,"computeReachSet");o(xOe,"getReachableTarget");o(bOe,"getUniqueAlt");o(Kae,"newDFAState");o(jae,"addDFAEdge");o(Qae,"addDFAState");o(wOe,"computeStartState");o(vk,"closure");o(TOe,"getEpsilonTarget");o(kOe,"hasConfigInRuleStopState");o(EOe,"allConfigsInRuleStopStates");o(COe,"hasConflictTerminatingPrediction");o(SOe,"getConflictingAltSets");o(AOe,"hasConflictingAltSet");o(_Oe,"hasStateAssociatedWithOneAlt")});var Jae=R(()=>{"use strict";Zae()});var ese,$N,tse,xk,Ur,wr,bk,rse,VN,nse,ise,ase,sse,UN,ose,lse,cse,wk,dg,pg,HN,mg,use,YN,WN,qN,XN,jN,hse,fse,KN,dse,QN,E2,pse,mse,gse,yse,vse,xse,bse,wse,Tk,Tse,kse,Ese,Cse,Sse,Ase,_se,Lse,Dse,Rse,Nse,kk,Mse,Ise,Ose,Pse,Bse,Fse,zse,Gse,$se,Vse,Use,Hse,Yse,ZN,JN,Wse,qse,Xse,jse,Kse,Qse,Zse,Jse,eoe,eM,Fe,tM=R(()=>{"use strict";(function(t){function e(r){return typeof r=="string"}o(e,"is"),t.is=e})(ese||(ese={}));(function(t){function e(r){return typeof r=="string"}o(e,"is"),t.is=e})($N||($N={}));(function(t){t.MIN_VALUE=-2147483648,t.MAX_VALUE=2147483647;function e(r){return typeof r=="number"&&t.MIN_VALUE<=r&&r<=t.MAX_VALUE}o(e,"is"),t.is=e})(tse||(tse={}));(function(t){t.MIN_VALUE=0,t.MAX_VALUE=2147483647;function e(r){return typeof r=="number"&&t.MIN_VALUE<=r&&r<=t.MAX_VALUE}o(e,"is"),t.is=e})(xk||(xk={}));(function(t){function e(n,i){return n===Number.MAX_VALUE&&(n=xk.MAX_VALUE),i===Number.MAX_VALUE&&(i=xk.MAX_VALUE),{line:n,character:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Fe.uinteger(i.line)&&Fe.uinteger(i.character)}o(r,"is"),t.is=r})(Ur||(Ur={}));(function(t){function e(n,i,a,s){if(Fe.uinteger(n)&&Fe.uinteger(i)&&Fe.uinteger(a)&&Fe.uinteger(s))return{start:Ur.create(n,i),end:Ur.create(a,s)};if(Ur.is(n)&&Ur.is(i))return{start:n,end:i};throw new Error(`Range#create called with invalid arguments[${n}, ${i}, ${a}, ${s}]`)}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Ur.is(i.start)&&Ur.is(i.end)}o(r,"is"),t.is=r})(wr||(wr={}));(function(t){function e(n,i){return{uri:n,range:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&wr.is(i.range)&&(Fe.string(i.uri)||Fe.undefined(i.uri))}o(r,"is"),t.is=r})(bk||(bk={}));(function(t){function e(n,i,a,s){return{targetUri:n,targetRange:i,targetSelectionRange:a,originSelectionRange:s}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&wr.is(i.targetRange)&&Fe.string(i.targetUri)&&wr.is(i.targetSelectionRange)&&(wr.is(i.originSelectionRange)||Fe.undefined(i.originSelectionRange))}o(r,"is"),t.is=r})(rse||(rse={}));(function(t){function e(n,i,a,s){return{red:n,green:i,blue:a,alpha:s}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Fe.numberRange(i.red,0,1)&&Fe.numberRange(i.green,0,1)&&Fe.numberRange(i.blue,0,1)&&Fe.numberRange(i.alpha,0,1)}o(r,"is"),t.is=r})(VN||(VN={}));(function(t){function e(n,i){return{range:n,color:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&wr.is(i.range)&&VN.is(i.color)}o(r,"is"),t.is=r})(nse||(nse={}));(function(t){function e(n,i,a){return{label:n,textEdit:i,additionalTextEdits:a}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Fe.string(i.label)&&(Fe.undefined(i.textEdit)||pg.is(i))&&(Fe.undefined(i.additionalTextEdits)||Fe.typedArray(i.additionalTextEdits,pg.is))}o(r,"is"),t.is=r})(ise||(ise={}));(function(t){t.Comment="comment",t.Imports="imports",t.Region="region"})(ase||(ase={}));(function(t){function e(n,i,a,s,l,u){let h={startLine:n,endLine:i};return Fe.defined(a)&&(h.startCharacter=a),Fe.defined(s)&&(h.endCharacter=s),Fe.defined(l)&&(h.kind=l),Fe.defined(u)&&(h.collapsedText=u),h}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Fe.uinteger(i.startLine)&&Fe.uinteger(i.startLine)&&(Fe.undefined(i.startCharacter)||Fe.uinteger(i.startCharacter))&&(Fe.undefined(i.endCharacter)||Fe.uinteger(i.endCharacter))&&(Fe.undefined(i.kind)||Fe.string(i.kind))}o(r,"is"),t.is=r})(sse||(sse={}));(function(t){function e(n,i){return{location:n,message:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&bk.is(i.location)&&Fe.string(i.message)}o(r,"is"),t.is=r})(UN||(UN={}));(function(t){t.Error=1,t.Warning=2,t.Information=3,t.Hint=4})(ose||(ose={}));(function(t){t.Unnecessary=1,t.Deprecated=2})(lse||(lse={}));(function(t){function e(r){let n=r;return Fe.objectLiteral(n)&&Fe.string(n.href)}o(e,"is"),t.is=e})(cse||(cse={}));(function(t){function e(n,i,a,s,l,u){let h={range:n,message:i};return Fe.defined(a)&&(h.severity=a),Fe.defined(s)&&(h.code=s),Fe.defined(l)&&(h.source=l),Fe.defined(u)&&(h.relatedInformation=u),h}o(e,"create"),t.create=e;function r(n){var i;let a=n;return Fe.defined(a)&&wr.is(a.range)&&Fe.string(a.message)&&(Fe.number(a.severity)||Fe.undefined(a.severity))&&(Fe.integer(a.code)||Fe.string(a.code)||Fe.undefined(a.code))&&(Fe.undefined(a.codeDescription)||Fe.string((i=a.codeDescription)===null||i===void 0?void 0:i.href))&&(Fe.string(a.source)||Fe.undefined(a.source))&&(Fe.undefined(a.relatedInformation)||Fe.typedArray(a.relatedInformation,UN.is))}o(r,"is"),t.is=r})(wk||(wk={}));(function(t){function e(n,i,...a){let s={title:n,command:i};return Fe.defined(a)&&a.length>0&&(s.arguments=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.string(i.title)&&Fe.string(i.command)}o(r,"is"),t.is=r})(dg||(dg={}));(function(t){function e(a,s){return{range:a,newText:s}}o(e,"replace"),t.replace=e;function r(a,s){return{range:{start:a,end:a},newText:s}}o(r,"insert"),t.insert=r;function n(a){return{range:a,newText:""}}o(n,"del"),t.del=n;function i(a){let s=a;return Fe.objectLiteral(s)&&Fe.string(s.newText)&&wr.is(s.range)}o(i,"is"),t.is=i})(pg||(pg={}));(function(t){function e(n,i,a){let s={label:n};return i!==void 0&&(s.needsConfirmation=i),a!==void 0&&(s.description=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Fe.string(i.label)&&(Fe.boolean(i.needsConfirmation)||i.needsConfirmation===void 0)&&(Fe.string(i.description)||i.description===void 0)}o(r,"is"),t.is=r})(HN||(HN={}));(function(t){function e(r){let n=r;return Fe.string(n)}o(e,"is"),t.is=e})(mg||(mg={}));(function(t){function e(a,s,l){return{range:a,newText:s,annotationId:l}}o(e,"replace"),t.replace=e;function r(a,s,l){return{range:{start:a,end:a},newText:s,annotationId:l}}o(r,"insert"),t.insert=r;function n(a,s){return{range:a,newText:"",annotationId:s}}o(n,"del"),t.del=n;function i(a){let s=a;return pg.is(s)&&(HN.is(s.annotationId)||mg.is(s.annotationId))}o(i,"is"),t.is=i})(use||(use={}));(function(t){function e(n,i){return{textDocument:n,edits:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&KN.is(i.textDocument)&&Array.isArray(i.edits)}o(r,"is"),t.is=r})(YN||(YN={}));(function(t){function e(n,i,a){let s={kind:"create",uri:n};return i!==void 0&&(i.overwrite!==void 0||i.ignoreIfExists!==void 0)&&(s.options=i),a!==void 0&&(s.annotationId=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return i&&i.kind==="create"&&Fe.string(i.uri)&&(i.options===void 0||(i.options.overwrite===void 0||Fe.boolean(i.options.overwrite))&&(i.options.ignoreIfExists===void 0||Fe.boolean(i.options.ignoreIfExists)))&&(i.annotationId===void 0||mg.is(i.annotationId))}o(r,"is"),t.is=r})(WN||(WN={}));(function(t){function e(n,i,a,s){let l={kind:"rename",oldUri:n,newUri:i};return a!==void 0&&(a.overwrite!==void 0||a.ignoreIfExists!==void 0)&&(l.options=a),s!==void 0&&(l.annotationId=s),l}o(e,"create"),t.create=e;function r(n){let i=n;return i&&i.kind==="rename"&&Fe.string(i.oldUri)&&Fe.string(i.newUri)&&(i.options===void 0||(i.options.overwrite===void 0||Fe.boolean(i.options.overwrite))&&(i.options.ignoreIfExists===void 0||Fe.boolean(i.options.ignoreIfExists)))&&(i.annotationId===void 0||mg.is(i.annotationId))}o(r,"is"),t.is=r})(qN||(qN={}));(function(t){function e(n,i,a){let s={kind:"delete",uri:n};return i!==void 0&&(i.recursive!==void 0||i.ignoreIfNotExists!==void 0)&&(s.options=i),a!==void 0&&(s.annotationId=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return i&&i.kind==="delete"&&Fe.string(i.uri)&&(i.options===void 0||(i.options.recursive===void 0||Fe.boolean(i.options.recursive))&&(i.options.ignoreIfNotExists===void 0||Fe.boolean(i.options.ignoreIfNotExists)))&&(i.annotationId===void 0||mg.is(i.annotationId))}o(r,"is"),t.is=r})(XN||(XN={}));(function(t){function e(r){let n=r;return n&&(n.changes!==void 0||n.documentChanges!==void 0)&&(n.documentChanges===void 0||n.documentChanges.every(i=>Fe.string(i.kind)?WN.is(i)||qN.is(i)||XN.is(i):YN.is(i)))}o(e,"is"),t.is=e})(jN||(jN={}));(function(t){function e(n){return{uri:n}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.string(i.uri)}o(r,"is"),t.is=r})(hse||(hse={}));(function(t){function e(n,i){return{uri:n,version:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.string(i.uri)&&Fe.integer(i.version)}o(r,"is"),t.is=r})(fse||(fse={}));(function(t){function e(n,i){return{uri:n,version:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.string(i.uri)&&(i.version===null||Fe.integer(i.version))}o(r,"is"),t.is=r})(KN||(KN={}));(function(t){function e(n,i,a,s){return{uri:n,languageId:i,version:a,text:s}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.string(i.uri)&&Fe.string(i.languageId)&&Fe.integer(i.version)&&Fe.string(i.text)}o(r,"is"),t.is=r})(dse||(dse={}));(function(t){t.PlainText="plaintext",t.Markdown="markdown";function e(r){let n=r;return n===t.PlainText||n===t.Markdown}o(e,"is"),t.is=e})(QN||(QN={}));(function(t){function e(r){let n=r;return Fe.objectLiteral(r)&&QN.is(n.kind)&&Fe.string(n.value)}o(e,"is"),t.is=e})(E2||(E2={}));(function(t){t.Text=1,t.Method=2,t.Function=3,t.Constructor=4,t.Field=5,t.Variable=6,t.Class=7,t.Interface=8,t.Module=9,t.Property=10,t.Unit=11,t.Value=12,t.Enum=13,t.Keyword=14,t.Snippet=15,t.Color=16,t.File=17,t.Reference=18,t.Folder=19,t.EnumMember=20,t.Constant=21,t.Struct=22,t.Event=23,t.Operator=24,t.TypeParameter=25})(pse||(pse={}));(function(t){t.PlainText=1,t.Snippet=2})(mse||(mse={}));(function(t){t.Deprecated=1})(gse||(gse={}));(function(t){function e(n,i,a){return{newText:n,insert:i,replace:a}}o(e,"create"),t.create=e;function r(n){let i=n;return i&&Fe.string(i.newText)&&wr.is(i.insert)&&wr.is(i.replace)}o(r,"is"),t.is=r})(yse||(yse={}));(function(t){t.asIs=1,t.adjustIndentation=2})(vse||(vse={}));(function(t){function e(r){let n=r;return n&&(Fe.string(n.detail)||n.detail===void 0)&&(Fe.string(n.description)||n.description===void 0)}o(e,"is"),t.is=e})(xse||(xse={}));(function(t){function e(r){return{label:r}}o(e,"create"),t.create=e})(bse||(bse={}));(function(t){function e(r,n){return{items:r||[],isIncomplete:!!n}}o(e,"create"),t.create=e})(wse||(wse={}));(function(t){function e(n){return n.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")}o(e,"fromPlainText"),t.fromPlainText=e;function r(n){let i=n;return Fe.string(i)||Fe.objectLiteral(i)&&Fe.string(i.language)&&Fe.string(i.value)}o(r,"is"),t.is=r})(Tk||(Tk={}));(function(t){function e(r){let n=r;return!!n&&Fe.objectLiteral(n)&&(E2.is(n.contents)||Tk.is(n.contents)||Fe.typedArray(n.contents,Tk.is))&&(r.range===void 0||wr.is(r.range))}o(e,"is"),t.is=e})(Tse||(Tse={}));(function(t){function e(r,n){return n?{label:r,documentation:n}:{label:r}}o(e,"create"),t.create=e})(kse||(kse={}));(function(t){function e(r,n,...i){let a={label:r};return Fe.defined(n)&&(a.documentation=n),Fe.defined(i)?a.parameters=i:a.parameters=[],a}o(e,"create"),t.create=e})(Ese||(Ese={}));(function(t){t.Text=1,t.Read=2,t.Write=3})(Cse||(Cse={}));(function(t){function e(r,n){let i={range:r};return Fe.number(n)&&(i.kind=n),i}o(e,"create"),t.create=e})(Sse||(Sse={}));(function(t){t.File=1,t.Module=2,t.Namespace=3,t.Package=4,t.Class=5,t.Method=6,t.Property=7,t.Field=8,t.Constructor=9,t.Enum=10,t.Interface=11,t.Function=12,t.Variable=13,t.Constant=14,t.String=15,t.Number=16,t.Boolean=17,t.Array=18,t.Object=19,t.Key=20,t.Null=21,t.EnumMember=22,t.Struct=23,t.Event=24,t.Operator=25,t.TypeParameter=26})(Ase||(Ase={}));(function(t){t.Deprecated=1})(_se||(_se={}));(function(t){function e(r,n,i,a,s){let l={name:r,kind:n,location:{uri:a,range:i}};return s&&(l.containerName=s),l}o(e,"create"),t.create=e})(Lse||(Lse={}));(function(t){function e(r,n,i,a){return a!==void 0?{name:r,kind:n,location:{uri:i,range:a}}:{name:r,kind:n,location:{uri:i}}}o(e,"create"),t.create=e})(Dse||(Dse={}));(function(t){function e(n,i,a,s,l,u){let h={name:n,detail:i,kind:a,range:s,selectionRange:l};return u!==void 0&&(h.children=u),h}o(e,"create"),t.create=e;function r(n){let i=n;return i&&Fe.string(i.name)&&Fe.number(i.kind)&&wr.is(i.range)&&wr.is(i.selectionRange)&&(i.detail===void 0||Fe.string(i.detail))&&(i.deprecated===void 0||Fe.boolean(i.deprecated))&&(i.children===void 0||Array.isArray(i.children))&&(i.tags===void 0||Array.isArray(i.tags))}o(r,"is"),t.is=r})(Rse||(Rse={}));(function(t){t.Empty="",t.QuickFix="quickfix",t.Refactor="refactor",t.RefactorExtract="refactor.extract",t.RefactorInline="refactor.inline",t.RefactorRewrite="refactor.rewrite",t.Source="source",t.SourceOrganizeImports="source.organizeImports",t.SourceFixAll="source.fixAll"})(Nse||(Nse={}));(function(t){t.Invoked=1,t.Automatic=2})(kk||(kk={}));(function(t){function e(n,i,a){let s={diagnostics:n};return i!=null&&(s.only=i),a!=null&&(s.triggerKind=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.typedArray(i.diagnostics,wk.is)&&(i.only===void 0||Fe.typedArray(i.only,Fe.string))&&(i.triggerKind===void 0||i.triggerKind===kk.Invoked||i.triggerKind===kk.Automatic)}o(r,"is"),t.is=r})(Mse||(Mse={}));(function(t){function e(n,i,a){let s={title:n},l=!0;return typeof i=="string"?(l=!1,s.kind=i):dg.is(i)?s.command=i:s.edit=i,l&&a!==void 0&&(s.kind=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return i&&Fe.string(i.title)&&(i.diagnostics===void 0||Fe.typedArray(i.diagnostics,wk.is))&&(i.kind===void 0||Fe.string(i.kind))&&(i.edit!==void 0||i.command!==void 0)&&(i.command===void 0||dg.is(i.command))&&(i.isPreferred===void 0||Fe.boolean(i.isPreferred))&&(i.edit===void 0||jN.is(i.edit))}o(r,"is"),t.is=r})(Ise||(Ise={}));(function(t){function e(n,i){let a={range:n};return Fe.defined(i)&&(a.data=i),a}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&wr.is(i.range)&&(Fe.undefined(i.command)||dg.is(i.command))}o(r,"is"),t.is=r})(Ose||(Ose={}));(function(t){function e(n,i){return{tabSize:n,insertSpaces:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&Fe.uinteger(i.tabSize)&&Fe.boolean(i.insertSpaces)}o(r,"is"),t.is=r})(Pse||(Pse={}));(function(t){function e(n,i,a){return{range:n,target:i,data:a}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&wr.is(i.range)&&(Fe.undefined(i.target)||Fe.string(i.target))}o(r,"is"),t.is=r})(Bse||(Bse={}));(function(t){function e(n,i){return{range:n,parent:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&wr.is(i.range)&&(i.parent===void 0||t.is(i.parent))}o(r,"is"),t.is=r})(Fse||(Fse={}));(function(t){t.namespace="namespace",t.type="type",t.class="class",t.enum="enum",t.interface="interface",t.struct="struct",t.typeParameter="typeParameter",t.parameter="parameter",t.variable="variable",t.property="property",t.enumMember="enumMember",t.event="event",t.function="function",t.method="method",t.macro="macro",t.keyword="keyword",t.modifier="modifier",t.comment="comment",t.string="string",t.number="number",t.regexp="regexp",t.operator="operator",t.decorator="decorator"})(zse||(zse={}));(function(t){t.declaration="declaration",t.definition="definition",t.readonly="readonly",t.static="static",t.deprecated="deprecated",t.abstract="abstract",t.async="async",t.modification="modification",t.documentation="documentation",t.defaultLibrary="defaultLibrary"})(Gse||(Gse={}));(function(t){function e(r){let n=r;return Fe.objectLiteral(n)&&(n.resultId===void 0||typeof n.resultId=="string")&&Array.isArray(n.data)&&(n.data.length===0||typeof n.data[0]=="number")}o(e,"is"),t.is=e})($se||($se={}));(function(t){function e(n,i){return{range:n,text:i}}o(e,"create"),t.create=e;function r(n){let i=n;return i!=null&&wr.is(i.range)&&Fe.string(i.text)}o(r,"is"),t.is=r})(Vse||(Vse={}));(function(t){function e(n,i,a){return{range:n,variableName:i,caseSensitiveLookup:a}}o(e,"create"),t.create=e;function r(n){let i=n;return i!=null&&wr.is(i.range)&&Fe.boolean(i.caseSensitiveLookup)&&(Fe.string(i.variableName)||i.variableName===void 0)}o(r,"is"),t.is=r})(Use||(Use={}));(function(t){function e(n,i){return{range:n,expression:i}}o(e,"create"),t.create=e;function r(n){let i=n;return i!=null&&wr.is(i.range)&&(Fe.string(i.expression)||i.expression===void 0)}o(r,"is"),t.is=r})(Hse||(Hse={}));(function(t){function e(n,i){return{frameId:n,stoppedLocation:i}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.defined(i)&&wr.is(n.stoppedLocation)}o(r,"is"),t.is=r})(Yse||(Yse={}));(function(t){t.Type=1,t.Parameter=2;function e(r){return r===1||r===2}o(e,"is"),t.is=e})(ZN||(ZN={}));(function(t){function e(n){return{value:n}}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&(i.tooltip===void 0||Fe.string(i.tooltip)||E2.is(i.tooltip))&&(i.location===void 0||bk.is(i.location))&&(i.command===void 0||dg.is(i.command))}o(r,"is"),t.is=r})(JN||(JN={}));(function(t){function e(n,i,a){let s={position:n,label:i};return a!==void 0&&(s.kind=a),s}o(e,"create"),t.create=e;function r(n){let i=n;return Fe.objectLiteral(i)&&Ur.is(i.position)&&(Fe.string(i.label)||Fe.typedArray(i.label,JN.is))&&(i.kind===void 0||ZN.is(i.kind))&&i.textEdits===void 0||Fe.typedArray(i.textEdits,pg.is)&&(i.tooltip===void 0||Fe.string(i.tooltip)||E2.is(i.tooltip))&&(i.paddingLeft===void 0||Fe.boolean(i.paddingLeft))&&(i.paddingRight===void 0||Fe.boolean(i.paddingRight))}o(r,"is"),t.is=r})(Wse||(Wse={}));(function(t){function e(r){return{kind:"snippet",value:r}}o(e,"createSnippet"),t.createSnippet=e})(qse||(qse={}));(function(t){function e(r,n,i,a){return{insertText:r,filterText:n,range:i,command:a}}o(e,"create"),t.create=e})(Xse||(Xse={}));(function(t){function e(r){return{items:r}}o(e,"create"),t.create=e})(jse||(jse={}));(function(t){t.Invoked=0,t.Automatic=1})(Kse||(Kse={}));(function(t){function e(r,n){return{range:r,text:n}}o(e,"create"),t.create=e})(Qse||(Qse={}));(function(t){function e(r,n){return{triggerKind:r,selectedCompletionInfo:n}}o(e,"create"),t.create=e})(Zse||(Zse={}));(function(t){function e(r){let n=r;return Fe.objectLiteral(n)&&$N.is(n.uri)&&Fe.string(n.name)}o(e,"is"),t.is=e})(Jse||(Jse={}));(function(t){function e(a,s,l,u){return new eM(a,s,l,u)}o(e,"create"),t.create=e;function r(a){let s=a;return!!(Fe.defined(s)&&Fe.string(s.uri)&&(Fe.undefined(s.languageId)||Fe.string(s.languageId))&&Fe.uinteger(s.lineCount)&&Fe.func(s.getText)&&Fe.func(s.positionAt)&&Fe.func(s.offsetAt))}o(r,"is"),t.is=r;function n(a,s){let l=a.getText(),u=i(s,(f,d)=>{let p=f.range.start.line-d.range.start.line;return p===0?f.range.start.character-d.range.start.character:p}),h=l.length;for(let f=u.length-1;f>=0;f--){let d=u[f],p=a.offsetAt(d.range.start),m=a.offsetAt(d.range.end);if(m<=h)l=l.substring(0,p)+d.newText+l.substring(m,l.length);else throw new Error("Overlapping edit");h=p}return l}o(n,"applyEdits"),t.applyEdits=n;function i(a,s){if(a.length<=1)return a;let l=a.length/2|0,u=a.slice(0,l),h=a.slice(l);i(u,s),i(h,s);let f=0,d=0,p=0;for(;f0&&e.push(r.length),this._lineOffsets=e}return this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);let r=this.getLineOffsets(),n=0,i=r.length;if(i===0)return Ur.create(0,e);for(;ne?i=s:n=s+1}let a=n-1;return Ur.create(a,e-r[a])}offsetAt(e){let r=this.getLineOffsets();if(e.line>=r.length)return this._content.length;if(e.line<0)return 0;let n=r[e.line],i=e.line+1"u"}o(n,"undefined"),t.undefined=n;function i(m){return m===!0||m===!1}o(i,"boolean"),t.boolean=i;function a(m){return e.call(m)==="[object String]"}o(a,"string"),t.string=a;function s(m){return e.call(m)==="[object Number]"}o(s,"number"),t.number=s;function l(m,g,y){return e.call(m)==="[object Number]"&&g<=m&&m<=y}o(l,"numberRange"),t.numberRange=l;function u(m){return e.call(m)==="[object Number]"&&-2147483648<=m&&m<=2147483647}o(u,"integer"),t.integer=u;function h(m){return e.call(m)==="[object Number]"&&0<=m&&m<=2147483647}o(h,"uinteger"),t.uinteger=h;function f(m){return e.call(m)==="[object Function]"}o(f,"func"),t.func=f;function d(m){return m!==null&&typeof m=="object"}o(d,"objectLiteral"),t.objectLiteral=d;function p(m,g){return Array.isArray(m)&&m.every(g)}o(p,"typedArray"),t.typedArray=p})(Fe||(Fe={}))});var C2,S2,d0,p0,rM,gg,Ek=R(()=>{"use strict";tM();Vo();Rl();C2=class{static{o(this,"CstNodeBuilder")}constructor(){this.nodeStack=[]}get current(){return this.nodeStack[this.nodeStack.length-1]}buildRootNode(e){return this.rootNode=new gg(e),this.rootNode.root=this.rootNode,this.nodeStack=[this.rootNode],this.rootNode}buildCompositeNode(e){let r=new p0;return r.grammarSource=e,r.root=this.rootNode,this.current.content.push(r),this.nodeStack.push(r),r}buildLeafNode(e,r){let n=new d0(e.startOffset,e.image.length,zm(e),e.tokenType,!1);return n.grammarSource=r,n.root=this.rootNode,this.current.content.push(n),n}removeNode(e){let r=e.container;if(r){let n=r.content.indexOf(e);n>=0&&r.content.splice(n,1)}}construct(e){let r=this.current;typeof e.$type=="string"&&(this.current.astNode=e),e.$cstNode=r;let n=this.nodeStack.pop();n?.content.length===0&&this.removeNode(n)}addHiddenTokens(e){for(let r of e){let n=new d0(r.startOffset,r.image.length,zm(r),r.tokenType,!0);n.root=this.rootNode,this.addHiddenToken(this.rootNode,n)}}addHiddenToken(e,r){let{offset:n,end:i}=r;for(let a=0;al&&i=0;e--){let r=this.content[e];if(!r.hidden)return r}return this.content[this.content.length-1]}},rM=class t extends Array{static{o(this,"CstNodeContainer")}constructor(e){super(),this.parent=e,Object.setPrototypeOf(this,t.prototype)}push(...e){return this.addParents(e),super.push(...e)}unshift(...e){return this.addParents(e),super.unshift(...e)}splice(e,r,...n){return this.addParents(n),super.splice(e,r,...n)}addParents(e){for(let r of e)r.container=this.parent}},gg=class extends p0{static{o(this,"RootCstNodeImpl")}get text(){return this._text.substring(this.offset,this.end)}get fullText(){return this._text}constructor(e){super(),this._text="",this._text=e??""}}});function nM(t){return t.$type===Ck}var Ck,toe,roe,A2,_2,Sk,yg,L2,LOe,iM,D2=R(()=>{"use strict";u0();Jae();Sc();Il();es();Ek();Ck=Symbol("Datatype");o(nM,"isDataTypeNode");toe="\u200B",roe=o(t=>t.endsWith(toe)?t:t+toe,"withRuleSuffix"),A2=class{static{o(this,"AbstractLangiumParser")}constructor(e){this._unorderedGroups=new Map,this.lexer=e.parser.Lexer;let r=this.lexer.definition;this.wrapper=new iM(r,Object.assign(Object.assign({},e.parser.ParserConfig),{errorMessageProvider:e.parser.ParserErrorMessageProvider}))}alternatives(e,r){this.wrapper.wrapOr(e,r)}optional(e,r){this.wrapper.wrapOption(e,r)}many(e,r){this.wrapper.wrapMany(e,r)}atLeastOne(e,r){this.wrapper.wrapAtLeastOne(e,r)}isRecording(){return this.wrapper.IS_RECORDING}get unorderedGroups(){return this._unorderedGroups}getRuleStack(){return this.wrapper.RULE_STACK}finalize(){this.wrapper.wrapSelfAnalysis()}},_2=class extends A2{static{o(this,"LangiumParser")}get current(){return this.stack[this.stack.length-1]}constructor(e){super(e),this.nodeBuilder=new C2,this.stack=[],this.assignmentMap=new Map,this.linker=e.references.Linker,this.converter=e.parser.ValueConverter,this.astReflection=e.shared.AstReflection}rule(e,r){let n=e.fragment?void 0:Jv(e)?Ck:r0(e),i=this.wrapper.DEFINE_RULE(roe(e.name),this.startImplementation(n,r).bind(this));return e.entry&&(this.mainRule=i),i}parse(e){this.nodeBuilder.buildRootNode(e);let r=this.lexer.tokenize(e);this.wrapper.input=r.tokens;let n=this.mainRule.call(this.wrapper,{});return this.nodeBuilder.addHiddenTokens(r.hidden),this.unorderedGroups.clear(),{value:n,lexerErrors:r.errors,parserErrors:this.wrapper.errors}}startImplementation(e,r){return n=>{if(!this.isRecording()){let a={$type:e};this.stack.push(a),e===Ck&&(a.value="")}let i;try{i=r(n)}catch{i=void 0}return!this.isRecording()&&i===void 0&&(i=this.construct()),i}}consume(e,r,n){let i=this.wrapper.wrapConsume(e,r);if(!this.isRecording()&&this.isValidToken(i)){let a=this.nodeBuilder.buildLeafNode(i,n),{assignment:s,isCrossRef:l}=this.getAssignment(n),u=this.current;if(s){let h=Ho(n)?i.image:this.converter.convert(i.image,a);this.assign(s.operator,s.feature,h,a,l)}else if(nM(u)){let h=i.image;Ho(n)||(h=this.converter.convert(h,a).toString()),u.value+=h}}}isValidToken(e){return!e.isInsertedInRecovery&&!isNaN(e.startOffset)&&typeof e.endOffset=="number"&&!isNaN(e.endOffset)}subrule(e,r,n,i){let a;this.isRecording()||(a=this.nodeBuilder.buildCompositeNode(n));let s=this.wrapper.wrapSubrule(e,r,i);!this.isRecording()&&a&&a.length>0&&this.performSubruleAssignment(s,n,a)}performSubruleAssignment(e,r,n){let{assignment:i,isCrossRef:a}=this.getAssignment(r);if(i)this.assign(i.operator,i.feature,e,n,a);else if(!i){let s=this.current;if(nM(s))s.value+=e.toString();else if(typeof e=="object"&&e){let l=e.$type,u=this.assignWithoutOverride(e,s);l&&(u.$type=l);let h=u;this.stack.pop(),this.stack.push(h)}}}action(e,r){if(!this.isRecording()){let n=this.current;if(!n.$cstNode&&r.feature&&r.operator){n=this.construct(!1);let a=n.$cstNode.feature;this.nodeBuilder.buildCompositeNode(a)}let i={$type:e};this.stack.pop(),this.stack.push(i),r.feature&&r.operator&&this.assign(r.operator,r.feature,n,n.$cstNode,!1)}}construct(e=!0){if(this.isRecording())return;let r=this.current;return ET(r),this.nodeBuilder.construct(r),e&&this.stack.pop(),nM(r)?this.converter.convert(r.value,r.$cstNode):(NR(this.astReflection,r),r)}getAssignment(e){if(!this.assignmentMap.has(e)){let r=Qd(e,Nl);this.assignmentMap.set(e,{assignment:r,isCrossRef:r?Kd(r.terminal):!1})}return this.assignmentMap.get(e)}assign(e,r,n,i,a){let s=this.current,l;switch(a&&typeof n=="string"?l=this.linker.buildReference(s,r,i,n):l=n,e){case"=":{s[r]=l;break}case"?=":{s[r]=!0;break}case"+=":Array.isArray(s[r])||(s[r]=[]),s[r].push(l)}}assignWithoutOverride(e,r){for(let[n,i]of Object.entries(r)){let a=e[n];a===void 0?e[n]=i:Array.isArray(a)&&Array.isArray(i)&&(i.push(...a),e[n]=i)}return e}get definitionErrors(){return this.wrapper.definitionErrors}},Sk=class{static{o(this,"AbstractParserErrorMessageProvider")}buildMismatchTokenMessage(e){return Gu.buildMismatchTokenMessage(e)}buildNotAllInputParsedMessage(e){return Gu.buildNotAllInputParsedMessage(e)}buildNoViableAltMessage(e){return Gu.buildNoViableAltMessage(e)}buildEarlyExitMessage(e){return Gu.buildEarlyExitMessage(e)}},yg=class extends Sk{static{o(this,"LangiumParserErrorMessageProvider")}buildMismatchTokenMessage({expected:e,actual:r}){return`Expecting ${e.LABEL?"`"+e.LABEL+"`":e.name.endsWith(":KW")?`keyword '${e.name.substring(0,e.name.length-3)}'`:`token of type '${e.name}'`} but found \`${r.image}\`.`}buildNotAllInputParsedMessage({firstRedundant:e}){return`Expecting end of file but found \`${e.image}\`.`}},L2=class extends A2{static{o(this,"LangiumCompletionParser")}constructor(){super(...arguments),this.tokens=[],this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}action(){}construct(){}parse(e){this.resetState();let r=this.lexer.tokenize(e);return this.tokens=r.tokens,this.wrapper.input=[...this.tokens],this.mainRule.call(this.wrapper,{}),this.unorderedGroups.clear(),{tokens:this.tokens,elementStack:[...this.lastElementStack],tokenIndex:this.nextTokenIndex}}rule(e,r){let n=this.wrapper.DEFINE_RULE(roe(e.name),this.startImplementation(r).bind(this));return e.entry&&(this.mainRule=n),n}resetState(){this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}startImplementation(e){return r=>{let n=this.keepStackSize();try{e(r)}finally{this.resetStackSize(n)}}}removeUnexpectedElements(){this.elementStack.splice(this.stackSize)}keepStackSize(){let e=this.elementStack.length;return this.stackSize=e,e}resetStackSize(e){this.removeUnexpectedElements(),this.stackSize=e}consume(e,r,n){this.wrapper.wrapConsume(e,r),this.isRecording()||(this.lastElementStack=[...this.elementStack,n],this.nextTokenIndex=this.currIdx+1)}subrule(e,r,n,i){this.before(n),this.wrapper.wrapSubrule(e,r,i),this.after(n)}before(e){this.isRecording()||this.elementStack.push(e)}after(e){if(!this.isRecording()){let r=this.elementStack.lastIndexOf(e);r>=0&&this.elementStack.splice(r)}}get currIdx(){return this.wrapper.currIdx}},LOe={recoveryEnabled:!0,nodeLocationTracking:"full",skipValidations:!0,errorMessageProvider:new yg},iM=class extends x2{static{o(this,"ChevrotainWrapper")}constructor(e,r){let n=r&&"maxLookahead"in r;super(e,Object.assign(Object.assign(Object.assign({},LOe),{lookaheadStrategy:n?new $u({maxLookahead:r.maxLookahead}):new k2}),r))}get IS_RECORDING(){return this.RECORDING_PHASE}DEFINE_RULE(e,r){return this.RULE(e,r)}wrapSelfAnalysis(){this.performSelfAnalysis()}wrapConsume(e,r){return this.consume(e,r)}wrapSubrule(e,r,n){return this.subrule(e,r,{ARGS:[n]})}wrapOr(e,r){this.or(e,r)}wrapOption(e,r){this.option(e,r)}wrapMany(e,r){this.many(e,r)}wrapAtLeastOne(e,r){this.atLeastOne(e,r)}}});function _k(t,e,r){return DOe({parser:e,tokens:r,rules:new Map,ruleNames:new Map},t),e}function DOe(t,e){let r=Qv(e,!1),n=Kr(e.rules).filter(Oa).filter(i=>r.has(i));for(let i of n){let a=Object.assign(Object.assign({},t),{consume:1,optional:1,subrule:1,many:1,or:1});a.rules.set(i.name,t.parser.rule(i,m0(a,i.definition)))}}function m0(t,e,r=!1){let n;if(Ho(e))n=BOe(t,e);else if(Iu(e))n=ROe(t,e);else if(Nl(e))n=m0(t,e.terminal);else if(Kd(e))n=noe(t,e);else if(Ml(e))n=NOe(t,e);else if(wT(e))n=IOe(t,e);else if(kT(e))n=OOe(t,e);else if(rf(e))n=POe(t,e);else if(fR(e)){let i=t.consume++;n=o(()=>t.parser.consume(i,fo,e),"method")}else throw new jd(e.$cstNode,`Unexpected element type: ${e.$type}`);return ioe(t,r?void 0:Ak(e),n,e.cardinality)}function ROe(t,e){let r=r0(e);return()=>t.parser.action(r,e)}function NOe(t,e){let r=e.rule.ref;if(Oa(r)){let n=t.subrule++,i=e.arguments.length>0?MOe(r,e.arguments):()=>({});return a=>t.parser.subrule(n,aoe(t,r),e,i(a))}else if(Uo(r)){let n=t.consume++,i=aM(t,r.name);return()=>t.parser.consume(n,i,e)}else if(r)tf(r);else throw new jd(e.$cstNode,`Undefined rule type: ${e.$type}`)}function MOe(t,e){let r=e.map(n=>Vu(n.value));return n=>{let i={};for(let a=0;ae(n)||r(n)}else if(FD(t)){let e=Vu(t.left),r=Vu(t.right);return n=>e(n)&&r(n)}else if(YD(t)){let e=Vu(t.value);return r=>!e(r)}else if(jD(t)){let e=t.parameter.ref.name;return r=>r!==void 0&&r[e]===!0}else if(PD(t)){let e=!!t.true;return()=>e}tf(t)}function IOe(t,e){if(e.elements.length===1)return m0(t,e.elements[0]);{let r=[];for(let i of e.elements){let a={ALT:m0(t,i,!0)},s=Ak(i);s&&(a.GATE=Vu(s)),r.push(a)}let n=t.or++;return i=>t.parser.alternatives(n,r.map(a=>{let s={ALT:o(()=>a.ALT(i),"ALT")},l=a.GATE;return l&&(s.GATE=()=>l(i)),s}))}}function OOe(t,e){if(e.elements.length===1)return m0(t,e.elements[0]);let r=[];for(let l of e.elements){let u={ALT:m0(t,l,!0)},h=Ak(l);h&&(u.GATE=Vu(h)),r.push(u)}let n=t.or++,i=o((l,u)=>{let h=u.getRuleStack().join("-");return`uGroup_${l}_${h}`},"idFunc"),a=o(l=>t.parser.alternatives(n,r.map((u,h)=>{let f={ALT:o(()=>!0,"ALT")},d=t.parser;f.ALT=()=>{if(u.ALT(l),!d.isRecording()){let m=i(n,d);d.unorderedGroups.get(m)||d.unorderedGroups.set(m,[]);let g=d.unorderedGroups.get(m);typeof g?.[h]>"u"&&(g[h]=!0)}};let p=u.GATE;return p?f.GATE=()=>p(l):f.GATE=()=>{let m=d.unorderedGroups.get(i(n,d));return!m?.[h]},f})),"alternatives"),s=ioe(t,Ak(e),a,"*");return l=>{s(l),t.parser.isRecording()||t.parser.unorderedGroups.delete(i(n,t.parser))}}function POe(t,e){let r=e.elements.map(n=>m0(t,n));return n=>r.forEach(i=>i(n))}function Ak(t){if(rf(t))return t.guardCondition}function noe(t,e,r=e.terminal){if(r)if(Ml(r)&&Oa(r.rule.ref)){let n=t.subrule++;return i=>t.parser.subrule(n,aoe(t,r.rule.ref),e,i)}else if(Ml(r)&&Uo(r.rule.ref)){let n=t.consume++,i=aM(t,r.rule.ref.name);return()=>t.parser.consume(n,i,e)}else if(Ho(r)){let n=t.consume++,i=aM(t,r.value);return()=>t.parser.consume(n,i,e)}else throw new Error("Could not build cross reference parser");else{if(!e.type.ref)throw new Error("Could not resolve reference to type: "+e.type.$refText);let n=DT(e.type.ref),i=n?.terminal;if(!i)throw new Error("Could not find name assignment for type: "+r0(e.type.ref));return noe(t,e,i)}}function BOe(t,e){let r=t.consume++,n=t.tokens[e.value];if(!n)throw new Error("Could not find token for keyword: "+e.value);return()=>t.parser.consume(r,n,e)}function ioe(t,e,r,n){let i=e&&Vu(e);if(!n)if(i){let a=t.or++;return s=>t.parser.alternatives(a,[{ALT:o(()=>r(s),"ALT"),GATE:o(()=>i(s),"GATE")},{ALT:gk(),GATE:o(()=>!i(s),"GATE")}])}else return r;if(n==="*"){let a=t.many++;return s=>t.parser.many(a,{DEF:o(()=>r(s),"DEF"),GATE:i?()=>i(s):void 0})}else if(n==="+"){let a=t.many++;if(i){let s=t.or++;return l=>t.parser.alternatives(s,[{ALT:o(()=>t.parser.atLeastOne(a,{DEF:o(()=>r(l),"DEF")}),"ALT"),GATE:o(()=>i(l),"GATE")},{ALT:gk(),GATE:o(()=>!i(l),"GATE")}])}else return s=>t.parser.atLeastOne(a,{DEF:o(()=>r(s),"DEF")})}else if(n==="?"){let a=t.optional++;return s=>t.parser.optional(a,{DEF:o(()=>r(s),"DEF"),GATE:i?()=>i(s):void 0})}else tf(n)}function aoe(t,e){let r=FOe(t,e),n=t.rules.get(r);if(!n)throw new Error(`Rule "${r}" not found."`);return n}function FOe(t,e){if(Oa(e))return e.name;if(t.ruleNames.has(e))return t.ruleNames.get(e);{let r=e,n=r.$container,i=e.$type;for(;!Oa(n);)(rf(n)||wT(n)||kT(n))&&(i=n.elements.indexOf(r).toString()+":"+i),r=n,n=n.$container;return i=n.name+":"+i,t.ruleNames.set(e,i),i}}function aM(t,e){let r=t.tokens[e];if(!r)throw new Error(`Token "${e}" not found."`);return r}var sM=R(()=>{"use strict";u0();Sc();pT();Ds();Il();o(_k,"createParser");o(DOe,"buildRules");o(m0,"buildElement");o(ROe,"buildAction");o(NOe,"buildRuleCall");o(MOe,"buildRuleCallPredicate");o(Vu,"buildPredicate");o(IOe,"buildAlternatives");o(OOe,"buildUnorderedGroup");o(POe,"buildGroup");o(Ak,"getGuardCondition");o(noe,"buildCrossReference");o(BOe,"buildKeyword");o(ioe,"wrap");o(aoe,"getRule");o(FOe,"getRuleName");o(aM,"getToken")});function oM(t){let e=t.Grammar,r=t.parser.Lexer,n=new L2(t);return _k(e,n,r.definition),n.finalize(),n}var lM=R(()=>{"use strict";D2();sM();o(oM,"createCompletionParser")});function cM(t){let e=soe(t);return e.finalize(),e}function soe(t){let e=t.Grammar,r=t.parser.Lexer,n=new _2(t);return _k(e,n,r.definition)}var uM=R(()=>{"use strict";D2();sM();o(cM,"createLangiumParser");o(soe,"prepareLangiumParser")});var g0,hM=R(()=>{"use strict";u0();Sc();es();Il();Um();Ds();g0=class{static{o(this,"DefaultTokenBuilder")}buildTokens(e,r){let n=Kr(Qv(e,!1)),i=this.buildTerminalTokens(n),a=this.buildKeywordTokens(n,i,r);return i.forEach(s=>{let l=s.PATTERN;typeof l=="object"&&l&&"test"in l&&_T(l)?a.unshift(s):a.push(s)}),a}buildTerminalTokens(e){return e.filter(Uo).filter(r=>!r.fragment).map(r=>this.buildTerminalToken(r)).toArray()}buildTerminalToken(e){let r=Hm(e),n=this.requiresCustomPattern(r)?this.regexPatternFunction(r):r,i={name:e.name,PATTERN:n,LINE_BREAKS:!0};return e.hidden&&(i.GROUP=_T(r)?ni.SKIPPED:"hidden"),i}requiresCustomPattern(e){return e.flags.includes("u")?!0:!!(e.source.includes("?<=")||e.source.includes("?(r.lastIndex=i,r.exec(n))}buildKeywordTokens(e,r,n){return e.filter(Oa).flatMap(i=>Ac(i).filter(Ho)).distinct(i=>i.value).toArray().sort((i,a)=>a.value.length-i.value.length).map(i=>this.buildKeywordToken(i,r,!!n?.caseInsensitive))}buildKeywordToken(e,r,n){return{name:e.value,PATTERN:this.buildKeywordPattern(e,n),LONGER_ALT:this.findLongerAlt(e,r)}}buildKeywordPattern(e,r){return r?new RegExp(zR(e.value)):e.value}findLongerAlt(e,r){return r.reduce((n,i)=>{let a=i?.PATTERN;return a?.source&&GR("^"+a.source+"$",e.value)&&n.push(i),n},[])}}});var y0,Dc,fM=R(()=>{"use strict";Sc();Il();y0=class{static{o(this,"DefaultValueConverter")}convert(e,r){let n=r.grammarSource;if(Kd(n)&&(n=UR(n)),Ml(n)){let i=n.rule.ref;if(!i)throw new Error("This cst node was not parsed by a rule.");return this.runConverter(i,e,r)}return e}runConverter(e,r,n){var i;switch(e.name.toUpperCase()){case"INT":return Dc.convertInt(r);case"STRING":return Dc.convertString(r);case"ID":return Dc.convertID(r)}switch((i=QR(e))===null||i===void 0?void 0:i.toLowerCase()){case"number":return Dc.convertNumber(r);case"boolean":return Dc.convertBoolean(r);case"bigint":return Dc.convertBigint(r);case"date":return Dc.convertDate(r);default:return r}}};(function(t){function e(h){let f="";for(let d=1;d{"use strict";Object.defineProperty(mM,"__esModule",{value:!0});var dM;function pM(){if(dM===void 0)throw new Error("No runtime abstraction layer installed");return dM}o(pM,"RAL");(function(t){function e(r){if(r===void 0)throw new Error("No runtime abstraction layer provided");dM=r}o(e,"install"),t.install=e})(pM||(pM={}));mM.default=pM});var coe=gi(Pa=>{"use strict";Object.defineProperty(Pa,"__esModule",{value:!0});Pa.stringArray=Pa.array=Pa.func=Pa.error=Pa.number=Pa.string=Pa.boolean=void 0;function zOe(t){return t===!0||t===!1}o(zOe,"boolean");Pa.boolean=zOe;function ooe(t){return typeof t=="string"||t instanceof String}o(ooe,"string");Pa.string=ooe;function GOe(t){return typeof t=="number"||t instanceof Number}o(GOe,"number");Pa.number=GOe;function $Oe(t){return t instanceof Error}o($Oe,"error");Pa.error=$Oe;function VOe(t){return typeof t=="function"}o(VOe,"func");Pa.func=VOe;function loe(t){return Array.isArray(t)}o(loe,"array");Pa.array=loe;function UOe(t){return loe(t)&&t.every(e=>ooe(e))}o(UOe,"stringArray");Pa.stringArray=UOe});var vM=gi(vg=>{"use strict";Object.defineProperty(vg,"__esModule",{value:!0});vg.Emitter=vg.Event=void 0;var HOe=gM(),uoe;(function(t){let e={dispose(){}};t.None=function(){return e}})(uoe||(vg.Event=uoe={}));var yM=class{static{o(this,"CallbackList")}add(e,r=null,n){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(e),this._contexts.push(r),Array.isArray(n)&&n.push({dispose:o(()=>this.remove(e,r),"dispose")})}remove(e,r=null){if(!this._callbacks)return;let n=!1;for(let i=0,a=this._callbacks.length;i{this._callbacks||(this._callbacks=new yM),this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(e,r);let i={dispose:o(()=>{this._callbacks&&(this._callbacks.remove(e,r),i.dispose=t._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))},"dispose")};return Array.isArray(n)&&n.push(i),i}),this._event}fire(e){this._callbacks&&this._callbacks.invoke.call(this._callbacks,e)}dispose(){this._callbacks&&(this._callbacks.dispose(),this._callbacks=void 0)}};vg.Emitter=Lk;Lk._noop=function(){}});var hoe=gi(xg=>{"use strict";Object.defineProperty(xg,"__esModule",{value:!0});xg.CancellationTokenSource=xg.CancellationToken=void 0;var YOe=gM(),WOe=coe(),xM=vM(),Dk;(function(t){t.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:xM.Event.None}),t.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:xM.Event.None});function e(r){let n=r;return n&&(n===t.None||n===t.Cancelled||WOe.boolean(n.isCancellationRequested)&&!!n.onCancellationRequested)}o(e,"is"),t.is=e})(Dk||(xg.CancellationToken=Dk={}));var qOe=Object.freeze(function(t,e){let r=(0,YOe.default)().timer.setTimeout(t.bind(e),0);return{dispose(){r.dispose()}}}),Rk=class{static{o(this,"MutableToken")}constructor(){this._isCancelled=!1}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?qOe:(this._emitter||(this._emitter=new xM.Emitter),this._emitter.event)}dispose(){this._emitter&&(this._emitter.dispose(),this._emitter=void 0)}},bM=class{static{o(this,"CancellationTokenSource")}get token(){return this._token||(this._token=new Rk),this._token}cancel(){this._token?this._token.cancel():this._token=Dk.Cancelled}dispose(){this._token?this._token instanceof Rk&&this._token.dispose():this._token=Dk.None}};xg.CancellationTokenSource=bM});var pr={};var Wo=R(()=>{"use strict";dr(pr,Xi(hoe(),1))});function TM(){return new Promise(t=>{typeof setImmediate>"u"?setTimeout(t,0):setImmediate(t)})}function doe(){return wM=Date.now(),new pr.CancellationTokenSource}function poe(t){foe=t}function of(t){return t===Rc}async function Bi(t){if(t===pr.CancellationToken.None)return;let e=Date.now();if(e-wM>=foe&&(wM=e,await TM()),t.isCancellationRequested)throw Rc}var wM,foe,Rc,as,qo=R(()=>{"use strict";Wo();o(TM,"delayNextTick");wM=0,foe=10;o(doe,"startCancelableOperation");o(poe,"setInterruptionPeriod");Rc=Symbol("OperationCancelled");o(of,"isOperationCancelled");o(Bi,"interruptAndCheck");as=class{static{o(this,"Deferred")}constructor(){this.promise=new Promise((e,r)=>{this.resolve=n=>(e(n),this),this.reject=n=>(r(n),this)})}}});function kM(t,e){if(t.length<=1)return t;let r=t.length/2|0,n=t.slice(0,r),i=t.slice(r);kM(n,e),kM(i,e);let a=0,s=0,l=0;for(;ar.line||e.line===r.line&&e.character>r.character?{start:r,end:e}:t}function XOe(t){let e=yoe(t.range);return e!==t.range?{newText:t.newText,range:e}:t}var Nk,bg,voe=R(()=>{"use strict";Nk=class t{static{o(this,"FullTextDocument")}constructor(e,r,n,i){this._uri=e,this._languageId=r,this._version=n,this._content=i,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){let r=this.offsetAt(e.start),n=this.offsetAt(e.end);return this._content.substring(r,n)}return this._content}update(e,r){for(let n of e)if(t.isIncremental(n)){let i=yoe(n.range),a=this.offsetAt(i.start),s=this.offsetAt(i.end);this._content=this._content.substring(0,a)+n.text+this._content.substring(s,this._content.length);let l=Math.max(i.start.line,0),u=Math.max(i.end.line,0),h=this._lineOffsets,f=moe(n.text,!1,a);if(u-l===f.length)for(let p=0,m=f.length;pe?i=s:n=s+1}let a=n-1;return e=this.ensureBeforeEOL(e,r[a]),{line:a,character:e-r[a]}}offsetAt(e){let r=this.getLineOffsets();if(e.line>=r.length)return this._content.length;if(e.line<0)return 0;let n=r[e.line];if(e.character<=0)return n;let i=e.line+1r&&goe(this._content.charCodeAt(e-1));)e--;return e}get lineCount(){return this.getLineOffsets().length}static isIncremental(e){let r=e;return r!=null&&typeof r.text=="string"&&r.range!==void 0&&(r.rangeLength===void 0||typeof r.rangeLength=="number")}static isFull(e){let r=e;return r!=null&&typeof r.text=="string"&&r.range===void 0&&r.rangeLength===void 0}};(function(t){function e(i,a,s,l){return new Nk(i,a,s,l)}o(e,"create"),t.create=e;function r(i,a,s){if(i instanceof Nk)return i.update(a,s),i;throw new Error("TextDocument.update: document must be created by TextDocument.create")}o(r,"update"),t.update=r;function n(i,a){let s=i.getText(),l=kM(a.map(XOe),(f,d)=>{let p=f.range.start.line-d.range.start.line;return p===0?f.range.start.character-d.range.start.character:p}),u=0,h=[];for(let f of l){let d=i.offsetAt(f.range.start);if(du&&h.push(s.substring(u,d)),f.newText.length&&h.push(f.newText),u=i.offsetAt(f.range.end)}return h.push(s.substr(u)),h.join("")}o(n,"applyEdits"),t.applyEdits=n})(bg||(bg={}));o(kM,"mergeSort");o(moe,"computeLineOffsets");o(goe,"isEOL");o(yoe,"getWellformedRange");o(XOe,"getWellformedEdit")});var xoe,Ms,wg,EM=R(()=>{"use strict";(()=>{"use strict";var t={470:i=>{function a(u){if(typeof u!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(u))}o(a,"e");function s(u,h){for(var f,d="",p=0,m=-1,g=0,y=0;y<=u.length;++y){if(y2){var v=d.lastIndexOf("/");if(v!==d.length-1){v===-1?(d="",p=0):p=(d=d.slice(0,v)).length-1-d.lastIndexOf("/"),m=y,g=0;continue}}else if(d.length===2||d.length===1){d="",p=0,m=y,g=0;continue}}h&&(d.length>0?d+="/..":d="..",p=2)}else d.length>0?d+="/"+u.slice(m+1,y):d=u.slice(m+1,y),p=y-m-1;m=y,g=0}else f===46&&g!==-1?++g:g=-1}return d}o(s,"r");var l={resolve:o(function(){for(var u,h="",f=!1,d=arguments.length-1;d>=-1&&!f;d--){var p;d>=0?p=arguments[d]:(u===void 0&&(u=process.cwd()),p=u),a(p),p.length!==0&&(h=p+"/"+h,f=p.charCodeAt(0)===47)}return h=s(h,!f),f?h.length>0?"/"+h:"/":h.length>0?h:"."},"resolve"),normalize:o(function(u){if(a(u),u.length===0)return".";var h=u.charCodeAt(0)===47,f=u.charCodeAt(u.length-1)===47;return(u=s(u,!h)).length!==0||h||(u="."),u.length>0&&f&&(u+="/"),h?"/"+u:u},"normalize"),isAbsolute:o(function(u){return a(u),u.length>0&&u.charCodeAt(0)===47},"isAbsolute"),join:o(function(){if(arguments.length===0)return".";for(var u,h=0;h0&&(u===void 0?u=f:u+="/"+f)}return u===void 0?".":l.normalize(u)},"join"),relative:o(function(u,h){if(a(u),a(h),u===h||(u=l.resolve(u))===(h=l.resolve(h)))return"";for(var f=1;fy){if(h.charCodeAt(m+x)===47)return h.slice(m+x+1);if(x===0)return h.slice(m+x)}else p>y&&(u.charCodeAt(f+x)===47?v=x:x===0&&(v=0));break}var b=u.charCodeAt(f+x);if(b!==h.charCodeAt(m+x))break;b===47&&(v=x)}var w="";for(x=f+v+1;x<=d;++x)x!==d&&u.charCodeAt(x)!==47||(w.length===0?w+="..":w+="/..");return w.length>0?w+h.slice(m+v):(m+=v,h.charCodeAt(m)===47&&++m,h.slice(m))},"relative"),_makeLong:o(function(u){return u},"_makeLong"),dirname:o(function(u){if(a(u),u.length===0)return".";for(var h=u.charCodeAt(0),f=h===47,d=-1,p=!0,m=u.length-1;m>=1;--m)if((h=u.charCodeAt(m))===47){if(!p){d=m;break}}else p=!1;return d===-1?f?"/":".":f&&d===1?"//":u.slice(0,d)},"dirname"),basename:o(function(u,h){if(h!==void 0&&typeof h!="string")throw new TypeError('"ext" argument must be a string');a(u);var f,d=0,p=-1,m=!0;if(h!==void 0&&h.length>0&&h.length<=u.length){if(h.length===u.length&&h===u)return"";var g=h.length-1,y=-1;for(f=u.length-1;f>=0;--f){var v=u.charCodeAt(f);if(v===47){if(!m){d=f+1;break}}else y===-1&&(m=!1,y=f+1),g>=0&&(v===h.charCodeAt(g)?--g==-1&&(p=f):(g=-1,p=y))}return d===p?p=y:p===-1&&(p=u.length),u.slice(d,p)}for(f=u.length-1;f>=0;--f)if(u.charCodeAt(f)===47){if(!m){d=f+1;break}}else p===-1&&(m=!1,p=f+1);return p===-1?"":u.slice(d,p)},"basename"),extname:o(function(u){a(u);for(var h=-1,f=0,d=-1,p=!0,m=0,g=u.length-1;g>=0;--g){var y=u.charCodeAt(g);if(y!==47)d===-1&&(p=!1,d=g+1),y===46?h===-1?h=g:m!==1&&(m=1):h!==-1&&(m=-1);else if(!p){f=g+1;break}}return h===-1||d===-1||m===0||m===1&&h===d-1&&h===f+1?"":u.slice(h,d)},"extname"),format:o(function(u){if(u===null||typeof u!="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof u);return function(h,f){var d=f.dir||f.root,p=f.base||(f.name||"")+(f.ext||"");return d?d===f.root?d+p:d+"/"+p:p}(0,u)},"format"),parse:o(function(u){a(u);var h={root:"",dir:"",base:"",ext:"",name:""};if(u.length===0)return h;var f,d=u.charCodeAt(0),p=d===47;p?(h.root="/",f=1):f=0;for(var m=-1,g=0,y=-1,v=!0,x=u.length-1,b=0;x>=f;--x)if((d=u.charCodeAt(x))!==47)y===-1&&(v=!1,y=x+1),d===46?m===-1?m=x:b!==1&&(b=1):m!==-1&&(b=-1);else if(!v){g=x+1;break}return m===-1||y===-1||b===0||b===1&&m===y-1&&m===g+1?y!==-1&&(h.base=h.name=g===0&&p?u.slice(1,y):u.slice(g,y)):(g===0&&p?(h.name=u.slice(1,m),h.base=u.slice(1,y)):(h.name=u.slice(g,m),h.base=u.slice(g,y)),h.ext=u.slice(m,y)),g>0?h.dir=u.slice(0,g-1):p&&(h.dir="/"),h},"parse"),sep:"/",delimiter:":",win32:null,posix:null};l.posix=l,i.exports=l}},e={};function r(i){var a=e[i];if(a!==void 0)return a.exports;var s=e[i]={exports:{}};return t[i](s,s.exports,r),s.exports}o(r,"r"),r.d=(i,a)=>{for(var s in a)r.o(a,s)&&!r.o(i,s)&&Object.defineProperty(i,s,{enumerable:!0,get:a[s]})},r.o=(i,a)=>Object.prototype.hasOwnProperty.call(i,a),r.r=i=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(i,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(i,"__esModule",{value:!0})};var n={};(()=>{let i;r.r(n),r.d(n,{URI:o(()=>p,"URI"),Utils:o(()=>M,"Utils")}),typeof process=="object"?i=process.platform==="win32":typeof navigator=="object"&&(i=navigator.userAgent.indexOf("Windows")>=0);let a=/^\w[\w\d+.-]*$/,s=/^\//,l=/^\/\//;function u(N,k){if(!N.scheme&&k)throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${N.authority}", path: "${N.path}", query: "${N.query}", fragment: "${N.fragment}"}`);if(N.scheme&&!a.test(N.scheme))throw new Error("[UriError]: Scheme contains illegal characters.");if(N.path){if(N.authority){if(!s.test(N.path))throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character')}else if(l.test(N.path))throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")')}}o(u,"s");let h="",f="/",d=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;class p{static{o(this,"f")}static isUri(k){return k instanceof p||!!k&&typeof k.authority=="string"&&typeof k.fragment=="string"&&typeof k.path=="string"&&typeof k.query=="string"&&typeof k.scheme=="string"&&typeof k.fsPath=="string"&&typeof k.with=="function"&&typeof k.toString=="function"}scheme;authority;path;query;fragment;constructor(k,I,C,O,D,P=!1){typeof k=="object"?(this.scheme=k.scheme||h,this.authority=k.authority||h,this.path=k.path||h,this.query=k.query||h,this.fragment=k.fragment||h):(this.scheme=function(F,B){return F||B?F:"file"}(k,P),this.authority=I||h,this.path=function(F,B){switch(F){case"https":case"http":case"file":B?B[0]!==f&&(B=f+B):B=f}return B}(this.scheme,C||h),this.query=O||h,this.fragment=D||h,u(this,P))}get fsPath(){return b(this,!1)}with(k){if(!k)return this;let{scheme:I,authority:C,path:O,query:D,fragment:P}=k;return I===void 0?I=this.scheme:I===null&&(I=h),C===void 0?C=this.authority:C===null&&(C=h),O===void 0?O=this.path:O===null&&(O=h),D===void 0?D=this.query:D===null&&(D=h),P===void 0?P=this.fragment:P===null&&(P=h),I===this.scheme&&C===this.authority&&O===this.path&&D===this.query&&P===this.fragment?this:new g(I,C,O,D,P)}static parse(k,I=!1){let C=d.exec(k);return C?new g(C[2]||h,E(C[4]||h),E(C[5]||h),E(C[7]||h),E(C[9]||h),I):new g(h,h,h,h,h)}static file(k){let I=h;if(i&&(k=k.replace(/\\/g,f)),k[0]===f&&k[1]===f){let C=k.indexOf(f,2);C===-1?(I=k.substring(2),k=f):(I=k.substring(2,C),k=k.substring(C)||f)}return new g("file",I,k,h,h)}static from(k){let I=new g(k.scheme,k.authority,k.path,k.query,k.fragment);return u(I,!0),I}toString(k=!1){return w(this,k)}toJSON(){return this}static revive(k){if(k){if(k instanceof p)return k;{let I=new g(k);return I._formatted=k.external,I._fsPath=k._sep===m?k.fsPath:null,I}}return k}}let m=i?1:void 0;class g extends p{static{o(this,"l")}_formatted=null;_fsPath=null;get fsPath(){return this._fsPath||(this._fsPath=b(this,!1)),this._fsPath}toString(k=!1){return k?w(this,!0):(this._formatted||(this._formatted=w(this,!1)),this._formatted)}toJSON(){let k={$mid:1};return this._fsPath&&(k.fsPath=this._fsPath,k._sep=m),this._formatted&&(k.external=this._formatted),this.path&&(k.path=this.path),this.scheme&&(k.scheme=this.scheme),this.authority&&(k.authority=this.authority),this.query&&(k.query=this.query),this.fragment&&(k.fragment=this.fragment),k}}let y={58:"%3A",47:"%2F",63:"%3F",35:"%23",91:"%5B",93:"%5D",64:"%40",33:"%21",36:"%24",38:"%26",39:"%27",40:"%28",41:"%29",42:"%2A",43:"%2B",44:"%2C",59:"%3B",61:"%3D",32:"%20"};function v(N,k,I){let C,O=-1;for(let D=0;D=97&&P<=122||P>=65&&P<=90||P>=48&&P<=57||P===45||P===46||P===95||P===126||k&&P===47||I&&P===91||I&&P===93||I&&P===58)O!==-1&&(C+=encodeURIComponent(N.substring(O,D)),O=-1),C!==void 0&&(C+=N.charAt(D));else{C===void 0&&(C=N.substr(0,D));let F=y[P];F!==void 0?(O!==-1&&(C+=encodeURIComponent(N.substring(O,D)),O=-1),C+=F):O===-1&&(O=D)}}return O!==-1&&(C+=encodeURIComponent(N.substring(O))),C!==void 0?C:N}o(v,"d");function x(N){let k;for(let I=0;I1&&N.scheme==="file"?`//${N.authority}${N.path}`:N.path.charCodeAt(0)===47&&(N.path.charCodeAt(1)>=65&&N.path.charCodeAt(1)<=90||N.path.charCodeAt(1)>=97&&N.path.charCodeAt(1)<=122)&&N.path.charCodeAt(2)===58?k?N.path.substr(1):N.path[1].toLowerCase()+N.path.substr(2):N.path,i&&(I=I.replace(/\//g,"\\")),I}o(b,"m");function w(N,k){let I=k?x:v,C="",{scheme:O,authority:D,path:P,query:F,fragment:B}=N;if(O&&(C+=O,C+=":"),(D||O==="file")&&(C+=f,C+=f),D){let $=D.indexOf("@");if($!==-1){let z=D.substr(0,$);D=D.substr($+1),$=z.lastIndexOf(":"),$===-1?C+=I(z,!1,!1):(C+=I(z.substr(0,$),!1,!1),C+=":",C+=I(z.substr($+1),!1,!0)),C+="@"}D=D.toLowerCase(),$=D.lastIndexOf(":"),$===-1?C+=I(D,!1,!0):(C+=I(D.substr(0,$),!1,!0),C+=D.substr($))}if(P){if(P.length>=3&&P.charCodeAt(0)===47&&P.charCodeAt(2)===58){let $=P.charCodeAt(1);$>=65&&$<=90&&(P=`/${String.fromCharCode($+32)}:${P.substr(3)}`)}else if(P.length>=2&&P.charCodeAt(1)===58){let $=P.charCodeAt(0);$>=65&&$<=90&&(P=`${String.fromCharCode($+32)}:${P.substr(2)}`)}C+=I(P,!0,!1)}return F&&(C+="?",C+=I(F,!1,!1)),B&&(C+="#",C+=k?B:v(B,!1,!1)),C}o(w,"y");function S(N){try{return decodeURIComponent(N)}catch{return N.length>3?N.substr(0,3)+S(N.substr(3)):N}}o(S,"v");let T=/(%[0-9A-Za-z][0-9A-Za-z])+/g;function E(N){return N.match(T)?N.replace(T,k=>S(k)):N}o(E,"C");var _=r(470);let A=_.posix||_,L="/";var M;(function(N){N.joinPath=function(k,...I){return k.with({path:A.join(k.path,...I)})},N.resolvePath=function(k,...I){let C=k.path,O=!1;C[0]!==L&&(C=L+C,O=!0);let D=A.resolve(C,...I);return O&&D[0]===L&&!k.authority&&(D=D.substring(1)),k.with({path:D})},N.dirname=function(k){if(k.path.length===0||k.path===L)return k;let I=A.dirname(k.path);return I.length===1&&I.charCodeAt(0)===46&&(I=""),k.with({path:I})},N.basename=function(k){return A.basename(k.path)},N.extname=function(k){return A.extname(k.path)}})(M||(M={}))})(),xoe=n})();({URI:Ms,Utils:wg}=xoe)});var ss,Nc=R(()=>{"use strict";EM();(function(t){t.basename=wg.basename,t.dirname=wg.dirname,t.extname=wg.extname,t.joinPath=wg.joinPath,t.resolvePath=wg.resolvePath;function e(n,i){return n?.toString()===i?.toString()}o(e,"equals"),t.equals=e;function r(n,i){let a=typeof n=="string"?n:n.path,s=typeof i=="string"?i:i.path,l=a.split("/").filter(p=>p.length>0),u=s.split("/").filter(p=>p.length>0),h=0;for(;h{"use strict";voe();Tg();Wo();Ds();Nc();(function(t){t[t.Changed=0]="Changed",t[t.Parsed=1]="Parsed",t[t.IndexedContent=2]="IndexedContent",t[t.ComputedScopes=3]="ComputedScopes",t[t.Linked=4]="Linked",t[t.IndexedReferences=5]="IndexedReferences",t[t.Validated=6]="Validated"})(yn||(yn={}));R2=class{static{o(this,"DefaultLangiumDocumentFactory")}constructor(e){this.serviceRegistry=e.ServiceRegistry,this.textDocuments=e.workspace.TextDocuments,this.fileSystemProvider=e.workspace.FileSystemProvider}async fromUri(e,r=pr.CancellationToken.None){let n=await this.fileSystemProvider.readFile(e);return this.createAsync(e,n,r)}fromTextDocument(e,r,n){return r=r??Ms.parse(e.uri),n?this.createAsync(r,e,n):this.create(r,e)}fromString(e,r,n){return n?this.createAsync(r,e,n):this.create(r,e)}fromModel(e,r){return this.create(r,{$model:e})}create(e,r){if(typeof r=="string"){let n=this.parse(e,r);return this.createLangiumDocument(n,e,void 0,r)}else if("$model"in r){let n={value:r.$model,parserErrors:[],lexerErrors:[]};return this.createLangiumDocument(n,e)}else{let n=this.parse(e,r.getText());return this.createLangiumDocument(n,e,r)}}async createAsync(e,r,n){if(typeof r=="string"){let i=await this.parseAsync(e,r,n);return this.createLangiumDocument(i,e,void 0,r)}else{let i=await this.parseAsync(e,r.getText(),n);return this.createLangiumDocument(i,e,r)}}createLangiumDocument(e,r,n,i){let a;if(n)a={parseResult:e,uri:r,state:yn.Parsed,references:[],textDocument:n};else{let s=this.createTextDocumentGetter(r,i);a={parseResult:e,uri:r,state:yn.Parsed,references:[],get textDocument(){return s()}}}return e.value.$document=a,a}async update(e,r){var n,i;let a=(n=e.parseResult.value.$cstNode)===null||n===void 0?void 0:n.root.fullText,s=(i=this.textDocuments)===null||i===void 0?void 0:i.get(e.uri.toString()),l=s?s.getText():await this.fileSystemProvider.readFile(e.uri);if(s)Object.defineProperty(e,"textDocument",{value:s});else{let u=this.createTextDocumentGetter(e.uri,l);Object.defineProperty(e,"textDocument",{get:u})}return a!==l&&(e.parseResult=await this.parseAsync(e.uri,l,r),e.parseResult.value.$document=e),e.state=yn.Parsed,e}parse(e,r){return this.serviceRegistry.getServices(e).parser.LangiumParser.parse(r)}parseAsync(e,r,n){return this.serviceRegistry.getServices(e).parser.AsyncParser.parse(r,n)}createTextDocumentGetter(e,r){let n=this.serviceRegistry,i;return()=>i??(i=bg.create(e.toString(),n.getServices(e).LanguageMetaData.languageId,0,r??""))}},N2=class{static{o(this,"DefaultLangiumDocuments")}constructor(e){this.documentMap=new Map,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory}get all(){return Kr(this.documentMap.values())}addDocument(e){let r=e.uri.toString();if(this.documentMap.has(r))throw new Error(`A document with the URI '${r}' is already present.`);this.documentMap.set(r,e)}getDocument(e){let r=e.toString();return this.documentMap.get(r)}async getOrCreateDocument(e,r){let n=this.getDocument(e);return n||(n=await this.langiumDocumentFactory.fromUri(e,r),this.addDocument(n),n)}createDocument(e,r,n){if(n)return this.langiumDocumentFactory.fromString(r,e,n).then(i=>(this.addDocument(i),i));{let i=this.langiumDocumentFactory.fromString(r,e);return this.addDocument(i),i}}hasDocument(e){return this.documentMap.has(e.toString())}invalidateDocument(e){let r=e.toString(),n=this.documentMap.get(r);return n&&(n.state=yn.Changed,n.precomputedScopes=void 0,n.references=[],n.diagnostics=void 0),n}deleteDocument(e){let r=e.toString(),n=this.documentMap.get(r);return n&&(n.state=yn.Changed,this.documentMap.delete(r)),n}}});var M2,CM=R(()=>{"use strict";Wo();Vo();es();qo();Tg();M2=class{static{o(this,"DefaultLinker")}constructor(e){this.reflection=e.shared.AstReflection,this.langiumDocuments=()=>e.shared.workspace.LangiumDocuments,this.scopeProvider=e.references.ScopeProvider,this.astNodeLocator=e.workspace.AstNodeLocator}async link(e,r=pr.CancellationToken.None){for(let n of Yo(e.parseResult.value))await Bi(r),$m(n).forEach(i=>this.doLink(i,e))}doLink(e,r){let n=e.reference;if(n._ref===void 0)try{let i=this.getCandidate(e);if(Wd(i))n._ref=i;else if(n._nodeDescription=i,this.langiumDocuments().hasDocument(i.documentUri)){let a=this.loadAstNode(i);n._ref=a??this.createLinkingError(e,i)}}catch(i){n._ref=Object.assign(Object.assign({},e),{message:`An error occurred while resolving reference to '${n.$refText}': ${i}`})}r.references.push(n)}unlink(e){for(let r of e.references)delete r._ref,delete r._nodeDescription;e.references=[]}getCandidate(e){let n=this.scopeProvider.getScope(e).getElement(e.reference.$refText);return n??this.createLinkingError(e)}buildReference(e,r,n,i){let a=this,s={$refNode:n,$refText:i,get ref(){var l;if(Xn(this._ref))return this._ref;if(ED(this._nodeDescription)){let u=a.loadAstNode(this._nodeDescription);this._ref=u??a.createLinkingError({reference:s,container:e,property:r},this._nodeDescription)}else if(this._ref===void 0){let u=a.getLinkedNode({reference:s,container:e,property:r});if(u.error&&Oi(e).state{"use strict";Il();o(boe,"isNamed");I2=class{static{o(this,"DefaultNameProvider")}getName(e){if(boe(e))return e.name}getNameNode(e){return Zv(e.$cstNode,"name")}}});var O2,AM=R(()=>{"use strict";Il();Vo();es();Rl();Ds();Nc();O2=class{static{o(this,"DefaultReferences")}constructor(e){this.nameProvider=e.references.NameProvider,this.index=e.shared.workspace.IndexManager,this.nodeLocator=e.workspace.AstNodeLocator}findDeclaration(e){if(e){let r=jR(e),n=e.astNode;if(r&&n){let i=n[r.feature];if(xa(i))return i.ref;if(Array.isArray(i)){for(let a of i)if(xa(a)&&a.$refNode&&a.$refNode.offset<=e.offset&&a.$refNode.end>=e.end)return a.ref}}if(n){let i=this.nameProvider.getNameNode(n);if(i&&(i===e||SD(e,i)))return n}}}findDeclarationNode(e){let r=this.findDeclaration(e);if(r?.$cstNode){let n=this.nameProvider.getNameNode(r);return n??r.$cstNode}}findReferences(e,r){let n=[];if(r.includeDeclaration){let a=this.getReferenceToSelf(e);a&&n.push(a)}let i=this.index.findAllReferences(e,this.nodeLocator.getAstNodePath(e));return r.documentUri&&(i=i.filter(a=>ss.equals(a.sourceUri,r.documentUri))),n.push(...i),Kr(n)}getReferenceToSelf(e){let r=this.nameProvider.getNameNode(e);if(r){let n=Oi(e),i=this.nodeLocator.getAstNodePath(e);return{sourceUri:n.uri,sourcePath:i,targetUri:n.uri,targetPath:i,segment:Xd(r),local:!0}}}}});var Mc,v0,kg=R(()=>{"use strict";Ds();Mc=class{static{o(this,"MultiMap")}constructor(e){if(this.map=new Map,e)for(let[r,n]of e)this.add(r,n)}get size(){return Fm.sum(Kr(this.map.values()).map(e=>e.length))}clear(){this.map.clear()}delete(e,r){if(r===void 0)return this.map.delete(e);{let n=this.map.get(e);if(n){let i=n.indexOf(r);if(i>=0)return n.length===1?this.map.delete(e):n.splice(i,1),!0}return!1}}get(e){var r;return(r=this.map.get(e))!==null&&r!==void 0?r:[]}has(e,r){if(r===void 0)return this.map.has(e);{let n=this.map.get(e);return n?n.indexOf(r)>=0:!1}}add(e,r){return this.map.has(e)?this.map.get(e).push(r):this.map.set(e,[r]),this}addAll(e,r){return this.map.has(e)?this.map.get(e).push(...r):this.map.set(e,Array.from(r)),this}forEach(e){this.map.forEach((r,n)=>r.forEach(i=>e(i,n,this)))}[Symbol.iterator](){return this.entries().iterator()}entries(){return Kr(this.map.entries()).flatMap(([e,r])=>r.map(n=>[e,n]))}keys(){return Kr(this.map.keys())}values(){return Kr(this.map.values()).flat()}entriesGroupedByKey(){return Kr(this.map.entries())}},v0=class{static{o(this,"BiMap")}get size(){return this.map.size}constructor(e){if(this.map=new Map,this.inverse=new Map,e)for(let[r,n]of e)this.set(r,n)}clear(){this.map.clear(),this.inverse.clear()}set(e,r){return this.map.set(e,r),this.inverse.set(r,e),this}get(e){return this.map.get(e)}getKey(e){return this.inverse.get(e)}delete(e){let r=this.map.get(e);return r!==void 0?(this.map.delete(e),this.inverse.delete(r),!0):!1}}});var P2,_M=R(()=>{"use strict";Wo();es();kg();qo();P2=class{static{o(this,"DefaultScopeComputation")}constructor(e){this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider}async computeExports(e,r=pr.CancellationToken.None){return this.computeExportsForNode(e.parseResult.value,e,void 0,r)}async computeExportsForNode(e,r,n=Wv,i=pr.CancellationToken.None){let a=[];this.exportNode(e,a,r);for(let s of n(e))await Bi(i),this.exportNode(s,a,r);return a}exportNode(e,r,n){let i=this.nameProvider.getName(e);i&&r.push(this.descriptions.createDescription(e,i,n))}async computeLocalScopes(e,r=pr.CancellationToken.None){let n=e.parseResult.value,i=new Mc;for(let a of Ac(n))await Bi(r),this.processNode(a,e,i);return i}processNode(e,r,n){let i=e.$container;if(i){let a=this.nameProvider.getName(e);a&&n.add(i,this.descriptions.createDescription(e,a,r))}}}});var Eg,B2,jOe,LM=R(()=>{"use strict";Ds();Eg=class{static{o(this,"StreamScope")}constructor(e,r,n){var i;this.elements=e,this.outerScope=r,this.caseInsensitive=(i=n?.caseInsensitive)!==null&&i!==void 0?i:!1}getAllElements(){return this.outerScope?this.elements.concat(this.outerScope.getAllElements()):this.elements}getElement(e){let r=this.caseInsensitive?this.elements.find(n=>n.name.toLowerCase()===e.toLowerCase()):this.elements.find(n=>n.name===e);if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}},B2=class{static{o(this,"MapScope")}constructor(e,r,n){var i;this.elements=new Map,this.caseInsensitive=(i=n?.caseInsensitive)!==null&&i!==void 0?i:!1;for(let a of e){let s=this.caseInsensitive?a.name.toLowerCase():a.name;this.elements.set(s,a)}this.outerScope=r}getElement(e){let r=this.caseInsensitive?e.toLowerCase():e,n=this.elements.get(r);if(n)return n;if(this.outerScope)return this.outerScope.getElement(e)}getAllElements(){let e=Kr(this.elements.values());return this.outerScope&&(e=e.concat(this.outerScope.getAllElements())),e}},jOe={getElement(){},getAllElements(){return Gv}}});var Cg,F2,x0,Mk,Sg,Ik=R(()=>{"use strict";Cg=class{static{o(this,"DisposableCache")}constructor(){this.toDispose=[],this.isDisposed=!1}onDispose(e){this.toDispose.push(e)}dispose(){this.throwIfDisposed(),this.clear(),this.isDisposed=!0,this.toDispose.forEach(e=>e.dispose())}throwIfDisposed(){if(this.isDisposed)throw new Error("This cache has already been disposed")}},F2=class extends Cg{static{o(this,"SimpleCache")}constructor(){super(...arguments),this.cache=new Map}has(e){return this.throwIfDisposed(),this.cache.has(e)}set(e,r){this.throwIfDisposed(),this.cache.set(e,r)}get(e,r){if(this.throwIfDisposed(),this.cache.has(e))return this.cache.get(e);if(r){let n=r();return this.cache.set(e,n),n}else return}delete(e){return this.throwIfDisposed(),this.cache.delete(e)}clear(){this.throwIfDisposed(),this.cache.clear()}},x0=class extends Cg{static{o(this,"ContextCache")}constructor(e){super(),this.cache=new Map,this.converter=e??(r=>r)}has(e,r){return this.throwIfDisposed(),this.cacheForContext(e).has(r)}set(e,r,n){this.throwIfDisposed(),this.cacheForContext(e).set(r,n)}get(e,r,n){this.throwIfDisposed();let i=this.cacheForContext(e);if(i.has(r))return i.get(r);if(n){let a=n();return i.set(r,a),a}else return}delete(e,r){return this.throwIfDisposed(),this.cacheForContext(e).delete(r)}clear(e){if(this.throwIfDisposed(),e){let r=this.converter(e);this.cache.delete(r)}else this.cache.clear()}cacheForContext(e){let r=this.converter(e),n=this.cache.get(r);return n||(n=new Map,this.cache.set(r,n)),n}},Mk=class extends x0{static{o(this,"DocumentCache")}constructor(e){super(r=>r.toString()),this.onDispose(e.workspace.DocumentBuilder.onUpdate((r,n)=>{let i=r.concat(n);for(let a of i)this.clear(a)}))}},Sg=class extends F2{static{o(this,"WorkspaceCache")}constructor(e){super(),this.onDispose(e.workspace.DocumentBuilder.onUpdate(()=>{this.clear()}))}}});var z2,DM=R(()=>{"use strict";LM();es();Ds();Ik();z2=class{static{o(this,"DefaultScopeProvider")}constructor(e){this.reflection=e.shared.AstReflection,this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider,this.indexManager=e.shared.workspace.IndexManager,this.globalScopeCache=new Sg(e.shared)}getScope(e){let r=[],n=this.reflection.getReferenceType(e),i=Oi(e.container).precomputedScopes;if(i){let s=e.container;do{let l=i.get(s);l.length>0&&r.push(Kr(l).filter(u=>this.reflection.isSubtype(u.type,n))),s=s.$container}while(s)}let a=this.getGlobalScope(n,e);for(let s=r.length-1;s>=0;s--)a=this.createScope(r[s],a);return a}createScope(e,r,n){return new Eg(Kr(e),r,n)}createScopeForNodes(e,r,n){let i=Kr(e).map(a=>{let s=this.nameProvider.getName(a);if(s)return this.descriptions.createDescription(a,s)}).nonNullable();return new Eg(i,r,n)}getGlobalScope(e,r){return this.globalScopeCache.get(e,()=>new B2(this.indexManager.allElements(e)))}}});function RM(t){return typeof t.$comment=="string"}function woe(t){return typeof t=="object"&&!!t&&("$ref"in t||"$error"in t)}var G2,Ok=R(()=>{"use strict";EM();Vo();es();Il();o(RM,"isAstNodeWithComment");o(woe,"isIntermediateReference");G2=class{static{o(this,"DefaultJsonSerializer")}constructor(e){this.ignoreProperties=new Set(["$container","$containerProperty","$containerIndex","$document","$cstNode"]),this.langiumDocuments=e.shared.workspace.LangiumDocuments,this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider,this.commentProvider=e.documentation.CommentProvider}serialize(e,r={}){let n=r?.replacer,i=o((s,l)=>this.replacer(s,l,r),"defaultReplacer"),a=n?(s,l)=>n(s,l,i):i;try{return this.currentDocument=Oi(e),JSON.stringify(e,a,r?.space)}finally{this.currentDocument=void 0}}deserialize(e,r={}){let n=JSON.parse(e);return this.linkNode(n,n,r),n}replacer(e,r,{refText:n,sourceText:i,textRegions:a,comments:s,uriConverter:l}){var u,h,f,d;if(!this.ignoreProperties.has(e))if(xa(r)){let p=r.ref,m=n?r.$refText:void 0;if(p){let g=Oi(p),y="";this.currentDocument&&this.currentDocument!==g&&(l?y=l(g.uri,r):y=g.uri.toString());let v=this.astNodeLocator.getAstNodePath(p);return{$ref:`${y}#${v}`,$refText:m}}else return{$error:(h=(u=r.error)===null||u===void 0?void 0:u.message)!==null&&h!==void 0?h:"Could not resolve reference",$refText:m}}else if(Xn(r)){let p;if(a&&(p=this.addAstNodeRegionWithAssignmentsTo(Object.assign({},r)),(!e||r.$document)&&p?.$textRegion&&(p.$textRegion.documentURI=(f=this.currentDocument)===null||f===void 0?void 0:f.uri.toString())),i&&!e&&(p??(p=Object.assign({},r)),p.$sourceText=(d=r.$cstNode)===null||d===void 0?void 0:d.text),s){p??(p=Object.assign({},r));let m=this.commentProvider.getComment(r);m&&(p.$comment=m.replace(/\r/g,""))}return p??r}else return r}addAstNodeRegionWithAssignmentsTo(e){let r=o(n=>({offset:n.offset,end:n.end,length:n.length,range:n.range}),"createDocumentSegment");if(e.$cstNode){let n=e.$textRegion=r(e.$cstNode),i=n.assignments={};return Object.keys(e).filter(a=>!a.startsWith("$")).forEach(a=>{let s=YR(e.$cstNode,a).map(r);s.length!==0&&(i[a]=s)}),e}}linkNode(e,r,n,i,a,s){for(let[u,h]of Object.entries(e))if(Array.isArray(h))for(let f=0;f{"use strict";Nc();$2=class{static{o(this,"DefaultServiceRegistry")}register(e){if(!this.singleton&&!this.map){this.singleton=e;return}if(!this.map&&(this.map={},this.singleton)){for(let r of this.singleton.LanguageMetaData.fileExtensions)this.map[r]=this.singleton;this.singleton=void 0}for(let r of e.LanguageMetaData.fileExtensions)this.map[r]!==void 0&&this.map[r]!==e&&console.warn(`The file extension ${r} is used by multiple languages. It is now assigned to '${e.LanguageMetaData.languageId}'.`),this.map[r]=e}getServices(e){if(this.singleton!==void 0)return this.singleton;if(this.map===void 0)throw new Error("The service registry is empty. Use `register` to register the services of a language.");let r=ss.extname(e),n=this.map[r];if(!n)throw new Error(`The service registry contains no services for the extension '${r}'.`);return n}get all(){return this.singleton!==void 0?[this.singleton]:this.map!==void 0?Object.values(this.map):[]}}});function Pk(t){return{code:t}}var Ag,V2,U2=R(()=>{"use strict";kg();qo();Ds();o(Pk,"diagnosticData");(function(t){t.all=["fast","slow","built-in"]})(Ag||(Ag={}));V2=class{static{o(this,"ValidationRegistry")}constructor(e){this.entries=new Mc,this.reflection=e.shared.AstReflection}register(e,r=this,n="fast"){if(n==="built-in")throw new Error("The 'built-in' category is reserved for lexer, parser, and linker errors.");for(let[i,a]of Object.entries(e)){let s=a;if(Array.isArray(s))for(let l of s){let u={check:this.wrapValidationException(l,r),category:n};this.addEntry(i,u)}else if(typeof s=="function"){let l={check:this.wrapValidationException(s,r),category:n};this.addEntry(i,l)}}}wrapValidationException(e,r){return async(n,i,a)=>{try{await e.call(r,n,i,a)}catch(s){if(of(s))throw s;console.error("An error occurred during validation:",s);let l=s instanceof Error?s.message:String(s);s instanceof Error&&s.stack&&console.error(s.stack),i("error","An error occurred during validation: "+l,{node:n})}}}addEntry(e,r){if(e==="AstNode"){this.entries.add("AstNode",r);return}for(let n of this.reflection.getAllSubTypes(e))this.entries.add(n,r)}getChecks(e,r){let n=Kr(this.entries.get(e)).concat(this.entries.get("AstNode"));return r&&(n=n.filter(i=>r.includes(i.category))),n.map(i=>i.check)}}});function Toe(t){if(t.range)return t.range;let e;return typeof t.property=="string"?e=Zv(t.node.$cstNode,t.property,t.index):typeof t.keyword=="string"&&(e=qR(t.node.$cstNode,t.keyword,t.index)),e??(e=t.node.$cstNode),e?e.range:{start:{line:0,character:0},end:{line:0,character:0}}}function Bk(t){switch(t){case"error":return 1;case"warning":return 2;case"info":return 3;case"hint":return 4;default:throw new Error("Invalid diagnostic severity: "+t)}}var H2,Uu,MM=R(()=>{"use strict";Wo();Il();es();Rl();qo();U2();H2=class{static{o(this,"DefaultDocumentValidator")}constructor(e){this.validationRegistry=e.validation.ValidationRegistry,this.metadata=e.LanguageMetaData}async validateDocument(e,r={},n=pr.CancellationToken.None){let i=e.parseResult,a=[];if(await Bi(n),(!r.categories||r.categories.includes("built-in"))&&(this.processLexingErrors(i,a,r),r.stopAfterLexingErrors&&a.some(s=>{var l;return((l=s.data)===null||l===void 0?void 0:l.code)===Uu.LexingError})||(this.processParsingErrors(i,a,r),r.stopAfterParsingErrors&&a.some(s=>{var l;return((l=s.data)===null||l===void 0?void 0:l.code)===Uu.ParsingError}))||(this.processLinkingErrors(e,a,r),r.stopAfterLinkingErrors&&a.some(s=>{var l;return((l=s.data)===null||l===void 0?void 0:l.code)===Uu.LinkingError}))))return a;try{a.push(...await this.validateAst(i.value,r,n))}catch(s){if(of(s))throw s;console.error("An error occurred during validation:",s)}return await Bi(n),a}processLexingErrors(e,r,n){for(let i of e.lexerErrors){let a={severity:Bk("error"),range:{start:{line:i.line-1,character:i.column-1},end:{line:i.line-1,character:i.column+i.length-1}},message:i.message,data:Pk(Uu.LexingError),source:this.getSource()};r.push(a)}}processParsingErrors(e,r,n){for(let i of e.parserErrors){let a;if(isNaN(i.token.startOffset)){if("previousToken"in i){let s=i.previousToken;if(isNaN(s.startOffset)){let l={line:0,character:0};a={start:l,end:l}}else{let l={line:s.endLine-1,character:s.endColumn};a={start:l,end:l}}}}else a=zm(i.token);if(a){let s={severity:Bk("error"),range:a,message:i.message,data:Pk(Uu.ParsingError),source:this.getSource()};r.push(s)}}}processLinkingErrors(e,r,n){for(let i of e.references){let a=i.error;if(a){let s={node:a.container,property:a.property,index:a.index,data:{code:Uu.LinkingError,containerType:a.container.$type,property:a.property,refText:a.reference.$refText}};r.push(this.toDiagnostic("error",a.message,s))}}}async validateAst(e,r,n=pr.CancellationToken.None){let i=[],a=o((s,l,u)=>{i.push(this.toDiagnostic(s,l,u))},"acceptor");return await Promise.all(Yo(e).map(async s=>{await Bi(n);let l=this.validationRegistry.getChecks(s.$type,r.categories);for(let u of l)await u(s,a,n)})),i}toDiagnostic(e,r,n){return{message:r,range:Toe(n),severity:Bk(e),code:n.code,codeDescription:n.codeDescription,tags:n.tags,relatedInformation:n.relatedInformation,data:n.data,source:this.getSource()}}getSource(){return this.metadata.languageId}};o(Toe,"getDiagnosticRange");o(Bk,"toDiagnosticSeverity");(function(t){t.LexingError="lexing-error",t.ParsingError="parsing-error",t.LinkingError="linking-error"})(Uu||(Uu={}))});var Y2,W2,IM=R(()=>{"use strict";Wo();Vo();es();Rl();qo();Nc();Y2=class{static{o(this,"DefaultAstNodeDescriptionProvider")}constructor(e){this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider}createDescription(e,r,n=Oi(e)){r??(r=this.nameProvider.getName(e));let i=this.astNodeLocator.getAstNodePath(e);if(!r)throw new Error(`Node at path ${i} has no name.`);let a,s=o(()=>{var l;return a??(a=Xd((l=this.nameProvider.getNameNode(e))!==null&&l!==void 0?l:e.$cstNode))},"nameSegmentGetter");return{node:e,name:r,get nameSegment(){return s()},selectionSegment:Xd(e.$cstNode),type:e.$type,documentUri:n.uri,path:i}}},W2=class{static{o(this,"DefaultReferenceDescriptionProvider")}constructor(e){this.nodeLocator=e.workspace.AstNodeLocator}async createDescriptions(e,r=pr.CancellationToken.None){let n=[],i=e.parseResult.value;for(let a of Yo(i))await Bi(r),$m(a).filter(s=>!Wd(s)).forEach(s=>{let l=this.createDescription(s);l&&n.push(l)});return n}createDescription(e){let r=e.reference.$nodeDescription,n=e.reference.$refNode;if(!r||!n)return;let i=Oi(e.container).uri;return{sourceUri:i,sourcePath:this.nodeLocator.getAstNodePath(e.container),targetUri:r.documentUri,targetPath:r.path,segment:Xd(n),local:ss.equals(r.documentUri,i)}}}});var q2,OM=R(()=>{"use strict";q2=class{static{o(this,"DefaultAstNodeLocator")}constructor(){this.segmentSeparator="/",this.indexSeparator="@"}getAstNodePath(e){if(e.$container){let r=this.getAstNodePath(e.$container),n=this.getPathSegment(e);return r+this.segmentSeparator+n}return""}getPathSegment({$containerProperty:e,$containerIndex:r}){if(!e)throw new Error("Missing '$containerProperty' in AST node.");return r!==void 0?e+this.indexSeparator+r:e}getAstNode(e,r){return r.split(this.segmentSeparator).reduce((i,a)=>{if(!i||a.length===0)return i;let s=a.indexOf(this.indexSeparator);if(s>0){let l=a.substring(0,s),u=parseInt(a.substring(s+1)),h=i[l];return h?.[u]}return i[a]},e)}}});var X2,PM=R(()=>{"use strict";qo();X2=class{static{o(this,"DefaultConfigurationProvider")}constructor(e){this._ready=new as,this.settings={},this.workspaceConfig=!1,this.serviceRegistry=e.ServiceRegistry}get ready(){return this._ready.promise}initialize(e){var r,n;this.workspaceConfig=(n=(r=e.capabilities.workspace)===null||r===void 0?void 0:r.configuration)!==null&&n!==void 0?n:!1}async initialized(e){if(this.workspaceConfig){if(e.register){let r=this.serviceRegistry.all;e.register({section:r.map(n=>this.toSectionName(n.LanguageMetaData.languageId))})}if(e.fetchConfiguration){let r=this.serviceRegistry.all.map(i=>({section:this.toSectionName(i.LanguageMetaData.languageId)})),n=await e.fetchConfiguration(r);r.forEach((i,a)=>{this.updateSectionConfiguration(i.section,n[a])})}}this._ready.resolve()}updateConfiguration(e){e.settings&&Object.keys(e.settings).forEach(r=>{this.updateSectionConfiguration(r,e.settings[r])})}updateSectionConfiguration(e,r){this.settings[e]=r}async getConfiguration(e,r){await this.ready;let n=this.toSectionName(e);if(this.settings[n])return this.settings[n][r]}toSectionName(e){return`${e}`}}});var b0,BM=R(()=>{"use strict";(function(t){function e(r){return{dispose:o(async()=>await r(),"dispose")}}o(e,"create"),t.create=e})(b0||(b0={}))});var j2,FM=R(()=>{"use strict";Wo();BM();kg();qo();Ds();U2();Tg();j2=class{static{o(this,"DefaultDocumentBuilder")}constructor(e){this.updateBuildOptions={validation:{categories:["built-in","fast"]}},this.updateListeners=[],this.buildPhaseListeners=new Mc,this.buildState=new Map,this.documentBuildWaiters=new Map,this.currentState=yn.Changed,this.langiumDocuments=e.workspace.LangiumDocuments,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory,this.indexManager=e.workspace.IndexManager,this.serviceRegistry=e.ServiceRegistry}async build(e,r={},n=pr.CancellationToken.None){var i,a;for(let s of e){let l=s.uri.toString();if(s.state===yn.Validated){if(typeof r.validation=="boolean"&&r.validation)s.state=yn.IndexedReferences,s.diagnostics=void 0,this.buildState.delete(l);else if(typeof r.validation=="object"){let u=this.buildState.get(l),h=(i=u?.result)===null||i===void 0?void 0:i.validationChecks;if(h){let d=((a=r.validation.categories)!==null&&a!==void 0?a:Ag.all).filter(p=>!h.includes(p));d.length>0&&(this.buildState.set(l,{completed:!1,options:{validation:Object.assign(Object.assign({},r.validation),{categories:d})},result:u.result}),s.state=yn.IndexedReferences)}}}else this.buildState.delete(l)}this.currentState=yn.Changed,await this.emitUpdate(e.map(s=>s.uri),[]),await this.buildDocuments(e,r,n)}async update(e,r,n=pr.CancellationToken.None){this.currentState=yn.Changed;for(let s of r)this.langiumDocuments.deleteDocument(s),this.buildState.delete(s.toString()),this.indexManager.remove(s);for(let s of e){if(!this.langiumDocuments.invalidateDocument(s)){let u=this.langiumDocumentFactory.fromModel({$type:"INVALID"},s);u.state=yn.Changed,this.langiumDocuments.addDocument(u)}this.buildState.delete(s.toString())}let i=Kr(e).concat(r).map(s=>s.toString()).toSet();this.langiumDocuments.all.filter(s=>!i.has(s.uri.toString())&&this.shouldRelink(s,i)).forEach(s=>{this.serviceRegistry.getServices(s.uri).references.Linker.unlink(s),s.state=Math.min(s.state,yn.ComputedScopes),s.diagnostics=void 0}),await this.emitUpdate(e,r),await Bi(n);let a=this.langiumDocuments.all.filter(s=>{var l;return s.staten(e,r)))}shouldRelink(e,r){return e.references.some(n=>n.error!==void 0)?!0:this.indexManager.isAffected(e,r)}onUpdate(e){return this.updateListeners.push(e),b0.create(()=>{let r=this.updateListeners.indexOf(e);r>=0&&this.updateListeners.splice(r,1)})}async buildDocuments(e,r,n){this.prepareBuild(e,r),await this.runCancelable(e,yn.Parsed,n,a=>this.langiumDocumentFactory.update(a,n)),await this.runCancelable(e,yn.IndexedContent,n,a=>this.indexManager.updateContent(a,n)),await this.runCancelable(e,yn.ComputedScopes,n,async a=>{let s=this.serviceRegistry.getServices(a.uri).references.ScopeComputation;a.precomputedScopes=await s.computeLocalScopes(a,n)}),await this.runCancelable(e,yn.Linked,n,a=>this.serviceRegistry.getServices(a.uri).references.Linker.link(a,n)),await this.runCancelable(e,yn.IndexedReferences,n,a=>this.indexManager.updateReferences(a,n));let i=e.filter(a=>this.shouldValidate(a));await this.runCancelable(i,yn.Validated,n,a=>this.validate(a,n));for(let a of e){let s=this.buildState.get(a.uri.toString());s&&(s.completed=!0)}}prepareBuild(e,r){for(let n of e){let i=n.uri.toString(),a=this.buildState.get(i);(!a||a.completed)&&this.buildState.set(i,{completed:!1,options:r,result:a?.result})}}async runCancelable(e,r,n,i){let a=e.filter(s=>s.state{this.buildPhaseListeners.delete(e,r)})}waitUntil(e,r,n){let i;if(r&&"path"in r?i=r:n=r,n??(n=pr.CancellationToken.None),i){let a=this.langiumDocuments.getDocument(i);if(a&&a.state>e)return Promise.resolve(i)}return this.currentState>=e?Promise.resolve(void 0):n.isCancellationRequested?Promise.reject(Rc):new Promise((a,s)=>{let l=this.onBuildPhase(e,()=>{if(l.dispose(),u.dispose(),i){let h=this.langiumDocuments.getDocument(i);a(h?.uri)}else a(void 0)}),u=n.onCancellationRequested(()=>{l.dispose(),u.dispose(),s(Rc)})})}async notifyBuildPhase(e,r,n){if(e.length===0)return;let i=this.buildPhaseListeners.get(r);for(let a of i)await Bi(n),await a(e,n)}shouldValidate(e){return!!this.getBuildOptions(e).validation}async validate(e,r){var n,i;let a=this.serviceRegistry.getServices(e.uri).validation.DocumentValidator,s=this.getBuildOptions(e).validation,l=typeof s=="object"?s:void 0,u=await a.validateDocument(e,l,r);e.diagnostics?e.diagnostics.push(...u):e.diagnostics=u;let h=this.buildState.get(e.uri.toString());if(h){(n=h.result)!==null&&n!==void 0||(h.result={});let f=(i=l?.categories)!==null&&i!==void 0?i:Ag.all;h.result.validationChecks?h.result.validationChecks.push(...f):h.result.validationChecks=[...f]}}getBuildOptions(e){var r,n;return(n=(r=this.buildState.get(e.uri.toString()))===null||r===void 0?void 0:r.options)!==null&&n!==void 0?n:{}}}});var K2,zM=R(()=>{"use strict";es();Ik();Wo();Ds();Nc();K2=class{static{o(this,"DefaultIndexManager")}constructor(e){this.symbolIndex=new Map,this.symbolByTypeIndex=new x0,this.referenceIndex=new Map,this.documents=e.workspace.LangiumDocuments,this.serviceRegistry=e.ServiceRegistry,this.astReflection=e.AstReflection}findAllReferences(e,r){let n=Oi(e).uri,i=[];return this.referenceIndex.forEach(a=>{a.forEach(s=>{ss.equals(s.targetUri,n)&&s.targetPath===r&&i.push(s)})}),Kr(i)}allElements(e,r){let n=Kr(this.symbolIndex.keys());return r&&(n=n.filter(i=>!r||r.has(i))),n.map(i=>this.getFileDescriptions(i,e)).flat()}getFileDescriptions(e,r){var n;return r?this.symbolByTypeIndex.get(e,r,()=>{var a;return((a=this.symbolIndex.get(e))!==null&&a!==void 0?a:[]).filter(l=>this.astReflection.isSubtype(l.type,r))}):(n=this.symbolIndex.get(e))!==null&&n!==void 0?n:[]}remove(e){let r=e.toString();this.symbolIndex.delete(r),this.symbolByTypeIndex.clear(r),this.referenceIndex.delete(r)}async updateContent(e,r=pr.CancellationToken.None){let i=await this.serviceRegistry.getServices(e.uri).references.ScopeComputation.computeExports(e,r),a=e.uri.toString();this.symbolIndex.set(a,i),this.symbolByTypeIndex.clear(a)}async updateReferences(e,r=pr.CancellationToken.None){let i=await this.serviceRegistry.getServices(e.uri).workspace.ReferenceDescriptionProvider.createDescriptions(e,r);this.referenceIndex.set(e.uri.toString(),i)}isAffected(e,r){let n=this.referenceIndex.get(e.uri.toString());return n?n.some(i=>!i.local&&r.has(i.targetUri.toString())):!1}}});var Q2,GM=R(()=>{"use strict";Wo();qo();Nc();Q2=class{static{o(this,"DefaultWorkspaceManager")}constructor(e){this.initialBuildOptions={},this._ready=new as,this.serviceRegistry=e.ServiceRegistry,this.langiumDocuments=e.workspace.LangiumDocuments,this.documentBuilder=e.workspace.DocumentBuilder,this.fileSystemProvider=e.workspace.FileSystemProvider,this.mutex=e.workspace.WorkspaceLock}get ready(){return this._ready.promise}initialize(e){var r;this.folders=(r=e.workspaceFolders)!==null&&r!==void 0?r:void 0}initialized(e){return this.mutex.write(r=>{var n;return this.initializeWorkspace((n=this.folders)!==null&&n!==void 0?n:[],r)})}async initializeWorkspace(e,r=pr.CancellationToken.None){let n=await this.performStartup(e);await Bi(r),await this.documentBuilder.build(n,this.initialBuildOptions,r)}async performStartup(e){let r=this.serviceRegistry.all.flatMap(a=>a.LanguageMetaData.fileExtensions),n=[],i=o(a=>{n.push(a),this.langiumDocuments.hasDocument(a.uri)||this.langiumDocuments.addDocument(a)},"collector");return await this.loadAdditionalDocuments(e,i),await Promise.all(e.map(a=>[a,this.getRootFolder(a)]).map(async a=>this.traverseFolder(...a,r,i))),this._ready.resolve(),n}loadAdditionalDocuments(e,r){return Promise.resolve()}getRootFolder(e){return Ms.parse(e.uri)}async traverseFolder(e,r,n,i){let a=await this.fileSystemProvider.readDirectory(r);await Promise.all(a.map(async s=>{if(this.includeEntry(e,s,n)){if(s.isDirectory)await this.traverseFolder(e,s.uri,n,i);else if(s.isFile){let l=await this.langiumDocuments.getOrCreateDocument(s.uri);i(l)}}}))}includeEntry(e,r,n){let i=ss.basename(r.uri);if(i.startsWith("."))return!1;if(r.isDirectory)return i!=="node_modules"&&i!=="out";if(r.isFile){let a=ss.extname(r.uri);return n.includes(a)}return!1}}});function koe(t){return Array.isArray(t)&&(t.length===0||"name"in t[0])}function VM(t){return t&&"modes"in t&&"defaultMode"in t}function $M(t){return!koe(t)&&!VM(t)}var Z2,UM=R(()=>{"use strict";u0();Z2=class{static{o(this,"DefaultLexer")}constructor(e){let r=e.parser.TokenBuilder.buildTokens(e.Grammar,{caseInsensitive:e.LanguageMetaData.caseInsensitive});this.tokenTypes=this.toTokenTypeDictionary(r);let n=$M(r)?Object.values(r):r;this.chevrotainLexer=new ni(n,{positionTracking:"full"})}get definition(){return this.tokenTypes}tokenize(e){var r;let n=this.chevrotainLexer.tokenize(e);return{tokens:n.tokens,errors:n.errors,hidden:(r=n.groups.hidden)!==null&&r!==void 0?r:[]}}toTokenTypeDictionary(e){if($M(e))return e;let r=VM(e)?Object.values(e.modes).flat():e,n={};return r.forEach(i=>n[i.name]=i),n}};o(koe,"isTokenTypeArray");o(VM,"isIMultiModeLexerDefinition");o($M,"isTokenTypeDictionary")});function WM(t,e,r){let n,i;typeof t=="string"?(i=e,n=r):(i=t.range.start,n=e),i||(i=Ur.create(0,0));let a=Soe(t),s=XM(n),l=QOe({lines:a,position:i,options:s});return rPe({index:0,tokens:l,position:i})}function qM(t,e){let r=XM(e),n=Soe(t);if(n.length===0)return!1;let i=n[0],a=n[n.length-1],s=r.start,l=r.end;return!!s?.exec(i)&&!!l?.exec(a)}function Soe(t){let e="";return typeof t=="string"?e=t:e=t.text,e.split(BR)}function QOe(t){var e,r,n;let i=[],a=t.position.line,s=t.position.character;for(let l=0;l=f.length){if(i.length>0){let m=Ur.create(a,s);i.push({type:"break",content:"",range:wr.create(m,m)})}}else{Eoe.lastIndex=d;let m=Eoe.exec(f);if(m){let g=m[0],y=m[1],v=Ur.create(a,s+d),x=Ur.create(a,s+d+g.length);i.push({type:"tag",content:y,range:wr.create(v,x)}),d+=g.length,d=YM(f,d)}if(d0&&i[i.length-1].type==="break"?i.slice(0,-1):i}function ZOe(t,e,r,n){let i=[];if(t.length===0){let a=Ur.create(r,n),s=Ur.create(r,n+e.length);i.push({type:"text",content:e,range:wr.create(a,s)})}else{let a=0;for(let l of t){let u=l.index,h=e.substring(a,u);h.length>0&&i.push({type:"text",content:e.substring(a,u),range:wr.create(Ur.create(r,a+n),Ur.create(r,u+n))});let f=h.length+1,d=l[1];if(i.push({type:"inline-tag",content:d,range:wr.create(Ur.create(r,a+f+n),Ur.create(r,a+f+d.length+n))}),f+=d.length,l.length===4){f+=l[2].length;let p=l[3];i.push({type:"text",content:p,range:wr.create(Ur.create(r,a+f+n),Ur.create(r,a+f+p.length+n))})}else i.push({type:"text",content:"",range:wr.create(Ur.create(r,a+f+n),Ur.create(r,a+f+n))});a=u+l[0].length}let s=e.substring(a);s.length>0&&i.push({type:"text",content:s,range:wr.create(Ur.create(r,a+n),Ur.create(r,a+n+s.length))})}return i}function YM(t,e){let r=t.substring(e).match(JOe);return r?e+r.index:t.length}function tPe(t){let e=t.match(ePe);if(e&&typeof e.index=="number")return e.index}function rPe(t){var e,r,n,i;let a=Ur.create(t.position.line,t.position.character);if(t.tokens.length===0)return new Fk([],wr.create(a,a));let s=[];for(;t.index0){let u=YM(e,a);s=e.substring(u),e=e.substring(0,a)}return(t==="linkcode"||t==="link"&&r.link==="code")&&(s=`\`${s}\``),(i=(n=r.renderLink)===null||n===void 0?void 0:n.call(r,e,s))!==null&&i!==void 0?i:oPe(e,s)}}function oPe(t,e){try{return Ms.parse(t,!0),`[${e}](${t})`}catch{return t}}function Coe(t){return t.endsWith(` +`)?` +`:` + +`}var Eoe,KOe,JOe,ePe,Fk,J2,ex,zk,jM=R(()=>{"use strict";tM();Um();Nc();o(WM,"parseJSDoc");o(qM,"isJSDoc");o(Soe,"getLines");Eoe=/\s*(@([\p{L}][\p{L}\p{N}]*)?)/uy,KOe=/\{(@[\p{L}][\p{L}\p{N}]*)(\s*)([^\r\n}]+)?\}/gu;o(QOe,"tokenize");o(ZOe,"buildInlineTokens");JOe=/\S/,ePe=/\s*$/;o(YM,"skipWhitespace");o(tPe,"lastCharacter");o(rPe,"parseJSDocComment");o(nPe,"parseJSDocElement");o(iPe,"appendEmptyLine");o(Aoe,"parseJSDocText");o(aPe,"parseJSDocInline");o(_oe,"parseJSDocTag");o(Loe,"parseJSDocLine");o(XM,"normalizeOptions");o(HM,"normalizeOption");Fk=class{static{o(this,"JSDocCommentImpl")}constructor(e,r){this.elements=e,this.range=r}getTag(e){return this.getAllTags().find(r=>r.name===e)}getTags(e){return this.getAllTags().filter(r=>r.name===e)}getAllTags(){return this.elements.filter(e=>"name"in e)}toString(){let e="";for(let r of this.elements)if(e.length===0)e=r.toString();else{let n=r.toString();e+=Coe(e)+n}return e.trim()}toMarkdown(e){let r="";for(let n of this.elements)if(r.length===0)r=n.toMarkdown(e);else{let i=n.toMarkdown(e);r+=Coe(r)+i}return r.trim()}},J2=class{static{o(this,"JSDocTagImpl")}constructor(e,r,n,i){this.name=e,this.content=r,this.inline=n,this.range=i}toString(){let e=`@${this.name}`,r=this.content.toString();return this.content.inlines.length===1?e=`${e} ${r}`:this.content.inlines.length>1&&(e=`${e} +${r}`),this.inline?`{${e}}`:e}toMarkdown(e){var r,n;return(n=(r=e?.renderTag)===null||r===void 0?void 0:r.call(e,this))!==null&&n!==void 0?n:this.toMarkdownDefault(e)}toMarkdownDefault(e){let r=this.content.toMarkdown(e);if(this.inline){let a=sPe(this.name,r,e??{});if(typeof a=="string")return a}let n="";e?.tag==="italic"||e?.tag===void 0?n="*":e?.tag==="bold"?n="**":e?.tag==="bold-italic"&&(n="***");let i=`${n}@${this.name}${n}`;return this.content.inlines.length===1?i=`${i} \u2014 ${r}`:this.content.inlines.length>1&&(i=`${i} +${r}`),this.inline?`{${i}}`:i}};o(sPe,"renderInlineTag");o(oPe,"renderLinkDefault");ex=class{static{o(this,"JSDocTextImpl")}constructor(e,r){this.inlines=e,this.range=r}toString(){let e="";for(let r=0;rn.range.start.line&&(e+=` +`)}return e}toMarkdown(e){let r="";for(let n=0;ni.range.start.line&&(r+=` +`)}return r}},zk=class{static{o(this,"JSDocLineImpl")}constructor(e,r){this.text=e,this.range=r}toString(){return this.text}toMarkdown(){return this.text}};o(Coe,"fillNewlines")});var tx,KM=R(()=>{"use strict";es();jM();tx=class{static{o(this,"JSDocDocumentationProvider")}constructor(e){this.indexManager=e.shared.workspace.IndexManager,this.commentProvider=e.documentation.CommentProvider}getDocumentation(e){let r=this.commentProvider.getComment(e);if(r&&qM(r))return WM(r).toMarkdown({renderLink:o((i,a)=>this.documentationLinkRenderer(e,i,a),"renderLink"),renderTag:o(i=>this.documentationTagRenderer(e,i),"renderTag")})}documentationLinkRenderer(e,r,n){var i;let a=(i=this.findNameInPrecomputedScopes(e,r))!==null&&i!==void 0?i:this.findNameInGlobalScope(e,r);if(a&&a.nameSegment){let s=a.nameSegment.range.start.line+1,l=a.nameSegment.range.start.character+1,u=a.documentUri.with({fragment:`L${s},${l}`});return`[${n}](${u.toString()})`}else return}documentationTagRenderer(e,r){}findNameInPrecomputedScopes(e,r){let i=Oi(e).precomputedScopes;if(!i)return;let a=e;do{let l=i.get(a).find(u=>u.name===r);if(l)return l;a=a.$container}while(a)}findNameInGlobalScope(e,r){return this.indexManager.allElements().find(i=>i.name===r)}}});var rx,QM=R(()=>{"use strict";Ok();Rl();rx=class{static{o(this,"DefaultCommentProvider")}constructor(e){this.grammarConfig=()=>e.parser.GrammarConfig}getComment(e){var r;return RM(e)?e.$comment:(r=_D(e.$cstNode,this.grammarConfig().multilineCommentRules))===null||r===void 0?void 0:r.text}}});var ii={};var ZM=R(()=>{"use strict";dr(ii,Xi(vM(),1))});var nx,JM,eI,tI=R(()=>{"use strict";qo();ZM();nx=class{static{o(this,"DefaultAsyncParser")}constructor(e){this.syncParser=e.parser.LangiumParser}parse(e){return Promise.resolve(this.syncParser.parse(e))}},JM=class{static{o(this,"AbstractThreadedAsyncParser")}constructor(e){this.threadCount=8,this.terminationDelay=200,this.workerPool=[],this.queue=[],this.hydrator=e.serializer.Hydrator}initializeWorkers(){for(;this.workerPool.length{if(this.queue.length>0){let r=this.queue.shift();r&&(e.lock(),r.resolve(e))}}),this.workerPool.push(e)}}async parse(e,r){let n=await this.acquireParserWorker(r),i=new as,a,s=r.onCancellationRequested(()=>{a=setTimeout(()=>{this.terminateWorker(n)},this.terminationDelay)});return n.parse(e).then(l=>{let u=this.hydrator.hydrate(l);i.resolve(u)}).catch(l=>{i.reject(l)}).finally(()=>{s.dispose(),clearTimeout(a)}),i.promise}terminateWorker(e){e.terminate();let r=this.workerPool.indexOf(e);r>=0&&this.workerPool.splice(r,1)}async acquireParserWorker(e){this.initializeWorkers();for(let n of this.workerPool)if(n.ready)return n.lock(),n;let r=new as;return e.onCancellationRequested(()=>{let n=this.queue.indexOf(r);n>=0&&this.queue.splice(n,1),r.reject(Rc)}),this.queue.push(r),r.promise}},eI=class{static{o(this,"ParserWorker")}get ready(){return this._ready}get onReady(){return this.onReadyEmitter.event}constructor(e,r,n,i){this.onReadyEmitter=new ii.Emitter,this.deferred=new as,this._ready=!0,this._parsing=!1,this.sendMessage=e,this._terminate=i,r(a=>{let s=a;this.deferred.resolve(s),this.unlock()}),n(a=>{this.deferred.reject(a),this.unlock()})}terminate(){this.deferred.reject(Rc),this._terminate()}lock(){this._ready=!1}unlock(){this._parsing=!1,this._ready=!0,this.onReadyEmitter.fire()}parse(e){if(this._parsing)throw new Error("Parser worker is busy");return this._parsing=!0,this.deferred=new as,this.sendMessage(e),this.deferred.promise}}});var ix,rI=R(()=>{"use strict";Wo();qo();ix=class{static{o(this,"DefaultWorkspaceLock")}constructor(){this.previousTokenSource=new pr.CancellationTokenSource,this.writeQueue=[],this.readQueue=[],this.done=!0}write(e){this.cancelWrite();let r=new pr.CancellationTokenSource;return this.previousTokenSource=r,this.enqueue(this.writeQueue,e,r.token)}read(e){return this.enqueue(this.readQueue,e)}enqueue(e,r,n){let i=new as,a={action:r,deferred:i,cancellationToken:n??pr.CancellationToken.None};return e.push(a),this.performNextOperation(),i.promise}async performNextOperation(){if(!this.done)return;let e=[];if(this.writeQueue.length>0)e.push(this.writeQueue.shift());else if(this.readQueue.length>0)e.push(...this.readQueue.splice(0,this.readQueue.length));else return;this.done=!1,await Promise.all(e.map(async({action:r,deferred:n,cancellationToken:i})=>{try{let a=await Promise.resolve().then(()=>r(i));n.resolve(a)}catch(a){of(a)?n.resolve(void 0):n.reject(a)}})),this.done=!0,this.performNextOperation()}cancelWrite(){this.previousTokenSource.cancel()}}});var ax,nI=R(()=>{"use strict";Ek();Sc();Vo();es();kg();Rl();ax=class{static{o(this,"DefaultHydrator")}constructor(e){this.grammarElementIdMap=new v0,this.tokenTypeIdMap=new v0,this.grammar=e.Grammar,this.lexer=e.parser.Lexer,this.linker=e.references.Linker}dehydrate(e){return{lexerErrors:e.lexerErrors.map(r=>Object.assign({},r)),parserErrors:e.parserErrors.map(r=>Object.assign({},r)),value:this.dehydrateAstNode(e.value,this.createDehyrationContext(e.value))}}createDehyrationContext(e){let r=new Map,n=new Map;for(let i of Yo(e))r.set(i,{});if(e.$cstNode)for(let i of qd(e.$cstNode))n.set(i,{});return{astNodes:r,cstNodes:n}}dehydrateAstNode(e,r){let n=r.astNodes.get(e);n.$type=e.$type,n.$containerIndex=e.$containerIndex,n.$containerProperty=e.$containerProperty,e.$cstNode!==void 0&&(n.$cstNode=this.dehydrateCstNode(e.$cstNode,r));for(let[i,a]of Object.entries(e))if(!i.startsWith("$"))if(Array.isArray(a)){let s=[];n[i]=s;for(let l of a)Xn(l)?s.push(this.dehydrateAstNode(l,r)):xa(l)?s.push(this.dehydrateReference(l,r)):s.push(l)}else Xn(a)?n[i]=this.dehydrateAstNode(a,r):xa(a)?n[i]=this.dehydrateReference(a,r):a!==void 0&&(n[i]=a);return n}dehydrateReference(e,r){let n={};return n.$refText=e.$refText,e.$refNode&&(n.$refNode=r.cstNodes.get(e.$refNode)),n}dehydrateCstNode(e,r){let n=r.cstNodes.get(e);return zv(e)?n.fullText=e.fullText:n.grammarSource=this.getGrammarElementId(e.grammarSource),n.hidden=e.hidden,n.astNode=r.astNodes.get(e.astNode),co(e)?n.content=e.content.map(i=>this.dehydrateCstNode(i,r)):ef(e)&&(n.tokenType=e.tokenType.name,n.offset=e.offset,n.length=e.length,n.startLine=e.range.start.line,n.startColumn=e.range.start.character,n.endLine=e.range.end.line,n.endColumn=e.range.end.character),n}hydrate(e){let r=e.value,n=this.createHydrationContext(r);return"$cstNode"in r&&this.hydrateCstNode(r.$cstNode,n),{lexerErrors:e.lexerErrors,parserErrors:e.parserErrors,value:this.hydrateAstNode(r,n)}}createHydrationContext(e){let r=new Map,n=new Map;for(let a of Yo(e))r.set(a,{});let i;if(e.$cstNode)for(let a of qd(e.$cstNode)){let s;"fullText"in a?(s=new gg(a.fullText),i=s):"content"in a?s=new p0:"tokenType"in a&&(s=this.hydrateCstLeafNode(a)),s&&(n.set(a,s),s.root=i)}return{astNodes:r,cstNodes:n}}hydrateAstNode(e,r){let n=r.astNodes.get(e);n.$type=e.$type,n.$containerIndex=e.$containerIndex,n.$containerProperty=e.$containerProperty,e.$cstNode&&(n.$cstNode=r.cstNodes.get(e.$cstNode));for(let[i,a]of Object.entries(e))if(!i.startsWith("$"))if(Array.isArray(a)){let s=[];n[i]=s;for(let l of a)Xn(l)?s.push(this.setParent(this.hydrateAstNode(l,r),n)):xa(l)?s.push(this.hydrateReference(l,n,i,r)):s.push(l)}else Xn(a)?n[i]=this.setParent(this.hydrateAstNode(a,r),n):xa(a)?n[i]=this.hydrateReference(a,n,i,r):a!==void 0&&(n[i]=a);return n}setParent(e,r){return e.$container=r,e}hydrateReference(e,r,n,i){return this.linker.buildReference(r,n,i.cstNodes.get(e.$refNode),e.$refText)}hydrateCstNode(e,r,n=0){let i=r.cstNodes.get(e);if(typeof e.grammarSource=="number"&&(i.grammarSource=this.getGrammarElement(e.grammarSource)),i.astNode=r.astNodes.get(e.astNode),co(i))for(let a of e.content){let s=this.hydrateCstNode(a,r,n++);i.content.push(s)}return i}hydrateCstLeafNode(e){let r=this.getTokenType(e.tokenType),n=e.offset,i=e.length,a=e.startLine,s=e.startColumn,l=e.endLine,u=e.endColumn,h=e.hidden;return new d0(n,i,{start:{line:a,character:s},end:{line:l,character:u}},r,h)}getTokenType(e){return this.lexer.definition[e]}getGrammarElementId(e){return this.grammarElementIdMap.size===0&&this.createGrammarElementIdMap(),this.grammarElementIdMap.get(e)}getGrammarElement(e){this.grammarElementIdMap.size===0&&this.createGrammarElementIdMap();let r=this.grammarElementIdMap.getKey(e);if(r)return r;throw new Error("Invalid grammar element id: "+e)}createGrammarElementIdMap(){let e=0;for(let r of Yo(this.grammar))Uv(r)&&this.grammarElementIdMap.set(r,e++)}}});function po(t){return{documentation:{CommentProvider:o(e=>new rx(e),"CommentProvider"),DocumentationProvider:o(e=>new tx(e),"DocumentationProvider")},parser:{AsyncParser:o(e=>new nx(e),"AsyncParser"),GrammarConfig:o(e=>JR(e),"GrammarConfig"),LangiumParser:o(e=>cM(e),"LangiumParser"),CompletionParser:o(e=>oM(e),"CompletionParser"),ValueConverter:o(()=>new y0,"ValueConverter"),TokenBuilder:o(()=>new g0,"TokenBuilder"),Lexer:o(e=>new Z2(e),"Lexer"),ParserErrorMessageProvider:o(()=>new yg,"ParserErrorMessageProvider")},workspace:{AstNodeLocator:o(()=>new q2,"AstNodeLocator"),AstNodeDescriptionProvider:o(e=>new Y2(e),"AstNodeDescriptionProvider"),ReferenceDescriptionProvider:o(e=>new W2(e),"ReferenceDescriptionProvider")},references:{Linker:o(e=>new M2(e),"Linker"),NameProvider:o(()=>new I2,"NameProvider"),ScopeProvider:o(e=>new z2(e),"ScopeProvider"),ScopeComputation:o(e=>new P2(e),"ScopeComputation"),References:o(e=>new O2(e),"References")},serializer:{Hydrator:o(e=>new ax(e),"Hydrator"),JsonSerializer:o(e=>new G2(e),"JsonSerializer")},validation:{DocumentValidator:o(e=>new H2(e),"DocumentValidator"),ValidationRegistry:o(e=>new V2(e),"ValidationRegistry")},shared:o(()=>t.shared,"shared")}}function mo(t){return{ServiceRegistry:o(()=>new $2,"ServiceRegistry"),workspace:{LangiumDocuments:o(e=>new N2(e),"LangiumDocuments"),LangiumDocumentFactory:o(e=>new R2(e),"LangiumDocumentFactory"),DocumentBuilder:o(e=>new j2(e),"DocumentBuilder"),IndexManager:o(e=>new K2(e),"IndexManager"),WorkspaceManager:o(e=>new Q2(e),"WorkspaceManager"),FileSystemProvider:o(e=>t.fileSystemProvider(e),"FileSystemProvider"),WorkspaceLock:o(()=>new ix,"WorkspaceLock"),ConfigurationProvider:o(e=>new X2(e),"ConfigurationProvider")}}}var iI=R(()=>{"use strict";eN();lM();uM();hM();fM();CM();SM();AM();_M();DM();Ok();NM();MM();U2();IM();OM();PM();FM();Tg();zM();GM();UM();KM();QM();D2();tI();rI();nI();o(po,"createDefaultCoreModule");o(mo,"createDefaultSharedCoreModule")});function Fi(t,e,r,n,i,a,s,l,u){let h=[t,e,r,n,i,a,s,l,u].reduce(Gk,{});return Moe(h)}function Noe(t){if(t&&t[sI])for(let e of Object.values(t))Noe(e);return t}function Moe(t,e){let r=new Proxy({},{deleteProperty:o(()=>!1,"deleteProperty"),get:o((n,i)=>Roe(n,i,t,e||r),"get"),getOwnPropertyDescriptor:o((n,i)=>(Roe(n,i,t,e||r),Object.getOwnPropertyDescriptor(n,i)),"getOwnPropertyDescriptor"),has:o((n,i)=>i in t,"has"),ownKeys:o(()=>[...Reflect.ownKeys(t),sI],"ownKeys")});return r[sI]=!0,r}function Roe(t,e,r,n){if(e in t){if(t[e]instanceof Error)throw new Error("Construction failure. Please make sure that your dependencies are constructable.",{cause:t[e]});if(t[e]===Doe)throw new Error('Cycle detected. Please make "'+String(e)+'" lazy. See https://langium.org/docs/configuration-services/#resolving-cyclic-dependencies');return t[e]}else if(e in r){let i=r[e];t[e]=Doe;try{t[e]=typeof i=="function"?i(n):Moe(i,n)}catch(a){throw t[e]=a instanceof Error?a:void 0,a}return t[e]}else return}function Gk(t,e){if(e){for(let[r,n]of Object.entries(e))if(n!==void 0){let i=t[r];i!==null&&n!==null&&typeof i=="object"&&typeof n=="object"?t[r]=Gk(i,n):t[r]=n}}return t}var aI,sI,Doe,oI=R(()=>{"use strict";(function(t){t.merge=(e,r)=>Gk(Gk({},e),r)})(aI||(aI={}));o(Fi,"inject");sI=Symbol("isProxy");o(Noe,"eagerLoad");o(Moe,"_inject");Doe=Symbol();o(Roe,"_resolve");o(Gk,"_merge")});var Ioe=R(()=>{"use strict"});var Ooe=R(()=>{"use strict";QM();KM();jM()});var Poe=R(()=>{"use strict"});var Boe=R(()=>{"use strict";eN();Poe()});var Foe=R(()=>{"use strict"});var zoe=R(()=>{"use strict";tI();lM();Ek();uM();D2();UM();Foe();hM();fM()});var Goe=R(()=>{"use strict";CM();SM();AM();LM();_M();DM()});var $oe=R(()=>{"use strict";nI();Ok()});var $k,go,lI=R(()=>{"use strict";$k=class{static{o(this,"EmptyFileSystemProvider")}readFile(){throw new Error("No file system is available.")}async readDirectory(){return[]}},go={fileSystemProvider:o(()=>new $k,"fileSystemProvider")}});function uPe(){let t=Fi(mo(go),cPe),e=Fi(po({shared:t}),lPe);return t.ServiceRegistry.register(e),e}function lf(t){var e;let r=uPe(),n=r.serializer.JsonSerializer.deserialize(t);return r.shared.workspace.LangiumDocumentFactory.fromModel(n,Ms.parse(`memory://${(e=n.name)!==null&&e!==void 0?e:"grammar"}.langium`)),n}var lPe,cPe,Voe=R(()=>{"use strict";iI();oI();Sc();lI();Nc();lPe={Grammar:o(()=>{},"Grammar"),LanguageMetaData:o(()=>({caseInsensitive:!1,fileExtensions:[".langium"],languageId:"langium"}),"LanguageMetaData")},cPe={AstReflection:o(()=>new Gm,"AstReflection")};o(uPe,"createMinimalGrammarServices");o(lf,"loadGrammarFromJson")});var Rr={};hr(Rr,{AstUtils:()=>CT,BiMap:()=>v0,Cancellation:()=>pr,ContextCache:()=>x0,CstUtils:()=>dT,DONE_RESULT:()=>Ja,Deferred:()=>as,Disposable:()=>b0,DisposableCache:()=>Cg,DocumentCache:()=>Mk,EMPTY_STREAM:()=>Gv,ErrorWithLocation:()=>jd,GrammarUtils:()=>RT,MultiMap:()=>Mc,OperationCancelled:()=>Rc,Reduction:()=>Fm,RegExpUtils:()=>LT,SimpleCache:()=>F2,StreamImpl:()=>uo,TreeStreamImpl:()=>Cc,URI:()=>Ms,UriUtils:()=>ss,WorkspaceCache:()=>Sg,assertUnreachable:()=>tf,delayNextTick:()=>TM,interruptAndCheck:()=>Bi,isOperationCancelled:()=>of,loadGrammarFromJson:()=>lf,setInterruptionPeriod:()=>poe,startCancelableOperation:()=>doe,stream:()=>Kr});var Uoe=R(()=>{"use strict";Ik();ZM();dr(Rr,ii);kg();BM();pT();Voe();qo();Ds();Nc();es();Wo();Rl();Il();Um()});var Hoe=R(()=>{"use strict";MM();U2()});var Yoe=R(()=>{"use strict";IM();OM();PM();FM();Tg();lI();zM();rI();GM()});var ba={};hr(ba,{AbstractAstReflection:()=>Yd,AbstractCstNode:()=>S2,AbstractLangiumParser:()=>A2,AbstractParserErrorMessageProvider:()=>Sk,AbstractThreadedAsyncParser:()=>JM,AstUtils:()=>CT,BiMap:()=>v0,Cancellation:()=>pr,CompositeCstNodeImpl:()=>p0,ContextCache:()=>x0,CstNodeBuilder:()=>C2,CstUtils:()=>dT,DONE_RESULT:()=>Ja,DatatypeSymbol:()=>Ck,DefaultAstNodeDescriptionProvider:()=>Y2,DefaultAstNodeLocator:()=>q2,DefaultAsyncParser:()=>nx,DefaultCommentProvider:()=>rx,DefaultConfigurationProvider:()=>X2,DefaultDocumentBuilder:()=>j2,DefaultDocumentValidator:()=>H2,DefaultHydrator:()=>ax,DefaultIndexManager:()=>K2,DefaultJsonSerializer:()=>G2,DefaultLangiumDocumentFactory:()=>R2,DefaultLangiumDocuments:()=>N2,DefaultLexer:()=>Z2,DefaultLinker:()=>M2,DefaultNameProvider:()=>I2,DefaultReferenceDescriptionProvider:()=>W2,DefaultReferences:()=>O2,DefaultScopeComputation:()=>P2,DefaultScopeProvider:()=>z2,DefaultServiceRegistry:()=>$2,DefaultTokenBuilder:()=>g0,DefaultValueConverter:()=>y0,DefaultWorkspaceLock:()=>ix,DefaultWorkspaceManager:()=>Q2,Deferred:()=>as,Disposable:()=>b0,DisposableCache:()=>Cg,DocumentCache:()=>Mk,DocumentState:()=>yn,DocumentValidator:()=>Uu,EMPTY_SCOPE:()=>jOe,EMPTY_STREAM:()=>Gv,EmptyFileSystem:()=>go,EmptyFileSystemProvider:()=>$k,ErrorWithLocation:()=>jd,GrammarAST:()=>Yv,GrammarUtils:()=>RT,JSDocDocumentationProvider:()=>tx,LangiumCompletionParser:()=>L2,LangiumParser:()=>_2,LangiumParserErrorMessageProvider:()=>yg,LeafCstNodeImpl:()=>d0,MapScope:()=>B2,Module:()=>aI,MultiMap:()=>Mc,OperationCancelled:()=>Rc,ParserWorker:()=>eI,Reduction:()=>Fm,RegExpUtils:()=>LT,RootCstNodeImpl:()=>gg,SimpleCache:()=>F2,StreamImpl:()=>uo,StreamScope:()=>Eg,TextDocument:()=>bg,TreeStreamImpl:()=>Cc,URI:()=>Ms,UriUtils:()=>ss,ValidationCategory:()=>Ag,ValidationRegistry:()=>V2,ValueConverter:()=>Dc,WorkspaceCache:()=>Sg,assertUnreachable:()=>tf,createCompletionParser:()=>oM,createDefaultCoreModule:()=>po,createDefaultSharedCoreModule:()=>mo,createGrammarConfig:()=>JR,createLangiumParser:()=>cM,delayNextTick:()=>TM,diagnosticData:()=>Pk,eagerLoad:()=>Noe,getDiagnosticRange:()=>Toe,inject:()=>Fi,interruptAndCheck:()=>Bi,isAstNode:()=>Xn,isAstNodeDescription:()=>ED,isAstNodeWithComment:()=>RM,isCompositeCstNode:()=>co,isIMultiModeLexerDefinition:()=>VM,isJSDoc:()=>qM,isLeafCstNode:()=>ef,isLinkingError:()=>Wd,isNamed:()=>boe,isOperationCancelled:()=>of,isReference:()=>xa,isRootCstNode:()=>zv,isTokenTypeArray:()=>koe,isTokenTypeDictionary:()=>$M,loadGrammarFromJson:()=>lf,parseJSDoc:()=>WM,prepareLangiumParser:()=>soe,setInterruptionPeriod:()=>poe,startCancelableOperation:()=>doe,stream:()=>Kr,toDiagnosticSeverity:()=>Bk});var Ic=R(()=>{"use strict";iI();oI();NM();Ioe();Vo();Ooe();Boe();zoe();Goe();$oe();Uoe();dr(ba,Rr);Hoe();Yoe();Sc()});function Joe(t){return Pl.isInstance(t,Zoe)}function ele(t){return Pl.isInstance(t,cI)}function tle(t){return Pl.isInstance(t,uI)}function rle(t){return Pl.isInstance(t,pPe)}function nle(t){return Pl.isInstance(t,hI)}function ale(t){return Pl.isInstance(t,ile)}function sle(t){return Pl.isInstance(t,fI)}function lle(t){return Pl.isInstance(t,ole)}function ule(t){return Pl.isInstance(t,cle)}function fle(t){return Pl.isInstance(t,hle)}function ple(t){return Pl.isInstance(t,dle)}var hPe,Tt,Qoe,Zoe,cI,fPe,dPe,uI,pPe,hI,ile,fI,ole,cle,hle,dle,mPe,mle,Pl,Woe,gPe,qoe,yPe,Xoe,vPe,joe,xPe,Koe,bPe,wPe,TPe,kPe,EPe,CPe,Bl,dI,pI,mI,gI,yI,SPe,APe,_Pe,LPe,_g,w0,Xo,DPe,jo=R(()=>{"use strict";Ic();Ic();Ic();Ic();hPe=Object.defineProperty,Tt=o((t,e)=>hPe(t,"name",{value:e,configurable:!0}),"__name"),Qoe="Statement",Zoe="Architecture";o(Joe,"isArchitecture");Tt(Joe,"isArchitecture");cI="Branch";o(ele,"isBranch");Tt(ele,"isBranch");fPe="Checkout",dPe="CherryPicking",uI="Commit";o(tle,"isCommit");Tt(tle,"isCommit");pPe="Common";o(rle,"isCommon");Tt(rle,"isCommon");hI="GitGraph";o(nle,"isGitGraph");Tt(nle,"isGitGraph");ile="Info";o(ale,"isInfo");Tt(ale,"isInfo");fI="Merge";o(sle,"isMerge");Tt(sle,"isMerge");ole="Packet";o(lle,"isPacket");Tt(lle,"isPacket");cle="PacketBlock";o(ule,"isPacketBlock");Tt(ule,"isPacketBlock");hle="Pie";o(fle,"isPie");Tt(fle,"isPie");dle="PieSection";o(ple,"isPieSection");Tt(ple,"isPieSection");mPe="Direction",mle=class extends Yd{static{o(this,"MermaidAstReflection")}static{Tt(this,"MermaidAstReflection")}getAllTypes(){return["Architecture","Branch","Checkout","CherryPicking","Commit","Common","Direction","Edge","GitGraph","Group","Info","Junction","Merge","Packet","PacketBlock","Pie","PieSection","Service","Statement"]}computeIsSubtype(t,e){switch(t){case cI:case fPe:case dPe:case uI:case fI:return this.isSubtype(Qoe,e);case mPe:return this.isSubtype(hI,e);default:return!1}}getReferenceType(t){let e=`${t.container.$type}:${t.property}`;switch(e){default:throw new Error(`${e} is not a valid reference id.`)}}getTypeMetaData(t){switch(t){case"Architecture":return{name:"Architecture",properties:[{name:"accDescr"},{name:"accTitle"},{name:"edges",defaultValue:[]},{name:"groups",defaultValue:[]},{name:"junctions",defaultValue:[]},{name:"services",defaultValue:[]},{name:"title"}]};case"Branch":return{name:"Branch",properties:[{name:"name"},{name:"order"}]};case"Checkout":return{name:"Checkout",properties:[{name:"branch"}]};case"CherryPicking":return{name:"CherryPicking",properties:[{name:"id"},{name:"parent"},{name:"tags",defaultValue:[]}]};case"Commit":return{name:"Commit",properties:[{name:"id"},{name:"message"},{name:"tags",defaultValue:[]},{name:"type"}]};case"Common":return{name:"Common",properties:[{name:"accDescr"},{name:"accTitle"},{name:"title"}]};case"Edge":return{name:"Edge",properties:[{name:"lhsDir"},{name:"lhsGroup",defaultValue:!1},{name:"lhsId"},{name:"lhsInto",defaultValue:!1},{name:"rhsDir"},{name:"rhsGroup",defaultValue:!1},{name:"rhsId"},{name:"rhsInto",defaultValue:!1},{name:"title"}]};case"GitGraph":return{name:"GitGraph",properties:[{name:"accDescr"},{name:"accTitle"},{name:"statements",defaultValue:[]},{name:"title"}]};case"Group":return{name:"Group",properties:[{name:"icon"},{name:"id"},{name:"in"},{name:"title"}]};case"Info":return{name:"Info",properties:[{name:"accDescr"},{name:"accTitle"},{name:"title"}]};case"Junction":return{name:"Junction",properties:[{name:"id"},{name:"in"}]};case"Merge":return{name:"Merge",properties:[{name:"branch"},{name:"id"},{name:"tags",defaultValue:[]},{name:"type"}]};case"Packet":return{name:"Packet",properties:[{name:"accDescr"},{name:"accTitle"},{name:"blocks",defaultValue:[]},{name:"title"}]};case"PacketBlock":return{name:"PacketBlock",properties:[{name:"end"},{name:"label"},{name:"start"}]};case"Pie":return{name:"Pie",properties:[{name:"accDescr"},{name:"accTitle"},{name:"sections",defaultValue:[]},{name:"showData",defaultValue:!1},{name:"title"}]};case"PieSection":return{name:"PieSection",properties:[{name:"label"},{name:"value"}]};case"Service":return{name:"Service",properties:[{name:"icon"},{name:"iconText"},{name:"id"},{name:"in"},{name:"title"}]};case"Direction":return{name:"Direction",properties:[{name:"accDescr"},{name:"accTitle"},{name:"dir"},{name:"statements",defaultValue:[]},{name:"title"}]};default:return{name:t,properties:[]}}}},Pl=new mle,gPe=Tt(()=>Woe??(Woe=lf('{"$type":"Grammar","isDeclared":true,"name":"Info","imports":[],"rules":[{"$type":"ParserRule","name":"Info","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"info"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"showInfo"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"*"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"?"}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}')),"InfoGrammar"),yPe=Tt(()=>qoe??(qoe=lf(`{"$type":"Grammar","isDeclared":true,"name":"Packet","imports":[],"rules":[{"$type":"ParserRule","name":"Packet","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"packet-beta"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"blocks","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"Assignment","feature":"blocks","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"+"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"PacketBlock","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"start","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"end","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"?"},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|'[^']*'/"},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}`)),"PacketGrammar"),vPe=Tt(()=>Xoe??(Xoe=lf('{"$type":"Grammar","isDeclared":true,"name":"Pie","imports":[],"rules":[{"$type":"ParserRule","name":"Pie","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"pie"},{"$type":"Assignment","feature":"showData","operator":"?=","terminal":{"$type":"Keyword","value":"showData"},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"sections","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"Assignment","feature":"sections","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"+"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"PieSection","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"PIE_SECTION_LABEL","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]+\\"/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"PIE_SECTION_VALUE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/(0|[1-9][0-9]*)(\\\\.[0-9]+)?/"},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}')),"PieGrammar"),xPe=Tt(()=>joe??(joe=lf('{"$type":"Grammar","isDeclared":true,"name":"Architecture","imports":[],"rules":[{"$type":"ParserRule","name":"Architecture","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"architecture-beta"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"*"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Statement","fragment":true,"definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"groups","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"services","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"junctions","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"edges","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"LeftPort","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"lhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"RightPort","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"rhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Keyword","value":":"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Arrow","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]},{"$type":"Assignment","feature":"lhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"--"},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Keyword","value":"-"}]}]},{"$type":"Assignment","feature":"rhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Group","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"group"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Service","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"service"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"iconText","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Junction","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"junction"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Edge","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"lhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"lhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"rhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"rhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"ARROW_DIRECTION","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"L"}},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"R"}}]},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"T"}}]},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"B"}}]},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_ID","definition":{"$type":"RegexToken","regex":"/[\\\\w]+/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_TEXT_ICON","definition":{"$type":"RegexToken","regex":"/\\\\(\\"[^\\"]+\\"\\\\)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_ICON","definition":{"$type":"RegexToken","regex":"/\\\\([\\\\w-:]+\\\\)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_TITLE","definition":{"$type":"RegexToken","regex":"/\\\\[[\\\\w ]+\\\\]/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_GROUP","definition":{"$type":"RegexToken","regex":"/\\\\{group\\\\}/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_INTO","definition":{"$type":"RegexToken","regex":"/<|>/"},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}')),"ArchitectureGrammar"),bPe=Tt(()=>Koe??(Koe=lf(`{"$type":"Grammar","isDeclared":true,"name":"GitGraph","interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"rules":[{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false},{"$type":"ParserRule","name":"GitGraph","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Keyword","value":":"}]},{"$type":"Keyword","value":"gitGraph:"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},{"$type":"Keyword","value":":"}]}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]},{"$type":"Assignment","feature":"statements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Direction","definition":{"$type":"Assignment","feature":"dir","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"LR"},{"$type":"Keyword","value":"TB"},{"$type":"Keyword","value":"BT"}]}},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Commit","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"commit"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"msg:","cardinality":"?"},{"$type":"Assignment","feature":"message","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Branch","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"branch"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"order:"},{"$type":"Assignment","feature":"order","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Merge","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"merge"},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]}},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Checkout","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"checkout"},{"$type":"Keyword","value":"switch"}]},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"CherryPicking","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"cherry-pick"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"parent:"},{"$type":"Assignment","feature":"parent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+(?=\\\\s)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\\\w([-\\\\./\\\\w]*[-\\\\w])?/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|'[^']*'/"},"fragment":false,"hidden":false}],"definesHiddenTokens":false,"hiddenTokens":[],"imports":[],"types":[],"usedGrammars":[]}`)),"GitGraphGrammar"),wPe={languageId:"info",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},TPe={languageId:"packet",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},kPe={languageId:"pie",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},EPe={languageId:"architecture",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},CPe={languageId:"gitGraph",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},Bl={AstReflection:Tt(()=>new mle,"AstReflection")},dI={Grammar:Tt(()=>gPe(),"Grammar"),LanguageMetaData:Tt(()=>wPe,"LanguageMetaData"),parser:{}},pI={Grammar:Tt(()=>yPe(),"Grammar"),LanguageMetaData:Tt(()=>TPe,"LanguageMetaData"),parser:{}},mI={Grammar:Tt(()=>vPe(),"Grammar"),LanguageMetaData:Tt(()=>kPe,"LanguageMetaData"),parser:{}},gI={Grammar:Tt(()=>xPe(),"Grammar"),LanguageMetaData:Tt(()=>EPe,"LanguageMetaData"),parser:{}},yI={Grammar:Tt(()=>bPe(),"Grammar"),LanguageMetaData:Tt(()=>CPe,"LanguageMetaData"),parser:{}},SPe=/accDescr(?:[\t ]*:([^\n\r]*)|\s*{([^}]*)})/,APe=/accTitle[\t ]*:([^\n\r]*)/,_Pe=/title([\t ][^\n\r]*|)/,LPe={ACC_DESCR:SPe,ACC_TITLE:APe,TITLE:_Pe},_g=class extends y0{static{o(this,"AbstractMermaidValueConverter")}static{Tt(this,"AbstractMermaidValueConverter")}runConverter(t,e,r){let n=this.runCommonConverter(t,e,r);return n===void 0&&(n=this.runCustomConverter(t,e,r)),n===void 0?super.runConverter(t,e,r):n}runCommonConverter(t,e,r){let n=LPe[t.name];if(n===void 0)return;let i=n.exec(e);if(i!==null){if(i[1]!==void 0)return i[1].trim().replace(/[\t ]{2,}/gm," ");if(i[2]!==void 0)return i[2].replace(/^\s*/gm,"").replace(/\s+$/gm,"").replace(/[\t ]{2,}/gm," ").replace(/[\n\r]{2,}/gm,` +`)}}},w0=class extends _g{static{o(this,"CommonValueConverter")}static{Tt(this,"CommonValueConverter")}runCustomConverter(t,e,r){}},Xo=class extends g0{static{o(this,"AbstractMermaidTokenBuilder")}static{Tt(this,"AbstractMermaidTokenBuilder")}constructor(t){super(),this.keywords=new Set(t)}buildKeywordTokens(t,e,r){let n=super.buildKeywordTokens(t,e,r);return n.forEach(i=>{this.keywords.has(i.name)&&i.PATTERN!==void 0&&(i.PATTERN=new RegExp(i.PATTERN.toString()+"(?:(?=%%)|(?!\\S))"))}),n}},DPe=class extends Xo{static{o(this,"CommonTokenBuilder")}static{Tt(this,"CommonTokenBuilder")}}});function Uk(t=go){let e=Fi(mo(t),Bl),r=Fi(po({shared:e}),yI,Vk);return e.ServiceRegistry.register(r),{shared:e,GitGraph:r}}var RPe,Vk,vI=R(()=>{"use strict";jo();Ic();RPe=class extends Xo{static{o(this,"GitGraphTokenBuilder")}static{Tt(this,"GitGraphTokenBuilder")}constructor(){super(["gitGraph"])}},Vk={parser:{TokenBuilder:Tt(()=>new RPe,"TokenBuilder"),ValueConverter:Tt(()=>new w0,"ValueConverter")}};o(Uk,"createGitGraphServices");Tt(Uk,"createGitGraphServices")});function Yk(t=go){let e=Fi(mo(t),Bl),r=Fi(po({shared:e}),dI,Hk);return e.ServiceRegistry.register(r),{shared:e,Info:r}}var NPe,Hk,xI=R(()=>{"use strict";jo();Ic();NPe=class extends Xo{static{o(this,"InfoTokenBuilder")}static{Tt(this,"InfoTokenBuilder")}constructor(){super(["info","showInfo"])}},Hk={parser:{TokenBuilder:Tt(()=>new NPe,"TokenBuilder"),ValueConverter:Tt(()=>new w0,"ValueConverter")}};o(Yk,"createInfoServices");Tt(Yk,"createInfoServices")});function qk(t=go){let e=Fi(mo(t),Bl),r=Fi(po({shared:e}),pI,Wk);return e.ServiceRegistry.register(r),{shared:e,Packet:r}}var MPe,Wk,bI=R(()=>{"use strict";jo();Ic();MPe=class extends Xo{static{o(this,"PacketTokenBuilder")}static{Tt(this,"PacketTokenBuilder")}constructor(){super(["packet-beta"])}},Wk={parser:{TokenBuilder:Tt(()=>new MPe,"TokenBuilder"),ValueConverter:Tt(()=>new w0,"ValueConverter")}};o(qk,"createPacketServices");Tt(qk,"createPacketServices")});function jk(t=go){let e=Fi(mo(t),Bl),r=Fi(po({shared:e}),mI,Xk);return e.ServiceRegistry.register(r),{shared:e,Pie:r}}var IPe,OPe,Xk,wI=R(()=>{"use strict";jo();Ic();IPe=class extends Xo{static{o(this,"PieTokenBuilder")}static{Tt(this,"PieTokenBuilder")}constructor(){super(["pie","showData"])}},OPe=class extends _g{static{o(this,"PieValueConverter")}static{Tt(this,"PieValueConverter")}runCustomConverter(t,e,r){if(t.name==="PIE_SECTION_LABEL")return e.replace(/"/g,"").trim()}},Xk={parser:{TokenBuilder:Tt(()=>new IPe,"TokenBuilder"),ValueConverter:Tt(()=>new OPe,"ValueConverter")}};o(jk,"createPieServices");Tt(jk,"createPieServices")});function Qk(t=go){let e=Fi(mo(t),Bl),r=Fi(po({shared:e}),gI,Kk);return e.ServiceRegistry.register(r),{shared:e,Architecture:r}}var PPe,BPe,Kk,TI=R(()=>{"use strict";jo();Ic();PPe=class extends Xo{static{o(this,"ArchitectureTokenBuilder")}static{Tt(this,"ArchitectureTokenBuilder")}constructor(){super(["architecture"])}},BPe=class extends _g{static{o(this,"ArchitectureValueConverter")}static{Tt(this,"ArchitectureValueConverter")}runCustomConverter(t,e,r){if(t.name==="ARCH_ICON")return e.replace(/[()]/g,"").trim();if(t.name==="ARCH_TEXT_ICON")return e.replace(/["()]/g,"");if(t.name==="ARCH_TITLE")return e.replace(/[[\]]/g,"").trim()}},Kk={parser:{TokenBuilder:Tt(()=>new PPe,"TokenBuilder"),ValueConverter:Tt(()=>new BPe,"ValueConverter")}};o(Qk,"createArchitectureServices");Tt(Qk,"createArchitectureServices")});var gle={};hr(gle,{InfoModule:()=>Hk,createInfoServices:()=>Yk});var yle=R(()=>{"use strict";xI();jo()});var vle={};hr(vle,{PacketModule:()=>Wk,createPacketServices:()=>qk});var xle=R(()=>{"use strict";bI();jo()});var ble={};hr(ble,{PieModule:()=>Xk,createPieServices:()=>jk});var wle=R(()=>{"use strict";wI();jo()});var Tle={};hr(Tle,{ArchitectureModule:()=>Kk,createArchitectureServices:()=>Qk});var kle=R(()=>{"use strict";TI();jo()});var Ele={};hr(Ele,{GitGraphModule:()=>Vk,createGitGraphServices:()=>Uk});var Cle=R(()=>{"use strict";vI();jo()});async function Fl(t,e){let r=FPe[t];if(!r)throw new Error(`Unknown diagram type: ${t}`);T0[t]||await r();let i=T0[t].parse(e);if(i.lexerErrors.length>0||i.parserErrors.length>0)throw new zPe(i);return i.value}var T0,FPe,zPe,Lg=R(()=>{"use strict";vI();xI();bI();wI();TI();jo();T0={},FPe={info:Tt(async()=>{let{createInfoServices:t}=await Promise.resolve().then(()=>(yle(),gle)),e=t().Info.parser.LangiumParser;T0.info=e},"info"),packet:Tt(async()=>{let{createPacketServices:t}=await Promise.resolve().then(()=>(xle(),vle)),e=t().Packet.parser.LangiumParser;T0.packet=e},"packet"),pie:Tt(async()=>{let{createPieServices:t}=await Promise.resolve().then(()=>(wle(),ble)),e=t().Pie.parser.LangiumParser;T0.pie=e},"pie"),architecture:Tt(async()=>{let{createArchitectureServices:t}=await Promise.resolve().then(()=>(kle(),Tle)),e=t().Architecture.parser.LangiumParser;T0.architecture=e},"architecture"),gitGraph:Tt(async()=>{let{createGitGraphServices:t}=await Promise.resolve().then(()=>(Cle(),Ele)),e=t().GitGraph.parser.LangiumParser;T0.gitGraph=e},"gitGraph")};o(Fl,"parse");Tt(Fl,"parse");zPe=class extends Error{static{o(this,"MermaidParseError")}constructor(t){let e=t.lexerErrors.map(n=>n.message).join(` +`),r=t.parserErrors.map(n=>n.message).join(` +`);super(`Parsing failed: ${e} ${r}`),this.result=t}static{Tt(this,"MermaidParseError")}}});function cf(t,e){t.accDescr&&e.setAccDescription?.(t.accDescr),t.accTitle&&e.setAccTitle?.(t.accTitle),t.title&&e.setDiagramTitle?.(t.title)}var sx=R(()=>{"use strict";o(cf,"populateCommonDb")});var Hr,Zk=R(()=>{"use strict";Hr={NORMAL:0,REVERSE:1,HIGHLIGHT:2,MERGE:3,CHERRY_PICK:4}});var uf,Jk=R(()=>{"use strict";uf=class{constructor(e){this.init=e;this.records=this.init()}static{o(this,"ImperativeState")}reset(){this.records=this.init()}}});function kI(){return J_({length:7})}function $Pe(t,e){let r=Object.create(null);return t.reduce((n,i)=>{let a=e(i);return r[a]||(r[a]=!0,n.push(i)),n},[])}function Sle(t,e,r){let n=t.indexOf(e);n===-1?t.push(r):t.splice(n,1,r)}function _le(t){let e=t.reduce((i,a)=>i.seq>a.seq?i:a,t[0]),r="";t.forEach(function(i){i===e?r+=" *":r+=" |"});let n=[r,e.id,e.seq];for(let i in pt.records.branches)pt.records.branches.get(i)===e.id&&n.push(i);if(V.debug(n.join(" ")),e.parents&&e.parents.length==2&&e.parents[0]&&e.parents[1]){let i=pt.records.commits.get(e.parents[0]);Sle(t,e,i),e.parents[1]&&t.push(pt.records.commits.get(e.parents[1]))}else{if(e.parents.length==0)return;if(e.parents[0]){let i=pt.records.commits.get(e.parents[0]);Sle(t,e,i)}}t=$Pe(t,i=>i.id),_le(t)}var GPe,k0,pt,VPe,UPe,HPe,YPe,WPe,qPe,XPe,Ale,jPe,KPe,QPe,ZPe,JPe,Lle,eBe,tBe,rBe,eE,EI=R(()=>{"use strict";ut();xr();qs();rr();bi();Zk();Jk();sl();GPe=mr.gitGraph,k0=o(()=>Ts({...GPe,...Or().gitGraph}),"getConfig"),pt=new uf(()=>{let t=k0(),e=t.mainBranchName,r=t.mainBranchOrder;return{mainBranchName:e,commits:new Map,head:null,branchConfig:new Map([[e,{name:e,order:r}]]),branches:new Map([[e,null]]),currBranch:e,direction:"LR",seq:0,options:{}}});o(kI,"getID");o($Pe,"uniqBy");VPe=o(function(t){pt.records.direction=t},"setDirection"),UPe=o(function(t){V.debug("options str",t),t=t?.trim(),t=t||"{}";try{pt.records.options=JSON.parse(t)}catch(e){V.error("error while parsing gitGraph options",e.message)}},"setOptions"),HPe=o(function(){return pt.records.options},"getOptions"),YPe=o(function(t){let e=t.msg,r=t.id,n=t.type,i=t.tags;V.info("commit",e,r,n,i),V.debug("Entering commit:",e,r,n,i);let a=k0();r=We.sanitizeText(r,a),e=We.sanitizeText(e,a),i=i?.map(l=>We.sanitizeText(l,a));let s={id:r||pt.records.seq+"-"+kI(),message:e,seq:pt.records.seq++,type:n??Hr.NORMAL,tags:i??[],parents:pt.records.head==null?[]:[pt.records.head.id],branch:pt.records.currBranch};pt.records.head=s,V.info("main branch",a.mainBranchName),pt.records.commits.set(s.id,s),pt.records.branches.set(pt.records.currBranch,s.id),V.debug("in pushCommit "+s.id)},"commit"),WPe=o(function(t){let e=t.name,r=t.order;if(e=We.sanitizeText(e,k0()),pt.records.branches.has(e))throw new Error(`Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ${e}")`);pt.records.branches.set(e,pt.records.head!=null?pt.records.head.id:null),pt.records.branchConfig.set(e,{name:e,order:r}),Ale(e),V.debug("in createBranch")},"branch"),qPe=o(t=>{let e=t.branch,r=t.id,n=t.type,i=t.tags,a=k0();e=We.sanitizeText(e,a),r&&(r=We.sanitizeText(r,a));let s=pt.records.branches.get(pt.records.currBranch),l=pt.records.branches.get(e),u=s?pt.records.commits.get(s):void 0,h=l?pt.records.commits.get(l):void 0;if(u&&h&&u.branch===e)throw new Error(`Cannot merge branch '${e}' into itself.`);if(pt.records.currBranch===e){let p=new Error('Incorrect usage of "merge". Cannot merge a branch to itself');throw p.hash={text:`merge ${e}`,token:`merge ${e}`,expected:["branch abc"]},p}if(u===void 0||!u){let p=new Error(`Incorrect usage of "merge". Current branch (${pt.records.currBranch})has no commits`);throw p.hash={text:`merge ${e}`,token:`merge ${e}`,expected:["commit"]},p}if(!pt.records.branches.has(e)){let p=new Error('Incorrect usage of "merge". Branch to be merged ('+e+") does not exist");throw p.hash={text:`merge ${e}`,token:`merge ${e}`,expected:[`branch ${e}`]},p}if(h===void 0||!h){let p=new Error('Incorrect usage of "merge". Branch to be merged ('+e+") has no commits");throw p.hash={text:`merge ${e}`,token:`merge ${e}`,expected:['"commit"']},p}if(u===h){let p=new Error('Incorrect usage of "merge". Both branches have same head');throw p.hash={text:`merge ${e}`,token:`merge ${e}`,expected:["branch abc"]},p}if(r&&pt.records.commits.has(r)){let p=new Error('Incorrect usage of "merge". Commit with id:'+r+" already exists, use different custom Id");throw p.hash={text:`merge ${e} ${r} ${n} ${i?.join(" ")}`,token:`merge ${e} ${r} ${n} ${i?.join(" ")}`,expected:[`merge ${e} ${r}_UNIQUE ${n} ${i?.join(" ")}`]},p}let f=l||"",d={id:r||`${pt.records.seq}-${kI()}`,message:`merged branch ${e} into ${pt.records.currBranch}`,seq:pt.records.seq++,parents:pt.records.head==null?[]:[pt.records.head.id,f],branch:pt.records.currBranch,type:Hr.MERGE,customType:n,customId:!!r,tags:i??[]};pt.records.head=d,pt.records.commits.set(d.id,d),pt.records.branches.set(pt.records.currBranch,d.id),V.debug(pt.records.branches),V.debug("in mergeBranch")},"merge"),XPe=o(function(t){let e=t.id,r=t.targetId,n=t.tags,i=t.parent;V.debug("Entering cherryPick:",e,r,n);let a=k0();if(e=We.sanitizeText(e,a),r=We.sanitizeText(r,a),n=n?.map(u=>We.sanitizeText(u,a)),i=We.sanitizeText(i,a),!e||!pt.records.commits.has(e)){let u=new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');throw u.hash={text:`cherryPick ${e} ${r}`,token:`cherryPick ${e} ${r}`,expected:["cherry-pick abc"]},u}let s=pt.records.commits.get(e);if(s===void 0||!s)throw new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');if(i&&!(Array.isArray(s.parents)&&s.parents.includes(i)))throw new Error("Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.");let l=s.branch;if(s.type===Hr.MERGE&&!i)throw new Error("Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.");if(!r||!pt.records.commits.has(r)){if(l===pt.records.currBranch){let d=new Error('Incorrect usage of "cherryPick". Source commit is already on current branch');throw d.hash={text:`cherryPick ${e} ${r}`,token:`cherryPick ${e} ${r}`,expected:["cherry-pick abc"]},d}let u=pt.records.branches.get(pt.records.currBranch);if(u===void 0||!u){let d=new Error(`Incorrect usage of "cherry-pick". Current branch (${pt.records.currBranch})has no commits`);throw d.hash={text:`cherryPick ${e} ${r}`,token:`cherryPick ${e} ${r}`,expected:["cherry-pick abc"]},d}let h=pt.records.commits.get(u);if(h===void 0||!h){let d=new Error(`Incorrect usage of "cherry-pick". Current branch (${pt.records.currBranch})has no commits`);throw d.hash={text:`cherryPick ${e} ${r}`,token:`cherryPick ${e} ${r}`,expected:["cherry-pick abc"]},d}let f={id:pt.records.seq+"-"+kI(),message:`cherry-picked ${s?.message} into ${pt.records.currBranch}`,seq:pt.records.seq++,parents:pt.records.head==null?[]:[pt.records.head.id,s.id],branch:pt.records.currBranch,type:Hr.CHERRY_PICK,tags:n?n.filter(Boolean):[`cherry-pick:${s.id}${s.type===Hr.MERGE?`|parent:${i}`:""}`]};pt.records.head=f,pt.records.commits.set(f.id,f),pt.records.branches.set(pt.records.currBranch,f.id),V.debug(pt.records.branches),V.debug("in cherryPick")}},"cherryPick"),Ale=o(function(t){if(t=We.sanitizeText(t,k0()),pt.records.branches.has(t)){pt.records.currBranch=t;let e=pt.records.branches.get(pt.records.currBranch);e===void 0||!e?pt.records.head=null:pt.records.head=pt.records.commits.get(e)??null}else{let e=new Error(`Trying to checkout branch which is not yet created. (Help try using "branch ${t}")`);throw e.hash={text:`checkout ${t}`,token:`checkout ${t}`,expected:[`branch ${t}`]},e}},"checkout");o(Sle,"upsert");o(_le,"prettyPrintCommitHistory");jPe=o(function(){V.debug(pt.records.commits);let t=Lle()[0];_le([t])},"prettyPrint"),KPe=o(function(){pt.reset(),vr()},"clear"),QPe=o(function(){return[...pt.records.branchConfig.values()].map((e,r)=>e.order!==null&&e.order!==void 0?e:{...e,order:parseFloat(`0.${r}`)}).sort((e,r)=>(e.order??0)-(r.order??0)).map(({name:e})=>({name:e}))},"getBranchesAsObjArray"),ZPe=o(function(){return pt.records.branches},"getBranches"),JPe=o(function(){return pt.records.commits},"getCommits"),Lle=o(function(){let t=[...pt.records.commits.values()];return t.forEach(function(e){V.debug(e.id)}),t.sort((e,r)=>e.seq-r.seq),t},"getCommitsArray"),eBe=o(function(){return pt.records.currBranch},"getCurrentBranch"),tBe=o(function(){return pt.records.direction},"getDirection"),rBe=o(function(){return pt.records.head},"getHead"),eE={commitType:Hr,getConfig:k0,setDirection:VPe,setOptions:UPe,getOptions:HPe,commit:YPe,branch:WPe,merge:qPe,cherryPick:XPe,checkout:Ale,prettyPrint:jPe,clear:KPe,getBranchesAsObjArray:QPe,getBranches:ZPe,getCommits:JPe,getCommitsArray:Lle,getCurrentBranch:eBe,getDirection:tBe,getHead:rBe,setAccTitle:kr,getAccTitle:Ar,getAccDescription:Lr,setAccDescription:_r,setDiagramTitle:nn,getDiagramTitle:Xr}});var nBe,iBe,aBe,sBe,oBe,lBe,cBe,Dle,Rle=R(()=>{"use strict";Lg();ut();sx();EI();Zk();nBe=o((t,e)=>{cf(t,e),t.dir&&e.setDirection(t.dir);for(let r of t.statements)iBe(r,e)},"populate"),iBe=o((t,e)=>{let n={Commit:o(i=>e.commit(aBe(i)),"Commit"),Branch:o(i=>e.branch(sBe(i)),"Branch"),Merge:o(i=>e.merge(oBe(i)),"Merge"),Checkout:o(i=>e.checkout(lBe(i)),"Checkout"),CherryPicking:o(i=>e.cherryPick(cBe(i)),"CherryPicking")}[t.$type];n?n(t):V.error(`Unknown statement type: ${t.$type}`)},"parseStatement"),aBe=o(t=>({id:t.id,msg:t.message??"",type:t.type!==void 0?Hr[t.type]:Hr.NORMAL,tags:t.tags??void 0}),"parseCommit"),sBe=o(t=>({name:t.name,order:t.order??0}),"parseBranch"),oBe=o(t=>({branch:t.branch,id:t.id??"",type:t.type!==void 0?Hr[t.type]:void 0,tags:t.tags??void 0}),"parseMerge"),lBe=o(t=>t.branch,"parseCheckout"),cBe=o(t=>({id:t.id,targetId:"",tags:t.tags?.length===0?void 0:t.tags,parent:t.parent}),"parseCherryPicking"),Dle={parse:o(async t=>{let e=await Fl("gitGraph",t);V.debug(e),nBe(e,eE)},"parse")}});var uBe,Ko,ff,df,Oc,Hu,E0,Is,Os,tE,ox,rE,hf,Tr,hBe,Mle,Ile,fBe,dBe,pBe,mBe,gBe,yBe,vBe,xBe,bBe,wBe,TBe,kBe,Nle,EBe,lx,CBe,SBe,ABe,_Be,LBe,Ole,Ple=R(()=>{"use strict";Zt();_t();ut();xr();Zk();uBe=de(),Ko=uBe?.gitGraph,ff=10,df=40,Oc=4,Hu=2,E0=8,Is=new Map,Os=new Map,tE=30,ox=new Map,rE=[],hf=0,Tr="LR",hBe=o(()=>{Is.clear(),Os.clear(),ox.clear(),hf=0,rE=[],Tr="LR"},"clear"),Mle=o(t=>{let e=document.createElementNS("http://www.w3.org/2000/svg","text");return(typeof t=="string"?t.split(/\\n|\n|/gi):t).forEach(n=>{let i=document.createElementNS("http://www.w3.org/2000/svg","tspan");i.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),i.setAttribute("dy","1em"),i.setAttribute("x","0"),i.setAttribute("class","row"),i.textContent=n.trim(),e.appendChild(i)}),e},"drawText"),Ile=o(t=>{let e,r,n;return Tr==="BT"?(r=o((i,a)=>i<=a,"comparisonFunc"),n=1/0):(r=o((i,a)=>i>=a,"comparisonFunc"),n=0),t.forEach(i=>{let a=Tr==="TB"||Tr=="BT"?Os.get(i)?.y:Os.get(i)?.x;a!==void 0&&r(a,n)&&(e=i,n=a)}),e},"findClosestParent"),fBe=o(t=>{let e="",r=1/0;return t.forEach(n=>{let i=Os.get(n).y;i<=r&&(e=n,r=i)}),e||void 0},"findClosestParentBT"),dBe=o((t,e,r)=>{let n=r,i=r,a=[];t.forEach(s=>{let l=e.get(s);if(!l)throw new Error(`Commit not found for key ${s}`);l.parents.length?(n=mBe(l),i=Math.max(n,i)):a.push(l),gBe(l,n)}),n=i,a.forEach(s=>{yBe(s,n,r)}),t.forEach(s=>{let l=e.get(s);if(l?.parents.length){let u=fBe(l.parents);n=Os.get(u).y-df,n<=i&&(i=n);let h=Is.get(l.branch).pos,f=n-ff;Os.set(l.id,{x:h,y:f})}})},"setParallelBTPos"),pBe=o(t=>{let e=Ile(t.parents.filter(n=>n!==null));if(!e)throw new Error(`Closest parent not found for commit ${t.id}`);let r=Os.get(e)?.y;if(r===void 0)throw new Error(`Closest parent position not found for commit ${t.id}`);return r},"findClosestParentPos"),mBe=o(t=>pBe(t)+df,"calculateCommitPosition"),gBe=o((t,e)=>{let r=Is.get(t.branch);if(!r)throw new Error(`Branch not found for commit ${t.id}`);let n=r.pos,i=e+ff;return Os.set(t.id,{x:n,y:i}),{x:n,y:i}},"setCommitPosition"),yBe=o((t,e,r)=>{let n=Is.get(t.branch);if(!n)throw new Error(`Branch not found for commit ${t.id}`);let i=e+r,a=n.pos;Os.set(t.id,{x:a,y:i})},"setRootPosition"),vBe=o((t,e,r,n,i,a)=>{if(a===Hr.HIGHLIGHT)t.append("rect").attr("x",r.x-10).attr("y",r.y-10).attr("width",20).attr("height",20).attr("class",`commit ${e.id} commit-highlight${i%E0} ${n}-outer`),t.append("rect").attr("x",r.x-6).attr("y",r.y-6).attr("width",12).attr("height",12).attr("class",`commit ${e.id} commit${i%E0} ${n}-inner`);else if(a===Hr.CHERRY_PICK)t.append("circle").attr("cx",r.x).attr("cy",r.y).attr("r",10).attr("class",`commit ${e.id} ${n}`),t.append("circle").attr("cx",r.x-3).attr("cy",r.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${e.id} ${n}`),t.append("circle").attr("cx",r.x+3).attr("cy",r.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${e.id} ${n}`),t.append("line").attr("x1",r.x+3).attr("y1",r.y+1).attr("x2",r.x).attr("y2",r.y-5).attr("stroke","#fff").attr("class",`commit ${e.id} ${n}`),t.append("line").attr("x1",r.x-3).attr("y1",r.y+1).attr("x2",r.x).attr("y2",r.y-5).attr("stroke","#fff").attr("class",`commit ${e.id} ${n}`);else{let s=t.append("circle");if(s.attr("cx",r.x),s.attr("cy",r.y),s.attr("r",e.type===Hr.MERGE?9:10),s.attr("class",`commit ${e.id} commit${i%E0}`),a===Hr.MERGE){let l=t.append("circle");l.attr("cx",r.x),l.attr("cy",r.y),l.attr("r",6),l.attr("class",`commit ${n} ${e.id} commit${i%E0}`)}a===Hr.REVERSE&&t.append("path").attr("d",`M ${r.x-5},${r.y-5}L${r.x+5},${r.y+5}M${r.x-5},${r.y+5}L${r.x+5},${r.y-5}`).attr("class",`commit ${n} ${e.id} commit${i%E0}`)}},"drawCommitBullet"),xBe=o((t,e,r,n)=>{if(e.type!==Hr.CHERRY_PICK&&(e.customId&&e.type===Hr.MERGE||e.type!==Hr.MERGE)&&Ko?.showCommitLabel){let i=t.append("g"),a=i.insert("rect").attr("class","commit-label-bkg"),s=i.append("text").attr("x",n).attr("y",r.y+25).attr("class","commit-label").text(e.id),l=s.node()?.getBBox();if(l&&(a.attr("x",r.posWithOffset-l.width/2-Hu).attr("y",r.y+13.5).attr("width",l.width+2*Hu).attr("height",l.height+2*Hu),Tr==="TB"||Tr==="BT"?(a.attr("x",r.x-(l.width+4*Oc+5)).attr("y",r.y-12),s.attr("x",r.x-(l.width+4*Oc)).attr("y",r.y+l.height-12)):s.attr("x",r.posWithOffset-l.width/2),Ko.rotateCommitLabel))if(Tr==="TB"||Tr==="BT")s.attr("transform","rotate(-45, "+r.x+", "+r.y+")"),a.attr("transform","rotate(-45, "+r.x+", "+r.y+")");else{let u=-7.5-(l.width+10)/25*9.5,h=10+l.width/25*8.5;i.attr("transform","translate("+u+", "+h+") rotate(-45, "+n+", "+r.y+")")}}},"drawCommitLabel"),bBe=o((t,e,r,n)=>{if(e.tags.length>0){let i=0,a=0,s=0,l=[];for(let u of e.tags.reverse()){let h=t.insert("polygon"),f=t.append("circle"),d=t.append("text").attr("y",r.y-16-i).attr("class","tag-label").text(u),p=d.node()?.getBBox();if(!p)throw new Error("Tag bbox not found");a=Math.max(a,p.width),s=Math.max(s,p.height),d.attr("x",r.posWithOffset-p.width/2),l.push({tag:d,hole:f,rect:h,yOffset:i}),i+=20}for(let{tag:u,hole:h,rect:f,yOffset:d}of l){let p=s/2,m=r.y-19.2-d;if(f.attr("class","tag-label-bkg").attr("points",` + ${n-a/2-Oc/2},${m+Hu} + ${n-a/2-Oc/2},${m-Hu} + ${r.posWithOffset-a/2-Oc},${m-p-Hu} + ${r.posWithOffset+a/2+Oc},${m-p-Hu} + ${r.posWithOffset+a/2+Oc},${m+p+Hu} + ${r.posWithOffset-a/2-Oc},${m+p+Hu}`),h.attr("cy",m).attr("cx",n-a/2+Oc/2).attr("r",1.5).attr("class","tag-hole"),Tr==="TB"||Tr==="BT"){let g=n+d;f.attr("class","tag-label-bkg").attr("points",` + ${r.x},${g+2} + ${r.x},${g-2} + ${r.x+ff},${g-p-2} + ${r.x+ff+a+4},${g-p-2} + ${r.x+ff+a+4},${g+p+2} + ${r.x+ff},${g+p+2}`).attr("transform","translate(12,12) rotate(45, "+r.x+","+n+")"),h.attr("cx",r.x+Oc/2).attr("cy",g).attr("transform","translate(12,12) rotate(45, "+r.x+","+n+")"),u.attr("x",r.x+5).attr("y",g+3).attr("transform","translate(14,14) rotate(45, "+r.x+","+n+")")}}}},"drawCommitTags"),wBe=o(t=>{switch(t.customType??t.type){case Hr.NORMAL:return"commit-normal";case Hr.REVERSE:return"commit-reverse";case Hr.HIGHLIGHT:return"commit-highlight";case Hr.MERGE:return"commit-merge";case Hr.CHERRY_PICK:return"commit-cherry-pick";default:return"commit-normal"}},"getCommitClassType"),TBe=o((t,e,r,n)=>{let i={x:0,y:0};if(t.parents.length>0){let a=Ile(t.parents);if(a){let s=n.get(a)??i;return e==="TB"?s.y+df:e==="BT"?(n.get(t.id)??i).y-df:s.x+df}}else return e==="TB"?tE:e==="BT"?(n.get(t.id)??i).y-df:0;return 0},"calculatePosition"),kBe=o((t,e,r)=>{let n=Tr==="BT"&&r?e:e+ff,i=Tr==="TB"||Tr==="BT"?n:Is.get(t.branch)?.pos,a=Tr==="TB"||Tr==="BT"?Is.get(t.branch)?.pos:n;if(a===void 0||i===void 0)throw new Error(`Position were undefined for commit ${t.id}`);return{x:a,y:i,posWithOffset:n}},"getCommitPosition"),Nle=o((t,e,r)=>{if(!Ko)throw new Error("GitGraph config not found");let n=t.append("g").attr("class","commit-bullets"),i=t.append("g").attr("class","commit-labels"),a=Tr==="TB"||Tr==="BT"?tE:0,s=[...e.keys()],l=Ko?.parallelCommits??!1,u=o((f,d)=>{let p=e.get(f)?.seq,m=e.get(d)?.seq;return p!==void 0&&m!==void 0?p-m:0},"sortKeys"),h=s.sort(u);Tr==="BT"&&(l&&dBe(h,e,a),h=h.reverse()),h.forEach(f=>{let d=e.get(f);if(!d)throw new Error(`Commit not found for key ${f}`);l&&(a=TBe(d,Tr,a,Os));let p=kBe(d,a,l);if(r){let m=wBe(d),g=d.customType??d.type,y=Is.get(d.branch)?.index??0;vBe(n,d,p,m,y,g),xBe(i,d,p,a),bBe(i,d,p,a)}Tr==="TB"||Tr==="BT"?Os.set(d.id,{x:p.x,y:p.posWithOffset}):Os.set(d.id,{x:p.posWithOffset,y:p.y}),a=Tr==="BT"&&l?a+df:a+df+ff,a>hf&&(hf=a)})},"drawCommits"),EBe=o((t,e,r,n,i)=>{let s=(Tr==="TB"||Tr==="BT"?r.xh.branch===s,"isOnBranchToGetCurve"),u=o(h=>h.seq>t.seq&&h.sequ(h)&&l(h))},"shouldRerouteArrow"),lx=o((t,e,r=0)=>{let n=t+Math.abs(t-e)/2;if(r>5)return n;if(rE.every(s=>Math.abs(s-n)>=10))return rE.push(n),n;let a=Math.abs(t-e);return lx(t,e-a/5,r+1)},"findLane"),CBe=o((t,e,r,n)=>{let i=Os.get(e.id),a=Os.get(r.id);if(i===void 0||a===void 0)throw new Error(`Commit positions not found for commits ${e.id} and ${r.id}`);let s=EBe(e,r,i,a,n),l="",u="",h=0,f=0,d=Is.get(r.branch)?.index;r.type===Hr.MERGE&&e.id!==r.parents[0]&&(d=Is.get(e.branch)?.index);let p;if(s){l="A 10 10, 0, 0, 0,",u="A 10 10, 0, 0, 1,",h=10,f=10;let m=i.ya.x&&(l="A 20 20, 0, 0, 0,",u="A 20 20, 0, 0, 1,",h=20,f=20,r.type===Hr.MERGE&&e.id!==r.parents[0]?p=`M ${i.x} ${i.y} L ${i.x} ${a.y-h} ${u} ${i.x-f} ${a.y} L ${a.x} ${a.y}`:p=`M ${i.x} ${i.y} L ${a.x+h} ${i.y} ${l} ${a.x} ${i.y+f} L ${a.x} ${a.y}`),i.x===a.x&&(p=`M ${i.x} ${i.y} L ${a.x} ${a.y}`)):Tr==="BT"?(i.xa.x&&(l="A 20 20, 0, 0, 0,",u="A 20 20, 0, 0, 1,",h=20,f=20,r.type===Hr.MERGE&&e.id!==r.parents[0]?p=`M ${i.x} ${i.y} L ${i.x} ${a.y+h} ${l} ${i.x-f} ${a.y} L ${a.x} ${a.y}`:p=`M ${i.x} ${i.y} L ${a.x-h} ${i.y} ${l} ${a.x} ${i.y-f} L ${a.x} ${a.y}`),i.x===a.x&&(p=`M ${i.x} ${i.y} L ${a.x} ${a.y}`)):(i.ya.y&&(r.type===Hr.MERGE&&e.id!==r.parents[0]?p=`M ${i.x} ${i.y} L ${a.x-h} ${i.y} ${l} ${a.x} ${i.y-f} L ${a.x} ${a.y}`:p=`M ${i.x} ${i.y} L ${i.x} ${a.y+h} ${u} ${i.x+f} ${a.y} L ${a.x} ${a.y}`),i.y===a.y&&(p=`M ${i.x} ${i.y} L ${a.x} ${a.y}`));if(p===void 0)throw new Error("Line definition not found");t.append("path").attr("d",p).attr("class","arrow arrow"+d%E0)},"drawArrow"),SBe=o((t,e)=>{let r=t.append("g").attr("class","commit-arrows");[...e.keys()].forEach(n=>{let i=e.get(n);i.parents&&i.parents.length>0&&i.parents.forEach(a=>{CBe(r,e.get(a),i,e)})})},"drawArrows"),ABe=o((t,e)=>{let r=t.append("g");e.forEach((n,i)=>{let a=i%E0,s=Is.get(n.name)?.pos;if(s===void 0)throw new Error(`Position not found for branch ${n.name}`);let l=r.append("line");l.attr("x1",0),l.attr("y1",s),l.attr("x2",hf),l.attr("y2",s),l.attr("class","branch branch"+a),Tr==="TB"?(l.attr("y1",tE),l.attr("x1",s),l.attr("y2",hf),l.attr("x2",s)):Tr==="BT"&&(l.attr("y1",hf),l.attr("x1",s),l.attr("y2",tE),l.attr("x2",s)),rE.push(s);let u=n.name,h=Mle(u),f=r.insert("rect"),p=r.insert("g").attr("class","branchLabel").insert("g").attr("class","label branch-label"+a);p.node().appendChild(h);let m=h.getBBox();f.attr("class","branchLabelBkg label"+a).attr("rx",4).attr("ry",4).attr("x",-m.width-4-(Ko?.rotateCommitLabel===!0?30:0)).attr("y",-m.height/2+8).attr("width",m.width+18).attr("height",m.height+4),p.attr("transform","translate("+(-m.width-14-(Ko?.rotateCommitLabel===!0?30:0))+", "+(s-m.height/2-1)+")"),Tr==="TB"?(f.attr("x",s-m.width/2-10).attr("y",0),p.attr("transform","translate("+(s-m.width/2-5)+", 0)")):Tr==="BT"?(f.attr("x",s-m.width/2-10).attr("y",hf),p.attr("transform","translate("+(s-m.width/2-5)+", "+hf+")")):f.attr("transform","translate(-19, "+(s-m.height/2)+")")})},"drawBranches"),_Be=o(function(t,e,r,n,i){return Is.set(t,{pos:e,index:r}),e+=50+(i?40:0)+(Tr==="TB"||Tr==="BT"?n.width/2:0),e},"setBranchPosition"),LBe=o(function(t,e,r,n){if(hBe(),V.debug("in gitgraph renderer",t+` +`,"id:",e,r),!Ko)throw new Error("GitGraph config not found");let i=Ko.rotateCommitLabel??!1,a=n.db;ox=a.getCommits();let s=a.getBranchesAsObjArray();Tr=a.getDirection();let l=$e(`[id="${e}"]`),u=0;s.forEach((h,f)=>{let d=Mle(h.name),p=l.append("g"),m=p.insert("g").attr("class","branchLabel"),g=m.insert("g").attr("class","label branch-label");g.node()?.appendChild(d);let y=d.getBBox();u=_Be(h.name,u,f,y,i),g.remove(),m.remove(),p.remove()}),Nle(l,ox,!1),Ko.showBranches&&ABe(l,s),SBe(l,ox),Nle(l,ox,!0),Lt.insertTitle(l,"gitTitleText",Ko.titleTopMargin??0,a.getDiagramTitle()),aS(void 0,l,Ko.diagramPadding,Ko.useMaxWidth)},"draw"),Ole={draw:LBe}});var DBe,Ble,Fle=R(()=>{"use strict";DBe=o(t=>` + .commit-id, + .commit-msg, + .branch-label { + fill: lightgrey; + color: lightgrey; + font-family: 'trebuchet ms', verdana, arial, sans-serif; + font-family: var(--mermaid-font-family); + } + ${[0,1,2,3,4,5,6,7].map(e=>` + .branch-label${e} { fill: ${t["gitBranchLabel"+e]}; } + .commit${e} { stroke: ${t["git"+e]}; fill: ${t["git"+e]}; } + .commit-highlight${e} { stroke: ${t["gitInv"+e]}; fill: ${t["gitInv"+e]}; } + .label${e} { fill: ${t["git"+e]}; } + .arrow${e} { stroke: ${t["git"+e]}; } + `).join(` +`)} + + .branch { + stroke-width: 1; + stroke: ${t.lineColor}; + stroke-dasharray: 2; + } + .commit-label { font-size: ${t.commitLabelFontSize}; fill: ${t.commitLabelColor};} + .commit-label-bkg { font-size: ${t.commitLabelFontSize}; fill: ${t.commitLabelBackground}; opacity: 0.5; } + .tag-label { font-size: ${t.tagLabelFontSize}; fill: ${t.tagLabelColor};} + .tag-label-bkg { fill: ${t.tagLabelBackground}; stroke: ${t.tagLabelBorder}; } + .tag-hole { fill: ${t.textColor}; } + + .commit-merge { + stroke: ${t.primaryColor}; + fill: ${t.primaryColor}; + } + .commit-reverse { + stroke: ${t.primaryColor}; + fill: ${t.primaryColor}; + stroke-width: 3; + } + .commit-highlight-outer { + } + .commit-highlight-inner { + stroke: ${t.primaryColor}; + fill: ${t.primaryColor}; + } + + .arrow { stroke-width: 8; stroke-linecap: round; fill: none} + .gitTitleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.textColor}; + } +`,"getStyles"),Ble=DBe});var zle={};hr(zle,{diagram:()=>RBe});var RBe,Gle=R(()=>{"use strict";Rle();EI();Ple();Fle();RBe={parser:Dle,db:eE,renderer:Ole,styles:Ble}});var CI,Ule,Hle=R(()=>{"use strict";CI=function(){var t=o(function(I,C,O,D){for(O=O||{},D=I.length;D--;O[I[D]]=C);return O},"o"),e=[6,8,10,12,13,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,31,33,35,36,38,40],r=[1,26],n=[1,27],i=[1,28],a=[1,29],s=[1,30],l=[1,31],u=[1,32],h=[1,33],f=[1,34],d=[1,9],p=[1,10],m=[1,11],g=[1,12],y=[1,13],v=[1,14],x=[1,15],b=[1,16],w=[1,19],S=[1,20],T=[1,21],E=[1,22],_=[1,23],A=[1,25],L=[1,35],M={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,gantt:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NL:10,weekday:11,weekday_monday:12,weekday_tuesday:13,weekday_wednesday:14,weekday_thursday:15,weekday_friday:16,weekday_saturday:17,weekday_sunday:18,weekend:19,weekend_friday:20,weekend_saturday:21,dateFormat:22,inclusiveEndDates:23,topAxis:24,axisFormat:25,tickInterval:26,excludes:27,includes:28,todayMarker:29,title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,section:36,clickStatement:37,taskTxt:38,taskData:39,click:40,callbackname:41,callbackargs:42,href:43,clickStatementDebug:44,$accept:0,$end:1},terminals_:{2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",12:"weekday_monday",13:"weekday_tuesday",14:"weekday_wednesday",15:"weekday_thursday",16:"weekday_friday",17:"weekday_saturday",18:"weekday_sunday",20:"weekend_friday",21:"weekend_saturday",22:"dateFormat",23:"inclusiveEndDates",24:"topAxis",25:"axisFormat",26:"tickInterval",27:"excludes",28:"includes",29:"todayMarker",30:"title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"section",38:"taskTxt",39:"taskData",40:"click",41:"callbackname",42:"callbackargs",43:"href"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[19,1],[19,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,2],[37,2],[37,3],[37,3],[37,4],[37,3],[37,4],[37,2],[44,2],[44,3],[44,3],[44,4],[44,3],[44,4],[44,2]],performAction:o(function(C,O,D,P,F,B,$){var z=B.length-1;switch(F){case 1:return B[z-1];case 2:this.$=[];break;case 3:B[z-1].push(B[z]),this.$=B[z-1];break;case 4:case 5:this.$=B[z];break;case 6:case 7:this.$=[];break;case 8:P.setWeekday("monday");break;case 9:P.setWeekday("tuesday");break;case 10:P.setWeekday("wednesday");break;case 11:P.setWeekday("thursday");break;case 12:P.setWeekday("friday");break;case 13:P.setWeekday("saturday");break;case 14:P.setWeekday("sunday");break;case 15:P.setWeekend("friday");break;case 16:P.setWeekend("saturday");break;case 17:P.setDateFormat(B[z].substr(11)),this.$=B[z].substr(11);break;case 18:P.enableInclusiveEndDates(),this.$=B[z].substr(18);break;case 19:P.TopAxis(),this.$=B[z].substr(8);break;case 20:P.setAxisFormat(B[z].substr(11)),this.$=B[z].substr(11);break;case 21:P.setTickInterval(B[z].substr(13)),this.$=B[z].substr(13);break;case 22:P.setExcludes(B[z].substr(9)),this.$=B[z].substr(9);break;case 23:P.setIncludes(B[z].substr(9)),this.$=B[z].substr(9);break;case 24:P.setTodayMarker(B[z].substr(12)),this.$=B[z].substr(12);break;case 27:P.setDiagramTitle(B[z].substr(6)),this.$=B[z].substr(6);break;case 28:this.$=B[z].trim(),P.setAccTitle(this.$);break;case 29:case 30:this.$=B[z].trim(),P.setAccDescription(this.$);break;case 31:P.addSection(B[z].substr(8)),this.$=B[z].substr(8);break;case 33:P.addTask(B[z-1],B[z]),this.$="task";break;case 34:this.$=B[z-1],P.setClickEvent(B[z-1],B[z],null);break;case 35:this.$=B[z-2],P.setClickEvent(B[z-2],B[z-1],B[z]);break;case 36:this.$=B[z-2],P.setClickEvent(B[z-2],B[z-1],null),P.setLink(B[z-2],B[z]);break;case 37:this.$=B[z-3],P.setClickEvent(B[z-3],B[z-2],B[z-1]),P.setLink(B[z-3],B[z]);break;case 38:this.$=B[z-2],P.setClickEvent(B[z-2],B[z],null),P.setLink(B[z-2],B[z-1]);break;case 39:this.$=B[z-3],P.setClickEvent(B[z-3],B[z-1],B[z]),P.setLink(B[z-3],B[z-2]);break;case 40:this.$=B[z-1],P.setLink(B[z-1],B[z]);break;case 41:case 47:this.$=B[z-1]+" "+B[z];break;case 42:case 43:case 45:this.$=B[z-2]+" "+B[z-1]+" "+B[z];break;case 44:case 46:this.$=B[z-3]+" "+B[z-2]+" "+B[z-1]+" "+B[z];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:17,12:r,13:n,14:i,15:a,16:s,17:l,18:u,19:18,20:h,21:f,22:d,23:p,24:m,25:g,26:y,27:v,28:x,29:b,30:w,31:S,33:T,35:E,36:_,37:24,38:A,40:L},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:36,11:17,12:r,13:n,14:i,15:a,16:s,17:l,18:u,19:18,20:h,21:f,22:d,23:p,24:m,25:g,26:y,27:v,28:x,29:b,30:w,31:S,33:T,35:E,36:_,37:24,38:A,40:L},t(e,[2,5]),t(e,[2,6]),t(e,[2,17]),t(e,[2,18]),t(e,[2,19]),t(e,[2,20]),t(e,[2,21]),t(e,[2,22]),t(e,[2,23]),t(e,[2,24]),t(e,[2,25]),t(e,[2,26]),t(e,[2,27]),{32:[1,37]},{34:[1,38]},t(e,[2,30]),t(e,[2,31]),t(e,[2,32]),{39:[1,39]},t(e,[2,8]),t(e,[2,9]),t(e,[2,10]),t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),{41:[1,40],43:[1,41]},t(e,[2,4]),t(e,[2,28]),t(e,[2,29]),t(e,[2,33]),t(e,[2,34],{42:[1,42],43:[1,43]}),t(e,[2,40],{41:[1,44]}),t(e,[2,35],{43:[1,45]}),t(e,[2,36]),t(e,[2,38],{42:[1,46]}),t(e,[2,37]),t(e,[2,39])],defaultActions:{},parseError:o(function(C,O){if(O.recoverable)this.trace(C);else{var D=new Error(C);throw D.hash=O,D}},"parseError"),parse:o(function(C){var O=this,D=[0],P=[],F=[null],B=[],$=this.table,z="",Y=0,Q=0,X=0,ie=2,j=1,J=B.slice.call(arguments,1),Z=Object.create(this.lexer),H={yy:{}};for(var q in this.yy)Object.prototype.hasOwnProperty.call(this.yy,q)&&(H.yy[q]=this.yy[q]);Z.setInput(C,H.yy),H.yy.lexer=Z,H.yy.parser=this,typeof Z.yylloc>"u"&&(Z.yylloc={});var K=Z.yylloc;B.push(K);var se=Z.options&&Z.options.ranges;typeof H.yy.parseError=="function"?this.parseError=H.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ce(ge){D.length=D.length-2*ge,F.length=F.length-ge,B.length=B.length-ge}o(ce,"popStack");function ue(){var ge;return ge=P.pop()||Z.lex()||j,typeof ge!="number"&&(ge instanceof Array&&(P=ge,ge=P.pop()),ge=O.symbols_[ge]||ge),ge}o(ue,"lex");for(var te,De,oe,ke,Ie,Se,Ue={},Pe,_e,me,W;;){if(oe=D[D.length-1],this.defaultActions[oe]?ke=this.defaultActions[oe]:((te===null||typeof te>"u")&&(te=ue()),ke=$[oe]&&$[oe][te]),typeof ke>"u"||!ke.length||!ke[0]){var fe="";W=[];for(Pe in $[oe])this.terminals_[Pe]&&Pe>ie&&W.push("'"+this.terminals_[Pe]+"'");Z.showPosition?fe="Parse error on line "+(Y+1)+`: +`+Z.showPosition()+` +Expecting `+W.join(", ")+", got '"+(this.terminals_[te]||te)+"'":fe="Parse error on line "+(Y+1)+": Unexpected "+(te==j?"end of input":"'"+(this.terminals_[te]||te)+"'"),this.parseError(fe,{text:Z.match,token:this.terminals_[te]||te,line:Z.yylineno,loc:K,expected:W})}if(ke[0]instanceof Array&&ke.length>1)throw new Error("Parse Error: multiple actions possible at state: "+oe+", token: "+te);switch(ke[0]){case 1:D.push(te),F.push(Z.yytext),B.push(Z.yylloc),D.push(ke[1]),te=null,De?(te=De,De=null):(Q=Z.yyleng,z=Z.yytext,Y=Z.yylineno,K=Z.yylloc,X>0&&X--);break;case 2:if(_e=this.productions_[ke[1]][1],Ue.$=F[F.length-_e],Ue._$={first_line:B[B.length-(_e||1)].first_line,last_line:B[B.length-1].last_line,first_column:B[B.length-(_e||1)].first_column,last_column:B[B.length-1].last_column},se&&(Ue._$.range=[B[B.length-(_e||1)].range[0],B[B.length-1].range[1]]),Se=this.performAction.apply(Ue,[z,Q,Y,H.yy,ke[1],F,B].concat(J)),typeof Se<"u")return Se;_e&&(D=D.slice(0,-1*_e*2),F=F.slice(0,-1*_e),B=B.slice(0,-1*_e)),D.push(this.productions_[ke[1]][0]),F.push(Ue.$),B.push(Ue._$),me=$[D[D.length-2]][D[D.length-1]],D.push(me);break;case 3:return!0}}return!0},"parse")},N=function(){var I={EOF:1,parseError:o(function(O,D){if(this.yy.parser)this.yy.parser.parseError(O,D);else throw new Error(O)},"parseError"),setInput:o(function(C,O){return this.yy=O||this.yy||{},this._input=C,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var C=this._input[0];this.yytext+=C,this.yyleng++,this.offset++,this.match+=C,this.matched+=C;var O=C.match(/(?:\r\n?|\n).*/g);return O?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),C},"input"),unput:o(function(C){var O=C.length,D=C.split(/(?:\r\n?|\n)/g);this._input=C+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-O),this.offset-=O;var P=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),D.length-1&&(this.yylineno-=D.length-1);var F=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:D?(D.length===P.length?this.yylloc.first_column:0)+P[P.length-D.length].length-D[0].length:this.yylloc.first_column-O},this.options.ranges&&(this.yylloc.range=[F[0],F[0]+this.yyleng-O]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(C){this.unput(this.match.slice(C))},"less"),pastInput:o(function(){var C=this.matched.substr(0,this.matched.length-this.match.length);return(C.length>20?"...":"")+C.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var C=this.match;return C.length<20&&(C+=this._input.substr(0,20-C.length)),(C.substr(0,20)+(C.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var C=this.pastInput(),O=new Array(C.length+1).join("-");return C+this.upcomingInput()+` +`+O+"^"},"showPosition"),test_match:o(function(C,O){var D,P,F;if(this.options.backtrack_lexer&&(F={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(F.yylloc.range=this.yylloc.range.slice(0))),P=C[0].match(/(?:\r\n?|\n).*/g),P&&(this.yylineno+=P.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:P?P[P.length-1].length-P[P.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+C[0].length},this.yytext+=C[0],this.match+=C[0],this.matches=C,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(C[0].length),this.matched+=C[0],D=this.performAction.call(this,this.yy,this,O,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),D)return D;if(this._backtrack){for(var B in F)this[B]=F[B];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var C,O,D,P;this._more||(this.yytext="",this.match="");for(var F=this._currentRules(),B=0;BO[0].length)){if(O=D,P=B,this.options.backtrack_lexer){if(C=this.test_match(D,F[B]),C!==!1)return C;if(this._backtrack){O=!1;continue}else return!1}else if(!this.options.flex)break}return O?(C=this.test_match(O,F[P]),C!==!1?C:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var O=this.next();return O||this.lex()},"lex"),begin:o(function(O){this.conditionStack.push(O)},"begin"),popState:o(function(){var O=this.conditionStack.length-1;return O>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(O){return O=this.conditionStack.length-1-Math.abs(O||0),O>=0?this.conditionStack[O]:"INITIAL"},"topState"),pushState:o(function(O){this.begin(O)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(O,D,P,F){var B=F;switch(P){case 0:return this.begin("open_directive"),"open_directive";break;case 1:return this.begin("acc_title"),31;break;case 2:return this.popState(),"acc_title_value";break;case 3:return this.begin("acc_descr"),33;break;case 4:return this.popState(),"acc_descr_value";break;case 5:this.begin("acc_descr_multiline");break;case 6:this.popState();break;case 7:return"acc_descr_multiline_value";case 8:break;case 9:break;case 10:break;case 11:return 10;case 12:break;case 13:break;case 14:this.begin("href");break;case 15:this.popState();break;case 16:return 43;case 17:this.begin("callbackname");break;case 18:this.popState();break;case 19:this.popState(),this.begin("callbackargs");break;case 20:return 41;case 21:this.popState();break;case 22:return 42;case 23:this.begin("click");break;case 24:this.popState();break;case 25:return 40;case 26:return 4;case 27:return 22;case 28:return 23;case 29:return 24;case 30:return 25;case 31:return 26;case 32:return 28;case 33:return 27;case 34:return 29;case 35:return 12;case 36:return 13;case 37:return 14;case 38:return 15;case 39:return 16;case 40:return 17;case 41:return 18;case 42:return 20;case 43:return 21;case 44:return"date";case 45:return 30;case 46:return"accDescription";case 47:return 36;case 48:return 38;case 49:return 39;case 50:return":";case 51:return 6;case 52:return"INVALID"}},"anonymous"),rules:[/^(?:%%\{)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:topAxis\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:tickInterval\s[^#\n;]+)/i,/^(?:includes\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:weekday\s+monday\b)/i,/^(?:weekday\s+tuesday\b)/i,/^(?:weekday\s+wednesday\b)/i,/^(?:weekday\s+thursday\b)/i,/^(?:weekday\s+friday\b)/i,/^(?:weekday\s+saturday\b)/i,/^(?:weekday\s+sunday\b)/i,/^(?:weekend\s+friday\b)/i,/^(?:weekend\s+saturday\b)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^\n]+)/i,/^(?:accDescription\s[^#\n;]+)/i,/^(?:section\s[^\n]+)/i,/^(?:[^:\n]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[6,7],inclusive:!1},acc_descr:{rules:[4],inclusive:!1},acc_title:{rules:[2],inclusive:!1},callbackargs:{rules:[21,22],inclusive:!1},callbackname:{rules:[18,19,20],inclusive:!1},href:{rules:[15,16],inclusive:!1},click:{rules:[24,25],inclusive:!1},INITIAL:{rules:[0,1,3,5,8,9,10,11,12,13,14,17,23,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],inclusive:!0}}};return I}();M.lexer=N;function k(){this.yy={}}return o(k,"Parser"),k.prototype=M,M.Parser=k,new k}();CI.parser=CI;Ule=CI});var Yle=gi((SI,AI)=>{"use strict";(function(t,e){typeof SI=="object"&&typeof AI<"u"?AI.exports=e():typeof define=="function"&&define.amd?define(e):(t=typeof globalThis<"u"?globalThis:t||self).dayjs_plugin_isoWeek=e()})(SI,function(){"use strict";var t="day";return function(e,r,n){var i=o(function(l){return l.add(4-l.isoWeekday(),t)},"a"),a=r.prototype;a.isoWeekYear=function(){return i(this).year()},a.isoWeek=function(l){if(!this.$utils().u(l))return this.add(7*(l-this.isoWeek()),t);var u,h,f,d,p=i(this),m=(u=this.isoWeekYear(),h=this.$u,f=(h?n.utc:n)().year(u).startOf("year"),d=4-f.isoWeekday(),f.isoWeekday()>4&&(d+=7),f.add(d,t));return p.diff(m,"week")+1},a.isoWeekday=function(l){return this.$utils().u(l)?this.day()||7:this.day(this.day()%7?l:l-7)};var s=a.startOf;a.startOf=function(l,u){var h=this.$utils(),f=!!h.u(u)||u;return h.p(l)==="isoweek"?f?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):s.bind(this)(l,u)}}})});var Wle=gi((_I,LI)=>{"use strict";(function(t,e){typeof _I=="object"&&typeof LI<"u"?LI.exports=e():typeof define=="function"&&define.amd?define(e):(t=typeof globalThis<"u"?globalThis:t||self).dayjs_plugin_customParseFormat=e()})(_I,function(){"use strict";var t={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},e=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,r=/\d/,n=/\d\d/,i=/\d\d?/,a=/\d*[^-_:/,()\s\d]+/,s={},l=o(function(g){return(g=+g)+(g>68?1900:2e3)},"a"),u=o(function(g){return function(y){this[g]=+y}},"f"),h=[/[+-]\d\d:?(\d\d)?|Z/,function(g){(this.zone||(this.zone={})).offset=function(y){if(!y||y==="Z")return 0;var v=y.match(/([+-]|\d\d)/g),x=60*v[1]+(+v[2]||0);return x===0?0:v[0]==="+"?-x:x}(g)}],f=o(function(g){var y=s[g];return y&&(y.indexOf?y:y.s.concat(y.f))},"u"),d=o(function(g,y){var v,x=s.meridiem;if(x){for(var b=1;b<=24;b+=1)if(g.indexOf(x(b,0,y))>-1){v=b>12;break}}else v=g===(y?"pm":"PM");return v},"d"),p={A:[a,function(g){this.afternoon=d(g,!1)}],a:[a,function(g){this.afternoon=d(g,!0)}],Q:[r,function(g){this.month=3*(g-1)+1}],S:[r,function(g){this.milliseconds=100*+g}],SS:[n,function(g){this.milliseconds=10*+g}],SSS:[/\d{3}/,function(g){this.milliseconds=+g}],s:[i,u("seconds")],ss:[i,u("seconds")],m:[i,u("minutes")],mm:[i,u("minutes")],H:[i,u("hours")],h:[i,u("hours")],HH:[i,u("hours")],hh:[i,u("hours")],D:[i,u("day")],DD:[n,u("day")],Do:[a,function(g){var y=s.ordinal,v=g.match(/\d+/);if(this.day=v[0],y)for(var x=1;x<=31;x+=1)y(x).replace(/\[|\]/g,"")===g&&(this.day=x)}],w:[i,u("week")],ww:[n,u("week")],M:[i,u("month")],MM:[n,u("month")],MMM:[a,function(g){var y=f("months"),v=(f("monthsShort")||y.map(function(x){return x.slice(0,3)})).indexOf(g)+1;if(v<1)throw new Error;this.month=v%12||v}],MMMM:[a,function(g){var y=f("months").indexOf(g)+1;if(y<1)throw new Error;this.month=y%12||y}],Y:[/[+-]?\d+/,u("year")],YY:[n,function(g){this.year=l(g)}],YYYY:[/\d{4}/,u("year")],Z:h,ZZ:h};function m(g){var y,v;y=g,v=s&&s.formats;for(var x=(g=y.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,function(A,L,M){var N=M&&M.toUpperCase();return L||v[M]||t[M]||v[N].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(k,I,C){return I||C.slice(1)})})).match(e),b=x.length,w=0;w-1)return new Date((D==="X"?1e3:1)*O);var B=m(D)(O),$=B.year,z=B.month,Y=B.day,Q=B.hours,X=B.minutes,ie=B.seconds,j=B.milliseconds,J=B.zone,Z=B.week,H=new Date,q=Y||($||z?1:H.getDate()),K=$||H.getFullYear(),se=0;$&&!z||(se=z>0?z-1:H.getMonth());var ce,ue=Q||0,te=X||0,De=ie||0,oe=j||0;return J?new Date(Date.UTC(K,se,q,ue,te,De,oe+60*J.offset*1e3)):P?new Date(Date.UTC(K,se,q,ue,te,De,oe)):(ce=new Date(K,se,q,ue,te,De,oe),Z&&(ce=F(ce).week(Z).toDate()),ce)}catch{return new Date("")}}(S,_,T,v),this.init(),N&&N!==!0&&(this.$L=this.locale(N).$L),M&&S!=this.format(_)&&(this.$d=new Date("")),s={}}else if(_ instanceof Array)for(var k=_.length,I=1;I<=k;I+=1){E[1]=_[I-1];var C=v.apply(this,E);if(C.isValid()){this.$d=C.$d,this.$L=C.$L,this.init();break}I===k&&(this.$d=new Date(""))}else b.call(this,w)}}})});var qle=gi((DI,RI)=>{"use strict";(function(t,e){typeof DI=="object"&&typeof RI<"u"?RI.exports=e():typeof define=="function"&&define.amd?define(e):(t=typeof globalThis<"u"?globalThis:t||self).dayjs_plugin_advancedFormat=e()})(DI,function(){"use strict";return function(t,e){var r=e.prototype,n=r.format;r.format=function(i){var a=this,s=this.$locale();if(!this.isValid())return n.bind(this)(i);var l=this.$utils(),u=(i||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,function(h){switch(h){case"Q":return Math.ceil((a.$M+1)/3);case"Do":return s.ordinal(a.$D);case"gggg":return a.weekYear();case"GGGG":return a.isoWeekYear();case"wo":return s.ordinal(a.week(),"W");case"w":case"ww":return l.s(a.week(),h==="w"?1:2,"0");case"W":case"WW":return l.s(a.isoWeek(),h==="W"?1:2,"0");case"k":case"kk":return l.s(String(a.$H===0?24:a.$H),h==="k"?1:2,"0");case"X":return Math.floor(a.$d.getTime()/1e3);case"x":return a.$d.getTime();case"z":return"["+a.offsetName()+"]";case"zzz":return"["+a.offsetName("long")+"]";default:return h}});return n.bind(this)(u)}}})});function cce(t,e,r){let n=!0;for(;n;)n=!1,r.forEach(function(i){let a="^\\s*"+i+"\\s*$",s=new RegExp(a);t[0].match(s)&&(e[i]=!0,t.shift(1),n=!0)})}var Kle,yo,Qle,Zle,Jle,Xle,Pc,OI,PI,BI,cx,ux,FI,zI,aE,Rg,GI,ece,$I,hx,VI,UI,sE,NI,OBe,PBe,BBe,FBe,zBe,GBe,$Be,VBe,UBe,HBe,YBe,WBe,qBe,XBe,jBe,KBe,QBe,ZBe,JBe,eFe,tFe,rFe,nFe,tce,iFe,aFe,sFe,rce,oFe,MI,nce,ice,nE,Dg,lFe,cFe,II,iE,zi,ace,uFe,C0,hFe,jle,fFe,sce,dFe,oce,pFe,mFe,lce,uce=R(()=>{"use strict";Kle=Xi(Up(),1),yo=Xi(Nb(),1),Qle=Xi(Yle(),1),Zle=Xi(Wle(),1),Jle=Xi(qle(),1);ut();_t();xr();bi();yo.default.extend(Qle.default);yo.default.extend(Zle.default);yo.default.extend(Jle.default);Xle={friday:5,saturday:6},Pc="",OI="",BI="",cx=[],ux=[],FI=new Map,zI=[],aE=[],Rg="",GI="",ece=["active","done","crit","milestone"],$I=[],hx=!1,VI=!1,UI="sunday",sE="saturday",NI=0,OBe=o(function(){zI=[],aE=[],Rg="",$I=[],nE=0,II=void 0,iE=void 0,zi=[],Pc="",OI="",GI="",PI=void 0,BI="",cx=[],ux=[],hx=!1,VI=!1,NI=0,FI=new Map,vr(),UI="sunday",sE="saturday"},"clear"),PBe=o(function(t){OI=t},"setAxisFormat"),BBe=o(function(){return OI},"getAxisFormat"),FBe=o(function(t){PI=t},"setTickInterval"),zBe=o(function(){return PI},"getTickInterval"),GBe=o(function(t){BI=t},"setTodayMarker"),$Be=o(function(){return BI},"getTodayMarker"),VBe=o(function(t){Pc=t},"setDateFormat"),UBe=o(function(){hx=!0},"enableInclusiveEndDates"),HBe=o(function(){return hx},"endDatesAreInclusive"),YBe=o(function(){VI=!0},"enableTopAxis"),WBe=o(function(){return VI},"topAxisEnabled"),qBe=o(function(t){GI=t},"setDisplayMode"),XBe=o(function(){return GI},"getDisplayMode"),jBe=o(function(){return Pc},"getDateFormat"),KBe=o(function(t){cx=t.toLowerCase().split(/[\s,]+/)},"setIncludes"),QBe=o(function(){return cx},"getIncludes"),ZBe=o(function(t){ux=t.toLowerCase().split(/[\s,]+/)},"setExcludes"),JBe=o(function(){return ux},"getExcludes"),eFe=o(function(){return FI},"getLinks"),tFe=o(function(t){Rg=t,zI.push(t)},"addSection"),rFe=o(function(){return zI},"getSections"),nFe=o(function(){let t=jle(),e=10,r=0;for(;!t&&r[\d\w- ]+)/.exec(r);if(i!==null){let s=null;for(let u of i.groups.ids.split(" ")){let h=C0(u);h!==void 0&&(!s||h.endTime>s.endTime)&&(s=h)}if(s)return s.endTime;let l=new Date;return l.setHours(0,0,0,0),l}let a=(0,yo.default)(r,e.trim(),!0);if(a.isValid())return a.toDate();{V.debug("Invalid date:"+r),V.debug("With date format:"+e.trim());let s=new Date(r);if(s===void 0||isNaN(s.getTime())||s.getFullYear()<-1e4||s.getFullYear()>1e4)throw new Error("Invalid date:"+r);return s}},"getStartDate"),nce=o(function(t){let e=/^(\d+(?:\.\d+)?)([Mdhmswy]|ms)$/.exec(t.trim());return e!==null?[Number.parseFloat(e[1]),e[2]]:[NaN,"ms"]},"parseDuration"),ice=o(function(t,e,r,n=!1){r=r.trim();let a=/^until\s+(?[\d\w- ]+)/.exec(r);if(a!==null){let f=null;for(let p of a.groups.ids.split(" ")){let m=C0(p);m!==void 0&&(!f||m.startTime{window.open(r,"_self")}),FI.set(n,r))}),sce(t,"clickable")},"setLink"),sce=o(function(t,e){t.split(",").forEach(function(r){let n=C0(r);n!==void 0&&n.classes.push(e)})},"setClass"),dFe=o(function(t,e,r){if(de().securityLevel!=="loose"||e===void 0)return;let n=[];if(typeof r=="string"){n=r.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let a=0;a{Lt.runFunc(e,...n)})},"setClickFun"),oce=o(function(t,e){$I.push(function(){let r=document.querySelector(`[id="${t}"]`);r!==null&&r.addEventListener("click",function(){e()})},function(){let r=document.querySelector(`[id="${t}-text"]`);r!==null&&r.addEventListener("click",function(){e()})})},"pushFun"),pFe=o(function(t,e,r){t.split(",").forEach(function(n){dFe(n,e,r)}),sce(t,"clickable")},"setClickEvent"),mFe=o(function(t){$I.forEach(function(e){e(t)})},"bindFunctions"),lce={getConfig:o(()=>de().gantt,"getConfig"),clear:OBe,setDateFormat:VBe,getDateFormat:jBe,enableInclusiveEndDates:UBe,endDatesAreInclusive:HBe,enableTopAxis:YBe,topAxisEnabled:WBe,setAxisFormat:PBe,getAxisFormat:BBe,setTickInterval:FBe,getTickInterval:zBe,setTodayMarker:GBe,getTodayMarker:$Be,setAccTitle:kr,getAccTitle:Ar,setDiagramTitle:nn,getDiagramTitle:Xr,setDisplayMode:qBe,getDisplayMode:XBe,setAccDescription:_r,getAccDescription:Lr,addSection:tFe,getSections:rFe,getTasks:nFe,addTask:uFe,findTaskById:C0,addTaskOrg:hFe,setIncludes:KBe,getIncludes:QBe,setExcludes:ZBe,getExcludes:JBe,setClickEvent:pFe,setLink:fFe,getLinks:eFe,bindFunctions:mFe,parseDuration:nce,isInvalidDate:tce,setWeekday:iFe,getWeekday:aFe,setWeekend:sFe};o(cce,"getTaskTags")});var oE,gFe,hce,yFe,Yu,vFe,fce,dce=R(()=>{"use strict";oE=Xi(Nb(),1);ut();Zt();rr();_t();Yn();gFe=o(function(){V.debug("Something is calling, setConf, remove the call")},"setConf"),hce={monday:_h,tuesday:k3,wednesday:E3,thursday:cc,friday:C3,saturday:S3,sunday:yl},yFe=o((t,e)=>{let r=[...t].map(()=>-1/0),n=[...t].sort((a,s)=>a.startTime-s.startTime||a.order-s.order),i=0;for(let a of n)for(let s=0;s=r[s]){r[s]=a.endTime,a.order=s+e,s>i&&(i=s);break}return i},"getMaxIntersections"),vFe=o(function(t,e,r,n){let i=de().gantt,a=de().securityLevel,s;a==="sandbox"&&(s=$e("#i"+e));let l=a==="sandbox"?$e(s.nodes()[0].contentDocument.body):$e("body"),u=a==="sandbox"?s.nodes()[0].contentDocument:document,h=u.getElementById(e);Yu=h.parentElement.offsetWidth,Yu===void 0&&(Yu=1200),i.useWidth!==void 0&&(Yu=i.useWidth);let f=n.db.getTasks(),d=[];for(let A of f)d.push(A.type);d=_(d);let p={},m=2*i.topPadding;if(n.db.getDisplayMode()==="compact"||i.displayMode==="compact"){let A={};for(let M of f)A[M.section]===void 0?A[M.section]=[M]:A[M.section].push(M);let L=0;for(let M of Object.keys(A)){let N=yFe(A[M],L)+1;L+=N,m+=N*(i.barHeight+i.barGap),p[M]=N}}else{m+=f.length*(i.barHeight+i.barGap);for(let A of d)p[A]=f.filter(L=>L.type===A).length}h.setAttribute("viewBox","0 0 "+Yu+" "+m);let g=l.select(`[id="${e}"]`),y=L3().domain([I4(f,function(A){return A.startTime}),M4(f,function(A){return A.endTime})]).rangeRound([0,Yu-i.leftPadding-i.rightPadding]);function v(A,L){let M=A.startTime,N=L.startTime,k=0;return M>N?k=1:M$.order))].map($=>A.find(z=>z.order===$));g.append("g").selectAll("rect").data(D).enter().append("rect").attr("x",0).attr("y",function($,z){return z=$.order,z*L+M-2}).attr("width",function(){return C-i.rightPadding/2}).attr("height",L).attr("class",function($){for(let[z,Y]of d.entries())if($.type===Y)return"section section"+z%i.numberSectionStyles;return"section section0"});let P=g.append("g").selectAll("rect").data(A).enter(),F=n.db.getLinks();if(P.append("rect").attr("id",function($){return $.id}).attr("rx",3).attr("ry",3).attr("x",function($){return $.milestone?y($.startTime)+N+.5*(y($.endTime)-y($.startTime))-.5*k:y($.startTime)+N}).attr("y",function($,z){return z=$.order,z*L+M}).attr("width",function($){return $.milestone?k:y($.renderEndTime||$.endTime)-y($.startTime)}).attr("height",k).attr("transform-origin",function($,z){return z=$.order,(y($.startTime)+N+.5*(y($.endTime)-y($.startTime))).toString()+"px "+(z*L+M+.5*k).toString()+"px"}).attr("class",function($){let z="task",Y="";$.classes.length>0&&(Y=$.classes.join(" "));let Q=0;for(let[ie,j]of d.entries())$.type===j&&(Q=ie%i.numberSectionStyles);let X="";return $.active?$.crit?X+=" activeCrit":X=" active":$.done?$.crit?X=" doneCrit":X=" done":$.crit&&(X+=" crit"),X.length===0&&(X=" task"),$.milestone&&(X=" milestone "+X),X+=Q,X+=" "+Y,z+X}),P.append("text").attr("id",function($){return $.id+"-text"}).text(function($){return $.task}).attr("font-size",i.fontSize).attr("x",function($){let z=y($.startTime),Y=y($.renderEndTime||$.endTime);$.milestone&&(z+=.5*(y($.endTime)-y($.startTime))-.5*k),$.milestone&&(Y=z+k);let Q=this.getBBox().width;return Q>Y-z?Y+Q+1.5*i.leftPadding>C?z+N-5:Y+N+5:(Y-z)/2+z+N}).attr("y",function($,z){return z=$.order,z*L+i.barHeight/2+(i.fontSize/2-2)+M}).attr("text-height",k).attr("class",function($){let z=y($.startTime),Y=y($.endTime);$.milestone&&(Y=z+k);let Q=this.getBBox().width,X="";$.classes.length>0&&(X=$.classes.join(" "));let ie=0;for(let[J,Z]of d.entries())$.type===Z&&(ie=J%i.numberSectionStyles);let j="";return $.active&&($.crit?j="activeCritText"+ie:j="activeText"+ie),$.done?$.crit?j=j+" doneCritText"+ie:j=j+" doneText"+ie:$.crit&&(j=j+" critText"+ie),$.milestone&&(j+=" milestoneText"),Q>Y-z?Y+Q+1.5*i.leftPadding>C?X+" taskTextOutsideLeft taskTextOutside"+ie+" "+j:X+" taskTextOutsideRight taskTextOutside"+ie+" "+j+" width-"+Q:X+" taskText taskText"+ie+" "+j+" width-"+Q}),de().securityLevel==="sandbox"){let $;$=$e("#i"+e);let z=$.nodes()[0].contentDocument;P.filter(function(Y){return F.has(Y.id)}).each(function(Y){var Q=z.querySelector("#"+Y.id),X=z.querySelector("#"+Y.id+"-text");let ie=Q.parentNode;var j=z.createElement("a");j.setAttribute("xlink:href",F.get(Y.id)),j.setAttribute("target","_top"),ie.appendChild(j),j.appendChild(Q),j.appendChild(X)})}}o(b,"drawRects");function w(A,L,M,N,k,I,C,O){if(C.length===0&&O.length===0)return;let D,P;for(let{startTime:Q,endTime:X}of I)(D===void 0||QP)&&(P=X);if(!D||!P)return;if((0,oE.default)(P).diff((0,oE.default)(D),"year")>5){V.warn("The difference between the min and max time is more than 5 years. This will cause performance issues. Skipping drawing exclude days.");return}let F=n.db.getDateFormat(),B=[],$=null,z=(0,oE.default)(D);for(;z.valueOf()<=P;)n.db.isInvalidDate(z,F,C,O)?$?$.end=z:$={start:z,end:z}:$&&(B.push($),$=null),z=z.add(1,"d");g.append("g").selectAll("rect").data(B).enter().append("rect").attr("id",function(Q){return"exclude-"+Q.start.format("YYYY-MM-DD")}).attr("x",function(Q){return y(Q.start)+M}).attr("y",i.gridLineStartPadding).attr("width",function(Q){let X=Q.end.add(1,"day");return y(X)-y(Q.start)}).attr("height",k-L-i.gridLineStartPadding).attr("transform-origin",function(Q,X){return(y(Q.start)+M+.5*(y(Q.end)-y(Q.start))).toString()+"px "+(X*A+.5*k).toString()+"px"}).attr("class","exclude-range")}o(w,"drawExcludeDays");function S(A,L,M,N){let k=vS(y).tickSize(-N+L+i.gridLineStartPadding).tickFormat(md(n.db.getAxisFormat()||i.axisFormat||"%Y-%m-%d")),C=/^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/.exec(n.db.getTickInterval()||i.tickInterval);if(C!==null){let O=C[1],D=C[2],P=n.db.getWeekday()||i.weekday;switch(D){case"millisecond":k.ticks(oc.every(O));break;case"second":k.ticks(Ks.every(O));break;case"minute":k.ticks(gu.every(O));break;case"hour":k.ticks(yu.every(O));break;case"day":k.ticks(Do.every(O));break;case"week":k.ticks(hce[P].every(O));break;case"month":k.ticks(vu.every(O));break}}if(g.append("g").attr("class","grid").attr("transform","translate("+A+", "+(N-50)+")").call(k).selectAll("text").style("text-anchor","middle").attr("fill","#000").attr("stroke","none").attr("font-size",10).attr("dy","1em"),n.db.topAxisEnabled()||i.topAxis){let O=yS(y).tickSize(-N+L+i.gridLineStartPadding).tickFormat(md(n.db.getAxisFormat()||i.axisFormat||"%Y-%m-%d"));if(C!==null){let D=C[1],P=C[2],F=n.db.getWeekday()||i.weekday;switch(P){case"millisecond":O.ticks(oc.every(D));break;case"second":O.ticks(Ks.every(D));break;case"minute":O.ticks(gu.every(D));break;case"hour":O.ticks(yu.every(D));break;case"day":O.ticks(Do.every(D));break;case"week":O.ticks(hce[F].every(D));break;case"month":O.ticks(vu.every(D));break}}g.append("g").attr("class","grid").attr("transform","translate("+A+", "+L+")").call(O).selectAll("text").style("text-anchor","middle").attr("fill","#000").attr("stroke","none").attr("font-size",10)}}o(S,"makeGrid");function T(A,L){let M=0,N=Object.keys(p).map(k=>[k,p[k]]);g.append("g").selectAll("text").data(N).enter().append(function(k){let I=k[0].split(We.lineBreakRegex),C=-(I.length-1)/2,O=u.createElementNS("http://www.w3.org/2000/svg","text");O.setAttribute("dy",C+"em");for(let[D,P]of I.entries()){let F=u.createElementNS("http://www.w3.org/2000/svg","tspan");F.setAttribute("alignment-baseline","central"),F.setAttribute("x","10"),D>0&&F.setAttribute("dy","1em"),F.textContent=P,O.appendChild(F)}return O}).attr("x",10).attr("y",function(k,I){if(I>0)for(let C=0;C{"use strict";xFe=o(t=>` + .mermaid-main-font { + font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif); + } + + .exclude-range { + fill: ${t.excludeBkgColor}; + } + + .section { + stroke: none; + opacity: 0.2; + } + + .section0 { + fill: ${t.sectionBkgColor}; + } + + .section2 { + fill: ${t.sectionBkgColor2}; + } + + .section1, + .section3 { + fill: ${t.altSectionBkgColor}; + opacity: 0.2; + } + + .sectionTitle0 { + fill: ${t.titleColor}; + } + + .sectionTitle1 { + fill: ${t.titleColor}; + } + + .sectionTitle2 { + fill: ${t.titleColor}; + } + + .sectionTitle3 { + fill: ${t.titleColor}; + } + + .sectionTitle { + text-anchor: start; + font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif); + } + + + /* Grid and axis */ + + .grid .tick { + stroke: ${t.gridColor}; + opacity: 0.8; + shape-rendering: crispEdges; + } + + .grid .tick text { + font-family: ${t.fontFamily}; + fill: ${t.textColor}; + } + + .grid path { + stroke-width: 0; + } + + + /* Today line */ + + .today { + fill: none; + stroke: ${t.todayLineColor}; + stroke-width: 2px; + } + + + /* Task styling */ + + /* Default task */ + + .task { + stroke-width: 2; + } + + .taskText { + text-anchor: middle; + font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif); + } + + .taskTextOutsideRight { + fill: ${t.taskTextDarkColor}; + text-anchor: start; + font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif); + } + + .taskTextOutsideLeft { + fill: ${t.taskTextDarkColor}; + text-anchor: end; + } + + + /* Special case clickable */ + + .task.clickable { + cursor: pointer; + } + + .taskText.clickable { + cursor: pointer; + fill: ${t.taskTextClickableColor} !important; + font-weight: bold; + } + + .taskTextOutsideLeft.clickable { + cursor: pointer; + fill: ${t.taskTextClickableColor} !important; + font-weight: bold; + } + + .taskTextOutsideRight.clickable { + cursor: pointer; + fill: ${t.taskTextClickableColor} !important; + font-weight: bold; + } + + + /* Specific task settings for the sections*/ + + .taskText0, + .taskText1, + .taskText2, + .taskText3 { + fill: ${t.taskTextColor}; + } + + .task0, + .task1, + .task2, + .task3 { + fill: ${t.taskBkgColor}; + stroke: ${t.taskBorderColor}; + } + + .taskTextOutside0, + .taskTextOutside2 + { + fill: ${t.taskTextOutsideColor}; + } + + .taskTextOutside1, + .taskTextOutside3 { + fill: ${t.taskTextOutsideColor}; + } + + + /* Active task */ + + .active0, + .active1, + .active2, + .active3 { + fill: ${t.activeTaskBkgColor}; + stroke: ${t.activeTaskBorderColor}; + } + + .activeText0, + .activeText1, + .activeText2, + .activeText3 { + fill: ${t.taskTextDarkColor} !important; + } + + + /* Completed task */ + + .done0, + .done1, + .done2, + .done3 { + stroke: ${t.doneTaskBorderColor}; + fill: ${t.doneTaskBkgColor}; + stroke-width: 2; + } + + .doneText0, + .doneText1, + .doneText2, + .doneText3 { + fill: ${t.taskTextDarkColor} !important; + } + + + /* Tasks on the critical line */ + + .crit0, + .crit1, + .crit2, + .crit3 { + stroke: ${t.critBorderColor}; + fill: ${t.critBkgColor}; + stroke-width: 2; + } + + .activeCrit0, + .activeCrit1, + .activeCrit2, + .activeCrit3 { + stroke: ${t.critBorderColor}; + fill: ${t.activeTaskBkgColor}; + stroke-width: 2; + } + + .doneCrit0, + .doneCrit1, + .doneCrit2, + .doneCrit3 { + stroke: ${t.critBorderColor}; + fill: ${t.doneTaskBkgColor}; + stroke-width: 2; + cursor: pointer; + shape-rendering: crispEdges; + } + + .milestone { + transform: rotate(45deg) scale(0.8,0.8); + } + + .milestoneText { + font-style: italic; + } + .doneCritText0, + .doneCritText1, + .doneCritText2, + .doneCritText3 { + fill: ${t.taskTextDarkColor} !important; + } + + .activeCritText0, + .activeCritText1, + .activeCritText2, + .activeCritText3 { + fill: ${t.taskTextDarkColor} !important; + } + + .titleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.titleColor||t.textColor}; + font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif); + } +`,"getStyles"),pce=xFe});var gce={};hr(gce,{diagram:()=>bFe});var bFe,yce=R(()=>{"use strict";Hle();uce();dce();mce();bFe={parser:Ule,db:lce,renderer:fce,styles:pce}});var bce,wce=R(()=>{"use strict";Lg();ut();bce={parse:o(async t=>{let e=await Fl("info",t);V.debug(e)},"parse")}});var fx,HI=R(()=>{fx="11.2.0"});var CFe,SFe,Tce,kce=R(()=>{"use strict";HI();CFe={version:fx},SFe=o(()=>CFe.version,"getVersion"),Tce={getVersion:SFe}});var Ps,pf=R(()=>{"use strict";Zt();_t();Ps=o(t=>{let{securityLevel:e}=de(),r=$e("body");if(e==="sandbox"){let a=$e(`#i${t}`).node()?.contentDocument??document;r=$e(a.body)}return r.select(`#${t}`)},"selectSvgElement")});var AFe,Ece,Cce=R(()=>{"use strict";ut();pf();Yn();AFe=o((t,e,r)=>{V.debug(`rendering info diagram +`+t);let n=Ps(e);Sr(n,100,400,!0),n.append("g").append("text").attr("x",100).attr("y",40).attr("class","version").attr("font-size",32).style("text-anchor","middle").text(`v${r}`)},"draw"),Ece={draw:AFe}});var Sce={};hr(Sce,{diagram:()=>_Fe});var _Fe,Ace=R(()=>{"use strict";wce();kce();Cce();_Fe={parser:bce,db:Tce,renderer:Ece}});var Dce,YI,lE,WI,RFe,NFe,MFe,IFe,OFe,PFe,BFe,cE,qI=R(()=>{"use strict";ut();bi();sl();Dce=mr.pie,YI={sections:new Map,showData:!1,config:Dce},lE=YI.sections,WI=YI.showData,RFe=structuredClone(Dce),NFe=o(()=>structuredClone(RFe),"getConfig"),MFe=o(()=>{lE=new Map,WI=YI.showData,vr()},"clear"),IFe=o(({label:t,value:e})=>{lE.has(t)||(lE.set(t,e),V.debug(`added new section: ${t}, with value: ${e}`))},"addSection"),OFe=o(()=>lE,"getSections"),PFe=o(t=>{WI=t},"setShowData"),BFe=o(()=>WI,"getShowData"),cE={getConfig:NFe,clear:MFe,setDiagramTitle:nn,getDiagramTitle:Xr,setAccTitle:kr,getAccTitle:Ar,setAccDescription:_r,getAccDescription:Lr,addSection:IFe,getSections:OFe,setShowData:PFe,getShowData:BFe}});var FFe,Rce,Nce=R(()=>{"use strict";Lg();ut();sx();qI();FFe=o((t,e)=>{cf(t,e),e.setShowData(t.showData),t.sections.map(e.addSection)},"populateDb"),Rce={parse:o(async t=>{let e=await Fl("pie",t);V.debug(e),FFe(e,cE)},"parse")}});var zFe,Mce,Ice=R(()=>{"use strict";zFe=o(t=>` + .pieCircle{ + stroke: ${t.pieStrokeColor}; + stroke-width : ${t.pieStrokeWidth}; + opacity : ${t.pieOpacity}; + } + .pieOuterCircle{ + stroke: ${t.pieOuterStrokeColor}; + stroke-width: ${t.pieOuterStrokeWidth}; + fill: none; + } + .pieTitleText { + text-anchor: middle; + font-size: ${t.pieTitleTextSize}; + fill: ${t.pieTitleTextColor}; + font-family: ${t.fontFamily}; + } + .slice { + font-family: ${t.fontFamily}; + fill: ${t.pieSectionTextColor}; + font-size:${t.pieSectionTextSize}; + // fill: white; + } + .legend text { + fill: ${t.pieLegendTextColor}; + font-family: ${t.fontFamily}; + font-size: ${t.pieLegendTextSize}; + } +`,"getStyles"),Mce=zFe});var GFe,$Fe,Oce,Pce=R(()=>{"use strict";Zt();_t();ut();pf();Yn();xr();GFe=o(t=>{let e=[...t.entries()].map(n=>({label:n[0],value:n[1]})).sort((n,i)=>i.value-n.value);return O3().value(n=>n.value)(e)},"createPieArcs"),$Fe=o((t,e,r,n)=>{V.debug(`rendering pie chart +`+t);let i=n.db,a=de(),s=Ts(i.getConfig(),a.pie),l=40,u=18,h=4,f=450,d=f,p=Ps(e),m=p.append("g");m.attr("transform","translate("+d/2+","+f/2+")");let{themeVariables:g}=a,[y]=mc(g.pieOuterStrokeWidth);y??=2;let v=s.textPosition,x=Math.min(d,f)/2-l,b=bl().innerRadius(0).outerRadius(x),w=bl().innerRadius(x*v).outerRadius(x*v);m.append("circle").attr("cx",0).attr("cy",0).attr("r",x+y/2).attr("class","pieOuterCircle");let S=i.getSections(),T=GFe(S),E=[g.pie1,g.pie2,g.pie3,g.pie4,g.pie5,g.pie6,g.pie7,g.pie8,g.pie9,g.pie10,g.pie11,g.pie12],_=pu(E);m.selectAll("mySlices").data(T).enter().append("path").attr("d",b).attr("fill",k=>_(k.data.label)).attr("class","pieCircle");let A=0;S.forEach(k=>{A+=k}),m.selectAll("mySlices").data(T).enter().append("text").text(k=>(k.data.value/A*100).toFixed(0)+"%").attr("transform",k=>"translate("+w.centroid(k)+")").style("text-anchor","middle").attr("class","slice"),m.append("text").text(i.getDiagramTitle()).attr("x",0).attr("y",-(f-50)/2).attr("class","pieTitleText");let L=m.selectAll(".legend").data(_.domain()).enter().append("g").attr("class","legend").attr("transform",(k,I)=>{let C=u+h,O=C*_.domain().length/2,D=12*u,P=I*C-O;return"translate("+D+","+P+")"});L.append("rect").attr("width",u).attr("height",u).style("fill",_).style("stroke",_),L.data(T).append("text").attr("x",u+h).attr("y",u-h).text(k=>{let{label:I,value:C}=k.data;return i.getShowData()?`${I} [${C}]`:I});let M=Math.max(...L.selectAll("text").nodes().map(k=>k?.getBoundingClientRect().width??0)),N=d+l+u+h+M;p.attr("viewBox",`0 0 ${N} ${f}`),Sr(p,f,N,s.useMaxWidth)},"draw"),Oce={draw:$Fe}});var Bce={};hr(Bce,{diagram:()=>VFe});var VFe,Fce=R(()=>{"use strict";Nce();qI();Ice();Pce();VFe={parser:Rce,db:cE,renderer:Oce,styles:Mce}});var XI,$ce,Vce=R(()=>{"use strict";XI=function(){var t=o(function(we,Te,Ce,Ae){for(Ce=Ce||{},Ae=we.length;Ae--;Ce[we[Ae]]=Te);return Ce},"o"),e=[1,3],r=[1,4],n=[1,5],i=[1,6],a=[1,7],s=[1,4,5,10,12,13,14,18,25,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],l=[1,4,5,10,12,13,14,18,25,28,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],u=[55,56,57],h=[2,36],f=[1,37],d=[1,36],p=[1,38],m=[1,35],g=[1,43],y=[1,41],v=[1,14],x=[1,23],b=[1,18],w=[1,19],S=[1,20],T=[1,21],E=[1,22],_=[1,24],A=[1,25],L=[1,26],M=[1,27],N=[1,28],k=[1,29],I=[1,32],C=[1,33],O=[1,34],D=[1,39],P=[1,40],F=[1,42],B=[1,44],$=[1,62],z=[1,61],Y=[4,5,8,10,12,13,14,18,44,47,49,55,56,57,63,64,65,66,67],Q=[1,65],X=[1,66],ie=[1,67],j=[1,68],J=[1,69],Z=[1,70],H=[1,71],q=[1,72],K=[1,73],se=[1,74],ce=[1,75],ue=[1,76],te=[4,5,6,7,8,9,10,11,12,13,14,15,18],De=[1,90],oe=[1,91],ke=[1,92],Ie=[1,99],Se=[1,93],Ue=[1,96],Pe=[1,94],_e=[1,95],me=[1,97],W=[1,98],fe=[1,102],ge=[10,55,56,57],re=[4,5,6,8,10,11,13,17,18,19,20,55,56,57],he={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,idStringToken:3,ALPHA:4,NUM:5,NODE_STRING:6,DOWN:7,MINUS:8,DEFAULT:9,COMMA:10,COLON:11,AMP:12,BRKT:13,MULT:14,UNICODE_TEXT:15,styleComponent:16,UNIT:17,SPACE:18,STYLE:19,PCT:20,idString:21,style:22,stylesOpt:23,classDefStatement:24,CLASSDEF:25,start:26,eol:27,QUADRANT:28,document:29,line:30,statement:31,axisDetails:32,quadrantDetails:33,points:34,title:35,title_value:36,acc_title:37,acc_title_value:38,acc_descr:39,acc_descr_value:40,acc_descr_multiline_value:41,section:42,text:43,point_start:44,point_x:45,point_y:46,class_name:47,"X-AXIS":48,"AXIS-TEXT-DELIMITER":49,"Y-AXIS":50,QUADRANT_1:51,QUADRANT_2:52,QUADRANT_3:53,QUADRANT_4:54,NEWLINE:55,SEMI:56,EOF:57,alphaNumToken:58,textNoTagsToken:59,STR:60,MD_STR:61,alphaNum:62,PUNCTUATION:63,PLUS:64,EQUALS:65,DOT:66,UNDERSCORE:67,$accept:0,$end:1},terminals_:{2:"error",4:"ALPHA",5:"NUM",6:"NODE_STRING",7:"DOWN",8:"MINUS",9:"DEFAULT",10:"COMMA",11:"COLON",12:"AMP",13:"BRKT",14:"MULT",15:"UNICODE_TEXT",17:"UNIT",18:"SPACE",19:"STYLE",20:"PCT",25:"CLASSDEF",28:"QUADRANT",35:"title",36:"title_value",37:"acc_title",38:"acc_title_value",39:"acc_descr",40:"acc_descr_value",41:"acc_descr_multiline_value",42:"section",44:"point_start",45:"point_x",46:"point_y",47:"class_name",48:"X-AXIS",49:"AXIS-TEXT-DELIMITER",50:"Y-AXIS",51:"QUADRANT_1",52:"QUADRANT_2",53:"QUADRANT_3",54:"QUADRANT_4",55:"NEWLINE",56:"SEMI",57:"EOF",60:"STR",61:"MD_STR",63:"PUNCTUATION",64:"PLUS",65:"EQUALS",66:"DOT",67:"UNDERSCORE"},productions_:[0,[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[21,1],[21,2],[22,1],[22,2],[23,1],[23,3],[24,5],[26,2],[26,2],[26,2],[29,0],[29,2],[30,2],[31,0],[31,1],[31,2],[31,1],[31,1],[31,1],[31,2],[31,2],[31,2],[31,1],[31,1],[34,4],[34,5],[34,5],[34,6],[32,4],[32,3],[32,2],[32,4],[32,3],[32,2],[33,2],[33,2],[33,2],[33,2],[27,1],[27,1],[27,1],[43,1],[43,2],[43,1],[43,1],[62,1],[62,2],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[59,1],[59,1],[59,1]],performAction:o(function(Te,Ce,Ae,Ge,Me,ye,He){var ze=ye.length-1;switch(Me){case 23:this.$=ye[ze];break;case 24:this.$=ye[ze-1]+""+ye[ze];break;case 26:this.$=ye[ze-1]+ye[ze];break;case 27:this.$=[ye[ze].trim()];break;case 28:ye[ze-2].push(ye[ze].trim()),this.$=ye[ze-2];break;case 29:this.$=ye[ze-4],Ge.addClass(ye[ze-2],ye[ze]);break;case 37:this.$=[];break;case 42:this.$=ye[ze].trim(),Ge.setDiagramTitle(this.$);break;case 43:this.$=ye[ze].trim(),Ge.setAccTitle(this.$);break;case 44:case 45:this.$=ye[ze].trim(),Ge.setAccDescription(this.$);break;case 46:Ge.addSection(ye[ze].substr(8)),this.$=ye[ze].substr(8);break;case 47:Ge.addPoint(ye[ze-3],"",ye[ze-1],ye[ze],[]);break;case 48:Ge.addPoint(ye[ze-4],ye[ze-3],ye[ze-1],ye[ze],[]);break;case 49:Ge.addPoint(ye[ze-4],"",ye[ze-2],ye[ze-1],ye[ze]);break;case 50:Ge.addPoint(ye[ze-5],ye[ze-4],ye[ze-2],ye[ze-1],ye[ze]);break;case 51:Ge.setXAxisLeftText(ye[ze-2]),Ge.setXAxisRightText(ye[ze]);break;case 52:ye[ze-1].text+=" \u27F6 ",Ge.setXAxisLeftText(ye[ze-1]);break;case 53:Ge.setXAxisLeftText(ye[ze]);break;case 54:Ge.setYAxisBottomText(ye[ze-2]),Ge.setYAxisTopText(ye[ze]);break;case 55:ye[ze-1].text+=" \u27F6 ",Ge.setYAxisBottomText(ye[ze-1]);break;case 56:Ge.setYAxisBottomText(ye[ze]);break;case 57:Ge.setQuadrant1Text(ye[ze]);break;case 58:Ge.setQuadrant2Text(ye[ze]);break;case 59:Ge.setQuadrant3Text(ye[ze]);break;case 60:Ge.setQuadrant4Text(ye[ze]);break;case 64:this.$={text:ye[ze],type:"text"};break;case 65:this.$={text:ye[ze-1].text+""+ye[ze],type:ye[ze-1].type};break;case 66:this.$={text:ye[ze],type:"text"};break;case 67:this.$={text:ye[ze],type:"markdown"};break;case 68:this.$=ye[ze];break;case 69:this.$=ye[ze-1]+""+ye[ze];break}},"anonymous"),table:[{18:e,26:1,27:2,28:r,55:n,56:i,57:a},{1:[3]},{18:e,26:8,27:2,28:r,55:n,56:i,57:a},{18:e,26:9,27:2,28:r,55:n,56:i,57:a},t(s,[2,33],{29:10}),t(l,[2,61]),t(l,[2,62]),t(l,[2,63]),{1:[2,30]},{1:[2,31]},t(u,h,{30:11,31:12,24:13,32:15,33:16,34:17,43:30,58:31,1:[2,32],4:f,5:d,10:p,12:m,13:g,14:y,18:v,25:x,35:b,37:w,39:S,41:T,42:E,48:_,50:A,51:L,52:M,53:N,54:k,60:I,61:C,63:O,64:D,65:P,66:F,67:B}),t(s,[2,34]),{27:45,55:n,56:i,57:a},t(u,[2,37]),t(u,h,{24:13,32:15,33:16,34:17,43:30,58:31,31:46,4:f,5:d,10:p,12:m,13:g,14:y,18:v,25:x,35:b,37:w,39:S,41:T,42:E,48:_,50:A,51:L,52:M,53:N,54:k,60:I,61:C,63:O,64:D,65:P,66:F,67:B}),t(u,[2,39]),t(u,[2,40]),t(u,[2,41]),{36:[1,47]},{38:[1,48]},{40:[1,49]},t(u,[2,45]),t(u,[2,46]),{18:[1,50]},{4:f,5:d,10:p,12:m,13:g,14:y,43:51,58:31,60:I,61:C,63:O,64:D,65:P,66:F,67:B},{4:f,5:d,10:p,12:m,13:g,14:y,43:52,58:31,60:I,61:C,63:O,64:D,65:P,66:F,67:B},{4:f,5:d,10:p,12:m,13:g,14:y,43:53,58:31,60:I,61:C,63:O,64:D,65:P,66:F,67:B},{4:f,5:d,10:p,12:m,13:g,14:y,43:54,58:31,60:I,61:C,63:O,64:D,65:P,66:F,67:B},{4:f,5:d,10:p,12:m,13:g,14:y,43:55,58:31,60:I,61:C,63:O,64:D,65:P,66:F,67:B},{4:f,5:d,10:p,12:m,13:g,14:y,43:56,58:31,60:I,61:C,63:O,64:D,65:P,66:F,67:B},{4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,44:[1,57],47:[1,58],58:60,59:59,63:O,64:D,65:P,66:F,67:B},t(Y,[2,64]),t(Y,[2,66]),t(Y,[2,67]),t(Y,[2,70]),t(Y,[2,71]),t(Y,[2,72]),t(Y,[2,73]),t(Y,[2,74]),t(Y,[2,75]),t(Y,[2,76]),t(Y,[2,77]),t(Y,[2,78]),t(Y,[2,79]),t(Y,[2,80]),t(s,[2,35]),t(u,[2,38]),t(u,[2,42]),t(u,[2,43]),t(u,[2,44]),{3:64,4:Q,5:X,6:ie,7:j,8:J,9:Z,10:H,11:q,12:K,13:se,14:ce,15:ue,21:63},t(u,[2,53],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,49:[1,77],63:O,64:D,65:P,66:F,67:B}),t(u,[2,56],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,49:[1,78],63:O,64:D,65:P,66:F,67:B}),t(u,[2,57],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,63:O,64:D,65:P,66:F,67:B}),t(u,[2,58],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,63:O,64:D,65:P,66:F,67:B}),t(u,[2,59],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,63:O,64:D,65:P,66:F,67:B}),t(u,[2,60],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,63:O,64:D,65:P,66:F,67:B}),{45:[1,79]},{44:[1,80]},t(Y,[2,65]),t(Y,[2,81]),t(Y,[2,82]),t(Y,[2,83]),{3:82,4:Q,5:X,6:ie,7:j,8:J,9:Z,10:H,11:q,12:K,13:se,14:ce,15:ue,18:[1,81]},t(te,[2,23]),t(te,[2,1]),t(te,[2,2]),t(te,[2,3]),t(te,[2,4]),t(te,[2,5]),t(te,[2,6]),t(te,[2,7]),t(te,[2,8]),t(te,[2,9]),t(te,[2,10]),t(te,[2,11]),t(te,[2,12]),t(u,[2,52],{58:31,43:83,4:f,5:d,10:p,12:m,13:g,14:y,60:I,61:C,63:O,64:D,65:P,66:F,67:B}),t(u,[2,55],{58:31,43:84,4:f,5:d,10:p,12:m,13:g,14:y,60:I,61:C,63:O,64:D,65:P,66:F,67:B}),{46:[1,85]},{45:[1,86]},{4:De,5:oe,6:ke,8:Ie,11:Se,13:Ue,16:89,17:Pe,18:_e,19:me,20:W,22:88,23:87},t(te,[2,24]),t(u,[2,51],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,63:O,64:D,65:P,66:F,67:B}),t(u,[2,54],{59:59,58:60,4:f,5:d,8:$,10:p,12:m,13:g,14:y,18:z,63:O,64:D,65:P,66:F,67:B}),t(u,[2,47],{22:88,16:89,23:100,4:De,5:oe,6:ke,8:Ie,11:Se,13:Ue,17:Pe,18:_e,19:me,20:W}),{46:[1,101]},t(u,[2,29],{10:fe}),t(ge,[2,27],{16:103,4:De,5:oe,6:ke,8:Ie,11:Se,13:Ue,17:Pe,18:_e,19:me,20:W}),t(re,[2,25]),t(re,[2,13]),t(re,[2,14]),t(re,[2,15]),t(re,[2,16]),t(re,[2,17]),t(re,[2,18]),t(re,[2,19]),t(re,[2,20]),t(re,[2,21]),t(re,[2,22]),t(u,[2,49],{10:fe}),t(u,[2,48],{22:88,16:89,23:104,4:De,5:oe,6:ke,8:Ie,11:Se,13:Ue,17:Pe,18:_e,19:me,20:W}),{4:De,5:oe,6:ke,8:Ie,11:Se,13:Ue,16:89,17:Pe,18:_e,19:me,20:W,22:105},t(re,[2,26]),t(u,[2,50],{10:fe}),t(ge,[2,28],{16:103,4:De,5:oe,6:ke,8:Ie,11:Se,13:Ue,17:Pe,18:_e,19:me,20:W})],defaultActions:{8:[2,30],9:[2,31]},parseError:o(function(Te,Ce){if(Ce.recoverable)this.trace(Te);else{var Ae=new Error(Te);throw Ae.hash=Ce,Ae}},"parseError"),parse:o(function(Te){var Ce=this,Ae=[0],Ge=[],Me=[null],ye=[],He=this.table,ze="",Ze=0,gt=0,yt=0,tt=2,Ye=1,Je=ye.slice.call(arguments,1),Ve=Object.create(this.lexer),je={yy:{}};for(var kt in this.yy)Object.prototype.hasOwnProperty.call(this.yy,kt)&&(je.yy[kt]=this.yy[kt]);Ve.setInput(Te,je.yy),je.yy.lexer=Ve,je.yy.parser=this,typeof Ve.yylloc>"u"&&(Ve.yylloc={});var at=Ve.yylloc;ye.push(at);var xt=Ve.options&&Ve.options.ranges;typeof je.yy.parseError=="function"?this.parseError=je.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function it(on){Ae.length=Ae.length-2*on,Me.length=Me.length-on,ye.length=ye.length-on}o(it,"popStack");function dt(){var on;return on=Ge.pop()||Ve.lex()||Ye,typeof on!="number"&&(on instanceof Array&&(Ge=on,on=Ge.pop()),on=Ce.symbols_[on]||on),on}o(dt,"lex");for(var lt,It,mt,St,gr,xn,jt={},rn,Er,Kn,hn;;){if(mt=Ae[Ae.length-1],this.defaultActions[mt]?St=this.defaultActions[mt]:((lt===null||typeof lt>"u")&&(lt=dt()),St=He[mt]&&He[mt][lt]),typeof St>"u"||!St.length||!St[0]){var Qn="";hn=[];for(rn in He[mt])this.terminals_[rn]&&rn>tt&&hn.push("'"+this.terminals_[rn]+"'");Ve.showPosition?Qn="Parse error on line "+(Ze+1)+`: +`+Ve.showPosition()+` +Expecting `+hn.join(", ")+", got '"+(this.terminals_[lt]||lt)+"'":Qn="Parse error on line "+(Ze+1)+": Unexpected "+(lt==Ye?"end of input":"'"+(this.terminals_[lt]||lt)+"'"),this.parseError(Qn,{text:Ve.match,token:this.terminals_[lt]||lt,line:Ve.yylineno,loc:at,expected:hn})}if(St[0]instanceof Array&&St.length>1)throw new Error("Parse Error: multiple actions possible at state: "+mt+", token: "+lt);switch(St[0]){case 1:Ae.push(lt),Me.push(Ve.yytext),ye.push(Ve.yylloc),Ae.push(St[1]),lt=null,It?(lt=It,It=null):(gt=Ve.yyleng,ze=Ve.yytext,Ze=Ve.yylineno,at=Ve.yylloc,yt>0&&yt--);break;case 2:if(Er=this.productions_[St[1]][1],jt.$=Me[Me.length-Er],jt._$={first_line:ye[ye.length-(Er||1)].first_line,last_line:ye[ye.length-1].last_line,first_column:ye[ye.length-(Er||1)].first_column,last_column:ye[ye.length-1].last_column},xt&&(jt._$.range=[ye[ye.length-(Er||1)].range[0],ye[ye.length-1].range[1]]),xn=this.performAction.apply(jt,[ze,gt,Ze,je.yy,St[1],Me,ye].concat(Je)),typeof xn<"u")return xn;Er&&(Ae=Ae.slice(0,-1*Er*2),Me=Me.slice(0,-1*Er),ye=ye.slice(0,-1*Er)),Ae.push(this.productions_[St[1]][0]),Me.push(jt.$),ye.push(jt._$),Kn=He[Ae[Ae.length-2]][Ae[Ae.length-1]],Ae.push(Kn);break;case 3:return!0}}return!0},"parse")},ne=function(){var we={EOF:1,parseError:o(function(Ce,Ae){if(this.yy.parser)this.yy.parser.parseError(Ce,Ae);else throw new Error(Ce)},"parseError"),setInput:o(function(Te,Ce){return this.yy=Ce||this.yy||{},this._input=Te,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var Te=this._input[0];this.yytext+=Te,this.yyleng++,this.offset++,this.match+=Te,this.matched+=Te;var Ce=Te.match(/(?:\r\n?|\n).*/g);return Ce?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),Te},"input"),unput:o(function(Te){var Ce=Te.length,Ae=Te.split(/(?:\r\n?|\n)/g);this._input=Te+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-Ce),this.offset-=Ce;var Ge=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),Ae.length-1&&(this.yylineno-=Ae.length-1);var Me=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:Ae?(Ae.length===Ge.length?this.yylloc.first_column:0)+Ge[Ge.length-Ae.length].length-Ae[0].length:this.yylloc.first_column-Ce},this.options.ranges&&(this.yylloc.range=[Me[0],Me[0]+this.yyleng-Ce]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(Te){this.unput(this.match.slice(Te))},"less"),pastInput:o(function(){var Te=this.matched.substr(0,this.matched.length-this.match.length);return(Te.length>20?"...":"")+Te.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var Te=this.match;return Te.length<20&&(Te+=this._input.substr(0,20-Te.length)),(Te.substr(0,20)+(Te.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var Te=this.pastInput(),Ce=new Array(Te.length+1).join("-");return Te+this.upcomingInput()+` +`+Ce+"^"},"showPosition"),test_match:o(function(Te,Ce){var Ae,Ge,Me;if(this.options.backtrack_lexer&&(Me={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(Me.yylloc.range=this.yylloc.range.slice(0))),Ge=Te[0].match(/(?:\r\n?|\n).*/g),Ge&&(this.yylineno+=Ge.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:Ge?Ge[Ge.length-1].length-Ge[Ge.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+Te[0].length},this.yytext+=Te[0],this.match+=Te[0],this.matches=Te,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(Te[0].length),this.matched+=Te[0],Ae=this.performAction.call(this,this.yy,this,Ce,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),Ae)return Ae;if(this._backtrack){for(var ye in Me)this[ye]=Me[ye];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var Te,Ce,Ae,Ge;this._more||(this.yytext="",this.match="");for(var Me=this._currentRules(),ye=0;yeCe[0].length)){if(Ce=Ae,Ge=ye,this.options.backtrack_lexer){if(Te=this.test_match(Ae,Me[ye]),Te!==!1)return Te;if(this._backtrack){Ce=!1;continue}else return!1}else if(!this.options.flex)break}return Ce?(Te=this.test_match(Ce,Me[Ge]),Te!==!1?Te:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var Ce=this.next();return Ce||this.lex()},"lex"),begin:o(function(Ce){this.conditionStack.push(Ce)},"begin"),popState:o(function(){var Ce=this.conditionStack.length-1;return Ce>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(Ce){return Ce=this.conditionStack.length-1-Math.abs(Ce||0),Ce>=0?this.conditionStack[Ce]:"INITIAL"},"topState"),pushState:o(function(Ce){this.begin(Ce)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(Ce,Ae,Ge,Me){var ye=Me;switch(Ge){case 0:break;case 1:break;case 2:return 55;case 3:break;case 4:return this.begin("title"),35;break;case 5:return this.popState(),"title_value";break;case 6:return this.begin("acc_title"),37;break;case 7:return this.popState(),"acc_title_value";break;case 8:return this.begin("acc_descr"),39;break;case 9:return this.popState(),"acc_descr_value";break;case 10:this.begin("acc_descr_multiline");break;case 11:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:return 48;case 14:return 50;case 15:return 49;case 16:return 51;case 17:return 52;case 18:return 53;case 19:return 54;case 20:return 25;case 21:this.begin("md_string");break;case 22:return"MD_STR";case 23:this.popState();break;case 24:this.begin("string");break;case 25:this.popState();break;case 26:return"STR";case 27:this.begin("class_name");break;case 28:return this.popState(),47;break;case 29:return this.begin("point_start"),44;break;case 30:return this.begin("point_x"),45;break;case 31:this.popState();break;case 32:this.popState(),this.begin("point_y");break;case 33:return this.popState(),46;break;case 34:return 28;case 35:return 4;case 36:return 11;case 37:return 64;case 38:return 10;case 39:return 65;case 40:return 65;case 41:return 14;case 42:return 13;case 43:return 67;case 44:return 66;case 45:return 12;case 46:return 8;case 47:return 5;case 48:return 18;case 49:return 56;case 50:return 63;case 51:return 57}},"anonymous"),rules:[/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:title\b)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?: *x-axis *)/i,/^(?: *y-axis *)/i,/^(?: *--+> *)/i,/^(?: *quadrant-1 *)/i,/^(?: *quadrant-2 *)/i,/^(?: *quadrant-3 *)/i,/^(?: *quadrant-4 *)/i,/^(?:classDef\b)/i,/^(?:["][`])/i,/^(?:[^`"]+)/i,/^(?:[`]["])/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?::::)/i,/^(?:^\w+)/i,/^(?:\s*:\s*\[\s*)/i,/^(?:(1)|(0(.\d+)?))/i,/^(?:\s*\] *)/i,/^(?:\s*,\s*)/i,/^(?:(1)|(0(.\d+)?))/i,/^(?: *quadrantChart *)/i,/^(?:[A-Za-z]+)/i,/^(?::)/i,/^(?:\+)/i,/^(?:,)/i,/^(?:=)/i,/^(?:=)/i,/^(?:\*)/i,/^(?:#)/i,/^(?:[\_])/i,/^(?:\.)/i,/^(?:&)/i,/^(?:-)/i,/^(?:[0-9]+)/i,/^(?:\s)/i,/^(?:;)/i,/^(?:[!"#$%&'*+,-.`?\\_/])/i,/^(?:$)/i],conditions:{class_name:{rules:[28],inclusive:!1},point_y:{rules:[33],inclusive:!1},point_x:{rules:[32],inclusive:!1},point_start:{rules:[30,31],inclusive:!1},acc_descr_multiline:{rules:[11,12],inclusive:!1},acc_descr:{rules:[9],inclusive:!1},acc_title:{rules:[7],inclusive:!1},title:{rules:[5],inclusive:!1},md_string:{rules:[22,23],inclusive:!1},string:{rules:[25,26],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,6,8,10,13,14,15,16,17,18,19,20,21,24,27,29,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],inclusive:!0}}};return we}();he.lexer=ne;function ae(){this.yy={}}return o(ae,"Parser"),ae.prototype=he,he.Parser=ae,new ae}();XI.parser=XI;$ce=XI});var os,uE,Uce=R(()=>{"use strict";Zt();sl();ut();jb();os=hp(),uE=class{constructor(){this.classes=new Map;this.config=this.getDefaultConfig(),this.themeConfig=this.getDefaultThemeConfig(),this.data=this.getDefaultData()}static{o(this,"QuadrantBuilder")}getDefaultData(){return{titleText:"",quadrant1Text:"",quadrant2Text:"",quadrant3Text:"",quadrant4Text:"",xAxisLeftText:"",xAxisRightText:"",yAxisBottomText:"",yAxisTopText:"",points:[]}}getDefaultConfig(){return{showXAxis:!0,showYAxis:!0,showTitle:!0,chartHeight:mr.quadrantChart?.chartWidth||500,chartWidth:mr.quadrantChart?.chartHeight||500,titlePadding:mr.quadrantChart?.titlePadding||10,titleFontSize:mr.quadrantChart?.titleFontSize||20,quadrantPadding:mr.quadrantChart?.quadrantPadding||5,xAxisLabelPadding:mr.quadrantChart?.xAxisLabelPadding||5,yAxisLabelPadding:mr.quadrantChart?.yAxisLabelPadding||5,xAxisLabelFontSize:mr.quadrantChart?.xAxisLabelFontSize||16,yAxisLabelFontSize:mr.quadrantChart?.yAxisLabelFontSize||16,quadrantLabelFontSize:mr.quadrantChart?.quadrantLabelFontSize||16,quadrantTextTopPadding:mr.quadrantChart?.quadrantTextTopPadding||5,pointTextPadding:mr.quadrantChart?.pointTextPadding||5,pointLabelFontSize:mr.quadrantChart?.pointLabelFontSize||12,pointRadius:mr.quadrantChart?.pointRadius||5,xAxisPosition:mr.quadrantChart?.xAxisPosition||"top",yAxisPosition:mr.quadrantChart?.yAxisPosition||"left",quadrantInternalBorderStrokeWidth:mr.quadrantChart?.quadrantInternalBorderStrokeWidth||1,quadrantExternalBorderStrokeWidth:mr.quadrantChart?.quadrantExternalBorderStrokeWidth||2}}getDefaultThemeConfig(){return{quadrant1Fill:os.quadrant1Fill,quadrant2Fill:os.quadrant2Fill,quadrant3Fill:os.quadrant3Fill,quadrant4Fill:os.quadrant4Fill,quadrant1TextFill:os.quadrant1TextFill,quadrant2TextFill:os.quadrant2TextFill,quadrant3TextFill:os.quadrant3TextFill,quadrant4TextFill:os.quadrant4TextFill,quadrantPointFill:os.quadrantPointFill,quadrantPointTextFill:os.quadrantPointTextFill,quadrantXAxisTextFill:os.quadrantXAxisTextFill,quadrantYAxisTextFill:os.quadrantYAxisTextFill,quadrantTitleFill:os.quadrantTitleFill,quadrantInternalBorderStrokeFill:os.quadrantInternalBorderStrokeFill,quadrantExternalBorderStrokeFill:os.quadrantExternalBorderStrokeFill}}clear(){this.config=this.getDefaultConfig(),this.themeConfig=this.getDefaultThemeConfig(),this.data=this.getDefaultData(),this.classes=new Map,V.info("clear called")}setData(e){this.data={...this.data,...e}}addPoints(e){this.data.points=[...e,...this.data.points]}addClass(e,r){this.classes.set(e,r)}setConfig(e){V.trace("setConfig called with: ",e),this.config={...this.config,...e}}setThemeConfig(e){V.trace("setThemeConfig called with: ",e),this.themeConfig={...this.themeConfig,...e}}calculateSpace(e,r,n,i){let a=this.config.xAxisLabelPadding*2+this.config.xAxisLabelFontSize,s={top:e==="top"&&r?a:0,bottom:e==="bottom"&&r?a:0},l=this.config.yAxisLabelPadding*2+this.config.yAxisLabelFontSize,u={left:this.config.yAxisPosition==="left"&&n?l:0,right:this.config.yAxisPosition==="right"&&n?l:0},h=this.config.titleFontSize+this.config.titlePadding*2,f={top:i?h:0},d=this.config.quadrantPadding+u.left,p=this.config.quadrantPadding+s.top+f.top,m=this.config.chartWidth-this.config.quadrantPadding*2-u.left-u.right,g=this.config.chartHeight-this.config.quadrantPadding*2-s.top-s.bottom-f.top,y=m/2,v=g/2;return{xAxisSpace:s,yAxisSpace:u,titleSpace:f,quadrantSpace:{quadrantLeft:d,quadrantTop:p,quadrantWidth:m,quadrantHalfWidth:y,quadrantHeight:g,quadrantHalfHeight:v}}}getAxisLabels(e,r,n,i){let{quadrantSpace:a,titleSpace:s}=i,{quadrantHalfHeight:l,quadrantHeight:u,quadrantLeft:h,quadrantHalfWidth:f,quadrantTop:d,quadrantWidth:p}=a,m=!!this.data.xAxisRightText,g=!!this.data.yAxisTopText,y=[];return this.data.xAxisLeftText&&r&&y.push({text:this.data.xAxisLeftText,fill:this.themeConfig.quadrantXAxisTextFill,x:h+(m?f/2:0),y:e==="top"?this.config.xAxisLabelPadding+s.top:this.config.xAxisLabelPadding+d+u+this.config.quadrantPadding,fontSize:this.config.xAxisLabelFontSize,verticalPos:m?"center":"left",horizontalPos:"top",rotation:0}),this.data.xAxisRightText&&r&&y.push({text:this.data.xAxisRightText,fill:this.themeConfig.quadrantXAxisTextFill,x:h+f+(m?f/2:0),y:e==="top"?this.config.xAxisLabelPadding+s.top:this.config.xAxisLabelPadding+d+u+this.config.quadrantPadding,fontSize:this.config.xAxisLabelFontSize,verticalPos:m?"center":"left",horizontalPos:"top",rotation:0}),this.data.yAxisBottomText&&n&&y.push({text:this.data.yAxisBottomText,fill:this.themeConfig.quadrantYAxisTextFill,x:this.config.yAxisPosition==="left"?this.config.yAxisLabelPadding:this.config.yAxisLabelPadding+h+p+this.config.quadrantPadding,y:d+u-(g?l/2:0),fontSize:this.config.yAxisLabelFontSize,verticalPos:g?"center":"left",horizontalPos:"top",rotation:-90}),this.data.yAxisTopText&&n&&y.push({text:this.data.yAxisTopText,fill:this.themeConfig.quadrantYAxisTextFill,x:this.config.yAxisPosition==="left"?this.config.yAxisLabelPadding:this.config.yAxisLabelPadding+h+p+this.config.quadrantPadding,y:d+l-(g?l/2:0),fontSize:this.config.yAxisLabelFontSize,verticalPos:g?"center":"left",horizontalPos:"top",rotation:-90}),y}getQuadrants(e){let{quadrantSpace:r}=e,{quadrantHalfHeight:n,quadrantLeft:i,quadrantHalfWidth:a,quadrantTop:s}=r,l=[{text:{text:this.data.quadrant1Text,fill:this.themeConfig.quadrant1TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:i+a,y:s,width:a,height:n,fill:this.themeConfig.quadrant1Fill},{text:{text:this.data.quadrant2Text,fill:this.themeConfig.quadrant2TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:i,y:s,width:a,height:n,fill:this.themeConfig.quadrant2Fill},{text:{text:this.data.quadrant3Text,fill:this.themeConfig.quadrant3TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:i,y:s+n,width:a,height:n,fill:this.themeConfig.quadrant3Fill},{text:{text:this.data.quadrant4Text,fill:this.themeConfig.quadrant4TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:i+a,y:s+n,width:a,height:n,fill:this.themeConfig.quadrant4Fill}];for(let u of l)u.text.x=u.x+u.width/2,this.data.points.length===0?(u.text.y=u.y+u.height/2,u.text.horizontalPos="middle"):(u.text.y=u.y+this.config.quadrantTextTopPadding,u.text.horizontalPos="top");return l}getQuadrantPoints(e){let{quadrantSpace:r}=e,{quadrantHeight:n,quadrantLeft:i,quadrantTop:a,quadrantWidth:s}=r,l=gl().domain([0,1]).range([i,s+i]),u=gl().domain([0,1]).range([n+a,a]);return this.data.points.map(f=>{let d=this.classes.get(f.className);return d&&(f={...d,...f}),{x:l(f.x),y:u(f.y),fill:f.color??this.themeConfig.quadrantPointFill,radius:f.radius??this.config.pointRadius,text:{text:f.text,fill:this.themeConfig.quadrantPointTextFill,x:l(f.x),y:u(f.y)+this.config.pointTextPadding,verticalPos:"center",horizontalPos:"top",fontSize:this.config.pointLabelFontSize,rotation:0},strokeColor:f.strokeColor??this.themeConfig.quadrantPointFill,strokeWidth:f.strokeWidth??"0px"}})}getBorders(e){let r=this.config.quadrantExternalBorderStrokeWidth/2,{quadrantSpace:n}=e,{quadrantHalfHeight:i,quadrantHeight:a,quadrantLeft:s,quadrantHalfWidth:l,quadrantTop:u,quadrantWidth:h}=n;return[{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s-r,y1:u,x2:s+h+r,y2:u},{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s+h,y1:u+r,x2:s+h,y2:u+a-r},{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s-r,y1:u+a,x2:s+h+r,y2:u+a},{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s,y1:u+r,x2:s,y2:u+a-r},{strokeFill:this.themeConfig.quadrantInternalBorderStrokeFill,strokeWidth:this.config.quadrantInternalBorderStrokeWidth,x1:s+l,y1:u+r,x2:s+l,y2:u+a-r},{strokeFill:this.themeConfig.quadrantInternalBorderStrokeFill,strokeWidth:this.config.quadrantInternalBorderStrokeWidth,x1:s+r,y1:u+i,x2:s+h-r,y2:u+i}]}getTitle(e){if(e)return{text:this.data.titleText,fill:this.themeConfig.quadrantTitleFill,fontSize:this.config.titleFontSize,horizontalPos:"top",verticalPos:"center",rotation:0,y:this.config.titlePadding,x:this.config.chartWidth/2}}build(){let e=this.config.showXAxis&&!!(this.data.xAxisLeftText||this.data.xAxisRightText),r=this.config.showYAxis&&!!(this.data.yAxisTopText||this.data.yAxisBottomText),n=this.config.showTitle&&!!this.data.titleText,i=this.data.points.length>0?"bottom":this.config.xAxisPosition,a=this.calculateSpace(i,e,r,n);return{points:this.getQuadrantPoints(a),quadrants:this.getQuadrants(a),axisLabels:this.getAxisLabels(i,e,r,a),borderLines:this.getBorders(a),title:this.getTitle(n)}}}});function jI(t){return!/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(t)}function Hce(t){return!/^\d+$/.test(t)}function Yce(t){return!/^\d+px$/.test(t)}var S0,Wce=R(()=>{"use strict";S0=class extends Error{static{o(this,"InvalidStyleError")}constructor(e,r,n){super(`value for ${e} ${r} is invalid, please use a valid ${n}`),this.name="InvalidStyleError"}};o(jI,"validateHexCode");o(Hce,"validateNumber");o(Yce,"validateSizeInPixels")});function Wu(t){return qr(t.trim(),YFe)}function WFe(t){wa.setData({quadrant1Text:Wu(t.text)})}function qFe(t){wa.setData({quadrant2Text:Wu(t.text)})}function XFe(t){wa.setData({quadrant3Text:Wu(t.text)})}function jFe(t){wa.setData({quadrant4Text:Wu(t.text)})}function KFe(t){wa.setData({xAxisLeftText:Wu(t.text)})}function QFe(t){wa.setData({xAxisRightText:Wu(t.text)})}function ZFe(t){wa.setData({yAxisTopText:Wu(t.text)})}function JFe(t){wa.setData({yAxisBottomText:Wu(t.text)})}function KI(t){let e={};for(let r of t){let[n,i]=r.trim().split(/\s*:\s*/);if(n==="radius"){if(Hce(i))throw new S0(n,i,"number");e.radius=parseInt(i)}else if(n==="color"){if(jI(i))throw new S0(n,i,"hex code");e.color=i}else if(n==="stroke-color"){if(jI(i))throw new S0(n,i,"hex code");e.strokeColor=i}else if(n==="stroke-width"){if(Yce(i))throw new S0(n,i,"number of pixels (eg. 10px)");e.strokeWidth=i}else throw new Error(`style named ${n} is not supported.`)}return e}function eze(t,e,r,n,i){let a=KI(i);wa.addPoints([{x:r,y:n,text:Wu(t.text),className:e,...a}])}function tze(t,e){wa.addClass(t,KI(e))}function rze(t){wa.setConfig({chartWidth:t})}function nze(t){wa.setConfig({chartHeight:t})}function ize(){let t=de(),{themeVariables:e,quadrantChart:r}=t;return r&&wa.setConfig(r),wa.setThemeConfig({quadrant1Fill:e.quadrant1Fill,quadrant2Fill:e.quadrant2Fill,quadrant3Fill:e.quadrant3Fill,quadrant4Fill:e.quadrant4Fill,quadrant1TextFill:e.quadrant1TextFill,quadrant2TextFill:e.quadrant2TextFill,quadrant3TextFill:e.quadrant3TextFill,quadrant4TextFill:e.quadrant4TextFill,quadrantPointFill:e.quadrantPointFill,quadrantPointTextFill:e.quadrantPointTextFill,quadrantXAxisTextFill:e.quadrantXAxisTextFill,quadrantYAxisTextFill:e.quadrantYAxisTextFill,quadrantExternalBorderStrokeFill:e.quadrantExternalBorderStrokeFill,quadrantInternalBorderStrokeFill:e.quadrantInternalBorderStrokeFill,quadrantTitleFill:e.quadrantTitleFill}),wa.setData({titleText:Xr()}),wa.build()}var YFe,wa,aze,qce,Xce=R(()=>{"use strict";_t();rr();bi();Uce();Wce();YFe=de();o(Wu,"textSanitizer");wa=new uE;o(WFe,"setQuadrant1Text");o(qFe,"setQuadrant2Text");o(XFe,"setQuadrant3Text");o(jFe,"setQuadrant4Text");o(KFe,"setXAxisLeftText");o(QFe,"setXAxisRightText");o(ZFe,"setYAxisTopText");o(JFe,"setYAxisBottomText");o(KI,"parseStyles");o(eze,"addPoint");o(tze,"addClass");o(rze,"setWidth");o(nze,"setHeight");o(ize,"getQuadrantData");aze=o(function(){wa.clear(),vr()},"clear"),qce={setWidth:rze,setHeight:nze,setQuadrant1Text:WFe,setQuadrant2Text:qFe,setQuadrant3Text:XFe,setQuadrant4Text:jFe,setXAxisLeftText:KFe,setXAxisRightText:QFe,setYAxisTopText:ZFe,setYAxisBottomText:JFe,parseStyles:KI,addPoint:eze,addClass:tze,getQuadrantData:ize,clear:aze,setAccTitle:kr,getAccTitle:Ar,setDiagramTitle:nn,getDiagramTitle:Xr,getAccDescription:Lr,setAccDescription:_r}});var sze,jce,Kce=R(()=>{"use strict";Zt();_t();ut();Yn();sze=o((t,e,r,n)=>{function i(A){return A==="top"?"hanging":"middle"}o(i,"getDominantBaseLine");function a(A){return A==="left"?"start":"middle"}o(a,"getTextAnchor");function s(A){return`translate(${A.x}, ${A.y}) rotate(${A.rotation||0})`}o(s,"getTransformation");let l=de();V.debug(`Rendering quadrant chart +`+t);let u=l.securityLevel,h;u==="sandbox"&&(h=$e("#i"+e));let d=(u==="sandbox"?$e(h.nodes()[0].contentDocument.body):$e("body")).select(`[id="${e}"]`),p=d.append("g").attr("class","main"),m=l.quadrantChart?.chartWidth??500,g=l.quadrantChart?.chartHeight??500;Sr(d,g,m,l.quadrantChart?.useMaxWidth??!0),d.attr("viewBox","0 0 "+m+" "+g),n.db.setHeight(g),n.db.setWidth(m);let y=n.db.getQuadrantData(),v=p.append("g").attr("class","quadrants"),x=p.append("g").attr("class","border"),b=p.append("g").attr("class","data-points"),w=p.append("g").attr("class","labels"),S=p.append("g").attr("class","title");y.title&&S.append("text").attr("x",0).attr("y",0).attr("fill",y.title.fill).attr("font-size",y.title.fontSize).attr("dominant-baseline",i(y.title.horizontalPos)).attr("text-anchor",a(y.title.verticalPos)).attr("transform",s(y.title)).text(y.title.text),y.borderLines&&x.selectAll("line").data(y.borderLines).enter().append("line").attr("x1",A=>A.x1).attr("y1",A=>A.y1).attr("x2",A=>A.x2).attr("y2",A=>A.y2).style("stroke",A=>A.strokeFill).style("stroke-width",A=>A.strokeWidth);let T=v.selectAll("g.quadrant").data(y.quadrants).enter().append("g").attr("class","quadrant");T.append("rect").attr("x",A=>A.x).attr("y",A=>A.y).attr("width",A=>A.width).attr("height",A=>A.height).attr("fill",A=>A.fill),T.append("text").attr("x",0).attr("y",0).attr("fill",A=>A.text.fill).attr("font-size",A=>A.text.fontSize).attr("dominant-baseline",A=>i(A.text.horizontalPos)).attr("text-anchor",A=>a(A.text.verticalPos)).attr("transform",A=>s(A.text)).text(A=>A.text.text),w.selectAll("g.label").data(y.axisLabels).enter().append("g").attr("class","label").append("text").attr("x",0).attr("y",0).text(A=>A.text).attr("fill",A=>A.fill).attr("font-size",A=>A.fontSize).attr("dominant-baseline",A=>i(A.horizontalPos)).attr("text-anchor",A=>a(A.verticalPos)).attr("transform",A=>s(A));let _=b.selectAll("g.data-point").data(y.points).enter().append("g").attr("class","data-point");_.append("circle").attr("cx",A=>A.x).attr("cy",A=>A.y).attr("r",A=>A.radius).attr("fill",A=>A.fill).attr("stroke",A=>A.strokeColor).attr("stroke-width",A=>A.strokeWidth),_.append("text").attr("x",0).attr("y",0).text(A=>A.text.text).attr("fill",A=>A.text.fill).attr("font-size",A=>A.text.fontSize).attr("dominant-baseline",A=>i(A.text.horizontalPos)).attr("text-anchor",A=>a(A.text.verticalPos)).attr("transform",A=>s(A.text))},"draw"),jce={draw:sze}});var Qce={};hr(Qce,{diagram:()=>oze});var oze,Zce=R(()=>{"use strict";Vce();Xce();Kce();oze={parser:$ce,db:qce,renderer:jce,styles:o(()=>"","styles")}});var QI,tue,rue=R(()=>{"use strict";QI=function(){var t=o(function(O,D,P,F){for(P=P||{},F=O.length;F--;P[O[F]]=D);return P},"o"),e=[1,10,12,14,16,18,19,21,23],r=[2,6],n=[1,3],i=[1,5],a=[1,6],s=[1,7],l=[1,5,10,12,14,16,18,19,21,23,34,35,36],u=[1,25],h=[1,26],f=[1,28],d=[1,29],p=[1,30],m=[1,31],g=[1,32],y=[1,33],v=[1,34],x=[1,35],b=[1,36],w=[1,37],S=[1,43],T=[1,42],E=[1,47],_=[1,50],A=[1,10,12,14,16,18,19,21,23,34,35,36],L=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],M=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],N=[1,64],k={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:o(function(D,P,F,B,$,z,Y){var Q=z.length-1;switch($){case 5:B.setOrientation(z[Q]);break;case 9:B.setDiagramTitle(z[Q].text.trim());break;case 12:B.setLineData({text:"",type:"text"},z[Q]);break;case 13:B.setLineData(z[Q-1],z[Q]);break;case 14:B.setBarData({text:"",type:"text"},z[Q]);break;case 15:B.setBarData(z[Q-1],z[Q]);break;case 16:this.$=z[Q].trim(),B.setAccTitle(this.$);break;case 17:case 18:this.$=z[Q].trim(),B.setAccDescription(this.$);break;case 19:this.$=z[Q-1];break;case 20:this.$=[Number(z[Q-2]),...z[Q]];break;case 21:this.$=[Number(z[Q])];break;case 22:B.setXAxisTitle(z[Q]);break;case 23:B.setXAxisTitle(z[Q-1]);break;case 24:B.setXAxisTitle({type:"text",text:""});break;case 25:B.setXAxisBand(z[Q]);break;case 26:B.setXAxisRangeData(Number(z[Q-2]),Number(z[Q]));break;case 27:this.$=z[Q-1];break;case 28:this.$=[z[Q-2],...z[Q]];break;case 29:this.$=[z[Q]];break;case 30:B.setYAxisTitle(z[Q]);break;case 31:B.setYAxisTitle(z[Q-1]);break;case 32:B.setYAxisTitle({type:"text",text:""});break;case 33:B.setYAxisRangeData(Number(z[Q-2]),Number(z[Q]));break;case 37:this.$={text:z[Q],type:"text"};break;case 38:this.$={text:z[Q],type:"text"};break;case 39:this.$={text:z[Q],type:"markdown"};break;case 40:this.$=z[Q];break;case 41:this.$=z[Q-1]+""+z[Q];break}},"anonymous"),table:[t(e,r,{3:1,4:2,7:4,5:n,34:i,35:a,36:s}),{1:[3]},t(e,r,{4:2,7:4,3:8,5:n,34:i,35:a,36:s}),t(e,r,{4:2,7:4,6:9,3:10,5:n,8:[1,11],34:i,35:a,36:s}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},t(l,[2,34]),t(l,[2,35]),t(l,[2,36]),{1:[2,1]},t(e,r,{4:2,7:4,3:21,5:n,34:i,35:a,36:s}),{1:[2,3]},t(l,[2,5]),t(e,[2,7],{4:22,34:i,35:a,36:s}),{11:23,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},{11:39,13:38,24:S,27:T,29:40,30:41,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},{11:45,15:44,27:E,33:46,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},{11:49,17:48,24:_,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},{11:52,17:51,24:_,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},{20:[1,53]},{22:[1,54]},t(A,[2,18]),{1:[2,2]},t(A,[2,8]),t(A,[2,9]),t(L,[2,37],{40:55,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w}),t(L,[2,38]),t(L,[2,39]),t(M,[2,40]),t(M,[2,42]),t(M,[2,43]),t(M,[2,44]),t(M,[2,45]),t(M,[2,46]),t(M,[2,47]),t(M,[2,48]),t(M,[2,49]),t(M,[2,50]),t(M,[2,51]),t(A,[2,10]),t(A,[2,22],{30:41,29:56,24:S,27:T}),t(A,[2,24]),t(A,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},t(A,[2,11]),t(A,[2,30],{33:60,27:E}),t(A,[2,32]),{31:[1,61]},t(A,[2,12]),{17:62,24:_},{25:63,27:N},t(A,[2,14]),{17:65,24:_},t(A,[2,16]),t(A,[2,17]),t(M,[2,41]),t(A,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},t(A,[2,31]),{27:[1,69]},t(A,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},t(A,[2,15]),t(A,[2,26]),t(A,[2,27]),{11:59,32:72,37:24,38:u,39:h,40:27,41:f,42:d,43:p,44:m,45:g,46:y,47:v,48:x,49:b,50:w},t(A,[2,33]),t(A,[2,19]),{25:73,27:N},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:o(function(D,P){if(P.recoverable)this.trace(D);else{var F=new Error(D);throw F.hash=P,F}},"parseError"),parse:o(function(D){var P=this,F=[0],B=[],$=[null],z=[],Y=this.table,Q="",X=0,ie=0,j=0,J=2,Z=1,H=z.slice.call(arguments,1),q=Object.create(this.lexer),K={yy:{}};for(var se in this.yy)Object.prototype.hasOwnProperty.call(this.yy,se)&&(K.yy[se]=this.yy[se]);q.setInput(D,K.yy),K.yy.lexer=q,K.yy.parser=this,typeof q.yylloc>"u"&&(q.yylloc={});var ce=q.yylloc;z.push(ce);var ue=q.options&&q.options.ranges;typeof K.yy.parseError=="function"?this.parseError=K.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function te(he){F.length=F.length-2*he,$.length=$.length-he,z.length=z.length-he}o(te,"popStack");function De(){var he;return he=B.pop()||q.lex()||Z,typeof he!="number"&&(he instanceof Array&&(B=he,he=B.pop()),he=P.symbols_[he]||he),he}o(De,"lex");for(var oe,ke,Ie,Se,Ue,Pe,_e={},me,W,fe,ge;;){if(Ie=F[F.length-1],this.defaultActions[Ie]?Se=this.defaultActions[Ie]:((oe===null||typeof oe>"u")&&(oe=De()),Se=Y[Ie]&&Y[Ie][oe]),typeof Se>"u"||!Se.length||!Se[0]){var re="";ge=[];for(me in Y[Ie])this.terminals_[me]&&me>J&&ge.push("'"+this.terminals_[me]+"'");q.showPosition?re="Parse error on line "+(X+1)+`: +`+q.showPosition()+` +Expecting `+ge.join(", ")+", got '"+(this.terminals_[oe]||oe)+"'":re="Parse error on line "+(X+1)+": Unexpected "+(oe==Z?"end of input":"'"+(this.terminals_[oe]||oe)+"'"),this.parseError(re,{text:q.match,token:this.terminals_[oe]||oe,line:q.yylineno,loc:ce,expected:ge})}if(Se[0]instanceof Array&&Se.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Ie+", token: "+oe);switch(Se[0]){case 1:F.push(oe),$.push(q.yytext),z.push(q.yylloc),F.push(Se[1]),oe=null,ke?(oe=ke,ke=null):(ie=q.yyleng,Q=q.yytext,X=q.yylineno,ce=q.yylloc,j>0&&j--);break;case 2:if(W=this.productions_[Se[1]][1],_e.$=$[$.length-W],_e._$={first_line:z[z.length-(W||1)].first_line,last_line:z[z.length-1].last_line,first_column:z[z.length-(W||1)].first_column,last_column:z[z.length-1].last_column},ue&&(_e._$.range=[z[z.length-(W||1)].range[0],z[z.length-1].range[1]]),Pe=this.performAction.apply(_e,[Q,ie,X,K.yy,Se[1],$,z].concat(H)),typeof Pe<"u")return Pe;W&&(F=F.slice(0,-1*W*2),$=$.slice(0,-1*W),z=z.slice(0,-1*W)),F.push(this.productions_[Se[1]][0]),$.push(_e.$),z.push(_e._$),fe=Y[F[F.length-2]][F[F.length-1]],F.push(fe);break;case 3:return!0}}return!0},"parse")},I=function(){var O={EOF:1,parseError:o(function(P,F){if(this.yy.parser)this.yy.parser.parseError(P,F);else throw new Error(P)},"parseError"),setInput:o(function(D,P){return this.yy=P||this.yy||{},this._input=D,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var D=this._input[0];this.yytext+=D,this.yyleng++,this.offset++,this.match+=D,this.matched+=D;var P=D.match(/(?:\r\n?|\n).*/g);return P?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),D},"input"),unput:o(function(D){var P=D.length,F=D.split(/(?:\r\n?|\n)/g);this._input=D+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-P),this.offset-=P;var B=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),F.length-1&&(this.yylineno-=F.length-1);var $=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:F?(F.length===B.length?this.yylloc.first_column:0)+B[B.length-F.length].length-F[0].length:this.yylloc.first_column-P},this.options.ranges&&(this.yylloc.range=[$[0],$[0]+this.yyleng-P]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(D){this.unput(this.match.slice(D))},"less"),pastInput:o(function(){var D=this.matched.substr(0,this.matched.length-this.match.length);return(D.length>20?"...":"")+D.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var D=this.match;return D.length<20&&(D+=this._input.substr(0,20-D.length)),(D.substr(0,20)+(D.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var D=this.pastInput(),P=new Array(D.length+1).join("-");return D+this.upcomingInput()+` +`+P+"^"},"showPosition"),test_match:o(function(D,P){var F,B,$;if(this.options.backtrack_lexer&&($={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&($.yylloc.range=this.yylloc.range.slice(0))),B=D[0].match(/(?:\r\n?|\n).*/g),B&&(this.yylineno+=B.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:B?B[B.length-1].length-B[B.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+D[0].length},this.yytext+=D[0],this.match+=D[0],this.matches=D,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(D[0].length),this.matched+=D[0],F=this.performAction.call(this,this.yy,this,P,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),F)return F;if(this._backtrack){for(var z in $)this[z]=$[z];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var D,P,F,B;this._more||(this.yytext="",this.match="");for(var $=this._currentRules(),z=0;z<$.length;z++)if(F=this._input.match(this.rules[$[z]]),F&&(!P||F[0].length>P[0].length)){if(P=F,B=z,this.options.backtrack_lexer){if(D=this.test_match(F,$[z]),D!==!1)return D;if(this._backtrack){P=!1;continue}else return!1}else if(!this.options.flex)break}return P?(D=this.test_match(P,$[B]),D!==!1?D:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var P=this.next();return P||this.lex()},"lex"),begin:o(function(P){this.conditionStack.push(P)},"begin"),popState:o(function(){var P=this.conditionStack.length-1;return P>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(P){return P=this.conditionStack.length-1-Math.abs(P||0),P>=0?this.conditionStack[P]:"INITIAL"},"topState"),pushState:o(function(P){this.begin(P)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(P,F,B,$){var z=$;switch(B){case 0:break;case 1:break;case 2:return this.popState(),34;break;case 3:return this.popState(),34;break;case 4:return 34;case 5:break;case 6:return 10;case 7:return this.pushState("acc_title"),19;break;case 8:return this.popState(),"acc_title_value";break;case 9:return this.pushState("acc_descr"),21;break;case 10:return this.popState(),"acc_descr_value";break;case 11:this.pushState("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 5;case 15:return 8;case 16:return this.pushState("axis_data"),"X_AXIS";break;case 17:return this.pushState("axis_data"),"Y_AXIS";break;case 18:return this.pushState("axis_band_data"),24;break;case 19:return 31;case 20:return this.pushState("data"),16;break;case 21:return this.pushState("data"),18;break;case 22:return this.pushState("data_inner"),24;break;case 23:return 27;case 24:return this.popState(),26;break;case 25:this.popState();break;case 26:this.pushState("string");break;case 27:this.popState();break;case 28:return"STR";case 29:return 24;case 30:return 26;case 31:return 43;case 32:return"COLON";case 33:return 44;case 34:return 28;case 35:return 45;case 36:return 46;case 37:return 48;case 38:return 50;case 39:return 47;case 40:return 41;case 41:return 49;case 42:return 42;case 43:break;case 44:return 35;case 45:return 36}},"anonymous"),rules:[/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:(\r?\n))/i,/^(?:(\r?\n))/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:title\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:\{)/i,/^(?:[^\}]*)/i,/^(?:xychart-beta\b)/i,/^(?:(?:vertical|horizontal))/i,/^(?:x-axis\b)/i,/^(?:y-axis\b)/i,/^(?:\[)/i,/^(?:-->)/i,/^(?:line\b)/i,/^(?:bar\b)/i,/^(?:\[)/i,/^(?:[+-]?(?:\d+(?:\.\d+)?|\.\d+))/i,/^(?:\])/i,/^(?:(?:`\) \{ this\.pushState\(md_string\); \}\n\(\?:\(\?!`"\)\.\)\+ \{ return MD_STR; \}\n\(\?:`))/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:\[)/i,/^(?:\])/i,/^(?:[A-Za-z]+)/i,/^(?::)/i,/^(?:\+)/i,/^(?:,)/i,/^(?:=)/i,/^(?:\*)/i,/^(?:#)/i,/^(?:[\_])/i,/^(?:\.)/i,/^(?:&)/i,/^(?:-)/i,/^(?:[0-9]+)/i,/^(?:\s+)/i,/^(?:;)/i,/^(?:$)/i],conditions:{data_inner:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,20,21,23,24,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},data:{rules:[0,1,3,4,5,6,7,9,11,14,15,16,17,20,21,22,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},axis_band_data:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,20,21,24,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},axis_data:{rules:[0,1,2,4,5,6,7,9,11,14,15,16,17,18,19,20,21,23,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},title:{rules:[],inclusive:!1},md_string:{rules:[],inclusive:!1},string:{rules:[27,28],inclusive:!1},INITIAL:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,20,21,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0}}};return O}();k.lexer=I;function C(){this.yy={}}return o(C,"Parser"),C.prototype=k,k.Parser=C,new C}();QI.parser=QI;tue=QI});function ZI(t){return t.type==="bar"}function hE(t){return t.type==="band"}function Ng(t){return t.type==="linear"}var fE=R(()=>{"use strict";o(ZI,"isBarPlot");o(hE,"isBandAxisData");o(Ng,"isLinearAxisData")});var Mg,JI=R(()=>{"use strict";Al();Mg=class{constructor(e){this.parentGroup=e}static{o(this,"TextDimensionCalculatorWithFont")}getMaxDimension(e,r){if(!this.parentGroup)return{width:e.reduce((a,s)=>Math.max(s.length,a),0)*r,height:r};let n={width:0,height:0},i=this.parentGroup.append("g").attr("visibility","hidden").attr("font-size",r);for(let a of e){let s=bj(i,1,a),l=s?s.width:a.length*r,u=s?s.height:r;n.width=Math.max(n.width,l),n.height=Math.max(n.height,u)}return i.remove(),n}}});var Ig,eO=R(()=>{"use strict";Ig=class{constructor(e,r,n,i){this.axisConfig=e;this.title=r;this.textDimensionCalculator=n;this.axisThemeConfig=i;this.boundingRect={x:0,y:0,width:0,height:0};this.axisPosition="left";this.showTitle=!1;this.showLabel=!1;this.showTick=!1;this.showAxisLine=!1;this.outerPadding=0;this.titleTextHeight=0;this.labelTextHeight=0;this.range=[0,10],this.boundingRect={x:0,y:0,width:0,height:0},this.axisPosition="left"}static{o(this,"BaseAxis")}setRange(e){this.range=e,this.axisPosition==="left"||this.axisPosition==="right"?this.boundingRect.height=e[1]-e[0]:this.boundingRect.width=e[1]-e[0],this.recalculateScale()}getRange(){return[this.range[0]+this.outerPadding,this.range[1]-this.outerPadding]}setAxisPosition(e){this.axisPosition=e,this.setRange(this.range)}getTickDistance(){let e=this.getRange();return Math.abs(e[0]-e[1])/this.getTickValues().length}getAxisOuterPadding(){return this.outerPadding}getLabelDimension(){return this.textDimensionCalculator.getMaxDimension(this.getTickValues().map(e=>e.toString()),this.axisConfig.labelFontSize)}recalculateOuterPaddingToDrawBar(){.7*this.getTickDistance()>this.outerPadding*2&&(this.outerPadding=Math.floor(.7*this.getTickDistance()/2)),this.recalculateScale()}calculateSpaceIfDrawnHorizontally(e){let r=e.height;if(this.axisConfig.showAxisLine&&r>this.axisConfig.axisLineWidth&&(r-=this.axisConfig.axisLineWidth,this.showAxisLine=!0),this.axisConfig.showLabel){let n=this.getLabelDimension(),i=.2*e.width;this.outerPadding=Math.min(n.width/2,i);let a=n.height+this.axisConfig.labelPadding*2;this.labelTextHeight=n.height,a<=r&&(r-=a,this.showLabel=!0)}if(this.axisConfig.showTick&&r>=this.axisConfig.tickLength&&(this.showTick=!0,r-=this.axisConfig.tickLength),this.axisConfig.showTitle&&this.title){let n=this.textDimensionCalculator.getMaxDimension([this.title],this.axisConfig.titleFontSize),i=n.height+this.axisConfig.titlePadding*2;this.titleTextHeight=n.height,i<=r&&(r-=i,this.showTitle=!0)}this.boundingRect.width=e.width,this.boundingRect.height=e.height-r}calculateSpaceIfDrawnVertical(e){let r=e.width;if(this.axisConfig.showAxisLine&&r>this.axisConfig.axisLineWidth&&(r-=this.axisConfig.axisLineWidth,this.showAxisLine=!0),this.axisConfig.showLabel){let n=this.getLabelDimension(),i=.2*e.height;this.outerPadding=Math.min(n.height/2,i);let a=n.width+this.axisConfig.labelPadding*2;a<=r&&(r-=a,this.showLabel=!0)}if(this.axisConfig.showTick&&r>=this.axisConfig.tickLength&&(this.showTick=!0,r-=this.axisConfig.tickLength),this.axisConfig.showTitle&&this.title){let n=this.textDimensionCalculator.getMaxDimension([this.title],this.axisConfig.titleFontSize),i=n.height+this.axisConfig.titlePadding*2;this.titleTextHeight=n.height,i<=r&&(r-=i,this.showTitle=!0)}this.boundingRect.width=e.width-r,this.boundingRect.height=e.height}calculateSpace(e){return this.axisPosition==="left"||this.axisPosition==="right"?this.calculateSpaceIfDrawnVertical(e):this.calculateSpaceIfDrawnHorizontally(e),this.recalculateScale(),{width:this.boundingRect.width,height:this.boundingRect.height}}setBoundingBoxXY(e){this.boundingRect.x=e.x,this.boundingRect.y=e.y}getDrawableElementsForLeftAxis(){let e=[];if(this.showAxisLine){let r=this.boundingRect.x+this.boundingRect.width-this.axisConfig.axisLineWidth/2;e.push({type:"path",groupTexts:["left-axis","axisl-line"],data:[{path:`M ${r},${this.boundingRect.y} L ${r},${this.boundingRect.y+this.boundingRect.height} `,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&e.push({type:"text",groupTexts:["left-axis","label"],data:this.getTickValues().map(r=>({text:r.toString(),x:this.boundingRect.x+this.boundingRect.width-(this.showLabel?this.axisConfig.labelPadding:0)-(this.showTick?this.axisConfig.tickLength:0)-(this.showAxisLine?this.axisConfig.axisLineWidth:0),y:this.getScaleValue(r),fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"middle",horizontalPos:"right"}))}),this.showTick){let r=this.boundingRect.x+this.boundingRect.width-(this.showAxisLine?this.axisConfig.axisLineWidth:0);e.push({type:"path",groupTexts:["left-axis","ticks"],data:this.getTickValues().map(n=>({path:`M ${r},${this.getScaleValue(n)} L ${r-this.axisConfig.tickLength},${this.getScaleValue(n)}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth}))})}return this.showTitle&&e.push({type:"text",groupTexts:["left-axis","title"],data:[{text:this.title,x:this.boundingRect.x+this.axisConfig.titlePadding,y:this.boundingRect.y+this.boundingRect.height/2,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:270,verticalPos:"top",horizontalPos:"center"}]}),e}getDrawableElementsForBottomAxis(){let e=[];if(this.showAxisLine){let r=this.boundingRect.y+this.axisConfig.axisLineWidth/2;e.push({type:"path",groupTexts:["bottom-axis","axis-line"],data:[{path:`M ${this.boundingRect.x},${r} L ${this.boundingRect.x+this.boundingRect.width},${r}`,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&e.push({type:"text",groupTexts:["bottom-axis","label"],data:this.getTickValues().map(r=>({text:r.toString(),x:this.getScaleValue(r),y:this.boundingRect.y+this.axisConfig.labelPadding+(this.showTick?this.axisConfig.tickLength:0)+(this.showAxisLine?this.axisConfig.axisLineWidth:0),fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}))}),this.showTick){let r=this.boundingRect.y+(this.showAxisLine?this.axisConfig.axisLineWidth:0);e.push({type:"path",groupTexts:["bottom-axis","ticks"],data:this.getTickValues().map(n=>({path:`M ${this.getScaleValue(n)},${r} L ${this.getScaleValue(n)},${r+this.axisConfig.tickLength}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth}))})}return this.showTitle&&e.push({type:"text",groupTexts:["bottom-axis","title"],data:[{text:this.title,x:this.range[0]+(this.range[1]-this.range[0])/2,y:this.boundingRect.y+this.boundingRect.height-this.axisConfig.titlePadding-this.titleTextHeight,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}]}),e}getDrawableElementsForTopAxis(){let e=[];if(this.showAxisLine){let r=this.boundingRect.y+this.boundingRect.height-this.axisConfig.axisLineWidth/2;e.push({type:"path",groupTexts:["top-axis","axis-line"],data:[{path:`M ${this.boundingRect.x},${r} L ${this.boundingRect.x+this.boundingRect.width},${r}`,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&e.push({type:"text",groupTexts:["top-axis","label"],data:this.getTickValues().map(r=>({text:r.toString(),x:this.getScaleValue(r),y:this.boundingRect.y+(this.showTitle?this.titleTextHeight+this.axisConfig.titlePadding*2:0)+this.axisConfig.labelPadding,fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}))}),this.showTick){let r=this.boundingRect.y;e.push({type:"path",groupTexts:["top-axis","ticks"],data:this.getTickValues().map(n=>({path:`M ${this.getScaleValue(n)},${r+this.boundingRect.height-(this.showAxisLine?this.axisConfig.axisLineWidth:0)} L ${this.getScaleValue(n)},${r+this.boundingRect.height-this.axisConfig.tickLength-(this.showAxisLine?this.axisConfig.axisLineWidth:0)}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth}))})}return this.showTitle&&e.push({type:"text",groupTexts:["top-axis","title"],data:[{text:this.title,x:this.boundingRect.x+this.boundingRect.width/2,y:this.boundingRect.y+this.axisConfig.titlePadding,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}]}),e}getDrawableElements(){if(this.axisPosition==="left")return this.getDrawableElementsForLeftAxis();if(this.axisPosition==="right")throw Error("Drawing of right axis is not implemented");return this.axisPosition==="bottom"?this.getDrawableElementsForBottomAxis():this.axisPosition==="top"?this.getDrawableElementsForTopAxis():[]}}});var dE,nue=R(()=>{"use strict";Zt();ut();eO();dE=class extends Ig{static{o(this,"BandAxis")}constructor(e,r,n,i,a){super(e,i,a,r),this.categories=n,this.scale=Op().domain(this.categories).range(this.getRange())}setRange(e){super.setRange(e)}recalculateScale(){this.scale=Op().domain(this.categories).range(this.getRange()).paddingInner(1).paddingOuter(0).align(.5),V.trace("BandAxis axis final categories, range: ",this.categories,this.getRange())}getTickValues(){return this.categories}getScaleValue(e){return this.scale(e)??this.getRange()[0]}}});var pE,iue=R(()=>{"use strict";Zt();eO();pE=class extends Ig{static{o(this,"LinearAxis")}constructor(e,r,n,i,a){super(e,i,a,r),this.domain=n,this.scale=gl().domain(this.domain).range(this.getRange())}getTickValues(){return this.scale.ticks()}recalculateScale(){let e=[...this.domain];this.axisPosition==="left"&&e.reverse(),this.scale=gl().domain(e).range(this.getRange())}getScaleValue(e){return this.scale(e)}}});function tO(t,e,r,n){let i=new Mg(n);return hE(t)?new dE(e,r,t.categories,t.title,i):new pE(e,r,[t.min,t.max],t.title,i)}var aue=R(()=>{"use strict";fE();JI();nue();iue();o(tO,"getAxis")});function sue(t,e,r,n){let i=new Mg(n);return new rO(i,t,e,r)}var rO,oue=R(()=>{"use strict";JI();rO=class{constructor(e,r,n,i){this.textDimensionCalculator=e;this.chartConfig=r;this.chartData=n;this.chartThemeConfig=i;this.boundingRect={x:0,y:0,width:0,height:0},this.showChartTitle=!1}static{o(this,"ChartTitle")}setBoundingBoxXY(e){this.boundingRect.x=e.x,this.boundingRect.y=e.y}calculateSpace(e){let r=this.textDimensionCalculator.getMaxDimension([this.chartData.title],this.chartConfig.titleFontSize),n=Math.max(r.width,e.width),i=r.height+2*this.chartConfig.titlePadding;return r.width<=n&&r.height<=i&&this.chartConfig.showTitle&&this.chartData.title&&(this.boundingRect.width=n,this.boundingRect.height=i,this.showChartTitle=!0),{width:this.boundingRect.width,height:this.boundingRect.height}}getDrawableElements(){let e=[];return this.showChartTitle&&e.push({groupTexts:["chart-title"],type:"text",data:[{fontSize:this.chartConfig.titleFontSize,text:this.chartData.title,verticalPos:"middle",horizontalPos:"center",x:this.boundingRect.x+this.boundingRect.width/2,y:this.boundingRect.y+this.boundingRect.height/2,fill:this.chartThemeConfig.titleColor,rotation:0}]}),e}};o(sue,"getChartTitleComponent")});var mE,lue=R(()=>{"use strict";Zt();mE=class{constructor(e,r,n,i,a){this.plotData=e;this.xAxis=r;this.yAxis=n;this.orientation=i;this.plotIndex=a}static{o(this,"LinePlot")}getDrawableElement(){let e=this.plotData.data.map(n=>[this.xAxis.getScaleValue(n[0]),this.yAxis.getScaleValue(n[1])]),r;return this.orientation==="horizontal"?r=ha().y(n=>n[0]).x(n=>n[1])(e):r=ha().x(n=>n[0]).y(n=>n[1])(e),r?[{groupTexts:["plot",`line-plot-${this.plotIndex}`],type:"path",data:[{path:r,strokeFill:this.plotData.strokeFill,strokeWidth:this.plotData.strokeWidth}]}]:[]}}});var gE,cue=R(()=>{"use strict";gE=class{constructor(e,r,n,i,a,s){this.barData=e;this.boundingRect=r;this.xAxis=n;this.yAxis=i;this.orientation=a;this.plotIndex=s}static{o(this,"BarPlot")}getDrawableElement(){let e=this.barData.data.map(a=>[this.xAxis.getScaleValue(a[0]),this.yAxis.getScaleValue(a[1])]),n=Math.min(this.xAxis.getAxisOuterPadding()*2,this.xAxis.getTickDistance())*(1-.05),i=n/2;return this.orientation==="horizontal"?[{groupTexts:["plot",`bar-plot-${this.plotIndex}`],type:"rect",data:e.map(a=>({x:this.boundingRect.x,y:a[0]-i,height:n,width:a[1]-this.boundingRect.x,fill:this.barData.fill,strokeWidth:0,strokeFill:this.barData.fill}))}]:[{groupTexts:["plot",`bar-plot-${this.plotIndex}`],type:"rect",data:e.map(a=>({x:a[0]-i,y:a[1],width:n,height:this.boundingRect.y+this.boundingRect.height-a[1],fill:this.barData.fill,strokeWidth:0,strokeFill:this.barData.fill}))}]}}});function uue(t,e,r){return new nO(t,e,r)}var nO,hue=R(()=>{"use strict";lue();cue();nO=class{constructor(e,r,n){this.chartConfig=e;this.chartData=r;this.chartThemeConfig=n;this.boundingRect={x:0,y:0,width:0,height:0}}static{o(this,"BasePlot")}setAxes(e,r){this.xAxis=e,this.yAxis=r}setBoundingBoxXY(e){this.boundingRect.x=e.x,this.boundingRect.y=e.y}calculateSpace(e){return this.boundingRect.width=e.width,this.boundingRect.height=e.height,{width:this.boundingRect.width,height:this.boundingRect.height}}getDrawableElements(){if(!(this.xAxis&&this.yAxis))throw Error("Axes must be passed to render Plots");let e=[];for(let[r,n]of this.chartData.plots.entries())switch(n.type){case"line":{let i=new mE(n,this.xAxis,this.yAxis,this.chartConfig.chartOrientation,r);e.push(...i.getDrawableElement())}break;case"bar":{let i=new gE(n,this.boundingRect,this.xAxis,this.yAxis,this.chartConfig.chartOrientation,r);e.push(...i.getDrawableElement())}break}return e}};o(uue,"getPlotComponent")});var yE,fue=R(()=>{"use strict";aue();oue();hue();fE();yE=class{constructor(e,r,n,i){this.chartConfig=e;this.chartData=r;this.componentStore={title:sue(e,r,n,i),plot:uue(e,r,n),xAxis:tO(r.xAxis,e.xAxis,{titleColor:n.xAxisTitleColor,labelColor:n.xAxisLabelColor,tickColor:n.xAxisTickColor,axisLineColor:n.xAxisLineColor},i),yAxis:tO(r.yAxis,e.yAxis,{titleColor:n.yAxisTitleColor,labelColor:n.yAxisLabelColor,tickColor:n.yAxisTickColor,axisLineColor:n.yAxisLineColor},i)}}static{o(this,"Orchestrator")}calculateVerticalSpace(){let e=this.chartConfig.width,r=this.chartConfig.height,n=0,i=0,a=Math.floor(e*this.chartConfig.plotReservedSpacePercent/100),s=Math.floor(r*this.chartConfig.plotReservedSpacePercent/100),l=this.componentStore.plot.calculateSpace({width:a,height:s});e-=l.width,r-=l.height,l=this.componentStore.title.calculateSpace({width:this.chartConfig.width,height:r}),i=l.height,r-=l.height,this.componentStore.xAxis.setAxisPosition("bottom"),l=this.componentStore.xAxis.calculateSpace({width:e,height:r}),r-=l.height,this.componentStore.yAxis.setAxisPosition("left"),l=this.componentStore.yAxis.calculateSpace({width:e,height:r}),n=l.width,e-=l.width,e>0&&(a+=e,e=0),r>0&&(s+=r,r=0),this.componentStore.plot.calculateSpace({width:a,height:s}),this.componentStore.plot.setBoundingBoxXY({x:n,y:i}),this.componentStore.xAxis.setRange([n,n+a]),this.componentStore.xAxis.setBoundingBoxXY({x:n,y:i+s}),this.componentStore.yAxis.setRange([i,i+s]),this.componentStore.yAxis.setBoundingBoxXY({x:0,y:i}),this.chartData.plots.some(u=>ZI(u))&&this.componentStore.xAxis.recalculateOuterPaddingToDrawBar()}calculateHorizontalSpace(){let e=this.chartConfig.width,r=this.chartConfig.height,n=0,i=0,a=0,s=Math.floor(e*this.chartConfig.plotReservedSpacePercent/100),l=Math.floor(r*this.chartConfig.plotReservedSpacePercent/100),u=this.componentStore.plot.calculateSpace({width:s,height:l});e-=u.width,r-=u.height,u=this.componentStore.title.calculateSpace({width:this.chartConfig.width,height:r}),n=u.height,r-=u.height,this.componentStore.xAxis.setAxisPosition("left"),u=this.componentStore.xAxis.calculateSpace({width:e,height:r}),e-=u.width,i=u.width,this.componentStore.yAxis.setAxisPosition("top"),u=this.componentStore.yAxis.calculateSpace({width:e,height:r}),r-=u.height,a=n+u.height,e>0&&(s+=e,e=0),r>0&&(l+=r,r=0),this.componentStore.plot.calculateSpace({width:s,height:l}),this.componentStore.plot.setBoundingBoxXY({x:i,y:a}),this.componentStore.yAxis.setRange([i,i+s]),this.componentStore.yAxis.setBoundingBoxXY({x:i,y:n}),this.componentStore.xAxis.setRange([a,a+l]),this.componentStore.xAxis.setBoundingBoxXY({x:0,y:a}),this.chartData.plots.some(h=>ZI(h))&&this.componentStore.xAxis.recalculateOuterPaddingToDrawBar()}calculateSpace(){this.chartConfig.chartOrientation==="horizontal"?this.calculateHorizontalSpace():this.calculateVerticalSpace()}getDrawableElement(){this.calculateSpace();let e=[];this.componentStore.plot.setAxes(this.componentStore.xAxis,this.componentStore.yAxis);for(let r of Object.values(this.componentStore))e.push(...r.getDrawableElements());return e}}});var vE,due=R(()=>{"use strict";fue();vE=class{static{o(this,"XYChartBuilder")}static build(e,r,n,i){return new yE(e,r,n,i).getDrawableElement()}}});function mue(){let t=hp(),e=Or();return Ts(t.xyChart,e.themeVariables.xyChart)}function gue(){let t=Or();return Ts(mr.xyChart,t.xyChart)}function yue(){return{yAxis:{type:"linear",title:"",min:1/0,max:-1/0},xAxis:{type:"band",title:"",categories:[]},title:"",plots:[]}}function sO(t){let e=Or();return qr(t.trim(),e)}function hze(t){pue=t}function fze(t){t==="horizontal"?px.chartOrientation="horizontal":px.chartOrientation="vertical"}function dze(t){sn.xAxis.title=sO(t.text)}function vue(t,e){sn.xAxis={type:"linear",title:sn.xAxis.title,min:t,max:e},xE=!0}function pze(t){sn.xAxis={type:"band",title:sn.xAxis.title,categories:t.map(e=>sO(e.text))},xE=!0}function mze(t){sn.yAxis.title=sO(t.text)}function gze(t,e){sn.yAxis={type:"linear",title:sn.yAxis.title,min:t,max:e},aO=!0}function yze(t){let e=Math.min(...t),r=Math.max(...t),n=Ng(sn.yAxis)?sn.yAxis.min:1/0,i=Ng(sn.yAxis)?sn.yAxis.max:-1/0;sn.yAxis={type:"linear",title:sn.yAxis.title,min:Math.min(n,e),max:Math.max(i,r)}}function xue(t){let e=[];if(t.length===0)return e;if(!xE){let r=Ng(sn.xAxis)?sn.xAxis.min:1/0,n=Ng(sn.xAxis)?sn.xAxis.max:-1/0;vue(Math.min(r,1),Math.max(n,t.length))}if(aO||yze(t),hE(sn.xAxis)&&(e=sn.xAxis.categories.map((r,n)=>[r,t[n]])),Ng(sn.xAxis)){let r=sn.xAxis.min,n=sn.xAxis.max,i=(n-r)/(t.length-1),a=[];for(let s=r;s<=n;s+=i)a.push(`${s}`);e=a.map((s,l)=>[s,t[l]])}return e}function bue(t){return iO[t===0?0:t%iO.length]}function vze(t,e){let r=xue(e);sn.plots.push({type:"line",strokeFill:bue(dx),strokeWidth:2,data:r}),dx++}function xze(t,e){let r=xue(e);sn.plots.push({type:"bar",fill:bue(dx),data:r}),dx++}function bze(){if(sn.plots.length===0)throw Error("No Plot to render, please provide a plot with some data");return sn.title=Xr(),vE.build(px,sn,mx,pue)}function wze(){return mx}function Tze(){return px}var dx,pue,px,mx,sn,iO,xE,aO,kze,wue,Tue=R(()=>{"use strict";qs();sl();jb();xr();rr();bi();due();fE();dx=0,px=gue(),mx=mue(),sn=yue(),iO=mx.plotColorPalette.split(",").map(t=>t.trim()),xE=!1,aO=!1;o(mue,"getChartDefaultThemeConfig");o(gue,"getChartDefaultConfig");o(yue,"getChartDefaultData");o(sO,"textSanitizer");o(hze,"setTmpSVGG");o(fze,"setOrientation");o(dze,"setXAxisTitle");o(vue,"setXAxisRangeData");o(pze,"setXAxisBand");o(mze,"setYAxisTitle");o(gze,"setYAxisRangeData");o(yze,"setYAxisRangeFromPlotData");o(xue,"transformDataWithoutCategory");o(bue,"getPlotColorFromPalette");o(vze,"setLineData");o(xze,"setBarData");o(bze,"getDrawableElem");o(wze,"getChartThemeConfig");o(Tze,"getChartConfig");kze=o(function(){vr(),dx=0,px=gue(),sn=yue(),mx=mue(),iO=mx.plotColorPalette.split(",").map(t=>t.trim()),xE=!1,aO=!1},"clear"),wue={getDrawableElem:bze,clear:kze,setAccTitle:kr,getAccTitle:Ar,setDiagramTitle:nn,getDiagramTitle:Xr,getAccDescription:Lr,setAccDescription:_r,setOrientation:fze,setXAxisTitle:dze,setXAxisRangeData:vue,setXAxisBand:pze,setYAxisTitle:mze,setYAxisRangeData:gze,setLineData:vze,setBarData:xze,setTmpSVGG:hze,getChartThemeConfig:wze,getChartConfig:Tze}});var Eze,kue,Eue=R(()=>{"use strict";ut();pf();Yn();Eze=o((t,e,r,n)=>{let i=n.db,a=i.getChartThemeConfig(),s=i.getChartConfig();function l(v){return v==="top"?"text-before-edge":"middle"}o(l,"getDominantBaseLine");function u(v){return v==="left"?"start":v==="right"?"end":"middle"}o(u,"getTextAnchor");function h(v){return`translate(${v.x}, ${v.y}) rotate(${v.rotation||0})`}o(h,"getTextTransformation"),V.debug(`Rendering xychart chart +`+t);let f=Ps(e),d=f.append("g").attr("class","main"),p=d.append("rect").attr("width",s.width).attr("height",s.height).attr("class","background");Sr(f,s.height,s.width,!0),f.attr("viewBox",`0 0 ${s.width} ${s.height}`),p.attr("fill",a.backgroundColor),i.setTmpSVGG(f.append("g").attr("class","mermaid-tmp-group"));let m=i.getDrawableElem(),g={};function y(v){let x=d,b="";for(let[w]of v.entries()){let S=d;w>0&&g[b]&&(S=g[b]),b+=v[w],x=g[b],x||(x=g[b]=S.append("g").attr("class",v[w]))}return x}o(y,"getGroup");for(let v of m){if(v.data.length===0)continue;let x=y(v.groupTexts);switch(v.type){case"rect":x.selectAll("rect").data(v.data).enter().append("rect").attr("x",b=>b.x).attr("y",b=>b.y).attr("width",b=>b.width).attr("height",b=>b.height).attr("fill",b=>b.fill).attr("stroke",b=>b.strokeFill).attr("stroke-width",b=>b.strokeWidth);break;case"text":x.selectAll("text").data(v.data).enter().append("text").attr("x",0).attr("y",0).attr("fill",b=>b.fill).attr("font-size",b=>b.fontSize).attr("dominant-baseline",b=>l(b.verticalPos)).attr("text-anchor",b=>u(b.horizontalPos)).attr("transform",b=>h(b)).text(b=>b.text);break;case"path":x.selectAll("path").data(v.data).enter().append("path").attr("d",b=>b.path).attr("fill",b=>b.fill?b.fill:"none").attr("stroke",b=>b.strokeFill).attr("stroke-width",b=>b.strokeWidth);break}}},"draw"),kue={draw:Eze}});var Cue={};hr(Cue,{diagram:()=>Cze});var Cze,Sue=R(()=>{"use strict";rue();Tue();Eue();Cze={parser:tue,db:wue,renderer:kue}});var oO,Lue,Due=R(()=>{"use strict";oO=function(){var t=o(function(ie,j,J,Z){for(J=J||{},Z=ie.length;Z--;J[ie[Z]]=j);return J},"o"),e=[1,3],r=[1,4],n=[1,5],i=[1,6],a=[5,6,8,9,11,13,31,32,33,34,35,36,44,62,63],s=[1,18],l=[2,7],u=[1,22],h=[1,23],f=[1,24],d=[1,25],p=[1,26],m=[1,27],g=[1,20],y=[1,28],v=[1,29],x=[62,63],b=[5,8,9,11,13,31,32,33,34,35,36,44,51,53,62,63],w=[1,47],S=[1,48],T=[1,49],E=[1,50],_=[1,51],A=[1,52],L=[1,53],M=[53,54],N=[1,64],k=[1,60],I=[1,61],C=[1,62],O=[1,63],D=[1,65],P=[1,69],F=[1,70],B=[1,67],$=[1,68],z=[5,8,9,11,13,31,32,33,34,35,36,44,62,63],Y={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,acc_title:9,acc_title_value:10,acc_descr:11,acc_descr_value:12,acc_descr_multiline_value:13,requirementDef:14,elementDef:15,relationshipDef:16,requirementType:17,requirementName:18,STRUCT_START:19,requirementBody:20,ID:21,COLONSEP:22,id:23,TEXT:24,text:25,RISK:26,riskLevel:27,VERIFYMTHD:28,verifyType:29,STRUCT_STOP:30,REQUIREMENT:31,FUNCTIONAL_REQUIREMENT:32,INTERFACE_REQUIREMENT:33,PERFORMANCE_REQUIREMENT:34,PHYSICAL_REQUIREMENT:35,DESIGN_CONSTRAINT:36,LOW_RISK:37,MED_RISK:38,HIGH_RISK:39,VERIFY_ANALYSIS:40,VERIFY_DEMONSTRATION:41,VERIFY_INSPECTION:42,VERIFY_TEST:43,ELEMENT:44,elementName:45,elementBody:46,TYPE:47,type:48,DOCREF:49,ref:50,END_ARROW_L:51,relationship:52,LINE:53,END_ARROW_R:54,CONTAINS:55,COPIES:56,DERIVES:57,SATISFIES:58,VERIFIES:59,REFINES:60,TRACES:61,unqString:62,qString:63,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",9:"acc_title",10:"acc_title_value",11:"acc_descr",12:"acc_descr_value",13:"acc_descr_multiline_value",19:"STRUCT_START",21:"ID",22:"COLONSEP",24:"TEXT",26:"RISK",28:"VERIFYMTHD",30:"STRUCT_STOP",31:"REQUIREMENT",32:"FUNCTIONAL_REQUIREMENT",33:"INTERFACE_REQUIREMENT",34:"PERFORMANCE_REQUIREMENT",35:"PHYSICAL_REQUIREMENT",36:"DESIGN_CONSTRAINT",37:"LOW_RISK",38:"MED_RISK",39:"HIGH_RISK",40:"VERIFY_ANALYSIS",41:"VERIFY_DEMONSTRATION",42:"VERIFY_INSPECTION",43:"VERIFY_TEST",44:"ELEMENT",47:"TYPE",49:"DOCREF",51:"END_ARROW_L",53:"LINE",54:"END_ARROW_R",55:"CONTAINS",56:"COPIES",57:"DERIVES",58:"SATISFIES",59:"VERIFIES",60:"REFINES",61:"TRACES",62:"unqString",63:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,2],[4,2],[4,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[14,5],[20,5],[20,5],[20,5],[20,5],[20,2],[20,1],[17,1],[17,1],[17,1],[17,1],[17,1],[17,1],[27,1],[27,1],[27,1],[29,1],[29,1],[29,1],[29,1],[15,5],[46,5],[46,5],[46,2],[46,1],[16,5],[16,5],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[18,1],[18,1],[23,1],[23,1],[25,1],[25,1],[45,1],[45,1],[48,1],[48,1],[50,1],[50,1]],performAction:o(function(j,J,Z,H,q,K,se){var ce=K.length-1;switch(q){case 4:this.$=K[ce].trim(),H.setAccTitle(this.$);break;case 5:case 6:this.$=K[ce].trim(),H.setAccDescription(this.$);break;case 7:this.$=[];break;case 13:H.addRequirement(K[ce-3],K[ce-4]);break;case 14:H.setNewReqId(K[ce-2]);break;case 15:H.setNewReqText(K[ce-2]);break;case 16:H.setNewReqRisk(K[ce-2]);break;case 17:H.setNewReqVerifyMethod(K[ce-2]);break;case 20:this.$=H.RequirementType.REQUIREMENT;break;case 21:this.$=H.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 22:this.$=H.RequirementType.INTERFACE_REQUIREMENT;break;case 23:this.$=H.RequirementType.PERFORMANCE_REQUIREMENT;break;case 24:this.$=H.RequirementType.PHYSICAL_REQUIREMENT;break;case 25:this.$=H.RequirementType.DESIGN_CONSTRAINT;break;case 26:this.$=H.RiskLevel.LOW_RISK;break;case 27:this.$=H.RiskLevel.MED_RISK;break;case 28:this.$=H.RiskLevel.HIGH_RISK;break;case 29:this.$=H.VerifyType.VERIFY_ANALYSIS;break;case 30:this.$=H.VerifyType.VERIFY_DEMONSTRATION;break;case 31:this.$=H.VerifyType.VERIFY_INSPECTION;break;case 32:this.$=H.VerifyType.VERIFY_TEST;break;case 33:H.addElement(K[ce-3]);break;case 34:H.setNewElementType(K[ce-2]);break;case 35:H.setNewElementDocRef(K[ce-2]);break;case 38:H.addRelationship(K[ce-2],K[ce],K[ce-4]);break;case 39:H.addRelationship(K[ce-2],K[ce-4],K[ce]);break;case 40:this.$=H.Relationships.CONTAINS;break;case 41:this.$=H.Relationships.COPIES;break;case 42:this.$=H.Relationships.DERIVES;break;case 43:this.$=H.Relationships.SATISFIES;break;case 44:this.$=H.Relationships.VERIFIES;break;case 45:this.$=H.Relationships.REFINES;break;case 46:this.$=H.Relationships.TRACES;break}},"anonymous"),table:[{3:1,4:2,6:e,9:r,11:n,13:i},{1:[3]},{3:8,4:2,5:[1,7],6:e,9:r,11:n,13:i},{5:[1,9]},{10:[1,10]},{12:[1,11]},t(a,[2,6]),{3:12,4:2,6:e,9:r,11:n,13:i},{1:[2,2]},{4:17,5:s,7:13,8:l,9:r,11:n,13:i,14:14,15:15,16:16,17:19,23:21,31:u,32:h,33:f,34:d,35:p,36:m,44:g,62:y,63:v},t(a,[2,4]),t(a,[2,5]),{1:[2,1]},{8:[1,30]},{4:17,5:s,7:31,8:l,9:r,11:n,13:i,14:14,15:15,16:16,17:19,23:21,31:u,32:h,33:f,34:d,35:p,36:m,44:g,62:y,63:v},{4:17,5:s,7:32,8:l,9:r,11:n,13:i,14:14,15:15,16:16,17:19,23:21,31:u,32:h,33:f,34:d,35:p,36:m,44:g,62:y,63:v},{4:17,5:s,7:33,8:l,9:r,11:n,13:i,14:14,15:15,16:16,17:19,23:21,31:u,32:h,33:f,34:d,35:p,36:m,44:g,62:y,63:v},{4:17,5:s,7:34,8:l,9:r,11:n,13:i,14:14,15:15,16:16,17:19,23:21,31:u,32:h,33:f,34:d,35:p,36:m,44:g,62:y,63:v},{4:17,5:s,7:35,8:l,9:r,11:n,13:i,14:14,15:15,16:16,17:19,23:21,31:u,32:h,33:f,34:d,35:p,36:m,44:g,62:y,63:v},{18:36,62:[1,37],63:[1,38]},{45:39,62:[1,40],63:[1,41]},{51:[1,42],53:[1,43]},t(x,[2,20]),t(x,[2,21]),t(x,[2,22]),t(x,[2,23]),t(x,[2,24]),t(x,[2,25]),t(b,[2,49]),t(b,[2,50]),{1:[2,3]},{8:[2,8]},{8:[2,9]},{8:[2,10]},{8:[2,11]},{8:[2,12]},{19:[1,44]},{19:[2,47]},{19:[2,48]},{19:[1,45]},{19:[2,53]},{19:[2,54]},{52:46,55:w,56:S,57:T,58:E,59:_,60:A,61:L},{52:54,55:w,56:S,57:T,58:E,59:_,60:A,61:L},{5:[1,55]},{5:[1,56]},{53:[1,57]},t(M,[2,40]),t(M,[2,41]),t(M,[2,42]),t(M,[2,43]),t(M,[2,44]),t(M,[2,45]),t(M,[2,46]),{54:[1,58]},{5:N,20:59,21:k,24:I,26:C,28:O,30:D},{5:P,30:F,46:66,47:B,49:$},{23:71,62:y,63:v},{23:72,62:y,63:v},t(z,[2,13]),{22:[1,73]},{22:[1,74]},{22:[1,75]},{22:[1,76]},{5:N,20:77,21:k,24:I,26:C,28:O,30:D},t(z,[2,19]),t(z,[2,33]),{22:[1,78]},{22:[1,79]},{5:P,30:F,46:80,47:B,49:$},t(z,[2,37]),t(z,[2,38]),t(z,[2,39]),{23:81,62:y,63:v},{25:82,62:[1,83],63:[1,84]},{27:85,37:[1,86],38:[1,87],39:[1,88]},{29:89,40:[1,90],41:[1,91],42:[1,92],43:[1,93]},t(z,[2,18]),{48:94,62:[1,95],63:[1,96]},{50:97,62:[1,98],63:[1,99]},t(z,[2,36]),{5:[1,100]},{5:[1,101]},{5:[2,51]},{5:[2,52]},{5:[1,102]},{5:[2,26]},{5:[2,27]},{5:[2,28]},{5:[1,103]},{5:[2,29]},{5:[2,30]},{5:[2,31]},{5:[2,32]},{5:[1,104]},{5:[2,55]},{5:[2,56]},{5:[1,105]},{5:[2,57]},{5:[2,58]},{5:N,20:106,21:k,24:I,26:C,28:O,30:D},{5:N,20:107,21:k,24:I,26:C,28:O,30:D},{5:N,20:108,21:k,24:I,26:C,28:O,30:D},{5:N,20:109,21:k,24:I,26:C,28:O,30:D},{5:P,30:F,46:110,47:B,49:$},{5:P,30:F,46:111,47:B,49:$},t(z,[2,14]),t(z,[2,15]),t(z,[2,16]),t(z,[2,17]),t(z,[2,34]),t(z,[2,35])],defaultActions:{8:[2,2],12:[2,1],30:[2,3],31:[2,8],32:[2,9],33:[2,10],34:[2,11],35:[2,12],37:[2,47],38:[2,48],40:[2,53],41:[2,54],83:[2,51],84:[2,52],86:[2,26],87:[2,27],88:[2,28],90:[2,29],91:[2,30],92:[2,31],93:[2,32],95:[2,55],96:[2,56],98:[2,57],99:[2,58]},parseError:o(function(j,J){if(J.recoverable)this.trace(j);else{var Z=new Error(j);throw Z.hash=J,Z}},"parseError"),parse:o(function(j){var J=this,Z=[0],H=[],q=[null],K=[],se=this.table,ce="",ue=0,te=0,De=0,oe=2,ke=1,Ie=K.slice.call(arguments,1),Se=Object.create(this.lexer),Ue={yy:{}};for(var Pe in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Pe)&&(Ue.yy[Pe]=this.yy[Pe]);Se.setInput(j,Ue.yy),Ue.yy.lexer=Se,Ue.yy.parser=this,typeof Se.yylloc>"u"&&(Se.yylloc={});var _e=Se.yylloc;K.push(_e);var me=Se.options&&Se.options.ranges;typeof Ue.yy.parseError=="function"?this.parseError=Ue.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function W(He){Z.length=Z.length-2*He,q.length=q.length-He,K.length=K.length-He}o(W,"popStack");function fe(){var He;return He=H.pop()||Se.lex()||ke,typeof He!="number"&&(He instanceof Array&&(H=He,He=H.pop()),He=J.symbols_[He]||He),He}o(fe,"lex");for(var ge,re,he,ne,ae,we,Te={},Ce,Ae,Ge,Me;;){if(he=Z[Z.length-1],this.defaultActions[he]?ne=this.defaultActions[he]:((ge===null||typeof ge>"u")&&(ge=fe()),ne=se[he]&&se[he][ge]),typeof ne>"u"||!ne.length||!ne[0]){var ye="";Me=[];for(Ce in se[he])this.terminals_[Ce]&&Ce>oe&&Me.push("'"+this.terminals_[Ce]+"'");Se.showPosition?ye="Parse error on line "+(ue+1)+`: +`+Se.showPosition()+` +Expecting `+Me.join(", ")+", got '"+(this.terminals_[ge]||ge)+"'":ye="Parse error on line "+(ue+1)+": Unexpected "+(ge==ke?"end of input":"'"+(this.terminals_[ge]||ge)+"'"),this.parseError(ye,{text:Se.match,token:this.terminals_[ge]||ge,line:Se.yylineno,loc:_e,expected:Me})}if(ne[0]instanceof Array&&ne.length>1)throw new Error("Parse Error: multiple actions possible at state: "+he+", token: "+ge);switch(ne[0]){case 1:Z.push(ge),q.push(Se.yytext),K.push(Se.yylloc),Z.push(ne[1]),ge=null,re?(ge=re,re=null):(te=Se.yyleng,ce=Se.yytext,ue=Se.yylineno,_e=Se.yylloc,De>0&&De--);break;case 2:if(Ae=this.productions_[ne[1]][1],Te.$=q[q.length-Ae],Te._$={first_line:K[K.length-(Ae||1)].first_line,last_line:K[K.length-1].last_line,first_column:K[K.length-(Ae||1)].first_column,last_column:K[K.length-1].last_column},me&&(Te._$.range=[K[K.length-(Ae||1)].range[0],K[K.length-1].range[1]]),we=this.performAction.apply(Te,[ce,te,ue,Ue.yy,ne[1],q,K].concat(Ie)),typeof we<"u")return we;Ae&&(Z=Z.slice(0,-1*Ae*2),q=q.slice(0,-1*Ae),K=K.slice(0,-1*Ae)),Z.push(this.productions_[ne[1]][0]),q.push(Te.$),K.push(Te._$),Ge=se[Z[Z.length-2]][Z[Z.length-1]],Z.push(Ge);break;case 3:return!0}}return!0},"parse")},Q=function(){var ie={EOF:1,parseError:o(function(J,Z){if(this.yy.parser)this.yy.parser.parseError(J,Z);else throw new Error(J)},"parseError"),setInput:o(function(j,J){return this.yy=J||this.yy||{},this._input=j,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var j=this._input[0];this.yytext+=j,this.yyleng++,this.offset++,this.match+=j,this.matched+=j;var J=j.match(/(?:\r\n?|\n).*/g);return J?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),j},"input"),unput:o(function(j){var J=j.length,Z=j.split(/(?:\r\n?|\n)/g);this._input=j+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-J),this.offset-=J;var H=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),Z.length-1&&(this.yylineno-=Z.length-1);var q=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:Z?(Z.length===H.length?this.yylloc.first_column:0)+H[H.length-Z.length].length-Z[0].length:this.yylloc.first_column-J},this.options.ranges&&(this.yylloc.range=[q[0],q[0]+this.yyleng-J]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(j){this.unput(this.match.slice(j))},"less"),pastInput:o(function(){var j=this.matched.substr(0,this.matched.length-this.match.length);return(j.length>20?"...":"")+j.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var j=this.match;return j.length<20&&(j+=this._input.substr(0,20-j.length)),(j.substr(0,20)+(j.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var j=this.pastInput(),J=new Array(j.length+1).join("-");return j+this.upcomingInput()+` +`+J+"^"},"showPosition"),test_match:o(function(j,J){var Z,H,q;if(this.options.backtrack_lexer&&(q={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(q.yylloc.range=this.yylloc.range.slice(0))),H=j[0].match(/(?:\r\n?|\n).*/g),H&&(this.yylineno+=H.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:H?H[H.length-1].length-H[H.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+j[0].length},this.yytext+=j[0],this.match+=j[0],this.matches=j,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(j[0].length),this.matched+=j[0],Z=this.performAction.call(this,this.yy,this,J,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),Z)return Z;if(this._backtrack){for(var K in q)this[K]=q[K];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var j,J,Z,H;this._more||(this.yytext="",this.match="");for(var q=this._currentRules(),K=0;KJ[0].length)){if(J=Z,H=K,this.options.backtrack_lexer){if(j=this.test_match(Z,q[K]),j!==!1)return j;if(this._backtrack){J=!1;continue}else return!1}else if(!this.options.flex)break}return J?(j=this.test_match(J,q[H]),j!==!1?j:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var J=this.next();return J||this.lex()},"lex"),begin:o(function(J){this.conditionStack.push(J)},"begin"),popState:o(function(){var J=this.conditionStack.length-1;return J>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(J){return J=this.conditionStack.length-1-Math.abs(J||0),J>=0?this.conditionStack[J]:"INITIAL"},"topState"),pushState:o(function(J){this.begin(J)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(J,Z,H,q){var K=q;switch(H){case 0:return"title";case 1:return this.begin("acc_title"),9;break;case 2:return this.popState(),"acc_title_value";break;case 3:return this.begin("acc_descr"),11;break;case 4:return this.popState(),"acc_descr_value";break;case 5:this.begin("acc_descr_multiline");break;case 6:this.popState();break;case 7:return"acc_descr_multiline_value";case 8:return 5;case 9:break;case 10:break;case 11:break;case 12:return 8;case 13:return 6;case 14:return 19;case 15:return 30;case 16:return 22;case 17:return 21;case 18:return 24;case 19:return 26;case 20:return 28;case 21:return 31;case 22:return 32;case 23:return 33;case 24:return 34;case 25:return 35;case 26:return 36;case 27:return 37;case 28:return 38;case 29:return 39;case 30:return 40;case 31:return 41;case 32:return 42;case 33:return 43;case 34:return 44;case 35:return 55;case 36:return 56;case 37:return 57;case 38:return 58;case 39:return 59;case 40:return 60;case 41:return 61;case 42:return 47;case 43:return 49;case 44:return 51;case 45:return 54;case 46:return 53;case 47:this.begin("string");break;case 48:this.popState();break;case 49:return"qString";case 50:return Z.yytext=Z.yytext.trim(),62;break}},"anonymous"),rules:[/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:$)/i,/^(?:requirementDiagram\b)/i,/^(?:\{)/i,/^(?:\})/i,/^(?::)/i,/^(?:id\b)/i,/^(?:text\b)/i,/^(?:risk\b)/i,/^(?:verifyMethod\b)/i,/^(?:requirement\b)/i,/^(?:functionalRequirement\b)/i,/^(?:interfaceRequirement\b)/i,/^(?:performanceRequirement\b)/i,/^(?:physicalRequirement\b)/i,/^(?:designConstraint\b)/i,/^(?:low\b)/i,/^(?:medium\b)/i,/^(?:high\b)/i,/^(?:analysis\b)/i,/^(?:demonstration\b)/i,/^(?:inspection\b)/i,/^(?:test\b)/i,/^(?:element\b)/i,/^(?:contains\b)/i,/^(?:copies\b)/i,/^(?:derives\b)/i,/^(?:satisfies\b)/i,/^(?:verifies\b)/i,/^(?:refines\b)/i,/^(?:traces\b)/i,/^(?:type\b)/i,/^(?:docref\b)/i,/^(?:<-)/i,/^(?:->)/i,/^(?:-)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[\w][^\r\n\{\<\>\-\=]*)/i],conditions:{acc_descr_multiline:{rules:[6,7],inclusive:!1},acc_descr:{rules:[4],inclusive:!1},acc_title:{rules:[2],inclusive:!1},unqString:{rules:[],inclusive:!1},token:{rules:[],inclusive:!1},string:{rules:[48,49],inclusive:!1},INITIAL:{rules:[0,1,3,5,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,50],inclusive:!0}}};return ie}();Y.lexer=Q;function X(){this.yy={}}return o(X,"Parser"),X.prototype=Y,Y.Parser=X,new X}();oO.parser=oO;Lue=oO});var lO,Bs,gx,mf,yx,Lze,Dze,Rze,Nze,Mze,Ize,Oze,Pze,Bze,Fze,zze,Gze,$ze,Vze,Uze,Hze,Yze,Rue,Nue=R(()=>{"use strict";_t();ut();bi();lO=[],Bs={},gx=new Map,mf={},yx=new Map,Lze={REQUIREMENT:"Requirement",FUNCTIONAL_REQUIREMENT:"Functional Requirement",INTERFACE_REQUIREMENT:"Interface Requirement",PERFORMANCE_REQUIREMENT:"Performance Requirement",PHYSICAL_REQUIREMENT:"Physical Requirement",DESIGN_CONSTRAINT:"Design Constraint"},Dze={LOW_RISK:"Low",MED_RISK:"Medium",HIGH_RISK:"High"},Rze={VERIFY_ANALYSIS:"Analysis",VERIFY_DEMONSTRATION:"Demonstration",VERIFY_INSPECTION:"Inspection",VERIFY_TEST:"Test"},Nze={CONTAINS:"contains",COPIES:"copies",DERIVES:"derives",SATISFIES:"satisfies",VERIFIES:"verifies",REFINES:"refines",TRACES:"traces"},Mze=o((t,e)=>(gx.has(t)||gx.set(t,{name:t,type:e,id:Bs.id,text:Bs.text,risk:Bs.risk,verifyMethod:Bs.verifyMethod}),Bs={},gx.get(t)),"addRequirement"),Ize=o(()=>gx,"getRequirements"),Oze=o(t=>{Bs!==void 0&&(Bs.id=t)},"setNewReqId"),Pze=o(t=>{Bs!==void 0&&(Bs.text=t)},"setNewReqText"),Bze=o(t=>{Bs!==void 0&&(Bs.risk=t)},"setNewReqRisk"),Fze=o(t=>{Bs!==void 0&&(Bs.verifyMethod=t)},"setNewReqVerifyMethod"),zze=o(t=>(yx.has(t)||(yx.set(t,{name:t,type:mf.type,docRef:mf.docRef}),V.info("Added new requirement: ",t)),mf={},yx.get(t)),"addElement"),Gze=o(()=>yx,"getElements"),$ze=o(t=>{mf!==void 0&&(mf.type=t)},"setNewElementType"),Vze=o(t=>{mf!==void 0&&(mf.docRef=t)},"setNewElementDocRef"),Uze=o((t,e,r)=>{lO.push({type:t,src:e,dst:r})},"addRelationship"),Hze=o(()=>lO,"getRelationships"),Yze=o(()=>{lO=[],Bs={},gx=new Map,mf={},yx=new Map,vr()},"clear"),Rue={RequirementType:Lze,RiskLevel:Dze,VerifyType:Rze,Relationships:Nze,getConfig:o(()=>de().req,"getConfig"),addRequirement:Mze,getRequirements:Ize,setNewReqId:Oze,setNewReqText:Pze,setNewReqRisk:Bze,setNewReqVerifyMethod:Fze,setAccTitle:kr,getAccTitle:Ar,setAccDescription:_r,getAccDescription:Lr,addElement:zze,getElements:Gze,setNewElementType:$ze,setNewElementDocRef:Vze,addRelationship:Uze,getRelationships:Hze,clear:Yze}});var Wze,Mue,Iue=R(()=>{"use strict";Wze=o(t=>` + + marker { + fill: ${t.relationColor}; + stroke: ${t.relationColor}; + } + + marker.cross { + stroke: ${t.lineColor}; + } + + svg { + font-family: ${t.fontFamily}; + font-size: ${t.fontSize}; + } + + .reqBox { + fill: ${t.requirementBackground}; + fill-opacity: 1.0; + stroke: ${t.requirementBorderColor}; + stroke-width: ${t.requirementBorderSize}; + } + + .reqTitle, .reqLabel{ + fill: ${t.requirementTextColor}; + } + .reqLabelBox { + fill: ${t.relationLabelBackground}; + fill-opacity: 1.0; + } + + .req-title-line { + stroke: ${t.requirementBorderColor}; + stroke-width: ${t.requirementBorderSize}; + } + .relationshipLine { + stroke: ${t.relationColor}; + stroke-width: 1; + } + .relationshipLabel { + fill: ${t.relationLabelColor}; + } + +`,"getStyles"),Mue=Wze});var cO,qze,uO,Oue=R(()=>{"use strict";cO={CONTAINS:"contains",ARROW:"arrow"},qze=o((t,e)=>{let r=t.append("defs").append("marker").attr("id",cO.CONTAINS+"_line_ending").attr("refX",0).attr("refY",e.line_height/2).attr("markerWidth",e.line_height).attr("markerHeight",e.line_height).attr("orient","auto").append("g");r.append("circle").attr("cx",e.line_height/2).attr("cy",e.line_height/2).attr("r",e.line_height/2).attr("fill","none"),r.append("line").attr("x1",0).attr("x2",e.line_height).attr("y1",e.line_height/2).attr("y2",e.line_height/2).attr("stroke-width",1),r.append("line").attr("y1",0).attr("y2",e.line_height).attr("x1",e.line_height/2).attr("x2",e.line_height/2).attr("stroke-width",1),t.append("defs").append("marker").attr("id",cO.ARROW+"_line_ending").attr("refX",e.line_height).attr("refY",.5*e.line_height).attr("markerWidth",e.line_height).attr("markerHeight",e.line_height).attr("orient","auto").append("path").attr("d",`M0,0 + L${e.line_height},${e.line_height/2} + M${e.line_height},${e.line_height/2} + L0,${e.line_height}`).attr("stroke-width",1)},"insertLineEndings"),uO={ReqMarkers:cO,insertLineEndings:qze}});var ai,Pue,Bue,Fue,zue,Xze,jze,Kze,Qze,Zze,Jze,Og,eGe,Gue,$ue=R(()=>{"use strict";Zt();Vd();ya();_t();ut();Yn();rr();Oue();ai={},Pue=0,Bue=o((t,e)=>t.insert("rect","#"+e).attr("class","req reqBox").attr("x",0).attr("y",0).attr("width",ai.rect_min_width+"px").attr("height",ai.rect_min_height+"px"),"newRectNode"),Fue=o((t,e,r)=>{let n=ai.rect_min_width/2,i=t.append("text").attr("class","req reqLabel reqTitle").attr("id",e).attr("x",n).attr("y",ai.rect_padding).attr("dominant-baseline","hanging"),a=0;r.forEach(h=>{a==0?i.append("tspan").attr("text-anchor","middle").attr("x",ai.rect_min_width/2).attr("dy",0).text(h):i.append("tspan").attr("text-anchor","middle").attr("x",ai.rect_min_width/2).attr("dy",ai.line_height*.75).text(h),a++});let s=1.5*ai.rect_padding,l=a*ai.line_height*.75,u=s+l;return t.append("line").attr("class","req-title-line").attr("x1","0").attr("x2",ai.rect_min_width).attr("y1",u).attr("y2",u),{titleNode:i,y:u}},"newTitleNode"),zue=o((t,e,r,n)=>{let i=t.append("text").attr("class","req reqLabel").attr("id",e).attr("x",ai.rect_padding).attr("y",n).attr("dominant-baseline","hanging"),a=0,s=30,l=[];return r.forEach(u=>{let h=u.length;for(;h>s&&a<3;){let f=u.substring(0,s);u=u.substring(s,u.length),h=u.length,l[l.length]=f,a++}if(a==3){let f=l[l.length-1];l[l.length-1]=f.substring(0,f.length-4)+"..."}else l[l.length]=u;a=0}),l.forEach(u=>{i.append("tspan").attr("x",ai.rect_padding).attr("dy",ai.line_height).text(u)}),i},"newBodyNode"),Xze=o((t,e,r,n)=>{let i=e.node().getTotalLength(),a=e.node().getPointAtLength(i*.5),s="rel"+Pue;Pue++;let u=t.append("text").attr("class","req relationshipLabel").attr("id",s).attr("x",a.x).attr("y",a.y).attr("text-anchor","middle").attr("dominant-baseline","middle").text(n).node().getBBox();t.insert("rect","#"+s).attr("class","req reqLabelBox").attr("x",a.x-u.width/2).attr("y",a.y-u.height/2).attr("width",u.width).attr("height",u.height).attr("fill","white").attr("fill-opacity","85%")},"addEdgeLabel"),jze=o(function(t,e,r,n,i){let a=r.edge(Og(e.src),Og(e.dst)),s=ha().x(function(u){return u.x}).y(function(u){return u.y}),l=t.insert("path","#"+n).attr("class","er relationshipLine").attr("d",s(a.points)).attr("fill","none");e.type==i.db.Relationships.CONTAINS?l.attr("marker-start","url("+We.getUrl(ai.arrowMarkerAbsolute)+"#"+e.type+"_line_ending)"):(l.attr("stroke-dasharray","10,7"),l.attr("marker-end","url("+We.getUrl(ai.arrowMarkerAbsolute)+"#"+uO.ReqMarkers.ARROW+"_line_ending)")),Xze(t,l,ai,`<<${e.type}>>`)},"drawRelationshipFromLayout"),Kze=o((t,e,r)=>{t.forEach((n,i)=>{i=Og(i),V.info("Added new requirement: ",i);let a=r.append("g").attr("id",i),s="req-"+i,l=Bue(a,s),u=[],h=Fue(a,i+"_title",[`<<${n.type}>>`,`${n.name}`]);u.push(h.titleNode);let f=zue(a,i+"_body",[`Id: ${n.id}`,`Text: ${n.text}`,`Risk: ${n.risk}`,`Verification: ${n.verifyMethod}`],h.y);u.push(f);let d=l.node().getBBox();e.setNode(i,{width:d.width,height:d.height,shape:"rect",id:i})})},"drawReqs"),Qze=o((t,e,r)=>{t.forEach((n,i)=>{let a=Og(i),s=r.append("g").attr("id",a),l="element-"+a,u=Bue(s,l),h=[],f=Fue(s,l+"_title",["<>",`${i}`]);h.push(f.titleNode);let d=zue(s,l+"_body",[`Type: ${n.type||"Not Specified"}`,`Doc Ref: ${n.docRef||"None"}`],f.y);h.push(d);let p=u.node().getBBox();e.setNode(a,{width:p.width,height:p.height,shape:"rect",id:a})})},"drawElements"),Zze=o((t,e)=>(t.forEach(function(r){let n=Og(r.src),i=Og(r.dst);e.setEdge(n,i,{relationship:r})}),t),"addRelationships"),Jze=o(function(t,e){e.nodes().forEach(function(r){r!==void 0&&e.node(r)!==void 0&&(t.select("#"+r),t.select("#"+r).attr("transform","translate("+(e.node(r).x-e.node(r).width/2)+","+(e.node(r).y-e.node(r).height/2)+" )"))})},"adjustEntities"),Og=o(t=>t.replace(/\s/g,"").replace(/\./g,"_"),"elementString"),eGe=o((t,e,r,n)=>{ai=de().requirement;let i=ai.securityLevel,a;i==="sandbox"&&(a=$e("#i"+e));let l=(i==="sandbox"?$e(a.nodes()[0].contentDocument.body):$e("body")).select(`[id='${e}']`);uO.insertLineEndings(l,ai);let u=new lr({multigraph:!1,compound:!1,directed:!0}).setGraph({rankdir:ai.layoutDirection,marginx:20,marginy:20,nodesep:100,edgesep:100,ranksep:100}).setDefaultEdgeLabel(function(){return{}}),h=n.db.getRequirements(),f=n.db.getElements(),d=n.db.getRelationships();Kze(h,u,l),Qze(f,u,l),Zze(d,u),lo(u),Jze(l,u),d.forEach(function(v){jze(l,v,u,e,n)});let p=ai.rect_padding,m=l.node().getBBox(),g=m.width+p*2,y=m.height+p*2;Sr(l,y,g,ai.useMaxWidth),l.attr("viewBox",`${m.x-p} ${m.y-p} ${g} ${y}`)},"draw"),Gue={draw:eGe}});var Vue={};hr(Vue,{diagram:()=>tGe});var tGe,Uue=R(()=>{"use strict";Due();Nue();Iue();$ue();tGe={parser:Lue,db:Rue,renderer:Gue,styles:Mue}});var hO,Wue,que=R(()=>{"use strict";hO=function(){var t=o(function(H,q,K,se){for(K=K||{},se=H.length;se--;K[H[se]]=q);return K},"o"),e=[1,2],r=[1,3],n=[1,4],i=[2,4],a=[1,9],s=[1,11],l=[1,13],u=[1,14],h=[1,16],f=[1,17],d=[1,18],p=[1,24],m=[1,25],g=[1,26],y=[1,27],v=[1,28],x=[1,29],b=[1,30],w=[1,31],S=[1,32],T=[1,33],E=[1,34],_=[1,35],A=[1,36],L=[1,37],M=[1,38],N=[1,39],k=[1,41],I=[1,42],C=[1,43],O=[1,44],D=[1,45],P=[1,46],F=[1,4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,48,49,50,52,53,54,59,60,61,62,70],B=[4,5,16,50,52,53],$=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],z=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,49,50,52,53,54,59,60,61,62,70],Y=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,48,50,52,53,54,59,60,61,62,70],Q=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,50,52,53,54,59,60,61,62,70],X=[68,69,70],ie=[1,122],j={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,SD:6,document:7,line:8,statement:9,box_section:10,box_line:11,participant_statement:12,create:13,box:14,restOfLine:15,end:16,signal:17,autonumber:18,NUM:19,off:20,activate:21,actor:22,deactivate:23,note_statement:24,links_statement:25,link_statement:26,properties_statement:27,details_statement:28,title:29,legacy_title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,loop:36,rect:37,opt:38,alt:39,else_sections:40,par:41,par_sections:42,par_over:43,critical:44,option_sections:45,break:46,option:47,and:48,else:49,participant:50,AS:51,participant_actor:52,destroy:53,note:54,placement:55,text2:56,over:57,actor_pair:58,links:59,link:60,properties:61,details:62,spaceList:63,",":64,left_of:65,right_of:66,signaltype:67,"+":68,"-":69,ACTOR:70,SOLID_OPEN_ARROW:71,DOTTED_OPEN_ARROW:72,SOLID_ARROW:73,BIDIRECTIONAL_SOLID_ARROW:74,DOTTED_ARROW:75,BIDIRECTIONAL_DOTTED_ARROW:76,SOLID_CROSS:77,DOTTED_CROSS:78,SOLID_POINT:79,DOTTED_POINT:80,TXT:81,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",6:"SD",13:"create",14:"box",15:"restOfLine",16:"end",18:"autonumber",19:"NUM",20:"off",21:"activate",23:"deactivate",29:"title",30:"legacy_title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"loop",37:"rect",38:"opt",39:"alt",41:"par",43:"par_over",44:"critical",46:"break",47:"option",48:"and",49:"else",50:"participant",51:"AS",52:"participant_actor",53:"destroy",54:"note",57:"over",59:"links",60:"link",61:"properties",62:"details",64:",",65:"left_of",66:"right_of",68:"+",69:"-",70:"ACTOR",71:"SOLID_OPEN_ARROW",72:"DOTTED_OPEN_ARROW",73:"SOLID_ARROW",74:"BIDIRECTIONAL_SOLID_ARROW",75:"DOTTED_ARROW",76:"BIDIRECTIONAL_DOTTED_ARROW",77:"SOLID_CROSS",78:"DOTTED_CROSS",79:"SOLID_POINT",80:"DOTTED_POINT",81:"TXT"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[10,0],[10,2],[11,2],[11,1],[11,1],[9,1],[9,2],[9,4],[9,2],[9,4],[9,3],[9,3],[9,2],[9,3],[9,3],[9,2],[9,2],[9,2],[9,2],[9,2],[9,1],[9,1],[9,2],[9,2],[9,1],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[45,1],[45,4],[42,1],[42,4],[40,1],[40,4],[12,5],[12,3],[12,5],[12,3],[12,3],[24,4],[24,4],[25,3],[26,3],[27,3],[28,3],[63,2],[63,1],[58,3],[58,1],[55,1],[55,1],[17,5],[17,5],[17,4],[22,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[56,1]],performAction:o(function(q,K,se,ce,ue,te,De){var oe=te.length-1;switch(ue){case 3:return ce.apply(te[oe]),te[oe];break;case 4:case 9:this.$=[];break;case 5:case 10:te[oe-1].push(te[oe]),this.$=te[oe-1];break;case 6:case 7:case 11:case 12:this.$=te[oe];break;case 8:case 13:this.$=[];break;case 15:te[oe].type="createParticipant",this.$=te[oe];break;case 16:te[oe-1].unshift({type:"boxStart",boxData:ce.parseBoxData(te[oe-2])}),te[oe-1].push({type:"boxEnd",boxText:te[oe-2]}),this.$=te[oe-1];break;case 18:this.$={type:"sequenceIndex",sequenceIndex:Number(te[oe-2]),sequenceIndexStep:Number(te[oe-1]),sequenceVisible:!0,signalType:ce.LINETYPE.AUTONUMBER};break;case 19:this.$={type:"sequenceIndex",sequenceIndex:Number(te[oe-1]),sequenceIndexStep:1,sequenceVisible:!0,signalType:ce.LINETYPE.AUTONUMBER};break;case 20:this.$={type:"sequenceIndex",sequenceVisible:!1,signalType:ce.LINETYPE.AUTONUMBER};break;case 21:this.$={type:"sequenceIndex",sequenceVisible:!0,signalType:ce.LINETYPE.AUTONUMBER};break;case 22:this.$={type:"activeStart",signalType:ce.LINETYPE.ACTIVE_START,actor:te[oe-1].actor};break;case 23:this.$={type:"activeEnd",signalType:ce.LINETYPE.ACTIVE_END,actor:te[oe-1].actor};break;case 29:ce.setDiagramTitle(te[oe].substring(6)),this.$=te[oe].substring(6);break;case 30:ce.setDiagramTitle(te[oe].substring(7)),this.$=te[oe].substring(7);break;case 31:this.$=te[oe].trim(),ce.setAccTitle(this.$);break;case 32:case 33:this.$=te[oe].trim(),ce.setAccDescription(this.$);break;case 34:te[oe-1].unshift({type:"loopStart",loopText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.LOOP_START}),te[oe-1].push({type:"loopEnd",loopText:te[oe-2],signalType:ce.LINETYPE.LOOP_END}),this.$=te[oe-1];break;case 35:te[oe-1].unshift({type:"rectStart",color:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.RECT_START}),te[oe-1].push({type:"rectEnd",color:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.RECT_END}),this.$=te[oe-1];break;case 36:te[oe-1].unshift({type:"optStart",optText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.OPT_START}),te[oe-1].push({type:"optEnd",optText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.OPT_END}),this.$=te[oe-1];break;case 37:te[oe-1].unshift({type:"altStart",altText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.ALT_START}),te[oe-1].push({type:"altEnd",signalType:ce.LINETYPE.ALT_END}),this.$=te[oe-1];break;case 38:te[oe-1].unshift({type:"parStart",parText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.PAR_START}),te[oe-1].push({type:"parEnd",signalType:ce.LINETYPE.PAR_END}),this.$=te[oe-1];break;case 39:te[oe-1].unshift({type:"parStart",parText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.PAR_OVER_START}),te[oe-1].push({type:"parEnd",signalType:ce.LINETYPE.PAR_END}),this.$=te[oe-1];break;case 40:te[oe-1].unshift({type:"criticalStart",criticalText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.CRITICAL_START}),te[oe-1].push({type:"criticalEnd",signalType:ce.LINETYPE.CRITICAL_END}),this.$=te[oe-1];break;case 41:te[oe-1].unshift({type:"breakStart",breakText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.BREAK_START}),te[oe-1].push({type:"breakEnd",optText:ce.parseMessage(te[oe-2]),signalType:ce.LINETYPE.BREAK_END}),this.$=te[oe-1];break;case 43:this.$=te[oe-3].concat([{type:"option",optionText:ce.parseMessage(te[oe-1]),signalType:ce.LINETYPE.CRITICAL_OPTION},te[oe]]);break;case 45:this.$=te[oe-3].concat([{type:"and",parText:ce.parseMessage(te[oe-1]),signalType:ce.LINETYPE.PAR_AND},te[oe]]);break;case 47:this.$=te[oe-3].concat([{type:"else",altText:ce.parseMessage(te[oe-1]),signalType:ce.LINETYPE.ALT_ELSE},te[oe]]);break;case 48:te[oe-3].draw="participant",te[oe-3].type="addParticipant",te[oe-3].description=ce.parseMessage(te[oe-1]),this.$=te[oe-3];break;case 49:te[oe-1].draw="participant",te[oe-1].type="addParticipant",this.$=te[oe-1];break;case 50:te[oe-3].draw="actor",te[oe-3].type="addParticipant",te[oe-3].description=ce.parseMessage(te[oe-1]),this.$=te[oe-3];break;case 51:te[oe-1].draw="actor",te[oe-1].type="addParticipant",this.$=te[oe-1];break;case 52:te[oe-1].type="destroyParticipant",this.$=te[oe-1];break;case 53:this.$=[te[oe-1],{type:"addNote",placement:te[oe-2],actor:te[oe-1].actor,text:te[oe]}];break;case 54:te[oe-2]=[].concat(te[oe-1],te[oe-1]).slice(0,2),te[oe-2][0]=te[oe-2][0].actor,te[oe-2][1]=te[oe-2][1].actor,this.$=[te[oe-1],{type:"addNote",placement:ce.PLACEMENT.OVER,actor:te[oe-2].slice(0,2),text:te[oe]}];break;case 55:this.$=[te[oe-1],{type:"addLinks",actor:te[oe-1].actor,text:te[oe]}];break;case 56:this.$=[te[oe-1],{type:"addALink",actor:te[oe-1].actor,text:te[oe]}];break;case 57:this.$=[te[oe-1],{type:"addProperties",actor:te[oe-1].actor,text:te[oe]}];break;case 58:this.$=[te[oe-1],{type:"addDetails",actor:te[oe-1].actor,text:te[oe]}];break;case 61:this.$=[te[oe-2],te[oe]];break;case 62:this.$=te[oe];break;case 63:this.$=ce.PLACEMENT.LEFTOF;break;case 64:this.$=ce.PLACEMENT.RIGHTOF;break;case 65:this.$=[te[oe-4],te[oe-1],{type:"addMessage",from:te[oe-4].actor,to:te[oe-1].actor,signalType:te[oe-3],msg:te[oe],activate:!0},{type:"activeStart",signalType:ce.LINETYPE.ACTIVE_START,actor:te[oe-1].actor}];break;case 66:this.$=[te[oe-4],te[oe-1],{type:"addMessage",from:te[oe-4].actor,to:te[oe-1].actor,signalType:te[oe-3],msg:te[oe]},{type:"activeEnd",signalType:ce.LINETYPE.ACTIVE_END,actor:te[oe-4].actor}];break;case 67:this.$=[te[oe-3],te[oe-1],{type:"addMessage",from:te[oe-3].actor,to:te[oe-1].actor,signalType:te[oe-2],msg:te[oe]}];break;case 68:this.$={type:"addParticipant",actor:te[oe]};break;case 69:this.$=ce.LINETYPE.SOLID_OPEN;break;case 70:this.$=ce.LINETYPE.DOTTED_OPEN;break;case 71:this.$=ce.LINETYPE.SOLID;break;case 72:this.$=ce.LINETYPE.BIDIRECTIONAL_SOLID;break;case 73:this.$=ce.LINETYPE.DOTTED;break;case 74:this.$=ce.LINETYPE.BIDIRECTIONAL_DOTTED;break;case 75:this.$=ce.LINETYPE.SOLID_CROSS;break;case 76:this.$=ce.LINETYPE.DOTTED_CROSS;break;case 77:this.$=ce.LINETYPE.SOLID_POINT;break;case 78:this.$=ce.LINETYPE.DOTTED_POINT;break;case 79:this.$=ce.parseMessage(te[oe].trim().substring(1));break}},"anonymous"),table:[{3:1,4:e,5:r,6:n},{1:[3]},{3:5,4:e,5:r,6:n},{3:6,4:e,5:r,6:n},t([1,4,5,13,14,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],i,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:a,5:s,8:8,9:10,12:12,13:l,14:u,17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},t(F,[2,5]),{9:47,12:12,13:l,14:u,17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},t(F,[2,7]),t(F,[2,8]),t(F,[2,14]),{12:48,50:L,52:M,53:N},{15:[1,49]},{5:[1,50]},{5:[1,53],19:[1,51],20:[1,52]},{22:54,70:P},{22:55,70:P},{5:[1,56]},{5:[1,57]},{5:[1,58]},{5:[1,59]},{5:[1,60]},t(F,[2,29]),t(F,[2,30]),{32:[1,61]},{34:[1,62]},t(F,[2,33]),{15:[1,63]},{15:[1,64]},{15:[1,65]},{15:[1,66]},{15:[1,67]},{15:[1,68]},{15:[1,69]},{15:[1,70]},{22:71,70:P},{22:72,70:P},{22:73,70:P},{67:74,71:[1,75],72:[1,76],73:[1,77],74:[1,78],75:[1,79],76:[1,80],77:[1,81],78:[1,82],79:[1,83],80:[1,84]},{55:85,57:[1,86],65:[1,87],66:[1,88]},{22:89,70:P},{22:90,70:P},{22:91,70:P},{22:92,70:P},t([5,51,64,71,72,73,74,75,76,77,78,79,80,81],[2,68]),t(F,[2,6]),t(F,[2,15]),t(B,[2,9],{10:93}),t(F,[2,17]),{5:[1,95],19:[1,94]},{5:[1,96]},t(F,[2,21]),{5:[1,97]},{5:[1,98]},t(F,[2,24]),t(F,[2,25]),t(F,[2,26]),t(F,[2,27]),t(F,[2,28]),t(F,[2,31]),t(F,[2,32]),t($,i,{7:99}),t($,i,{7:100}),t($,i,{7:101}),t(z,i,{40:102,7:103}),t(Y,i,{42:104,7:105}),t(Y,i,{7:105,42:106}),t(Q,i,{45:107,7:108}),t($,i,{7:109}),{5:[1,111],51:[1,110]},{5:[1,113],51:[1,112]},{5:[1,114]},{22:117,68:[1,115],69:[1,116],70:P},t(X,[2,69]),t(X,[2,70]),t(X,[2,71]),t(X,[2,72]),t(X,[2,73]),t(X,[2,74]),t(X,[2,75]),t(X,[2,76]),t(X,[2,77]),t(X,[2,78]),{22:118,70:P},{22:120,58:119,70:P},{70:[2,63]},{70:[2,64]},{56:121,81:ie},{56:123,81:ie},{56:124,81:ie},{56:125,81:ie},{4:[1,128],5:[1,130],11:127,12:129,16:[1,126],50:L,52:M,53:N},{5:[1,131]},t(F,[2,19]),t(F,[2,20]),t(F,[2,22]),t(F,[2,23]),{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[1,132],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[1,133],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[1,134],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{16:[1,135]},{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[2,46],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,49:[1,136],50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{16:[1,137]},{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[2,44],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,48:[1,138],50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{16:[1,139]},{16:[1,140]},{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[2,42],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,47:[1,141],50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{4:a,5:s,8:8,9:10,12:12,13:l,14:u,16:[1,142],17:15,18:h,21:f,22:40,23:d,24:19,25:20,26:21,27:22,28:23,29:p,30:m,31:g,33:y,35:v,36:x,37:b,38:w,39:S,41:T,43:E,44:_,46:A,50:L,52:M,53:N,54:k,59:I,60:C,61:O,62:D,70:P},{15:[1,143]},t(F,[2,49]),{15:[1,144]},t(F,[2,51]),t(F,[2,52]),{22:145,70:P},{22:146,70:P},{56:147,81:ie},{56:148,81:ie},{56:149,81:ie},{64:[1,150],81:[2,62]},{5:[2,55]},{5:[2,79]},{5:[2,56]},{5:[2,57]},{5:[2,58]},t(F,[2,16]),t(B,[2,10]),{12:151,50:L,52:M,53:N},t(B,[2,12]),t(B,[2,13]),t(F,[2,18]),t(F,[2,34]),t(F,[2,35]),t(F,[2,36]),t(F,[2,37]),{15:[1,152]},t(F,[2,38]),{15:[1,153]},t(F,[2,39]),t(F,[2,40]),{15:[1,154]},t(F,[2,41]),{5:[1,155]},{5:[1,156]},{56:157,81:ie},{56:158,81:ie},{5:[2,67]},{5:[2,53]},{5:[2,54]},{22:159,70:P},t(B,[2,11]),t(z,i,{7:103,40:160}),t(Y,i,{7:105,42:161}),t(Q,i,{7:108,45:162}),t(F,[2,48]),t(F,[2,50]),{5:[2,65]},{5:[2,66]},{81:[2,61]},{16:[2,47]},{16:[2,45]},{16:[2,43]}],defaultActions:{5:[2,1],6:[2,2],87:[2,63],88:[2,64],121:[2,55],122:[2,79],123:[2,56],124:[2,57],125:[2,58],147:[2,67],148:[2,53],149:[2,54],157:[2,65],158:[2,66],159:[2,61],160:[2,47],161:[2,45],162:[2,43]},parseError:o(function(q,K){if(K.recoverable)this.trace(q);else{var se=new Error(q);throw se.hash=K,se}},"parseError"),parse:o(function(q){var K=this,se=[0],ce=[],ue=[null],te=[],De=this.table,oe="",ke=0,Ie=0,Se=0,Ue=2,Pe=1,_e=te.slice.call(arguments,1),me=Object.create(this.lexer),W={yy:{}};for(var fe in this.yy)Object.prototype.hasOwnProperty.call(this.yy,fe)&&(W.yy[fe]=this.yy[fe]);me.setInput(q,W.yy),W.yy.lexer=me,W.yy.parser=this,typeof me.yylloc>"u"&&(me.yylloc={});var ge=me.yylloc;te.push(ge);var re=me.options&&me.options.ranges;typeof W.yy.parseError=="function"?this.parseError=W.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function he(yt){se.length=se.length-2*yt,ue.length=ue.length-yt,te.length=te.length-yt}o(he,"popStack");function ne(){var yt;return yt=ce.pop()||me.lex()||Pe,typeof yt!="number"&&(yt instanceof Array&&(ce=yt,yt=ce.pop()),yt=K.symbols_[yt]||yt),yt}o(ne,"lex");for(var ae,we,Te,Ce,Ae,Ge,Me={},ye,He,ze,Ze;;){if(Te=se[se.length-1],this.defaultActions[Te]?Ce=this.defaultActions[Te]:((ae===null||typeof ae>"u")&&(ae=ne()),Ce=De[Te]&&De[Te][ae]),typeof Ce>"u"||!Ce.length||!Ce[0]){var gt="";Ze=[];for(ye in De[Te])this.terminals_[ye]&&ye>Ue&&Ze.push("'"+this.terminals_[ye]+"'");me.showPosition?gt="Parse error on line "+(ke+1)+`: +`+me.showPosition()+` +Expecting `+Ze.join(", ")+", got '"+(this.terminals_[ae]||ae)+"'":gt="Parse error on line "+(ke+1)+": Unexpected "+(ae==Pe?"end of input":"'"+(this.terminals_[ae]||ae)+"'"),this.parseError(gt,{text:me.match,token:this.terminals_[ae]||ae,line:me.yylineno,loc:ge,expected:Ze})}if(Ce[0]instanceof Array&&Ce.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Te+", token: "+ae);switch(Ce[0]){case 1:se.push(ae),ue.push(me.yytext),te.push(me.yylloc),se.push(Ce[1]),ae=null,we?(ae=we,we=null):(Ie=me.yyleng,oe=me.yytext,ke=me.yylineno,ge=me.yylloc,Se>0&&Se--);break;case 2:if(He=this.productions_[Ce[1]][1],Me.$=ue[ue.length-He],Me._$={first_line:te[te.length-(He||1)].first_line,last_line:te[te.length-1].last_line,first_column:te[te.length-(He||1)].first_column,last_column:te[te.length-1].last_column},re&&(Me._$.range=[te[te.length-(He||1)].range[0],te[te.length-1].range[1]]),Ge=this.performAction.apply(Me,[oe,Ie,ke,W.yy,Ce[1],ue,te].concat(_e)),typeof Ge<"u")return Ge;He&&(se=se.slice(0,-1*He*2),ue=ue.slice(0,-1*He),te=te.slice(0,-1*He)),se.push(this.productions_[Ce[1]][0]),ue.push(Me.$),te.push(Me._$),ze=De[se[se.length-2]][se[se.length-1]],se.push(ze);break;case 3:return!0}}return!0},"parse")},J=function(){var H={EOF:1,parseError:o(function(K,se){if(this.yy.parser)this.yy.parser.parseError(K,se);else throw new Error(K)},"parseError"),setInput:o(function(q,K){return this.yy=K||this.yy||{},this._input=q,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var q=this._input[0];this.yytext+=q,this.yyleng++,this.offset++,this.match+=q,this.matched+=q;var K=q.match(/(?:\r\n?|\n).*/g);return K?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),q},"input"),unput:o(function(q){var K=q.length,se=q.split(/(?:\r\n?|\n)/g);this._input=q+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-K),this.offset-=K;var ce=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),se.length-1&&(this.yylineno-=se.length-1);var ue=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:se?(se.length===ce.length?this.yylloc.first_column:0)+ce[ce.length-se.length].length-se[0].length:this.yylloc.first_column-K},this.options.ranges&&(this.yylloc.range=[ue[0],ue[0]+this.yyleng-K]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(q){this.unput(this.match.slice(q))},"less"),pastInput:o(function(){var q=this.matched.substr(0,this.matched.length-this.match.length);return(q.length>20?"...":"")+q.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var q=this.match;return q.length<20&&(q+=this._input.substr(0,20-q.length)),(q.substr(0,20)+(q.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var q=this.pastInput(),K=new Array(q.length+1).join("-");return q+this.upcomingInput()+` +`+K+"^"},"showPosition"),test_match:o(function(q,K){var se,ce,ue;if(this.options.backtrack_lexer&&(ue={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(ue.yylloc.range=this.yylloc.range.slice(0))),ce=q[0].match(/(?:\r\n?|\n).*/g),ce&&(this.yylineno+=ce.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:ce?ce[ce.length-1].length-ce[ce.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+q[0].length},this.yytext+=q[0],this.match+=q[0],this.matches=q,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(q[0].length),this.matched+=q[0],se=this.performAction.call(this,this.yy,this,K,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),se)return se;if(this._backtrack){for(var te in ue)this[te]=ue[te];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var q,K,se,ce;this._more||(this.yytext="",this.match="");for(var ue=this._currentRules(),te=0;teK[0].length)){if(K=se,ce=te,this.options.backtrack_lexer){if(q=this.test_match(se,ue[te]),q!==!1)return q;if(this._backtrack){K=!1;continue}else return!1}else if(!this.options.flex)break}return K?(q=this.test_match(K,ue[ce]),q!==!1?q:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var K=this.next();return K||this.lex()},"lex"),begin:o(function(K){this.conditionStack.push(K)},"begin"),popState:o(function(){var K=this.conditionStack.length-1;return K>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(K){return K=this.conditionStack.length-1-Math.abs(K||0),K>=0?this.conditionStack[K]:"INITIAL"},"topState"),pushState:o(function(K){this.begin(K)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(K,se,ce,ue){var te=ue;switch(ce){case 0:return 5;case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:return 19;case 7:return this.begin("LINE"),14;break;case 8:return this.begin("ID"),50;break;case 9:return this.begin("ID"),52;break;case 10:return 13;case 11:return this.begin("ID"),53;break;case 12:return se.yytext=se.yytext.trim(),this.begin("ALIAS"),70;break;case 13:return this.popState(),this.popState(),this.begin("LINE"),51;break;case 14:return this.popState(),this.popState(),5;break;case 15:return this.begin("LINE"),36;break;case 16:return this.begin("LINE"),37;break;case 17:return this.begin("LINE"),38;break;case 18:return this.begin("LINE"),39;break;case 19:return this.begin("LINE"),49;break;case 20:return this.begin("LINE"),41;break;case 21:return this.begin("LINE"),43;break;case 22:return this.begin("LINE"),48;break;case 23:return this.begin("LINE"),44;break;case 24:return this.begin("LINE"),47;break;case 25:return this.begin("LINE"),46;break;case 26:return this.popState(),15;break;case 27:return 16;case 28:return 65;case 29:return 66;case 30:return 59;case 31:return 60;case 32:return 61;case 33:return 62;case 34:return 57;case 35:return 54;case 36:return this.begin("ID"),21;break;case 37:return this.begin("ID"),23;break;case 38:return 29;case 39:return 30;case 40:return this.begin("acc_title"),31;break;case 41:return this.popState(),"acc_title_value";break;case 42:return this.begin("acc_descr"),33;break;case 43:return this.popState(),"acc_descr_value";break;case 44:this.begin("acc_descr_multiline");break;case 45:this.popState();break;case 46:return"acc_descr_multiline_value";case 47:return 6;case 48:return 18;case 49:return 20;case 50:return 64;case 51:return 5;case 52:return se.yytext=se.yytext.trim(),70;break;case 53:return 73;case 54:return 74;case 55:return 75;case 56:return 76;case 57:return 71;case 58:return 72;case 59:return 77;case 60:return 78;case 61:return 79;case 62:return 80;case 63:return 81;case 64:return 68;case 65:return 69;case 66:return 5;case 67:return"INVALID"}},"anonymous"),rules:[/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[0-9]+(?=[ \n]+))/i,/^(?:box\b)/i,/^(?:participant\b)/i,/^(?:actor\b)/i,/^(?:create\b)/i,/^(?:destroy\b)/i,/^(?:[^\<->\->:\n,;]+?([\-]*[^\<->\->:\n,;]+?)*?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:par_over\b)/i,/^(?:and\b)/i,/^(?:critical\b)/i,/^(?:option\b)/i,/^(?:break\b)/i,/^(?:(?:[:]?(?:no)?wrap)?[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:links\b)/i,/^(?:link\b)/i,/^(?:properties\b)/i,/^(?:details\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:title:\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:sequenceDiagram\b)/i,/^(?:autonumber\b)/i,/^(?:off\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\<->\->:\n,;]+((?!(-x|--x|-\)|--\)))[\-]*[^\+\<->\->:\n,;]+)*)/i,/^(?:->>)/i,/^(?:<<->>)/i,/^(?:-->>)/i,/^(?:<<-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?:-[\)])/i,/^(?:--[\)])/i,/^(?::(?:(?:no)?wrap)?[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[45,46],inclusive:!1},acc_descr:{rules:[43],inclusive:!1},acc_title:{rules:[41],inclusive:!1},ID:{rules:[2,3,12],inclusive:!1},ALIAS:{rules:[2,3,13,14],inclusive:!1},LINE:{rules:[2,3,26],inclusive:!1},INITIAL:{rules:[0,1,3,4,5,6,7,8,9,10,11,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,42,44,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67],inclusive:!0}}};return H}();j.lexer=J;function Z(){this.yy={}}return o(Z,"Parser"),Z.prototype=j,j.Parser=Z,new Z}();hO.parser=hO;Wue=hO});function dO(t,e){if(t.links==null)t.links=e;else for(let r in e)t.links[r]=e[r]}function Zue(t,e){if(t.properties==null)t.properties=e;else for(let r in e)t.properties[r]=e[r]}function SGe(){Mt.records.currentBox=void 0}var Mt,aGe,fO,sGe,oGe,pi,lGe,cGe,uGe,hGe,fGe,dGe,pGe,xx,mGe,gGe,yGe,vGe,xGe,Xue,A0,bGe,wGe,TGe,vx,kGe,EGe,jue,Kue,CGe,Que,Jue,AGe,ehe,pO,the=R(()=>{"use strict";_t();ut();Jk();rr();bi();Mt=new uf(()=>({prevActor:void 0,actors:new Map,createdActors:new Map,destroyedActors:new Map,boxes:[],messages:[],notes:[],sequenceNumbersEnabled:!1,wrapEnabled:void 0,currentBox:void 0,lastCreated:void 0,lastDestroyed:void 0})),aGe=o(function(t){Mt.records.boxes.push({name:t.text,wrap:t.wrap??A0(),fill:t.color,actorKeys:[]}),Mt.records.currentBox=Mt.records.boxes.slice(-1)[0]},"addBox"),fO=o(function(t,e,r,n){let i=Mt.records.currentBox,a=Mt.records.actors.get(t);if(a){if(Mt.records.currentBox&&a.box&&Mt.records.currentBox!==a.box)throw new Error(`A same participant should only be defined in one Box: ${a.name} can't be in '${a.box.name}' and in '${Mt.records.currentBox.name}' at the same time.`);if(i=a.box?a.box:Mt.records.currentBox,a.box=i,a&&e===a.name&&r==null)return}if(r?.text==null&&(r={text:e,type:n}),(n==null||r.text==null)&&(r={text:e,type:n}),Mt.records.actors.set(t,{box:i,name:e,description:r.text,wrap:r.wrap??A0(),prevActor:Mt.records.prevActor,links:{},properties:{},actorCnt:null,rectData:null,type:n??"participant"}),Mt.records.prevActor){let s=Mt.records.actors.get(Mt.records.prevActor);s&&(s.nextActor=t)}Mt.records.currentBox&&Mt.records.currentBox.actorKeys.push(t),Mt.records.prevActor=t},"addActor"),sGe=o(t=>{let e,r=0;if(!t)return 0;for(e=0;e>-",token:"->>-",line:"1",loc:{first_line:1,last_line:1,first_column:1,last_column:1},expected:["'ACTIVE_PARTICIPANT'"]},s}return Mt.records.messages.push({from:t,to:e,message:r?.text??"",wrap:r?.wrap??A0(),type:n,activate:i}),!0},"addSignal"),lGe=o(function(){return Mt.records.boxes.length>0},"hasAtLeastOneBox"),cGe=o(function(){return Mt.records.boxes.some(t=>t.name)},"hasAtLeastOneBoxWithTitle"),uGe=o(function(){return Mt.records.messages},"getMessages"),hGe=o(function(){return Mt.records.boxes},"getBoxes"),fGe=o(function(){return Mt.records.actors},"getActors"),dGe=o(function(){return Mt.records.createdActors},"getCreatedActors"),pGe=o(function(){return Mt.records.destroyedActors},"getDestroyedActors"),xx=o(function(t){return Mt.records.actors.get(t)},"getActor"),mGe=o(function(){return[...Mt.records.actors.keys()]},"getActorKeys"),gGe=o(function(){Mt.records.sequenceNumbersEnabled=!0},"enableSequenceNumbers"),yGe=o(function(){Mt.records.sequenceNumbersEnabled=!1},"disableSequenceNumbers"),vGe=o(()=>Mt.records.sequenceNumbersEnabled,"showSequenceNumbers"),xGe=o(function(t){Mt.records.wrapEnabled=t},"setWrap"),Xue=o(t=>{if(t===void 0)return{};t=t.trim();let e=/^:?wrap:/.exec(t)!==null?!0:/^:?nowrap:/.exec(t)!==null?!1:void 0;return{cleanedText:(e===void 0?t:t.replace(/^:?(?:no)?wrap:/,"")).trim(),wrap:e}},"extractWrap"),A0=o(()=>Mt.records.wrapEnabled!==void 0?Mt.records.wrapEnabled:de().sequence?.wrap??!1,"autoWrap"),bGe=o(function(){Mt.reset(),vr()},"clear"),wGe=o(function(t){let e=t.trim(),{wrap:r,cleanedText:n}=Xue(e),i={text:n,wrap:r};return V.debug(`parseMessage: ${JSON.stringify(i)}`),i},"parseMessage"),TGe=o(function(t){let e=/^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/.exec(t),r=e?.[1]?e[1].trim():"transparent",n=e?.[2]?e[2].trim():void 0;if(window?.CSS)window.CSS.supports("color",r)||(r="transparent",n=t.trim());else{let s=new Option().style;s.color=r,s.color!==r&&(r="transparent",n=t.trim())}let{wrap:i,cleanedText:a}=Xue(n);return{text:a?qr(a,de()):void 0,color:r,wrap:i}},"parseBoxData"),vx={SOLID:0,DOTTED:1,NOTE:2,SOLID_CROSS:3,DOTTED_CROSS:4,SOLID_OPEN:5,DOTTED_OPEN:6,LOOP_START:10,LOOP_END:11,ALT_START:12,ALT_ELSE:13,ALT_END:14,OPT_START:15,OPT_END:16,ACTIVE_START:17,ACTIVE_END:18,PAR_START:19,PAR_AND:20,PAR_END:21,RECT_START:22,RECT_END:23,SOLID_POINT:24,DOTTED_POINT:25,AUTONUMBER:26,CRITICAL_START:27,CRITICAL_OPTION:28,CRITICAL_END:29,BREAK_START:30,BREAK_END:31,PAR_OVER_START:32,BIDIRECTIONAL_SOLID:33,BIDIRECTIONAL_DOTTED:34},kGe={FILLED:0,OPEN:1},EGe={LEFTOF:0,RIGHTOF:1,OVER:2},jue=o(function(t,e,r){let n={actor:t,placement:e,message:r.text,wrap:r.wrap??A0()},i=[].concat(t,t);Mt.records.notes.push(n),Mt.records.messages.push({from:i[0],to:i[1],message:r.text,wrap:r.wrap??A0(),type:vx.NOTE,placement:e})},"addNote"),Kue=o(function(t,e){let r=xx(t);try{let n=qr(e.text,de());n=n.replace(/&/g,"&"),n=n.replace(/=/g,"=");let i=JSON.parse(n);dO(r,i)}catch(n){V.error("error while parsing actor link text",n)}},"addLinks"),CGe=o(function(t,e){let r=xx(t);try{let n={},i=qr(e.text,de()),a=i.indexOf("@");i=i.replace(/&/g,"&"),i=i.replace(/=/g,"=");let s=i.slice(0,a-1).trim(),l=i.slice(a+1).trim();n[s]=l,dO(r,n)}catch(n){V.error("error while parsing actor link text",n)}},"addALink");o(dO,"insertLinks");Que=o(function(t,e){let r=xx(t);try{let n=qr(e.text,de()),i=JSON.parse(n);Zue(r,i)}catch(n){V.error("error while parsing actor properties text",n)}},"addProperties");o(Zue,"insertProperties");o(SGe,"boxEnd");Jue=o(function(t,e){let r=xx(t),n=document.getElementById(e.text);try{let i=n.innerHTML,a=JSON.parse(i);a.properties&&Zue(r,a.properties),a.links&&dO(r,a.links)}catch(i){V.error("error while parsing actor details text",i)}},"addDetails"),AGe=o(function(t,e){if(t?.properties!==void 0)return t.properties[e]},"getActorProperty"),ehe=o(function(t){if(Array.isArray(t))t.forEach(function(e){ehe(e)});else switch(t.type){case"sequenceIndex":Mt.records.messages.push({from:void 0,to:void 0,message:{start:t.sequenceIndex,step:t.sequenceIndexStep,visible:t.sequenceVisible},wrap:!1,type:t.signalType});break;case"addParticipant":fO(t.actor,t.actor,t.description,t.draw);break;case"createParticipant":if(Mt.records.actors.has(t.actor))throw new Error("It is not possible to have actors with the same id, even if one is destroyed before the next is created. Use 'AS' aliases to simulate the behavior");Mt.records.lastCreated=t.actor,fO(t.actor,t.actor,t.description,t.draw),Mt.records.createdActors.set(t.actor,Mt.records.messages.length);break;case"destroyParticipant":Mt.records.lastDestroyed=t.actor,Mt.records.destroyedActors.set(t.actor,Mt.records.messages.length);break;case"activeStart":pi(t.actor,void 0,void 0,t.signalType);break;case"activeEnd":pi(t.actor,void 0,void 0,t.signalType);break;case"addNote":jue(t.actor,t.placement,t.text);break;case"addLinks":Kue(t.actor,t.text);break;case"addALink":CGe(t.actor,t.text);break;case"addProperties":Que(t.actor,t.text);break;case"addDetails":Jue(t.actor,t.text);break;case"addMessage":if(Mt.records.lastCreated){if(t.to!==Mt.records.lastCreated)throw new Error("The created participant "+Mt.records.lastCreated.name+" does not have an associated creating message after its declaration. Please check the sequence diagram.");Mt.records.lastCreated=void 0}else if(Mt.records.lastDestroyed){if(t.to!==Mt.records.lastDestroyed&&t.from!==Mt.records.lastDestroyed)throw new Error("The destroyed participant "+Mt.records.lastDestroyed.name+" does not have an associated destroying message after its declaration. Please check the sequence diagram.");Mt.records.lastDestroyed=void 0}pi(t.from,t.to,t.msg,t.signalType,t.activate);break;case"boxStart":aGe(t.boxData);break;case"boxEnd":SGe();break;case"loopStart":pi(void 0,void 0,t.loopText,t.signalType);break;case"loopEnd":pi(void 0,void 0,void 0,t.signalType);break;case"rectStart":pi(void 0,void 0,t.color,t.signalType);break;case"rectEnd":pi(void 0,void 0,void 0,t.signalType);break;case"optStart":pi(void 0,void 0,t.optText,t.signalType);break;case"optEnd":pi(void 0,void 0,void 0,t.signalType);break;case"altStart":pi(void 0,void 0,t.altText,t.signalType);break;case"else":pi(void 0,void 0,t.altText,t.signalType);break;case"altEnd":pi(void 0,void 0,void 0,t.signalType);break;case"setAccTitle":kr(t.text);break;case"parStart":pi(void 0,void 0,t.parText,t.signalType);break;case"and":pi(void 0,void 0,t.parText,t.signalType);break;case"parEnd":pi(void 0,void 0,void 0,t.signalType);break;case"criticalStart":pi(void 0,void 0,t.criticalText,t.signalType);break;case"option":pi(void 0,void 0,t.optionText,t.signalType);break;case"criticalEnd":pi(void 0,void 0,void 0,t.signalType);break;case"breakStart":pi(void 0,void 0,t.breakText,t.signalType);break;case"breakEnd":pi(void 0,void 0,void 0,t.signalType);break}},"apply"),pO={addActor:fO,addMessage:oGe,addSignal:pi,addLinks:Kue,addDetails:Jue,addProperties:Que,autoWrap:A0,setWrap:xGe,enableSequenceNumbers:gGe,disableSequenceNumbers:yGe,showSequenceNumbers:vGe,getMessages:uGe,getActors:fGe,getCreatedActors:dGe,getDestroyedActors:pGe,getActor:xx,getActorKeys:mGe,getActorProperty:AGe,getAccTitle:Ar,getBoxes:hGe,getDiagramTitle:Xr,setDiagramTitle:nn,getConfig:o(()=>de().sequence,"getConfig"),clear:bGe,parseMessage:wGe,parseBoxData:TGe,LINETYPE:vx,ARROWTYPE:kGe,PLACEMENT:EGe,addNote:jue,setAccTitle:kr,apply:ehe,setAccDescription:_r,getAccDescription:Lr,hasAtLeastOneBox:lGe,hasAtLeastOneBoxWithTitle:cGe}});var _Ge,rhe,nhe=R(()=>{"use strict";_Ge=o(t=>`.actor { + stroke: ${t.actorBorder}; + fill: ${t.actorBkg}; + } + + text.actor > tspan { + fill: ${t.actorTextColor}; + stroke: none; + } + + .actor-line { + stroke: ${t.actorLineColor}; + } + + .messageLine0 { + stroke-width: 1.5; + stroke-dasharray: none; + stroke: ${t.signalColor}; + } + + .messageLine1 { + stroke-width: 1.5; + stroke-dasharray: 2, 2; + stroke: ${t.signalColor}; + } + + #arrowhead path { + fill: ${t.signalColor}; + stroke: ${t.signalColor}; + } + + .sequenceNumber { + fill: ${t.sequenceNumberColor}; + } + + #sequencenumber { + fill: ${t.signalColor}; + } + + #crosshead path { + fill: ${t.signalColor}; + stroke: ${t.signalColor}; + } + + .messageText { + fill: ${t.signalTextColor}; + stroke: none; + } + + .labelBox { + stroke: ${t.labelBoxBorderColor}; + fill: ${t.labelBoxBkgColor}; + } + + .labelText, .labelText > tspan { + fill: ${t.labelTextColor}; + stroke: none; + } + + .loopText, .loopText > tspan { + fill: ${t.loopTextColor}; + stroke: none; + } + + .loopLine { + stroke-width: 2px; + stroke-dasharray: 2, 2; + stroke: ${t.labelBoxBorderColor}; + fill: ${t.labelBoxBorderColor}; + } + + .note { + //stroke: #decc93; + stroke: ${t.noteBorderColor}; + fill: ${t.noteBkgColor}; + } + + .noteText, .noteText > tspan { + fill: ${t.noteTextColor}; + stroke: none; + } + + .activation0 { + fill: ${t.activationBkgColor}; + stroke: ${t.activationBorderColor}; + } + + .activation1 { + fill: ${t.activationBkgColor}; + stroke: ${t.activationBorderColor}; + } + + .activation2 { + fill: ${t.activationBkgColor}; + stroke: ${t.activationBorderColor}; + } + + .actorPopupMenu { + position: absolute; + } + + .actorPopupMenuPanel { + position: absolute; + fill: ${t.actorBkg}; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4)); +} + .actor-man line { + stroke: ${t.actorBorder}; + fill: ${t.actorBkg}; + } + .actor-man circle, line { + stroke: ${t.actorBorder}; + fill: ${t.actorBkg}; + stroke-width: 2px; + } +`,"getStyles"),rhe=_Ge});var mO,gf,ahe,she,LGe,ihe,gO,DGe,RGe,bx,_0,ohe,Bc,yO,NGe,MGe,IGe,OGe,PGe,BGe,FGe,lhe,zGe,GGe,$Ge,VGe,UGe,HGe,YGe,che,WGe,vO,qGe,si,uhe=R(()=>{"use strict";rr();Qy();xr();mO=Xi(Up(),1);qs();gf=18*2,ahe="actor-top",she="actor-bottom",LGe="actor-box",ihe="actor-man",gO=o(function(t,e){return yd(t,e)},"drawRect"),DGe=o(function(t,e,r,n,i){if(e.links===void 0||e.links===null||Object.keys(e.links).length===0)return{height:0,width:0};let a=e.links,s=e.actorCnt,l=e.rectData;var u="none";i&&(u="block !important");let h=t.append("g");h.attr("id","actor"+s+"_popup"),h.attr("class","actorPopupMenu"),h.attr("display",u);var f="";l.class!==void 0&&(f=" "+l.class);let d=l.width>r?l.width:r,p=h.append("rect");if(p.attr("class","actorPopupMenuPanel"+f),p.attr("x",l.x),p.attr("y",l.height),p.attr("fill",l.fill),p.attr("stroke",l.stroke),p.attr("width",d),p.attr("height",l.height),p.attr("rx",l.rx),p.attr("ry",l.ry),a!=null){var m=20;for(let v in a){var g=h.append("a"),y=(0,mO.sanitizeUrl)(a[v]);g.attr("xlink:href",y),g.attr("target","_blank"),qGe(n)(v,g,l.x+10,l.height+m,d,20,{class:"actor"},n),m+=30}}return p.attr("height",m),{height:l.height+m,width:d}},"drawPopup"),RGe=o(function(t){return"var pu = document.getElementById('"+t+"'); if (pu != null) { pu.style.display = pu.style.display == 'block' ? 'none' : 'block'; }"},"popupMenuToggle"),bx=o(async function(t,e,r=null){let n=t.append("foreignObject"),i=await yh(e.text,Or()),s=n.append("xhtml:div").attr("style","width: fit-content;").attr("xmlns","http://www.w3.org/1999/xhtml").html(i).node().getBoundingClientRect();if(n.attr("height",Math.round(s.height)).attr("width",Math.round(s.width)),e.class==="noteText"){let l=t.node().firstChild;l.setAttribute("height",s.height+2*e.textMargin);let u=l.getBBox();n.attr("x",Math.round(u.x+u.width/2-s.width/2)).attr("y",Math.round(u.y+u.height/2-s.height/2))}else if(r){let{startx:l,stopx:u,starty:h}=r;if(l>u){let f=l;l=u,u=f}n.attr("x",Math.round(l+Math.abs(l-u)/2-s.width/2)),e.class==="loopText"?n.attr("y",Math.round(h)):n.attr("y",Math.round(h-s.height))}return[n]},"drawKatex"),_0=o(function(t,e){let r=0,n=0,i=e.text.split(We.lineBreakRegex),[a,s]=mc(e.fontSize),l=[],u=0,h=o(()=>e.y,"yfunc");if(e.valign!==void 0&&e.textMargin!==void 0&&e.textMargin>0)switch(e.valign){case"top":case"start":h=o(()=>Math.round(e.y+e.textMargin),"yfunc");break;case"middle":case"center":h=o(()=>Math.round(e.y+(r+n+e.textMargin)/2),"yfunc");break;case"bottom":case"end":h=o(()=>Math.round(e.y+(r+n+2*e.textMargin)-e.textMargin),"yfunc");break}if(e.anchor!==void 0&&e.textMargin!==void 0&&e.width!==void 0)switch(e.anchor){case"left":case"start":e.x=Math.round(e.x+e.textMargin),e.anchor="start",e.dominantBaseline="middle",e.alignmentBaseline="middle";break;case"middle":case"center":e.x=Math.round(e.x+e.width/2),e.anchor="middle",e.dominantBaseline="middle",e.alignmentBaseline="middle";break;case"right":case"end":e.x=Math.round(e.x+e.width-e.textMargin),e.anchor="end",e.dominantBaseline="middle",e.alignmentBaseline="middle";break}for(let[f,d]of i.entries()){e.textMargin!==void 0&&e.textMargin===0&&a!==void 0&&(u=f*a);let p=t.append("text");p.attr("x",e.x),p.attr("y",h()),e.anchor!==void 0&&p.attr("text-anchor",e.anchor).attr("dominant-baseline",e.dominantBaseline).attr("alignment-baseline",e.alignmentBaseline),e.fontFamily!==void 0&&p.style("font-family",e.fontFamily),s!==void 0&&p.style("font-size",s),e.fontWeight!==void 0&&p.style("font-weight",e.fontWeight),e.fill!==void 0&&p.attr("fill",e.fill),e.class!==void 0&&p.attr("class",e.class),e.dy!==void 0?p.attr("dy",e.dy):u!==0&&p.attr("dy",u);let m=d||K_;if(e.tspan){let g=p.append("tspan");g.attr("x",e.x),e.fill!==void 0&&g.attr("fill",e.fill),g.text(m)}else p.text(m);e.valign!==void 0&&e.textMargin!==void 0&&e.textMargin>0&&(n+=(p._groups||p)[0][0].getBBox().height,r=n),l.push(p)}return l},"drawText"),ohe=o(function(t,e){function r(i,a,s,l,u){return i+","+a+" "+(i+s)+","+a+" "+(i+s)+","+(a+l-u)+" "+(i+s-u*1.2)+","+(a+l)+" "+i+","+(a+l)}o(r,"genPoints");let n=t.append("polygon");return n.attr("points",r(e.x,e.y,e.width,e.height,7)),n.attr("class","labelBox"),e.y=e.y+e.height/2,_0(t,e),n},"drawLabel"),Bc=-1,yO=o((t,e,r,n)=>{t.select&&r.forEach(i=>{let a=e.get(i),s=t.select("#actor"+a.actorCnt);!n.mirrorActors&&a.stopy?s.attr("y2",a.stopy+a.height/2):n.mirrorActors&&s.attr("y2",a.stopy)})},"fixLifeLineHeights"),NGe=o(function(t,e,r,n){let i=n?e.stopy:e.starty,a=e.x+e.width/2,s=i+5,l=t.append("g").lower();var u=l;n||(Bc++,Object.keys(e.links||{}).length&&!r.forceMenus&&u.attr("onclick",RGe(`actor${Bc}_popup`)).attr("cursor","pointer"),u.append("line").attr("id","actor"+Bc).attr("x1",a).attr("y1",s).attr("x2",a).attr("y2",2e3).attr("class","actor-line 200").attr("stroke-width","0.5px").attr("stroke","#999").attr("name",e.name),u=l.append("g"),e.actorCnt=Bc,e.links!=null&&u.attr("id","root-"+Bc));let h=wl();var f="actor";e.properties?.class?f=e.properties.class:h.fill="#eaeaea",n?f+=` ${she}`:f+=` ${ahe}`,h.x=e.x,h.y=i,h.width=e.width,h.height=e.height,h.class=f,h.rx=3,h.ry=3,h.name=e.name;let d=gO(u,h);if(e.rectData=h,e.properties?.icon){let m=e.properties.icon.trim();m.charAt(0)==="@"?EW(u,h.x+h.width-20,h.y+10,m.substr(1)):kW(u,h.x+h.width-20,h.y+10,m)}vO(r,Ni(e.description))(e.description,u,h.x,h.y,h.width,h.height,{class:`actor ${LGe}`},r);let p=e.height;if(d.node){let m=d.node().getBBox();e.height=m.height,p=m.height}return p},"drawActorTypeParticipant"),MGe=o(function(t,e,r,n){let i=n?e.stopy:e.starty,a=e.x+e.width/2,s=i+80,l=t.append("g").lower();n||(Bc++,l.append("line").attr("id","actor"+Bc).attr("x1",a).attr("y1",s).attr("x2",a).attr("y2",2e3).attr("class","actor-line 200").attr("stroke-width","0.5px").attr("stroke","#999").attr("name",e.name),e.actorCnt=Bc);let u=t.append("g"),h=ihe;n?h+=` ${she}`:h+=` ${ahe}`,u.attr("class",h),u.attr("name",e.name);let f=wl();f.x=e.x,f.y=i,f.fill="#eaeaea",f.width=e.width,f.height=e.height,f.class="actor",f.rx=3,f.ry=3,u.append("line").attr("id","actor-man-torso"+Bc).attr("x1",a).attr("y1",i+25).attr("x2",a).attr("y2",i+45),u.append("line").attr("id","actor-man-arms"+Bc).attr("x1",a-gf/2).attr("y1",i+33).attr("x2",a+gf/2).attr("y2",i+33),u.append("line").attr("x1",a-gf/2).attr("y1",i+60).attr("x2",a).attr("y2",i+45),u.append("line").attr("x1",a).attr("y1",i+45).attr("x2",a+gf/2-2).attr("y2",i+60);let d=u.append("circle");d.attr("cx",e.x+e.width/2),d.attr("cy",i+10),d.attr("r",15),d.attr("width",e.width),d.attr("height",e.height);let p=u.node().getBBox();return e.height=p.height,vO(r,Ni(e.description))(e.description,u,f.x,f.y+35,f.width,f.height,{class:`actor ${ihe}`},r),e.height},"drawActorTypeActor"),IGe=o(async function(t,e,r,n){switch(e.type){case"actor":return await MGe(t,e,r,n);case"participant":return await NGe(t,e,r,n)}},"drawActor"),OGe=o(function(t,e,r){let i=t.append("g");lhe(i,e),e.name&&vO(r)(e.name,i,e.x,e.y+(e.textMaxHeight||0)/2,e.width,0,{class:"text"},r),i.lower()},"drawBox"),PGe=o(function(t){return t.append("g")},"anchorElement"),BGe=o(function(t,e,r,n,i){let a=wl(),s=e.anchored;a.x=e.startx,a.y=e.starty,a.class="activation"+i%3,a.width=e.stopx-e.startx,a.height=r-e.starty,gO(s,a)},"drawActivation"),FGe=o(async function(t,e,r,n){let{boxMargin:i,boxTextMargin:a,labelBoxHeight:s,labelBoxWidth:l,messageFontFamily:u,messageFontSize:h,messageFontWeight:f}=n,d=t.append("g"),p=o(function(y,v,x,b){return d.append("line").attr("x1",y).attr("y1",v).attr("x2",x).attr("y2",b).attr("class","loopLine")},"drawLoopLine");p(e.startx,e.starty,e.stopx,e.starty),p(e.stopx,e.starty,e.stopx,e.stopy),p(e.startx,e.stopy,e.stopx,e.stopy),p(e.startx,e.starty,e.startx,e.stopy),e.sections!==void 0&&e.sections.forEach(function(y){p(e.startx,y.y,e.stopx,y.y).style("stroke-dasharray","3, 3")});let m=Ky();m.text=r,m.x=e.startx,m.y=e.starty,m.fontFamily=u,m.fontSize=h,m.fontWeight=f,m.anchor="middle",m.valign="middle",m.tspan=!1,m.width=l||50,m.height=s||20,m.textMargin=a,m.class="labelText",ohe(d,m),m=che(),m.text=e.title,m.x=e.startx+l/2+(e.stopx-e.startx)/2,m.y=e.starty+i+a,m.anchor="middle",m.valign="middle",m.textMargin=a,m.class="loopText",m.fontFamily=u,m.fontSize=h,m.fontWeight=f,m.wrap=!0;let g=Ni(m.text)?await bx(d,m,e):_0(d,m);if(e.sectionTitles!==void 0){for(let[y,v]of Object.entries(e.sectionTitles))if(v.message){m.text=v.message,m.x=e.startx+(e.stopx-e.startx)/2,m.y=e.sections[y].y+i+a,m.class="loopText",m.anchor="middle",m.valign="middle",m.tspan=!1,m.fontFamily=u,m.fontSize=h,m.fontWeight=f,m.wrap=e.wrap,Ni(m.text)?(e.starty=e.sections[y].y,await bx(d,m,e)):_0(d,m);let x=Math.round(g.map(b=>(b._groups||b)[0][0].getBBox().height).reduce((b,w)=>b+w));e.sections[y].height+=x-(i+a)}}return e.height=Math.round(e.stopy-e.starty),d},"drawLoop"),lhe=o(function(t,e){j3(t,e)},"drawBackgroundRect"),zGe=o(function(t){t.append("defs").append("symbol").attr("id","database").attr("fill-rule","evenodd").attr("clip-rule","evenodd").append("path").attr("transform","scale(.5)").attr("d","M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z")},"insertDatabaseIcon"),GGe=o(function(t){t.append("defs").append("symbol").attr("id","computer").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z")},"insertComputerIcon"),$Ge=o(function(t){t.append("defs").append("symbol").attr("id","clock").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z")},"insertClockIcon"),VGe=o(function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",7.9).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto-start-reverse").append("path").attr("d","M -1 0 L 10 5 L 0 10 z")},"insertArrowHead"),UGe=o(function(t){t.append("defs").append("marker").attr("id","filled-head").attr("refX",15.5).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"insertArrowFilledHead"),HGe=o(function(t){t.append("defs").append("marker").attr("id","sequencenumber").attr("refX",15).attr("refY",15).attr("markerWidth",60).attr("markerHeight",40).attr("orient","auto").append("circle").attr("cx",15).attr("cy",15).attr("r",6)},"insertSequenceNumber"),YGe=o(function(t){t.append("defs").append("marker").attr("id","crosshead").attr("markerWidth",15).attr("markerHeight",8).attr("orient","auto").attr("refX",4).attr("refY",4.5).append("path").attr("fill","none").attr("stroke","#000000").style("stroke-dasharray","0, 0").attr("stroke-width","1pt").attr("d","M 1,2 L 6,7 M 6,2 L 1,7")},"insertArrowCrossHead"),che=o(function(){return{x:0,y:0,fill:void 0,anchor:void 0,style:"#666",width:void 0,height:void 0,textMargin:0,rx:0,ry:0,tspan:!0,valign:void 0}},"getTextObj"),WGe=o(function(){return{x:0,y:0,fill:"#EDF2AE",stroke:"#666",width:100,anchor:"start",height:100,rx:0,ry:0}},"getNoteRect"),vO=function(){function t(a,s,l,u,h,f,d){let p=s.append("text").attr("x",l+h/2).attr("y",u+f/2+5).style("text-anchor","middle").text(a);i(p,d)}o(t,"byText");function e(a,s,l,u,h,f,d,p){let{actorFontSize:m,actorFontFamily:g,actorFontWeight:y}=p,[v,x]=mc(m),b=a.split(We.lineBreakRegex);for(let w=0;w{let s=L0(Ne),l=a.actorKeys.reduce((f,d)=>f+=t.get(d).width+(t.get(d).margin||0),0);l-=2*Ne.boxTextMargin,a.wrap&&(a.name=Lt.wrapLabel(a.name,l-2*Ne.wrapPadding,s));let u=Lt.calculateTextDimensions(a.name,s);i=We.getMax(u.height,i);let h=We.getMax(l,u.width+2*Ne.wrapPadding);if(a.margin=Ne.boxTextMargin,la.textMaxHeight=i),We.getMax(n,Ne.height)}var Ne,Ke,XGe,L0,Pg,xO,KGe,QGe,bO,fhe,dhe,bE,hhe,JGe,t$e,n$e,i$e,a$e,phe,mhe=R(()=>{"use strict";Zt();uhe();ut();rr();Qy();_t();cp();xr();Yn();Ne={},Ke={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],activations:[],models:{getHeight:o(function(){return Math.max.apply(null,this.actors.length===0?[0]:this.actors.map(t=>t.height||0))+(this.loops.length===0?0:this.loops.map(t=>t.height||0).reduce((t,e)=>t+e))+(this.messages.length===0?0:this.messages.map(t=>t.height||0).reduce((t,e)=>t+e))+(this.notes.length===0?0:this.notes.map(t=>t.height||0).reduce((t,e)=>t+e))},"getHeight"),clear:o(function(){this.actors=[],this.boxes=[],this.loops=[],this.messages=[],this.notes=[]},"clear"),addBox:o(function(t){this.boxes.push(t)},"addBox"),addActor:o(function(t){this.actors.push(t)},"addActor"),addLoop:o(function(t){this.loops.push(t)},"addLoop"),addMessage:o(function(t){this.messages.push(t)},"addMessage"),addNote:o(function(t){this.notes.push(t)},"addNote"),lastActor:o(function(){return this.actors[this.actors.length-1]},"lastActor"),lastLoop:o(function(){return this.loops[this.loops.length-1]},"lastLoop"),lastMessage:o(function(){return this.messages[this.messages.length-1]},"lastMessage"),lastNote:o(function(){return this.notes[this.notes.length-1]},"lastNote"),actors:[],boxes:[],loops:[],messages:[],notes:[]},init:o(function(){this.sequenceItems=[],this.activations=[],this.models.clear(),this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0,dhe(de())},"init"),updateVal:o(function(t,e,r,n){t[e]===void 0?t[e]=r:t[e]=n(r,t[e])},"updateVal"),updateBounds:o(function(t,e,r,n){let i=this,a=0;function s(l){return o(function(h){a++;let f=i.sequenceItems.length-a+1;i.updateVal(h,"starty",e-f*Ne.boxMargin,Math.min),i.updateVal(h,"stopy",n+f*Ne.boxMargin,Math.max),i.updateVal(Ke.data,"startx",t-f*Ne.boxMargin,Math.min),i.updateVal(Ke.data,"stopx",r+f*Ne.boxMargin,Math.max),l!=="activation"&&(i.updateVal(h,"startx",t-f*Ne.boxMargin,Math.min),i.updateVal(h,"stopx",r+f*Ne.boxMargin,Math.max),i.updateVal(Ke.data,"starty",e-f*Ne.boxMargin,Math.min),i.updateVal(Ke.data,"stopy",n+f*Ne.boxMargin,Math.max))},"updateItemBounds")}o(s,"updateFn"),this.sequenceItems.forEach(s()),this.activations.forEach(s("activation"))},"updateBounds"),insert:o(function(t,e,r,n){let i=We.getMin(t,r),a=We.getMax(t,r),s=We.getMin(e,n),l=We.getMax(e,n);this.updateVal(Ke.data,"startx",i,Math.min),this.updateVal(Ke.data,"starty",s,Math.min),this.updateVal(Ke.data,"stopx",a,Math.max),this.updateVal(Ke.data,"stopy",l,Math.max),this.updateBounds(i,s,a,l)},"insert"),newActivation:o(function(t,e,r){let n=r.get(t.from),i=bE(t.from).length||0,a=n.x+n.width/2+(i-1)*Ne.activationWidth/2;this.activations.push({startx:a,starty:this.verticalPos+2,stopx:a+Ne.activationWidth,stopy:void 0,actor:t.from,anchored:si.anchorElement(e)})},"newActivation"),endActivation:o(function(t){let e=this.activations.map(function(r){return r.actor}).lastIndexOf(t.from);return this.activations.splice(e,1)[0]},"endActivation"),createLoop:o(function(t={message:void 0,wrap:!1,width:void 0},e){return{startx:void 0,starty:this.verticalPos,stopx:void 0,stopy:void 0,title:t.message,wrap:t.wrap,width:t.width,height:0,fill:e}},"createLoop"),newLoop:o(function(t={message:void 0,wrap:!1,width:void 0},e){this.sequenceItems.push(this.createLoop(t,e))},"newLoop"),endLoop:o(function(){return this.sequenceItems.pop()},"endLoop"),isLoopOverlap:o(function(){return this.sequenceItems.length?this.sequenceItems[this.sequenceItems.length-1].overlap:!1},"isLoopOverlap"),addSectionToLoop:o(function(t){let e=this.sequenceItems.pop();e.sections=e.sections||[],e.sectionTitles=e.sectionTitles||[],e.sections.push({y:Ke.getVerticalPos(),height:0}),e.sectionTitles.push(t),this.sequenceItems.push(e)},"addSectionToLoop"),saveVerticalPos:o(function(){this.isLoopOverlap()&&(this.savedVerticalPos=this.verticalPos)},"saveVerticalPos"),resetVerticalPos:o(function(){this.isLoopOverlap()&&(this.verticalPos=this.savedVerticalPos)},"resetVerticalPos"),bumpVerticalPos:o(function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=We.getMax(this.data.stopy,this.verticalPos)},"bumpVerticalPos"),getVerticalPos:o(function(){return this.verticalPos},"getVerticalPos"),getBounds:o(function(){return{bounds:this.data,models:this.models}},"getBounds")},XGe=o(async function(t,e){Ke.bumpVerticalPos(Ne.boxMargin),e.height=Ne.boxMargin,e.starty=Ke.getVerticalPos();let r=wl();r.x=e.startx,r.y=e.starty,r.width=e.width||Ne.width,r.class="note";let n=t.append("g"),i=si.drawRect(n,r),a=Ky();a.x=e.startx,a.y=e.starty,a.width=r.width,a.dy="1em",a.text=e.message,a.class="noteText",a.fontFamily=Ne.noteFontFamily,a.fontSize=Ne.noteFontSize,a.fontWeight=Ne.noteFontWeight,a.anchor=Ne.noteAlign,a.textMargin=Ne.noteMargin,a.valign="center";let s=Ni(a.text)?await bx(n,a):_0(n,a),l=Math.round(s.map(u=>(u._groups||u)[0][0].getBBox().height).reduce((u,h)=>u+h));i.attr("height",l+2*Ne.noteMargin),e.height+=l+2*Ne.noteMargin,Ke.bumpVerticalPos(l+2*Ne.noteMargin),e.stopy=e.starty+l+2*Ne.noteMargin,e.stopx=e.startx+r.width,Ke.insert(e.startx,e.starty,e.stopx,e.stopy),Ke.models.addNote(e)},"drawNote"),L0=o(t=>({fontFamily:t.messageFontFamily,fontSize:t.messageFontSize,fontWeight:t.messageFontWeight}),"messageFont"),Pg=o(t=>({fontFamily:t.noteFontFamily,fontSize:t.noteFontSize,fontWeight:t.noteFontWeight}),"noteFont"),xO=o(t=>({fontFamily:t.actorFontFamily,fontSize:t.actorFontSize,fontWeight:t.actorFontWeight}),"actorFont");o(jGe,"boundMessage");KGe=o(async function(t,e,r,n){let{startx:i,stopx:a,starty:s,message:l,type:u,sequenceIndex:h,sequenceVisible:f}=e,d=Lt.calculateTextDimensions(l,L0(Ne)),p=Ky();p.x=i,p.y=s+10,p.width=a-i,p.class="messageText",p.dy="1em",p.text=l,p.fontFamily=Ne.messageFontFamily,p.fontSize=Ne.messageFontSize,p.fontWeight=Ne.messageFontWeight,p.anchor=Ne.messageAlign,p.valign="center",p.textMargin=Ne.wrapPadding,p.tspan=!1,Ni(p.text)?await bx(t,p,{startx:i,stopx:a,starty:r}):_0(t,p);let m=d.width,g;i===a?Ne.rightAngles?g=t.append("path").attr("d",`M ${i},${r} H ${i+We.getMax(Ne.width/2,m/2)} V ${r+25} H ${i}`):g=t.append("path").attr("d","M "+i+","+r+" C "+(i+60)+","+(r-10)+" "+(i+60)+","+(r+30)+" "+i+","+(r+20)):(g=t.append("line"),g.attr("x1",i),g.attr("y1",r),g.attr("x2",a),g.attr("y2",r)),u===n.db.LINETYPE.DOTTED||u===n.db.LINETYPE.DOTTED_CROSS||u===n.db.LINETYPE.DOTTED_POINT||u===n.db.LINETYPE.DOTTED_OPEN||u===n.db.LINETYPE.BIDIRECTIONAL_DOTTED?(g.style("stroke-dasharray","3, 3"),g.attr("class","messageLine1")):g.attr("class","messageLine0");let y="";Ne.arrowMarkerAbsolute&&(y=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,y=y.replace(/\(/g,"\\("),y=y.replace(/\)/g,"\\)")),g.attr("stroke-width",2),g.attr("stroke","none"),g.style("fill","none"),(u===n.db.LINETYPE.SOLID||u===n.db.LINETYPE.DOTTED)&&g.attr("marker-end","url("+y+"#arrowhead)"),(u===n.db.LINETYPE.BIDIRECTIONAL_SOLID||u===n.db.LINETYPE.BIDIRECTIONAL_DOTTED)&&(g.attr("marker-start","url("+y+"#arrowhead)"),g.attr("marker-end","url("+y+"#arrowhead)")),(u===n.db.LINETYPE.SOLID_POINT||u===n.db.LINETYPE.DOTTED_POINT)&&g.attr("marker-end","url("+y+"#filled-head)"),(u===n.db.LINETYPE.SOLID_CROSS||u===n.db.LINETYPE.DOTTED_CROSS)&&g.attr("marker-end","url("+y+"#crosshead)"),(f||Ne.showSequenceNumbers)&&(g.attr("marker-start","url("+y+"#sequencenumber)"),t.append("text").attr("x",i).attr("y",r+4).attr("font-family","sans-serif").attr("font-size","12px").attr("text-anchor","middle").attr("class","sequenceNumber").text(h))},"drawMessage"),QGe=o(function(t,e,r,n,i,a,s){let l=0,u=0,h,f=0;for(let d of n){let p=e.get(d),m=p.box;h&&h!=m&&(s||Ke.models.addBox(h),u+=Ne.boxMargin+h.margin),m&&m!=h&&(s||(m.x=l+u,m.y=i),u+=m.margin),p.width=p.width||Ne.width,p.height=We.getMax(p.height||Ne.height,Ne.height),p.margin=p.margin||Ne.actorMargin,f=We.getMax(f,p.height),r.get(p.name)&&(u+=p.width/2),p.x=l+u,p.starty=Ke.getVerticalPos(),Ke.insert(p.x,i,p.x+p.width,p.height),l+=p.width+u,p.box&&(p.box.width=l+m.margin-p.box.x),u=p.margin,h=p.box,Ke.models.addActor(p)}h&&!s&&Ke.models.addBox(h),Ke.bumpVerticalPos(f)},"addActorRenderingData"),bO=o(async function(t,e,r,n){if(n){let i=0;Ke.bumpVerticalPos(Ne.boxMargin*2);for(let a of r){let s=e.get(a);s.stopy||(s.stopy=Ke.getVerticalPos());let l=await si.drawActor(t,s,Ne,!0);i=We.getMax(i,l)}Ke.bumpVerticalPos(i+Ne.boxMargin)}else for(let i of r){let a=e.get(i);await si.drawActor(t,a,Ne,!1)}},"drawActors"),fhe=o(function(t,e,r,n){let i=0,a=0;for(let s of r){let l=e.get(s),u=t$e(l),h=si.drawPopup(t,l,u,Ne,Ne.forceMenus,n);h.height>i&&(i=h.height),h.width+l.x>a&&(a=h.width+l.x)}return{maxHeight:i,maxWidth:a}},"drawActorsPopup"),dhe=o(function(t){On(Ne,t),t.fontFamily&&(Ne.actorFontFamily=Ne.noteFontFamily=Ne.messageFontFamily=t.fontFamily),t.fontSize&&(Ne.actorFontSize=Ne.noteFontSize=Ne.messageFontSize=t.fontSize),t.fontWeight&&(Ne.actorFontWeight=Ne.noteFontWeight=Ne.messageFontWeight=t.fontWeight)},"setConf"),bE=o(function(t){return Ke.activations.filter(function(e){return e.actor===t})},"actorActivations"),hhe=o(function(t,e){let r=e.get(t),n=bE(t),i=n.reduce(function(s,l){return We.getMin(s,l.startx)},r.x+r.width/2-1),a=n.reduce(function(s,l){return We.getMax(s,l.stopx)},r.x+r.width/2+1);return[i,a]},"activationBounds");o(Fc,"adjustLoopHeightForWrap");o(ZGe,"adjustCreatedDestroyedData");JGe=o(async function(t,e,r,n){let{securityLevel:i,sequence:a}=de();Ne=a;let s;i==="sandbox"&&(s=$e("#i"+e));let l=i==="sandbox"?$e(s.nodes()[0].contentDocument.body):$e("body"),u=i==="sandbox"?s.nodes()[0].contentDocument:document;Ke.init(),V.debug(n.db);let h=i==="sandbox"?l.select(`[id="${e}"]`):$e(`[id="${e}"]`),f=n.db.getActors(),d=n.db.getCreatedActors(),p=n.db.getDestroyedActors(),m=n.db.getBoxes(),g=n.db.getActorKeys(),y=n.db.getMessages(),v=n.db.getDiagramTitle(),x=n.db.hasAtLeastOneBox(),b=n.db.hasAtLeastOneBoxWithTitle(),w=await e$e(f,y,n);if(Ne.height=await r$e(f,w,m),si.insertComputerIcon(h),si.insertDatabaseIcon(h),si.insertClockIcon(h),x&&(Ke.bumpVerticalPos(Ne.boxMargin),b&&Ke.bumpVerticalPos(m[0].textMaxHeight)),Ne.hideUnusedParticipants===!0){let F=new Set;y.forEach(B=>{F.add(B.from),F.add(B.to)}),g=g.filter(B=>F.has(B))}QGe(h,f,d,g,0,y,!1);let S=await a$e(y,f,w,n);si.insertArrowHead(h),si.insertArrowCrossHead(h),si.insertArrowFilledHead(h),si.insertSequenceNumber(h);function T(F,B){let $=Ke.endActivation(F);$.starty+18>B&&($.starty=B-6,B+=12),si.drawActivation(h,$,B,Ne,bE(F.from).length),Ke.insert($.startx,B-10,$.stopx,B)}o(T,"activeEnd");let E=1,_=1,A=[],L=[],M=0;for(let F of y){let B,$,z;switch(F.type){case n.db.LINETYPE.NOTE:Ke.resetVerticalPos(),$=F.noteModel,await XGe(h,$);break;case n.db.LINETYPE.ACTIVE_START:Ke.newActivation(F,h,f);break;case n.db.LINETYPE.ACTIVE_END:T(F,Ke.getVerticalPos());break;case n.db.LINETYPE.LOOP_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin+Ne.boxTextMargin,Y=>Ke.newLoop(Y));break;case n.db.LINETYPE.LOOP_END:B=Ke.endLoop(),await si.drawLoop(h,B,"loop",Ne),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos()),Ke.models.addLoop(B);break;case n.db.LINETYPE.RECT_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin,Y=>Ke.newLoop(void 0,Y.message));break;case n.db.LINETYPE.RECT_END:B=Ke.endLoop(),L.push(B),Ke.models.addLoop(B),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos());break;case n.db.LINETYPE.OPT_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin+Ne.boxTextMargin,Y=>Ke.newLoop(Y));break;case n.db.LINETYPE.OPT_END:B=Ke.endLoop(),await si.drawLoop(h,B,"opt",Ne),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos()),Ke.models.addLoop(B);break;case n.db.LINETYPE.ALT_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin+Ne.boxTextMargin,Y=>Ke.newLoop(Y));break;case n.db.LINETYPE.ALT_ELSE:Fc(S,F,Ne.boxMargin+Ne.boxTextMargin,Ne.boxMargin,Y=>Ke.addSectionToLoop(Y));break;case n.db.LINETYPE.ALT_END:B=Ke.endLoop(),await si.drawLoop(h,B,"alt",Ne),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos()),Ke.models.addLoop(B);break;case n.db.LINETYPE.PAR_START:case n.db.LINETYPE.PAR_OVER_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin+Ne.boxTextMargin,Y=>Ke.newLoop(Y)),Ke.saveVerticalPos();break;case n.db.LINETYPE.PAR_AND:Fc(S,F,Ne.boxMargin+Ne.boxTextMargin,Ne.boxMargin,Y=>Ke.addSectionToLoop(Y));break;case n.db.LINETYPE.PAR_END:B=Ke.endLoop(),await si.drawLoop(h,B,"par",Ne),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos()),Ke.models.addLoop(B);break;case n.db.LINETYPE.AUTONUMBER:E=F.message.start||E,_=F.message.step||_,F.message.visible?n.db.enableSequenceNumbers():n.db.disableSequenceNumbers();break;case n.db.LINETYPE.CRITICAL_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin+Ne.boxTextMargin,Y=>Ke.newLoop(Y));break;case n.db.LINETYPE.CRITICAL_OPTION:Fc(S,F,Ne.boxMargin+Ne.boxTextMargin,Ne.boxMargin,Y=>Ke.addSectionToLoop(Y));break;case n.db.LINETYPE.CRITICAL_END:B=Ke.endLoop(),await si.drawLoop(h,B,"critical",Ne),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos()),Ke.models.addLoop(B);break;case n.db.LINETYPE.BREAK_START:Fc(S,F,Ne.boxMargin,Ne.boxMargin+Ne.boxTextMargin,Y=>Ke.newLoop(Y));break;case n.db.LINETYPE.BREAK_END:B=Ke.endLoop(),await si.drawLoop(h,B,"break",Ne),Ke.bumpVerticalPos(B.stopy-Ke.getVerticalPos()),Ke.models.addLoop(B);break;default:try{z=F.msgModel,z.starty=Ke.getVerticalPos(),z.sequenceIndex=E,z.sequenceVisible=n.db.showSequenceNumbers();let Y=await jGe(h,z);ZGe(F,z,Y,M,f,d,p),A.push({messageModel:z,lineStartY:Y}),Ke.models.addMessage(z)}catch(Y){V.error("error while drawing message",Y)}}[n.db.LINETYPE.SOLID_OPEN,n.db.LINETYPE.DOTTED_OPEN,n.db.LINETYPE.SOLID,n.db.LINETYPE.DOTTED,n.db.LINETYPE.SOLID_CROSS,n.db.LINETYPE.DOTTED_CROSS,n.db.LINETYPE.SOLID_POINT,n.db.LINETYPE.DOTTED_POINT,n.db.LINETYPE.BIDIRECTIONAL_SOLID,n.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(F.type)&&(E=E+_),M++}V.debug("createdActors",d),V.debug("destroyedActors",p),await bO(h,f,g,!1);for(let F of A)await KGe(h,F.messageModel,F.lineStartY,n);Ne.mirrorActors&&await bO(h,f,g,!0),L.forEach(F=>si.drawBackgroundRect(h,F)),yO(h,f,g,Ne);for(let F of Ke.models.boxes)F.height=Ke.getVerticalPos()-F.y,Ke.insert(F.x,F.y,F.x+F.width,F.height),F.startx=F.x,F.starty=F.y,F.stopx=F.startx+F.width,F.stopy=F.starty+F.height,F.stroke="rgb(0,0,0, 0.5)",si.drawBox(h,F,Ne);x&&Ke.bumpVerticalPos(Ne.boxMargin);let N=fhe(h,f,g,u),{bounds:k}=Ke.getBounds();k.startx===void 0&&(k.startx=0),k.starty===void 0&&(k.starty=0),k.stopx===void 0&&(k.stopx=0),k.stopy===void 0&&(k.stopy=0);let I=k.stopy-k.starty;I2,d=o(y=>l?-y:y,"adjustValue");t.from===t.to?h=u:(t.activate&&!f&&(h+=d(Ne.activationWidth/2-1)),[r.db.LINETYPE.SOLID_OPEN,r.db.LINETYPE.DOTTED_OPEN].includes(t.type)||(h+=d(3)),[r.db.LINETYPE.BIDIRECTIONAL_SOLID,r.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(t.type)&&(u-=d(3)));let p=[n,i,a,s],m=Math.abs(u-h);t.wrap&&t.message&&(t.message=Lt.wrapLabel(t.message,We.getMax(m+2*Ne.wrapPadding,Ne.width),L0(Ne)));let g=Lt.calculateTextDimensions(t.message,L0(Ne));return{width:We.getMax(t.wrap?0:g.width+2*Ne.wrapPadding,m+2*Ne.wrapPadding,Ne.width),height:0,startx:u,stopx:h,starty:0,stopy:0,message:t.message,type:t.type,wrap:t.wrap,fromBounds:Math.min.apply(null,p),toBounds:Math.max.apply(null,p)}},"buildMessageModel"),a$e=o(async function(t,e,r,n){let i={},a=[],s,l,u;for(let h of t){switch(h.id=Lt.random({length:10}),h.type){case n.db.LINETYPE.LOOP_START:case n.db.LINETYPE.ALT_START:case n.db.LINETYPE.OPT_START:case n.db.LINETYPE.PAR_START:case n.db.LINETYPE.PAR_OVER_START:case n.db.LINETYPE.CRITICAL_START:case n.db.LINETYPE.BREAK_START:a.push({id:h.id,msg:h.message,from:Number.MAX_SAFE_INTEGER,to:Number.MIN_SAFE_INTEGER,width:0});break;case n.db.LINETYPE.ALT_ELSE:case n.db.LINETYPE.PAR_AND:case n.db.LINETYPE.CRITICAL_OPTION:h.message&&(s=a.pop(),i[s.id]=s,i[h.id]=s,a.push(s));break;case n.db.LINETYPE.LOOP_END:case n.db.LINETYPE.ALT_END:case n.db.LINETYPE.OPT_END:case n.db.LINETYPE.PAR_END:case n.db.LINETYPE.CRITICAL_END:case n.db.LINETYPE.BREAK_END:s=a.pop(),i[s.id]=s;break;case n.db.LINETYPE.ACTIVE_START:{let d=e.get(h.from?h.from:h.to.actor),p=bE(h.from?h.from:h.to.actor).length,m=d.x+d.width/2+(p-1)*Ne.activationWidth/2,g={startx:m,stopx:m+Ne.activationWidth,actor:h.from,enabled:!0};Ke.activations.push(g)}break;case n.db.LINETYPE.ACTIVE_END:{let d=Ke.activations.map(p=>p.actor).lastIndexOf(h.from);Ke.activations.splice(d,1).splice(0,1)}break}h.placement!==void 0?(l=await n$e(h,e,n),h.noteModel=l,a.forEach(d=>{s=d,s.from=We.getMin(s.from,l.startx),s.to=We.getMax(s.to,l.startx+l.width),s.width=We.getMax(s.width,Math.abs(s.from-s.to))-Ne.labelBoxWidth})):(u=i$e(h,e,n),h.msgModel=u,u.startx&&u.stopx&&a.length>0&&a.forEach(d=>{if(s=d,u.startx===u.stopx){let p=e.get(h.from),m=e.get(h.to);s.from=We.getMin(p.x-u.width/2,p.x-p.width/2,s.from),s.to=We.getMax(m.x+u.width/2,m.x+p.width/2,s.to),s.width=We.getMax(s.width,Math.abs(s.to-s.from))-Ne.labelBoxWidth}else s.from=We.getMin(u.startx,s.from),s.to=We.getMax(u.stopx,s.to),s.width=We.getMax(s.width,u.width)-Ne.labelBoxWidth}))}return Ke.activations=[],V.debug("Loop type widths:",i),i},"calculateLoopBounds"),phe={bounds:Ke,drawActors:bO,drawActorsPopup:fhe,setConf:dhe,draw:JGe}});var ghe={};hr(ghe,{diagram:()=>s$e});var s$e,yhe=R(()=>{"use strict";que();the();nhe();mhe();s$e={parser:Wue,db:pO,renderer:phe,styles:rhe,init:o(({wrap:t})=>{pO.setWrap(t)},"init")}});var wO,wE,TO=R(()=>{"use strict";wO=function(){var t=o(function(Pe,_e,me,W){for(me=me||{},W=Pe.length;W--;me[Pe[W]]=_e);return me},"o"),e=[1,17],r=[1,18],n=[1,19],i=[1,39],a=[1,40],s=[1,25],l=[1,23],u=[1,24],h=[1,31],f=[1,32],d=[1,33],p=[1,34],m=[1,35],g=[1,36],y=[1,26],v=[1,27],x=[1,28],b=[1,29],w=[1,43],S=[1,30],T=[1,42],E=[1,44],_=[1,41],A=[1,45],L=[1,9],M=[1,8,9],N=[1,56],k=[1,57],I=[1,58],C=[1,59],O=[1,60],D=[1,61],P=[1,62],F=[1,8,9,39],B=[1,74],$=[1,8,9,12,13,21,37,39,42,59,60,61,62,63,64,65,70,72],z=[1,8,9,12,13,19,21,37,39,42,46,59,60,61,62,63,64,65,70,72,74,80,95,97,98],Y=[13,74,80,95,97,98],Q=[13,64,65,74,80,95,97,98],X=[13,59,60,61,62,63,74,80,95,97,98],ie=[1,93],j=[1,110],J=[1,108],Z=[1,102],H=[1,103],q=[1,104],K=[1,105],se=[1,106],ce=[1,107],ue=[1,109],te=[1,8,9,37,39,42],De=[1,8,9,21],oe=[1,8,9,78],ke=[1,8,9,21,73,74,78,80,81,82,83,84,85],Ie={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,statements:5,graphConfig:6,CLASS_DIAGRAM:7,NEWLINE:8,EOF:9,statement:10,classLabel:11,SQS:12,STR:13,SQE:14,namespaceName:15,alphaNumToken:16,className:17,classLiteralName:18,GENERICTYPE:19,relationStatement:20,LABEL:21,namespaceStatement:22,classStatement:23,memberStatement:24,annotationStatement:25,clickStatement:26,styleStatement:27,cssClassStatement:28,noteStatement:29,direction:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,namespaceIdentifier:36,STRUCT_START:37,classStatements:38,STRUCT_STOP:39,NAMESPACE:40,classIdentifier:41,STYLE_SEPARATOR:42,members:43,CLASS:44,ANNOTATION_START:45,ANNOTATION_END:46,MEMBER:47,SEPARATOR:48,relation:49,NOTE_FOR:50,noteText:51,NOTE:52,direction_tb:53,direction_bt:54,direction_rl:55,direction_lr:56,relationType:57,lineType:58,AGGREGATION:59,EXTENSION:60,COMPOSITION:61,DEPENDENCY:62,LOLLIPOP:63,LINE:64,DOTTED_LINE:65,CALLBACK:66,LINK:67,LINK_TARGET:68,CLICK:69,CALLBACK_NAME:70,CALLBACK_ARGS:71,HREF:72,STYLE:73,ALPHA:74,stylesOpt:75,CSSCLASS:76,style:77,COMMA:78,styleComponent:79,NUM:80,COLON:81,UNIT:82,SPACE:83,BRKT:84,PCT:85,commentToken:86,textToken:87,graphCodeTokens:88,textNoTagsToken:89,TAGSTART:90,TAGEND:91,"==":92,"--":93,DEFAULT:94,MINUS:95,keywords:96,UNICODE_TEXT:97,BQUOTE_STR:98,$accept:0,$end:1},terminals_:{2:"error",7:"CLASS_DIAGRAM",8:"NEWLINE",9:"EOF",12:"SQS",13:"STR",14:"SQE",19:"GENERICTYPE",21:"LABEL",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",37:"STRUCT_START",39:"STRUCT_STOP",40:"NAMESPACE",42:"STYLE_SEPARATOR",44:"CLASS",45:"ANNOTATION_START",46:"ANNOTATION_END",47:"MEMBER",48:"SEPARATOR",50:"NOTE_FOR",52:"NOTE",53:"direction_tb",54:"direction_bt",55:"direction_rl",56:"direction_lr",59:"AGGREGATION",60:"EXTENSION",61:"COMPOSITION",62:"DEPENDENCY",63:"LOLLIPOP",64:"LINE",65:"DOTTED_LINE",66:"CALLBACK",67:"LINK",68:"LINK_TARGET",69:"CLICK",70:"CALLBACK_NAME",71:"CALLBACK_ARGS",72:"HREF",73:"STYLE",74:"ALPHA",76:"CSSCLASS",78:"COMMA",80:"NUM",81:"COLON",82:"UNIT",83:"SPACE",84:"BRKT",85:"PCT",88:"graphCodeTokens",90:"TAGSTART",91:"TAGEND",92:"==",93:"--",94:"DEFAULT",95:"MINUS",96:"keywords",97:"UNICODE_TEXT",98:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[4,1],[6,4],[5,1],[5,2],[5,3],[11,3],[15,1],[15,2],[17,1],[17,1],[17,2],[17,2],[17,2],[10,1],[10,2],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,2],[10,1],[22,4],[22,5],[36,2],[38,1],[38,2],[38,3],[23,1],[23,3],[23,4],[23,6],[41,2],[41,3],[25,4],[43,1],[43,2],[24,1],[24,2],[24,1],[24,1],[20,3],[20,4],[20,4],[20,5],[29,3],[29,2],[30,1],[30,1],[30,1],[30,1],[49,3],[49,2],[49,2],[49,1],[57,1],[57,1],[57,1],[57,1],[57,1],[58,1],[58,1],[26,3],[26,4],[26,3],[26,4],[26,4],[26,5],[26,3],[26,4],[26,4],[26,5],[26,4],[26,5],[26,5],[26,6],[27,3],[28,3],[75,1],[75,3],[77,1],[77,2],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[79,1],[86,1],[86,1],[87,1],[87,1],[87,1],[87,1],[87,1],[87,1],[87,1],[89,1],[89,1],[89,1],[89,1],[16,1],[16,1],[16,1],[16,1],[18,1],[51,1]],performAction:o(function(_e,me,W,fe,ge,re,he){var ne=re.length-1;switch(ge){case 8:this.$=re[ne-1];break;case 9:case 11:case 12:this.$=re[ne];break;case 10:case 13:this.$=re[ne-1]+re[ne];break;case 14:case 15:this.$=re[ne-1]+"~"+re[ne]+"~";break;case 16:fe.addRelation(re[ne]);break;case 17:re[ne-1].title=fe.cleanupLabel(re[ne]),fe.addRelation(re[ne-1]);break;case 27:this.$=re[ne].trim(),fe.setAccTitle(this.$);break;case 28:case 29:this.$=re[ne].trim(),fe.setAccDescription(this.$);break;case 30:fe.addClassesToNamespace(re[ne-3],re[ne-1]);break;case 31:fe.addClassesToNamespace(re[ne-4],re[ne-1]);break;case 32:this.$=re[ne],fe.addNamespace(re[ne]);break;case 33:this.$=[re[ne]];break;case 34:this.$=[re[ne-1]];break;case 35:re[ne].unshift(re[ne-2]),this.$=re[ne];break;case 37:fe.setCssClass(re[ne-2],re[ne]);break;case 38:fe.addMembers(re[ne-3],re[ne-1]);break;case 39:fe.setCssClass(re[ne-5],re[ne-3]),fe.addMembers(re[ne-5],re[ne-1]);break;case 40:this.$=re[ne],fe.addClass(re[ne]);break;case 41:this.$=re[ne-1],fe.addClass(re[ne-1]),fe.setClassLabel(re[ne-1],re[ne]);break;case 42:fe.addAnnotation(re[ne],re[ne-2]);break;case 43:this.$=[re[ne]];break;case 44:re[ne].push(re[ne-1]),this.$=re[ne];break;case 45:break;case 46:fe.addMember(re[ne-1],fe.cleanupLabel(re[ne]));break;case 47:break;case 48:break;case 49:this.$={id1:re[ne-2],id2:re[ne],relation:re[ne-1],relationTitle1:"none",relationTitle2:"none"};break;case 50:this.$={id1:re[ne-3],id2:re[ne],relation:re[ne-1],relationTitle1:re[ne-2],relationTitle2:"none"};break;case 51:this.$={id1:re[ne-3],id2:re[ne],relation:re[ne-2],relationTitle1:"none",relationTitle2:re[ne-1]};break;case 52:this.$={id1:re[ne-4],id2:re[ne],relation:re[ne-2],relationTitle1:re[ne-3],relationTitle2:re[ne-1]};break;case 53:fe.addNote(re[ne],re[ne-1]);break;case 54:fe.addNote(re[ne]);break;case 55:fe.setDirection("TB");break;case 56:fe.setDirection("BT");break;case 57:fe.setDirection("RL");break;case 58:fe.setDirection("LR");break;case 59:this.$={type1:re[ne-2],type2:re[ne],lineType:re[ne-1]};break;case 60:this.$={type1:"none",type2:re[ne],lineType:re[ne-1]};break;case 61:this.$={type1:re[ne-1],type2:"none",lineType:re[ne]};break;case 62:this.$={type1:"none",type2:"none",lineType:re[ne]};break;case 63:this.$=fe.relationType.AGGREGATION;break;case 64:this.$=fe.relationType.EXTENSION;break;case 65:this.$=fe.relationType.COMPOSITION;break;case 66:this.$=fe.relationType.DEPENDENCY;break;case 67:this.$=fe.relationType.LOLLIPOP;break;case 68:this.$=fe.lineType.LINE;break;case 69:this.$=fe.lineType.DOTTED_LINE;break;case 70:case 76:this.$=re[ne-2],fe.setClickEvent(re[ne-1],re[ne]);break;case 71:case 77:this.$=re[ne-3],fe.setClickEvent(re[ne-2],re[ne-1]),fe.setTooltip(re[ne-2],re[ne]);break;case 72:this.$=re[ne-2],fe.setLink(re[ne-1],re[ne]);break;case 73:this.$=re[ne-3],fe.setLink(re[ne-2],re[ne-1],re[ne]);break;case 74:this.$=re[ne-3],fe.setLink(re[ne-2],re[ne-1]),fe.setTooltip(re[ne-2],re[ne]);break;case 75:this.$=re[ne-4],fe.setLink(re[ne-3],re[ne-2],re[ne]),fe.setTooltip(re[ne-3],re[ne-1]);break;case 78:this.$=re[ne-3],fe.setClickEvent(re[ne-2],re[ne-1],re[ne]);break;case 79:this.$=re[ne-4],fe.setClickEvent(re[ne-3],re[ne-2],re[ne-1]),fe.setTooltip(re[ne-3],re[ne]);break;case 80:this.$=re[ne-3],fe.setLink(re[ne-2],re[ne]);break;case 81:this.$=re[ne-4],fe.setLink(re[ne-3],re[ne-1],re[ne]);break;case 82:this.$=re[ne-4],fe.setLink(re[ne-3],re[ne-1]),fe.setTooltip(re[ne-3],re[ne]);break;case 83:this.$=re[ne-5],fe.setLink(re[ne-4],re[ne-2],re[ne]),fe.setTooltip(re[ne-4],re[ne-1]);break;case 84:this.$=re[ne-2],fe.setCssStyle(re[ne-1],re[ne]);break;case 85:fe.setCssClass(re[ne-1],re[ne]);break;case 86:this.$=[re[ne]];break;case 87:re[ne-2].push(re[ne]),this.$=re[ne-2];break;case 89:this.$=re[ne-1]+re[ne];break}},"anonymous"),table:[{3:1,4:2,5:3,6:4,7:[1,6],10:5,16:37,17:20,18:38,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,31:e,33:r,35:n,36:21,40:i,41:22,44:a,45:s,47:l,48:u,50:h,52:f,53:d,54:p,55:m,56:g,66:y,67:v,69:x,73:b,74:w,76:S,80:T,95:E,97:_,98:A},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,3]},t(L,[2,5],{8:[1,46]}),{8:[1,47]},t(M,[2,16],{21:[1,48]}),t(M,[2,18]),t(M,[2,19]),t(M,[2,20]),t(M,[2,21]),t(M,[2,22]),t(M,[2,23]),t(M,[2,24]),t(M,[2,25]),t(M,[2,26]),{32:[1,49]},{34:[1,50]},t(M,[2,29]),t(M,[2,45],{49:51,57:54,58:55,13:[1,52],21:[1,53],59:N,60:k,61:I,62:C,63:O,64:D,65:P}),{37:[1,63]},t(F,[2,36],{37:[1,65],42:[1,64]}),t(M,[2,47]),t(M,[2,48]),{16:66,74:w,80:T,95:E,97:_},{16:37,17:67,18:38,74:w,80:T,95:E,97:_,98:A},{16:37,17:68,18:38,74:w,80:T,95:E,97:_,98:A},{16:37,17:69,18:38,74:w,80:T,95:E,97:_,98:A},{74:[1,70]},{13:[1,71]},{16:37,17:72,18:38,74:w,80:T,95:E,97:_,98:A},{13:B,51:73},t(M,[2,55]),t(M,[2,56]),t(M,[2,57]),t(M,[2,58]),t($,[2,11],{16:37,18:38,17:75,19:[1,76],74:w,80:T,95:E,97:_,98:A}),t($,[2,12],{19:[1,77]}),{15:78,16:79,74:w,80:T,95:E,97:_},{16:37,17:80,18:38,74:w,80:T,95:E,97:_,98:A},t(z,[2,112]),t(z,[2,113]),t(z,[2,114]),t(z,[2,115]),t([1,8,9,12,13,19,21,37,39,42,59,60,61,62,63,64,65,70,72],[2,116]),t(L,[2,6],{10:5,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,17:20,36:21,41:22,16:37,18:38,5:81,31:e,33:r,35:n,40:i,44:a,45:s,47:l,48:u,50:h,52:f,53:d,54:p,55:m,56:g,66:y,67:v,69:x,73:b,74:w,76:S,80:T,95:E,97:_,98:A}),{5:82,10:5,16:37,17:20,18:38,20:7,22:8,23:9,24:10,25:11,26:12,27:13,28:14,29:15,30:16,31:e,33:r,35:n,36:21,40:i,41:22,44:a,45:s,47:l,48:u,50:h,52:f,53:d,54:p,55:m,56:g,66:y,67:v,69:x,73:b,74:w,76:S,80:T,95:E,97:_,98:A},t(M,[2,17]),t(M,[2,27]),t(M,[2,28]),{13:[1,84],16:37,17:83,18:38,74:w,80:T,95:E,97:_,98:A},{49:85,57:54,58:55,59:N,60:k,61:I,62:C,63:O,64:D,65:P},t(M,[2,46]),{58:86,64:D,65:P},t(Y,[2,62],{57:87,59:N,60:k,61:I,62:C,63:O}),t(Q,[2,63]),t(Q,[2,64]),t(Q,[2,65]),t(Q,[2,66]),t(Q,[2,67]),t(X,[2,68]),t(X,[2,69]),{8:[1,89],23:90,38:88,41:22,44:a},{16:91,74:w,80:T,95:E,97:_},{43:92,47:ie},{46:[1,94]},{13:[1,95]},{13:[1,96]},{70:[1,97],72:[1,98]},{21:j,73:J,74:Z,75:99,77:100,79:101,80:H,81:q,82:K,83:se,84:ce,85:ue},{74:[1,111]},{13:B,51:112},t(M,[2,54]),t(M,[2,117]),t($,[2,13]),t($,[2,14]),t($,[2,15]),{37:[2,32]},{15:113,16:79,37:[2,9],74:w,80:T,95:E,97:_},t(te,[2,40],{11:114,12:[1,115]}),t(L,[2,7]),{9:[1,116]},t(De,[2,49]),{16:37,17:117,18:38,74:w,80:T,95:E,97:_,98:A},{13:[1,119],16:37,17:118,18:38,74:w,80:T,95:E,97:_,98:A},t(Y,[2,61],{57:120,59:N,60:k,61:I,62:C,63:O}),t(Y,[2,60]),{39:[1,121]},{23:90,38:122,41:22,44:a},{8:[1,123],39:[2,33]},t(F,[2,37],{37:[1,124]}),{39:[1,125]},{39:[2,43],43:126,47:ie},{16:37,17:127,18:38,74:w,80:T,95:E,97:_,98:A},t(M,[2,70],{13:[1,128]}),t(M,[2,72],{13:[1,130],68:[1,129]}),t(M,[2,76],{13:[1,131],71:[1,132]}),{13:[1,133]},t(M,[2,84],{78:[1,134]}),t(oe,[2,86],{79:135,21:j,73:J,74:Z,80:H,81:q,82:K,83:se,84:ce,85:ue}),t(ke,[2,88]),t(ke,[2,90]),t(ke,[2,91]),t(ke,[2,92]),t(ke,[2,93]),t(ke,[2,94]),t(ke,[2,95]),t(ke,[2,96]),t(ke,[2,97]),t(ke,[2,98]),t(M,[2,85]),t(M,[2,53]),{37:[2,10]},t(te,[2,41]),{13:[1,136]},{1:[2,4]},t(De,[2,51]),t(De,[2,50]),{16:37,17:137,18:38,74:w,80:T,95:E,97:_,98:A},t(Y,[2,59]),t(M,[2,30]),{39:[1,138]},{23:90,38:139,39:[2,34],41:22,44:a},{43:140,47:ie},t(F,[2,38]),{39:[2,44]},t(M,[2,42]),t(M,[2,71]),t(M,[2,73]),t(M,[2,74],{68:[1,141]}),t(M,[2,77]),t(M,[2,78],{13:[1,142]}),t(M,[2,80],{13:[1,144],68:[1,143]}),{21:j,73:J,74:Z,77:145,79:101,80:H,81:q,82:K,83:se,84:ce,85:ue},t(ke,[2,89]),{14:[1,146]},t(De,[2,52]),t(M,[2,31]),{39:[2,35]},{39:[1,147]},t(M,[2,75]),t(M,[2,79]),t(M,[2,81]),t(M,[2,82],{68:[1,148]}),t(oe,[2,87],{79:135,21:j,73:J,74:Z,80:H,81:q,82:K,83:se,84:ce,85:ue}),t(te,[2,8]),t(F,[2,39]),t(M,[2,83])],defaultActions:{2:[2,1],3:[2,2],4:[2,3],78:[2,32],113:[2,10],116:[2,4],126:[2,44],139:[2,35]},parseError:o(function(_e,me){if(me.recoverable)this.trace(_e);else{var W=new Error(_e);throw W.hash=me,W}},"parseError"),parse:o(function(_e){var me=this,W=[0],fe=[],ge=[null],re=[],he=this.table,ne="",ae=0,we=0,Te=0,Ce=2,Ae=1,Ge=re.slice.call(arguments,1),Me=Object.create(this.lexer),ye={yy:{}};for(var He in this.yy)Object.prototype.hasOwnProperty.call(this.yy,He)&&(ye.yy[He]=this.yy[He]);Me.setInput(_e,ye.yy),ye.yy.lexer=Me,ye.yy.parser=this,typeof Me.yylloc>"u"&&(Me.yylloc={});var ze=Me.yylloc;re.push(ze);var Ze=Me.options&&Me.options.ranges;typeof ye.yy.parseError=="function"?this.parseError=ye.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function gt(mt){W.length=W.length-2*mt,ge.length=ge.length-mt,re.length=re.length-mt}o(gt,"popStack");function yt(){var mt;return mt=fe.pop()||Me.lex()||Ae,typeof mt!="number"&&(mt instanceof Array&&(fe=mt,mt=fe.pop()),mt=me.symbols_[mt]||mt),mt}o(yt,"lex");for(var tt,Ye,Je,Ve,je,kt,at={},xt,it,dt,lt;;){if(Je=W[W.length-1],this.defaultActions[Je]?Ve=this.defaultActions[Je]:((tt===null||typeof tt>"u")&&(tt=yt()),Ve=he[Je]&&he[Je][tt]),typeof Ve>"u"||!Ve.length||!Ve[0]){var It="";lt=[];for(xt in he[Je])this.terminals_[xt]&&xt>Ce&<.push("'"+this.terminals_[xt]+"'");Me.showPosition?It="Parse error on line "+(ae+1)+`: +`+Me.showPosition()+` +Expecting `+lt.join(", ")+", got '"+(this.terminals_[tt]||tt)+"'":It="Parse error on line "+(ae+1)+": Unexpected "+(tt==Ae?"end of input":"'"+(this.terminals_[tt]||tt)+"'"),this.parseError(It,{text:Me.match,token:this.terminals_[tt]||tt,line:Me.yylineno,loc:ze,expected:lt})}if(Ve[0]instanceof Array&&Ve.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Je+", token: "+tt);switch(Ve[0]){case 1:W.push(tt),ge.push(Me.yytext),re.push(Me.yylloc),W.push(Ve[1]),tt=null,Ye?(tt=Ye,Ye=null):(we=Me.yyleng,ne=Me.yytext,ae=Me.yylineno,ze=Me.yylloc,Te>0&&Te--);break;case 2:if(it=this.productions_[Ve[1]][1],at.$=ge[ge.length-it],at._$={first_line:re[re.length-(it||1)].first_line,last_line:re[re.length-1].last_line,first_column:re[re.length-(it||1)].first_column,last_column:re[re.length-1].last_column},Ze&&(at._$.range=[re[re.length-(it||1)].range[0],re[re.length-1].range[1]]),kt=this.performAction.apply(at,[ne,we,ae,ye.yy,Ve[1],ge,re].concat(Ge)),typeof kt<"u")return kt;it&&(W=W.slice(0,-1*it*2),ge=ge.slice(0,-1*it),re=re.slice(0,-1*it)),W.push(this.productions_[Ve[1]][0]),ge.push(at.$),re.push(at._$),dt=he[W[W.length-2]][W[W.length-1]],W.push(dt);break;case 3:return!0}}return!0},"parse")},Se=function(){var Pe={EOF:1,parseError:o(function(me,W){if(this.yy.parser)this.yy.parser.parseError(me,W);else throw new Error(me)},"parseError"),setInput:o(function(_e,me){return this.yy=me||this.yy||{},this._input=_e,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var _e=this._input[0];this.yytext+=_e,this.yyleng++,this.offset++,this.match+=_e,this.matched+=_e;var me=_e.match(/(?:\r\n?|\n).*/g);return me?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),_e},"input"),unput:o(function(_e){var me=_e.length,W=_e.split(/(?:\r\n?|\n)/g);this._input=_e+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-me),this.offset-=me;var fe=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),W.length-1&&(this.yylineno-=W.length-1);var ge=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:W?(W.length===fe.length?this.yylloc.first_column:0)+fe[fe.length-W.length].length-W[0].length:this.yylloc.first_column-me},this.options.ranges&&(this.yylloc.range=[ge[0],ge[0]+this.yyleng-me]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(_e){this.unput(this.match.slice(_e))},"less"),pastInput:o(function(){var _e=this.matched.substr(0,this.matched.length-this.match.length);return(_e.length>20?"...":"")+_e.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var _e=this.match;return _e.length<20&&(_e+=this._input.substr(0,20-_e.length)),(_e.substr(0,20)+(_e.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var _e=this.pastInput(),me=new Array(_e.length+1).join("-");return _e+this.upcomingInput()+` +`+me+"^"},"showPosition"),test_match:o(function(_e,me){var W,fe,ge;if(this.options.backtrack_lexer&&(ge={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(ge.yylloc.range=this.yylloc.range.slice(0))),fe=_e[0].match(/(?:\r\n?|\n).*/g),fe&&(this.yylineno+=fe.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:fe?fe[fe.length-1].length-fe[fe.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+_e[0].length},this.yytext+=_e[0],this.match+=_e[0],this.matches=_e,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(_e[0].length),this.matched+=_e[0],W=this.performAction.call(this,this.yy,this,me,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),W)return W;if(this._backtrack){for(var re in ge)this[re]=ge[re];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var _e,me,W,fe;this._more||(this.yytext="",this.match="");for(var ge=this._currentRules(),re=0;reme[0].length)){if(me=W,fe=re,this.options.backtrack_lexer){if(_e=this.test_match(W,ge[re]),_e!==!1)return _e;if(this._backtrack){me=!1;continue}else return!1}else if(!this.options.flex)break}return me?(_e=this.test_match(me,ge[fe]),_e!==!1?_e:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var me=this.next();return me||this.lex()},"lex"),begin:o(function(me){this.conditionStack.push(me)},"begin"),popState:o(function(){var me=this.conditionStack.length-1;return me>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(me){return me=this.conditionStack.length-1-Math.abs(me||0),me>=0?this.conditionStack[me]:"INITIAL"},"topState"),pushState:o(function(me){this.begin(me)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:o(function(me,W,fe,ge){var re=ge;switch(fe){case 0:return 53;case 1:return 54;case 2:return 55;case 3:return 56;case 4:break;case 5:break;case 6:return this.begin("acc_title"),31;break;case 7:return this.popState(),"acc_title_value";break;case 8:return this.begin("acc_descr"),33;break;case 9:return this.popState(),"acc_descr_value";break;case 10:this.begin("acc_descr_multiline");break;case 11:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:return 8;case 14:break;case 15:return 7;case 16:return 7;case 17:return"EDGE_STATE";case 18:this.begin("callback_name");break;case 19:this.popState();break;case 20:this.popState(),this.begin("callback_args");break;case 21:return 70;case 22:this.popState();break;case 23:return 71;case 24:this.popState();break;case 25:return"STR";case 26:this.begin("string");break;case 27:return 73;case 28:return this.begin("namespace"),40;break;case 29:return this.popState(),8;break;case 30:break;case 31:return this.begin("namespace-body"),37;break;case 32:return this.popState(),39;break;case 33:return"EOF_IN_STRUCT";case 34:return 8;case 35:break;case 36:return"EDGE_STATE";case 37:return this.begin("class"),44;break;case 38:return this.popState(),8;break;case 39:break;case 40:return this.popState(),this.popState(),39;break;case 41:return this.begin("class-body"),37;break;case 42:return this.popState(),39;break;case 43:return"EOF_IN_STRUCT";case 44:return"EDGE_STATE";case 45:return"OPEN_IN_STRUCT";case 46:break;case 47:return"MEMBER";case 48:return 76;case 49:return 66;case 50:return 67;case 51:return 69;case 52:return 50;case 53:return 52;case 54:return 45;case 55:return 46;case 56:return 72;case 57:this.popState();break;case 58:return"GENERICTYPE";case 59:this.begin("generic");break;case 60:this.popState();break;case 61:return"BQUOTE_STR";case 62:this.begin("bqstring");break;case 63:return 68;case 64:return 68;case 65:return 68;case 66:return 68;case 67:return 60;case 68:return 60;case 69:return 62;case 70:return 62;case 71:return 61;case 72:return 59;case 73:return 63;case 74:return 64;case 75:return 65;case 76:return 21;case 77:return 42;case 78:return 95;case 79:return"DOT";case 80:return"PLUS";case 81:return 81;case 82:return 78;case 83:return 84;case 84:return 84;case 85:return 85;case 86:return"EQUALS";case 87:return"EQUALS";case 88:return 74;case 89:return 12;case 90:return 14;case 91:return"PUNCTUATION";case 92:return 80;case 93:return 97;case 94:return 83;case 95:return 83;case 96:return 9}},"anonymous"),rules:[/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:\[\*\])/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:["])/,/^(?:[^"]*)/,/^(?:["])/,/^(?:style\b)/,/^(?:namespace\b)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:[{])/,/^(?:[}])/,/^(?:$)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:\[\*\])/,/^(?:class\b)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:[}])/,/^(?:[{])/,/^(?:[}])/,/^(?:$)/,/^(?:\[\*\])/,/^(?:[{])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:note for\b)/,/^(?:note\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:href\b)/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:~)/,/^(?:[`])/,/^(?:[^`]+)/,/^(?:[`])/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:\s*\(\))/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?::)/,/^(?:,)/,/^(?:#)/,/^(?:#)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:\[)/,/^(?:\])/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\s)/,/^(?:\s)/,/^(?:$)/],conditions:{"namespace-body":{rules:[26,32,33,34,35,36,37,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},namespace:{rules:[26,28,29,30,31,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},"class-body":{rules:[26,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},class:{rules:[26,38,39,40,41,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},acc_descr_multiline:{rules:[11,12,26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},acc_descr:{rules:[9,26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},acc_title:{rules:[7,26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},callback_args:{rules:[22,23,26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},callback_name:{rules:[19,20,21,26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},href:{rules:[26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},struct:{rules:[26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},generic:{rules:[26,48,49,50,51,52,53,54,55,56,57,58,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},bqstring:{rules:[26,48,49,50,51,52,53,54,55,56,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},string:{rules:[24,25,26,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,85,86,87,88,89,90,91,92,93,94,96],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,8,10,13,14,15,16,17,18,26,27,28,37,48,49,50,51,52,53,54,55,56,59,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96],inclusive:!0}}};return Pe}();Ie.lexer=Se;function Ue(){this.yy={}}return o(Ue,"Parser"),Ue.prototype=Ie,Ie.Parser=Ue,new Ue}();wO.parser=wO;wE=wO});var bhe,wx,whe=R(()=>{"use strict";_t();rr();bhe=["#","+","~","-",""],wx=class{static{o(this,"ClassMember")}constructor(e,r){this.memberType=r,this.visibility="",this.classifier="";let n=qr(e,de());this.parseMember(n)}getDisplayDetails(){let e=this.visibility+gh(this.id);this.memberType==="method"&&(e+=`(${gh(this.parameters.trim())})`,this.returnType&&(e+=" : "+gh(this.returnType))),e=e.trim();let r=this.parseClassifier();return{displayText:e,cssStyle:r}}parseMember(e){let r="";if(this.memberType==="method"){let i=/([#+~-])?(.+)\((.*)\)([\s$*])?(.*)([$*])?/.exec(e);if(i){let a=i[1]?i[1].trim():"";if(bhe.includes(a)&&(this.visibility=a),this.id=i[2].trim(),this.parameters=i[3]?i[3].trim():"",r=i[4]?i[4].trim():"",this.returnType=i[5]?i[5].trim():"",r===""){let s=this.returnType.substring(this.returnType.length-1);/[$*]/.exec(s)&&(r=s,this.returnType=this.returnType.substring(0,this.returnType.length-1))}}}else{let n=e.length,i=e.substring(0,1),a=e.substring(n-1);bhe.includes(i)&&(this.visibility=i),/[$*]/.exec(a)&&(r=a),this.id=e.substring(this.visibility===""?0:1,r===""?n:n-1)}this.classifier=r}parseClassifier(){switch(this.classifier){case"*":return"font-style:italic;";case"$":return"text-decoration:underline;";default:return""}}}});var EE,EO,Gi,TE,The,qu,kO,Tx,D0,R0,u$e,kE,khe,h$e,f$e,d$e,p$e,m$e,g$e,y$e,Ehe,v$e,x$e,b$e,CO,w$e,T$e,k$e,E$e,C$e,S$e,A$e,_$e,Che,SO,L$e,D$e,R$e,N$e,M$e,I$e,O$e,Bg,AO=R(()=>{"use strict";Zt();ut();_t();rr();xr();bi();whe();EE="classId-",EO=[],Gi=new Map,TE=[],The=0,qu=new Map,kO=0,Tx=[],D0=o(t=>We.sanitizeText(t,de()),"sanitizeText"),R0=o(function(t){let e=We.sanitizeText(t,de()),r="",n=e;if(e.indexOf("~")>0){let i=e.split("~");n=D0(i[0]),r=D0(i[1])}return{className:n,type:r}},"splitClassNameAndType"),u$e=o(function(t,e){let r=We.sanitizeText(t,de());e&&(e=D0(e));let{className:n}=R0(r);Gi.get(n).label=e},"setClassLabel"),kE=o(function(t){let e=We.sanitizeText(t,de()),{className:r,type:n}=R0(e);if(Gi.has(r))return;let i=We.sanitizeText(r,de());Gi.set(i,{id:i,type:n,label:i,cssClasses:[],methods:[],members:[],annotations:[],styles:[],domId:EE+i+"-"+The}),The++},"addClass"),khe=o(function(t){let e=We.sanitizeText(t,de());if(Gi.has(e))return Gi.get(e).domId;throw new Error("Class not found: "+e)},"lookUpDomId"),h$e=o(function(){EO=[],Gi=new Map,TE=[],Tx=[],Tx.push(Che),qu=new Map,kO=0,SO="TB",vr()},"clear"),f$e=o(function(t){return Gi.get(t)},"getClass"),d$e=o(function(){return Gi},"getClasses"),p$e=o(function(){return EO},"getRelations"),m$e=o(function(){return TE},"getNotes"),g$e=o(function(t){V.debug("Adding relation: "+JSON.stringify(t)),kE(t.id1),kE(t.id2),t.id1=R0(t.id1).className,t.id2=R0(t.id2).className,t.relationTitle1=We.sanitizeText(t.relationTitle1.trim(),de()),t.relationTitle2=We.sanitizeText(t.relationTitle2.trim(),de()),EO.push(t)},"addRelation"),y$e=o(function(t,e){let r=R0(t).className;Gi.get(r).annotations.push(e)},"addAnnotation"),Ehe=o(function(t,e){kE(t);let r=R0(t).className,n=Gi.get(r);if(typeof e=="string"){let i=e.trim();i.startsWith("<<")&&i.endsWith(">>")?n.annotations.push(D0(i.substring(2,i.length-2))):i.indexOf(")")>0?n.methods.push(new wx(i,"method")):i&&n.members.push(new wx(i,"attribute"))}},"addMember"),v$e=o(function(t,e){Array.isArray(e)&&(e.reverse(),e.forEach(r=>Ehe(t,r)))},"addMembers"),x$e=o(function(t,e){let r={id:`note${TE.length}`,class:e,text:t};TE.push(r)},"addNote"),b$e=o(function(t){return t.startsWith(":")&&(t=t.substring(1)),D0(t.trim())},"cleanupLabel"),CO=o(function(t,e){t.split(",").forEach(function(r){let n=r;/\d/.exec(r[0])&&(n=EE+n);let i=Gi.get(n);i&&i.cssClasses.push(e)})},"setCssClass"),w$e=o(function(t,e){t.split(",").forEach(function(r){e!==void 0&&(Gi.get(r).tooltip=D0(e))})},"setTooltip"),T$e=o(function(t,e){return e&&qu.has(e)?qu.get(e).classes.get(t).tooltip:Gi.get(t).tooltip},"getTooltip"),k$e=o(function(t,e,r){let n=de();t.split(",").forEach(function(i){let a=i;/\d/.exec(i[0])&&(a=EE+a);let s=Gi.get(a);s&&(s.link=Lt.formatUrl(e,n),n.securityLevel==="sandbox"?s.linkTarget="_top":typeof r=="string"?s.linkTarget=D0(r):s.linkTarget="_blank")}),CO(t,"clickable")},"setLink"),E$e=o(function(t,e,r){t.split(",").forEach(function(n){C$e(n,e,r),Gi.get(n).haveCallback=!0}),CO(t,"clickable")},"setClickEvent"),C$e=o(function(t,e,r){let n=We.sanitizeText(t,de());if(de().securityLevel!=="loose"||e===void 0)return;let a=n;if(Gi.has(a)){let s=khe(a),l=[];if(typeof r=="string"){l=r.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let u=0;u")),i.classed("hover",!0)}).on("mouseout",function(){e.transition().duration(500).style("opacity",0),$e(this).classed("hover",!1)})},"setupToolTips");Tx.push(Che);SO="TB",L$e=o(()=>SO,"getDirection"),D$e=o(t=>{SO=t},"setDirection"),R$e=o(function(t){qu.has(t)||(qu.set(t,{id:t,classes:new Map,children:{},domId:EE+t+"-"+kO}),kO++)},"addNamespace"),N$e=o(function(t){return qu.get(t)},"getNamespace"),M$e=o(function(){return qu},"getNamespaces"),I$e=o(function(t,e){if(qu.has(t))for(let r of e){let{className:n}=R0(r);Gi.get(n).parent=t,qu.get(t).classes.set(n,Gi.get(n))}},"addClassesToNamespace"),O$e=o(function(t,e){let r=Gi.get(t);if(!(!e||!r))for(let n of e)n.includes(",")?r.styles.push(...n.split(",")):r.styles.push(n)},"setCssStyle"),Bg={setAccTitle:kr,getAccTitle:Ar,getAccDescription:Lr,setAccDescription:_r,getConfig:o(()=>de().class,"getConfig"),addClass:kE,bindFunctions:S$e,clear:h$e,getClass:f$e,getClasses:d$e,getNotes:m$e,addAnnotation:y$e,addNote:x$e,getRelations:p$e,addRelation:g$e,getDirection:L$e,setDirection:D$e,addMember:Ehe,addMembers:v$e,cleanupLabel:b$e,lineType:A$e,relationType:_$e,setClickEvent:E$e,setCssClass:CO,setLink:k$e,getTooltip:T$e,setTooltip:w$e,lookUpDomId:khe,setDiagramTitle:nn,getDiagramTitle:Xr,setClassLabel:u$e,addNamespace:R$e,addClassesToNamespace:I$e,getNamespace:N$e,getNamespaces:M$e,setCssStyle:O$e}});var P$e,CE,_O=R(()=>{"use strict";P$e=o(t=>`g.classGroup text { + fill: ${t.nodeBorder||t.classText}; + stroke: none; + font-family: ${t.fontFamily}; + font-size: 10px; + + .title { + font-weight: bolder; + } + +} + +.nodeLabel, .edgeLabel { + color: ${t.classText}; +} +.edgeLabel .label rect { + fill: ${t.mainBkg}; +} +.label text { + fill: ${t.classText}; +} +.edgeLabel .label span { + background: ${t.mainBkg}; +} + +.classTitle { + font-weight: bolder; +} +.node rect, + .node circle, + .node ellipse, + .node polygon, + .node path { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; + stroke-width: 1px; + } + + +.divider { + stroke: ${t.nodeBorder}; + stroke-width: 1; +} + +g.clickable { + cursor: pointer; +} + +g.classGroup rect { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; +} + +g.classGroup line { + stroke: ${t.nodeBorder}; + stroke-width: 1; +} + +.classLabel .box { + stroke: none; + stroke-width: 0; + fill: ${t.mainBkg}; + opacity: 0.5; +} + +.classLabel .label { + fill: ${t.nodeBorder}; + font-size: 10px; +} + +.relation { + stroke: ${t.lineColor}; + stroke-width: 1; + fill: none; +} + +.dashed-line{ + stroke-dasharray: 3; +} + +.dotted-line{ + stroke-dasharray: 1 2; +} + +#compositionStart, .composition { + fill: ${t.lineColor} !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#compositionEnd, .composition { + fill: ${t.lineColor} !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#dependencyStart, .dependency { + fill: ${t.lineColor} !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#dependencyStart, .dependency { + fill: ${t.lineColor} !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#extensionStart, .extension { + fill: transparent !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#extensionEnd, .extension { + fill: transparent !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#aggregationStart, .aggregation { + fill: transparent !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#aggregationEnd, .aggregation { + fill: transparent !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#lollipopStart, .lollipop { + fill: ${t.mainBkg} !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +#lollipopEnd, .lollipop { + fill: ${t.mainBkg} !important; + stroke: ${t.lineColor} !important; + stroke-width: 1; +} + +.edgeTerminals { + font-size: 11px; + line-height: initial; +} + +.classTitleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.textColor}; +} +`,"getStyles"),CE=P$e});var She,B$e,F$e,_he,z$e,Ahe,SE,Lhe=R(()=>{"use strict";Zt();xr();ut();rr();She=0,B$e=o(function(t,e,r,n,i){let a=o(function(b){switch(b){case i.db.relationType.AGGREGATION:return"aggregation";case i.db.relationType.EXTENSION:return"extension";case i.db.relationType.COMPOSITION:return"composition";case i.db.relationType.DEPENDENCY:return"dependency";case i.db.relationType.LOLLIPOP:return"lollipop"}},"getRelationType");e.points=e.points.filter(b=>!Number.isNaN(b.y));let s=e.points,l=ha().x(function(b){return b.x}).y(function(b){return b.y}).curve(vs),u=t.append("path").attr("d",l(s)).attr("id","edge"+She).attr("class","relation"),h="";n.arrowMarkerAbsolute&&(h=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,h=h.replace(/\(/g,"\\("),h=h.replace(/\)/g,"\\)")),r.relation.lineType==1&&u.attr("class","relation dashed-line"),r.relation.lineType==10&&u.attr("class","relation dotted-line"),r.relation.type1!=="none"&&u.attr("marker-start","url("+h+"#"+a(r.relation.type1)+"Start)"),r.relation.type2!=="none"&&u.attr("marker-end","url("+h+"#"+a(r.relation.type2)+"End)");let f,d,p=e.points.length,m=Lt.calcLabelPosition(e.points);f=m.x,d=m.y;let g,y,v,x;if(p%2!==0&&p>1){let b=Lt.calcCardinalityPosition(r.relation.type1!=="none",e.points,e.points[0]),w=Lt.calcCardinalityPosition(r.relation.type2!=="none",e.points,e.points[p-1]);V.debug("cardinality_1_point "+JSON.stringify(b)),V.debug("cardinality_2_point "+JSON.stringify(w)),g=b.x,y=b.y,v=w.x,x=w.y}if(r.title!==void 0){let b=t.append("g").attr("class","classLabel"),w=b.append("text").attr("class","label").attr("x",f).attr("y",d).attr("fill","red").attr("text-anchor","middle").text(r.title);window.label=w;let S=w.node().getBBox();b.insert("rect",":first-child").attr("class","box").attr("x",S.x-n.padding/2).attr("y",S.y-n.padding/2).attr("width",S.width+n.padding).attr("height",S.height+n.padding)}V.info("Rendering relation "+JSON.stringify(r)),r.relationTitle1!==void 0&&r.relationTitle1!=="none"&&t.append("g").attr("class","cardinality").append("text").attr("class","type1").attr("x",g).attr("y",y).attr("fill","black").attr("font-size","6").text(r.relationTitle1),r.relationTitle2!==void 0&&r.relationTitle2!=="none"&&t.append("g").attr("class","cardinality").append("text").attr("class","type2").attr("x",v).attr("y",x).attr("fill","black").attr("font-size","6").text(r.relationTitle2),She++},"drawEdge"),F$e=o(function(t,e,r,n){V.debug("Rendering class ",e,r);let i=e.id,a={id:i,label:e.id,width:0,height:0},s=t.append("g").attr("id",n.db.lookUpDomId(i)).attr("class","classGroup"),l;e.link?l=s.append("svg:a").attr("xlink:href",e.link).attr("target",e.linkTarget).append("text").attr("y",r.textHeight+r.padding).attr("x",0):l=s.append("text").attr("y",r.textHeight+r.padding).attr("x",0);let u=!0;e.annotations.forEach(function(w){let S=l.append("tspan").text("\xAB"+w+"\xBB");u||S.attr("dy",r.textHeight),u=!1});let h=_he(e),f=l.append("tspan").text(h).attr("class","title");u||f.attr("dy",r.textHeight);let d=l.node().getBBox().height,p,m,g;if(e.members.length>0){p=s.append("line").attr("x1",0).attr("y1",r.padding+d+r.dividerMargin/2).attr("y2",r.padding+d+r.dividerMargin/2);let w=s.append("text").attr("x",r.padding).attr("y",d+r.dividerMargin+r.textHeight).attr("fill","white").attr("class","classText");u=!0,e.members.forEach(function(S){Ahe(w,S,u,r),u=!1}),m=w.node().getBBox()}if(e.methods.length>0){g=s.append("line").attr("x1",0).attr("y1",r.padding+d+r.dividerMargin+m.height).attr("y2",r.padding+d+r.dividerMargin+m.height);let w=s.append("text").attr("x",r.padding).attr("y",d+2*r.dividerMargin+m.height+r.textHeight).attr("fill","white").attr("class","classText");u=!0,e.methods.forEach(function(S){Ahe(w,S,u,r),u=!1})}let y=s.node().getBBox();var v=" ";e.cssClasses.length>0&&(v=v+e.cssClasses.join(" "));let b=s.insert("rect",":first-child").attr("x",0).attr("y",0).attr("width",y.width+2*r.padding).attr("height",y.height+r.padding+.5*r.dividerMargin).attr("class",v).node().getBBox().width;return l.node().childNodes.forEach(function(w){w.setAttribute("x",(b-w.getBBox().width)/2)}),e.tooltip&&l.insert("title").text(e.tooltip),p&&p.attr("x2",b),g&&g.attr("x2",b),a.width=b,a.height=y.height+r.padding+.5*r.dividerMargin,a},"drawClass"),_he=o(function(t){let e=t.id;return t.type&&(e+="<"+gh(t.type)+">"),e},"getClassTitleString"),z$e=o(function(t,e,r,n){V.debug("Rendering note ",e,r);let i=e.id,a={id:i,text:e.text,width:0,height:0},s=t.append("g").attr("id",i).attr("class","classGroup"),l=s.append("text").attr("y",r.textHeight+r.padding).attr("x",0),u=JSON.parse(`"${e.text}"`).split(` +`);u.forEach(function(p){V.debug(`Adding line: ${p}`),l.append("tspan").text(p).attr("class","title").attr("dy",r.textHeight)});let h=s.node().getBBox(),d=s.insert("rect",":first-child").attr("x",0).attr("y",0).attr("width",h.width+2*r.padding).attr("height",h.height+u.length*r.textHeight+r.padding+.5*r.dividerMargin).node().getBBox().width;return l.node().childNodes.forEach(function(p){p.setAttribute("x",(d-p.getBBox().width)/2)}),a.width=d,a.height=h.height+u.length*r.textHeight+r.padding+.5*r.dividerMargin,a},"drawNote"),Ahe=o(function(t,e,r,n){let{displayText:i,cssStyle:a}=e.getDisplayDetails(),s=t.append("tspan").attr("x",n.padding).text(i);a!==""&&s.attr("style",e.cssStyle),r||s.attr("dy",n.textHeight)},"addTspan"),SE={getClassTitleString:_he,drawClass:F$e,drawEdge:B$e,drawNote:z$e}});var _E,AE,kx,G$e,$$e,Dhe,Rhe=R(()=>{"use strict";Zt();Vd();ya();ut();Lhe();Yn();_t();_E={},AE=20,kx=o(function(t){let e=Object.entries(_E).find(r=>r[1].label===t);if(e)return e[0]},"getGraphId"),G$e=o(function(t){t.append("defs").append("marker").attr("id","extensionStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),t.append("defs").append("marker").attr("id","extensionEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z"),t.append("defs").append("marker").attr("id","compositionStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id","compositionEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id","aggregationStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id","aggregationEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id","dependencyStart").attr("class","extension").attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"insertMarkers"),$$e=o(function(t,e,r,n){let i=de().class;_E={},V.info("Rendering diagram "+t);let a=de().securityLevel,s;a==="sandbox"&&(s=$e("#i"+e));let l=a==="sandbox"?$e(s.nodes()[0].contentDocument.body):$e("body"),u=l.select(`[id='${e}']`);G$e(u);let h=new lr({multigraph:!0});h.setGraph({isMultiGraph:!0}),h.setDefaultEdgeLabel(function(){return{}});let f=n.db.getClasses(),d=[...f.keys()];for(let b of d){let w=f.get(b),S=SE.drawClass(u,w,i,n);_E[S.id]=S,h.setNode(S.id,S),V.info("Org height: "+S.height)}n.db.getRelations().forEach(function(b){V.info("tjoho"+kx(b.id1)+kx(b.id2)+JSON.stringify(b)),h.setEdge(kx(b.id1),kx(b.id2),{relation:b},b.title||"DEFAULT")}),n.db.getNotes().forEach(function(b){V.debug(`Adding note: ${JSON.stringify(b)}`);let w=SE.drawNote(u,b,i,n);_E[w.id]=w,h.setNode(w.id,w),b.class&&f.has(b.class)&&h.setEdge(b.id,kx(b.class),{relation:{id1:b.id,id2:b.class,relation:{type1:"none",type2:"none",lineType:10}}},"DEFAULT")}),lo(h),h.nodes().forEach(function(b){b!==void 0&&h.node(b)!==void 0&&(V.debug("Node "+b+": "+JSON.stringify(h.node(b))),l.select("#"+(n.db.lookUpDomId(b)||b)).attr("transform","translate("+(h.node(b).x-h.node(b).width/2)+","+(h.node(b).y-h.node(b).height/2)+" )"))}),h.edges().forEach(function(b){b!==void 0&&h.edge(b)!==void 0&&(V.debug("Edge "+b.v+" -> "+b.w+": "+JSON.stringify(h.edge(b))),SE.drawEdge(u,h.edge(b),h.edge(b).relation,i,n))});let g=u.node().getBBox(),y=g.width+AE*2,v=g.height+AE*2;Sr(u,v,y,i.useMaxWidth);let x=`${g.x-AE} ${g.y-AE} ${y} ${v}`;V.debug(`viewBox ${x}`),u.attr("viewBox",x)},"draw"),Dhe={draw:$$e}});var Nhe={};hr(Nhe,{diagram:()=>V$e});var V$e,Mhe=R(()=>{"use strict";TO();AO();_O();Rhe();V$e={parser:wE,db:Bg,renderer:Dhe,styles:CE,init:o(t=>{t.class||(t.class={}),t.class.arrowMarkerAbsolute=t.arrowMarkerAbsolute,Bg.clear()},"init")}});var W$e,q$e,X$e,j$e,K$e,Q$e,Z$e,J$e,eVe,tVe,rVe,LE,LO=R(()=>{"use strict";ut();W$e=o((t,e,r,n)=>{e.forEach(i=>{rVe[i](t,r,n)})},"insertMarkers"),q$e=o((t,e,r)=>{V.trace("Making markers for ",r),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionStart").attr("class","marker extension "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionEnd").attr("class","marker extension "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z")},"extension"),X$e=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionStart").attr("class","marker composition "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionEnd").attr("class","marker composition "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"composition"),j$e=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationStart").attr("class","marker aggregation "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationEnd").attr("class","marker aggregation "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")},"aggregation"),K$e=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyStart").attr("class","marker dependency "+e).attr("refX",6).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyEnd").attr("class","marker dependency "+e).attr("refX",13).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")},"dependency"),Q$e=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopStart").attr("class","marker lollipop "+e).attr("refX",13).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6),t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopEnd").attr("class","marker lollipop "+e).attr("refX",1).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6)},"lollipop"),Z$e=o((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-pointEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",6).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-pointStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",4.5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 5 L 10 10 L 10 0 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"point"),J$e=o((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-circleEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",11).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-circleStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",-1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")},"circle"),eVe=o((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-crossEnd").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",12).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-crossStart").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",-1).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0")},"cross"),tVe=o((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-barbEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",14).attr("markerUnits","strokeWidth").attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"barb"),rVe={extension:q$e,composition:X$e,aggregation:j$e,dependency:K$e,lollipop:Q$e,point:Z$e,circle:J$e,cross:eVe,barb:tVe},LE=W$e});var tr,zl,Phe,Bhe,RE,nVe,Fhe,zhe,Fg,DE,Ghe,$he,Vhe,Uhe,Hhe=R(()=>{"use strict";ut();Pv();ya();tr={},zl={},Phe={},Bhe=o(()=>{zl={},Phe={},tr={}},"clear"),RE=o((t,e)=>(V.trace("In isDescendant",e," ",t," = ",zl[e].includes(t)),!!zl[e].includes(t)),"isDescendant"),nVe=o((t,e)=>(V.info("Descendants of ",e," is ",zl[e]),V.info("Edge is ",t),t.v===e||t.w===e?!1:zl[e]?zl[e].includes(t.v)||RE(t.v,e)||RE(t.w,e)||zl[e].includes(t.w):(V.debug("Tilt, ",e,",not in descendants"),!1)),"edgeInCluster"),Fhe=o((t,e,r,n)=>{V.warn("Copying children of ",t,"root",n,"data",e.node(t),n);let i=e.children(t)||[];t!==n&&i.push(t),V.warn("Copying (nodes) clusterId",t,"nodes",i),i.forEach(a=>{if(e.children(a).length>0)Fhe(a,e,r,n);else{let s=e.node(a);V.info("cp ",a," to ",n," with parent ",t),r.setNode(a,s),n!==e.parent(a)&&(V.warn("Setting parent",a,e.parent(a)),r.setParent(a,e.parent(a))),t!==n&&a!==t?(V.debug("Setting parent",a,t),r.setParent(a,t)):(V.info("In copy ",t,"root",n,"data",e.node(t),n),V.debug("Not Setting parent for node=",a,"cluster!==rootId",t!==n,"node!==clusterId",a!==t));let l=e.edges(a);V.debug("Copying Edges",l),l.forEach(u=>{V.info("Edge",u);let h=e.edge(u.v,u.w,u.name);V.info("Edge data",h,n);try{nVe(u,n)?(V.info("Copying as ",u.v,u.w,h,u.name),r.setEdge(u.v,u.w,h,u.name),V.info("newGraph edges ",r.edges(),r.edge(r.edges()[0]))):V.info("Skipping copy of edge ",u.v,"-->",u.w," rootId: ",n," clusterId:",t)}catch(f){V.error(f)}})}V.debug("Removing node",a),e.removeNode(a)})},"copy"),zhe=o((t,e)=>{let r=e.children(t),n=[...r];for(let i of r)Phe[i]=t,n=[...n,...zhe(i,e)];return n},"extractDescendants"),Fg=o((t,e)=>{V.trace("Searching",t);let r=e.children(t);if(V.trace("Searching children of id ",t,r),r.length<1)return V.trace("This is a valid node",t),t;for(let n of r){let i=Fg(n,e);if(i)return V.trace("Found replacement for",t," => ",i),i}},"findNonClusterChild"),DE=o(t=>!tr[t]||!tr[t].externalConnections?t:tr[t]?tr[t].id:t,"getAnchorId"),Ghe=o((t,e)=>{if(!t||e>10){V.debug("Opting out, no graph ");return}else V.debug("Opting in, graph ");t.nodes().forEach(function(r){t.children(r).length>0&&(V.warn("Cluster identified",r," Replacement id in edges: ",Fg(r,t)),zl[r]=zhe(r,t),tr[r]={id:Fg(r,t),clusterData:t.node(r)})}),t.nodes().forEach(function(r){let n=t.children(r),i=t.edges();n.length>0?(V.debug("Cluster identified",r,zl),i.forEach(a=>{if(a.v!==r&&a.w!==r){let s=RE(a.v,r),l=RE(a.w,r);s^l&&(V.warn("Edge: ",a," leaves cluster ",r),V.warn("Descendants of XXX ",r,": ",zl[r]),tr[r].externalConnections=!0)}})):V.debug("Not a cluster ",r,zl)});for(let r of Object.keys(tr)){let n=tr[r].id,i=t.parent(n);i!==r&&tr[i]&&!tr[i].externalConnections&&(tr[r].id=i)}t.edges().forEach(function(r){let n=t.edge(r);V.warn("Edge "+r.v+" -> "+r.w+": "+JSON.stringify(r)),V.warn("Edge "+r.v+" -> "+r.w+": "+JSON.stringify(t.edge(r)));let i=r.v,a=r.w;if(V.warn("Fix XXX",tr,"ids:",r.v,r.w,"Translating: ",tr[r.v]," --- ",tr[r.w]),tr[r.v]&&tr[r.w]&&tr[r.v]===tr[r.w]){V.warn("Fixing and trixing link to self - removing XXX",r.v,r.w,r.name),V.warn("Fixing and trixing - removing XXX",r.v,r.w,r.name),i=DE(r.v),a=DE(r.w),t.removeEdge(r.v,r.w,r.name);let s=r.w+"---"+r.v;t.setNode(s,{domId:s,id:s,labelStyle:"",labelText:n.label,padding:0,shape:"labelRect",style:""});let l=structuredClone(n),u=structuredClone(n);l.label="",l.arrowTypeEnd="none",u.label="",l.fromCluster=r.v,u.toCluster=r.v,t.setEdge(i,s,l,r.name+"-cyclic-special"),t.setEdge(s,a,u,r.name+"-cyclic-special")}else if(tr[r.v]||tr[r.w]){if(V.warn("Fixing and trixing - removing XXX",r.v,r.w,r.name),i=DE(r.v),a=DE(r.w),t.removeEdge(r.v,r.w,r.name),i!==r.v){let s=t.parent(i);tr[s].externalConnections=!0,n.fromCluster=r.v}if(a!==r.w){let s=t.parent(a);tr[s].externalConnections=!0,n.toCluster=r.w}V.warn("Fix Replacing with XXX",i,a,r.name),t.setEdge(i,a,n,r.name)}}),V.warn("Adjusted Graph",zn(t)),$he(t,0),V.trace(tr)},"adjustClustersAndEdges"),$he=o((t,e)=>{if(V.warn("extractor - ",e,zn(t),t.children("D")),e>10){V.error("Bailing out");return}let r=t.nodes(),n=!1;for(let i of r){let a=t.children(i);n=n||a.length>0}if(!n){V.debug("Done, no node has children",t.nodes());return}V.debug("Nodes = ",r,e);for(let i of r)if(V.debug("Extracting node",i,tr,tr[i]&&!tr[i].externalConnections,!t.parent(i),t.node(i),t.children("D")," Depth ",e),!tr[i])V.debug("Not a cluster",i,e);else if(!tr[i].externalConnections&&t.children(i)&&t.children(i).length>0){V.warn("Cluster without external connections, without a parent and with children",i,e);let s=t.graph().rankdir==="TB"?"LR":"TB";tr[i]?.clusterData?.dir&&(s=tr[i].clusterData.dir,V.warn("Fixing dir",tr[i].clusterData.dir,s));let l=new lr({multigraph:!0,compound:!0}).setGraph({rankdir:s,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});V.warn("Old graph before copy",zn(t)),Fhe(i,t,l,i),t.setNode(i,{clusterNode:!0,id:i,clusterData:tr[i].clusterData,labelText:tr[i].labelText,graph:l}),V.warn("New graph after copy node: (",i,")",zn(l)),V.debug("Old graph after copy",zn(t))}else V.warn("Cluster ** ",i," **not meeting the criteria !externalConnections:",!tr[i].externalConnections," no parent: ",!t.parent(i)," children ",t.children(i)&&t.children(i).length>0,t.children("D"),e),V.debug(tr);r=t.nodes(),V.warn("New list of nodes",r);for(let i of r){let a=t.node(i);V.warn(" Now next level",i,a),a.clusterNode&&$he(a.graph,e+1)}},"extractor"),Vhe=o((t,e)=>{if(e.length===0)return[];let r=Object.assign(e);return e.forEach(n=>{let i=t.children(n),a=Vhe(t,i);r=[...r,...a]}),r},"sorter"),Uhe=o(t=>Vhe(t,t.children()),"sortNodesByHierarchy")});var iVe,aVe,sVe,oVe,lVe,Yhe,Whe,qhe,Xhe=R(()=>{"use strict";S9();ut();bv();Al();Zt();_t();rr();_d();iVe=o((t,e)=>{V.info("Creating subgraph rect for ",e.id,e);let r=de(),n=t.insert("g").attr("class","cluster"+(e.class?" "+e.class:"")).attr("id",e.id),i=n.insert("rect",":first-child"),a=yr(r.flowchart.htmlLabels),s=n.insert("g").attr("class","cluster-label"),l=e.labelType==="markdown"?ta(s,e.labelText,{style:e.labelStyle,useHtmlLabels:a},r):s.node().appendChild(ra(e.labelText,e.labelStyle,void 0,!0)),u=l.getBBox();if(yr(r.flowchart.htmlLabels)){let g=l.children[0],y=$e(l);u=g.getBoundingClientRect(),y.attr("width",u.width),y.attr("height",u.height)}let h=0*e.padding,f=h/2,d=e.width<=u.width+h?u.width+h:e.width;e.width<=u.width+h?e.diff=(u.width-e.width)/2-e.padding/2:e.diff=-e.padding/2,V.trace("Data ",e,JSON.stringify(e)),i.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",e.x-d/2).attr("y",e.y-e.height/2-f).attr("width",d).attr("height",e.height+h);let{subGraphTitleTopMargin:p}=io(r);a?s.attr("transform",`translate(${e.x-u.width/2}, ${e.y-e.height/2+p})`):s.attr("transform",`translate(${e.x}, ${e.y-e.height/2+p})`);let m=i.node().getBBox();return e.width=m.width,e.height=m.height,e.intersect=function(g){return Ad(e,g)},n},"rect"),aVe=o((t,e)=>{let r=t.insert("g").attr("class","note-cluster").attr("id",e.id),n=r.insert("rect",":first-child"),i=0*e.padding,a=i/2;n.attr("rx",e.rx).attr("ry",e.ry).attr("x",e.x-e.width/2-a).attr("y",e.y-e.height/2-a).attr("width",e.width+i).attr("height",e.height+i).attr("fill","none");let s=n.node().getBBox();return e.width=s.width,e.height=s.height,e.intersect=function(l){return Ad(e,l)},r},"noteGroup"),sVe=o((t,e)=>{let r=de(),n=t.insert("g").attr("class",e.classes).attr("id",e.id),i=n.insert("rect",":first-child"),a=n.insert("g").attr("class","cluster-label"),s=n.append("rect"),l=a.node().appendChild(ra(e.labelText,e.labelStyle,void 0,!0)),u=l.getBBox();if(yr(r.flowchart.htmlLabels)){let g=l.children[0],y=$e(l);u=g.getBoundingClientRect(),y.attr("width",u.width),y.attr("height",u.height)}u=l.getBBox();let h=0*e.padding,f=h/2,d=e.width<=u.width+e.padding?u.width+e.padding:e.width;e.width<=u.width+e.padding?e.diff=(u.width+e.padding*0-e.width)/2:e.diff=-e.padding/2,i.attr("class","outer").attr("x",e.x-d/2-f).attr("y",e.y-e.height/2-f).attr("width",d+h).attr("height",e.height+h),s.attr("class","inner").attr("x",e.x-d/2-f).attr("y",e.y-e.height/2-f+u.height-1).attr("width",d+h).attr("height",e.height+h-u.height-3);let{subGraphTitleTopMargin:p}=io(r);a.attr("transform",`translate(${e.x-u.width/2}, ${e.y-e.height/2-e.padding/3+(yr(r.flowchart.htmlLabels)?5:3)+p})`);let m=i.node().getBBox();return e.height=m.height,e.intersect=function(g){return Ad(e,g)},n},"roundedWithTitle"),oVe=o((t,e)=>{let r=t.insert("g").attr("class",e.classes).attr("id",e.id),n=r.insert("rect",":first-child"),i=0*e.padding,a=i/2;n.attr("class","divider").attr("x",e.x-e.width/2-a).attr("y",e.y-e.height/2).attr("width",e.width+i).attr("height",e.height+i);let s=n.node().getBBox();return e.width=s.width,e.height=s.height,e.diff=-e.padding/2,e.intersect=function(l){return Ad(e,l)},r},"divider"),lVe={rect:iVe,roundedWithTitle:sVe,noteGroup:aVe,divider:oVe},Yhe={},Whe=o((t,e)=>{V.trace("Inserting cluster");let r=e.shape||"rect";Yhe[e.id]=lVe[r](t,e)},"insertCluster"),qhe=o(()=>{Yhe={}},"clear")});var Khe,cVe,jhe,Qhe=R(()=>{"use strict";ut();Khe=o((t,e,r,n,i)=>{e.arrowTypeStart&&jhe(t,"start",e.arrowTypeStart,r,n,i),e.arrowTypeEnd&&jhe(t,"end",e.arrowTypeEnd,r,n,i)},"addEdgeMarkers"),cVe={arrow_cross:"cross",arrow_point:"point",arrow_barb:"barb",arrow_circle:"circle",aggregation:"aggregation",extension:"extension",composition:"composition",dependency:"dependency",lollipop:"lollipop"},jhe=o((t,e,r,n,i,a)=>{let s=cVe[r];if(!s){V.warn(`Unknown arrow type: ${r}`);return}let l=e==="start"?"Start":"End";t.attr(`marker-${e}`,`url(${n}#${i}_${a}-${s}${l})`)},"addEdgeMarker")});function NE(t,e){de().flowchart.htmlLabels&&t&&(t.style.width=e.length*9+"px",t.style.height="12px")}var ME,Ta,Jhe,IE,OE,uVe,hVe,Zhe,PE,DO=R(()=>{"use strict";ut();bv();Al();Zt();_t();xr();rr();j9();_d();Qhe();ME={},Ta={},Jhe=o(()=>{ME={},Ta={}},"clear"),IE=o((t,e)=>{let r=de(),n=yr(r.flowchart.htmlLabels),i=e.labelType==="markdown"?ta(t,e.label,{style:e.labelStyle,useHtmlLabels:n,addSvgBackground:!0},r):ra(e.label,e.labelStyle),a=t.insert("g").attr("class","edgeLabel"),s=a.insert("g").attr("class","label");s.node().appendChild(i);let l=i.getBBox();if(n){let h=i.children[0],f=$e(i);l=h.getBoundingClientRect(),f.attr("width",l.width),f.attr("height",l.height)}s.attr("transform","translate("+-l.width/2+", "+-l.height/2+")"),ME[e.id]=a,e.width=l.width,e.height=l.height;let u;if(e.startLabelLeft){let h=ra(e.startLabelLeft,e.labelStyle),f=t.insert("g").attr("class","edgeTerminals"),d=f.insert("g").attr("class","inner");u=d.node().appendChild(h);let p=h.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),Ta[e.id]||(Ta[e.id]={}),Ta[e.id].startLeft=f,NE(u,e.startLabelLeft)}if(e.startLabelRight){let h=ra(e.startLabelRight,e.labelStyle),f=t.insert("g").attr("class","edgeTerminals"),d=f.insert("g").attr("class","inner");u=f.node().appendChild(h),d.node().appendChild(h);let p=h.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),Ta[e.id]||(Ta[e.id]={}),Ta[e.id].startRight=f,NE(u,e.startLabelRight)}if(e.endLabelLeft){let h=ra(e.endLabelLeft,e.labelStyle),f=t.insert("g").attr("class","edgeTerminals"),d=f.insert("g").attr("class","inner");u=d.node().appendChild(h);let p=h.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),f.node().appendChild(h),Ta[e.id]||(Ta[e.id]={}),Ta[e.id].endLeft=f,NE(u,e.endLabelLeft)}if(e.endLabelRight){let h=ra(e.endLabelRight,e.labelStyle),f=t.insert("g").attr("class","edgeTerminals"),d=f.insert("g").attr("class","inner");u=d.node().appendChild(h);let p=h.getBBox();d.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),f.node().appendChild(h),Ta[e.id]||(Ta[e.id]={}),Ta[e.id].endRight=f,NE(u,e.endLabelRight)}return i},"insertEdgeLabel");o(NE,"setTerminalWidth");OE=o((t,e)=>{V.debug("Moving label abc88 ",t.id,t.label,ME[t.id],e);let r=e.updatedPath?e.updatedPath:e.originalPath,n=de(),{subGraphTitleTotalMargin:i}=io(n);if(t.label){let a=ME[t.id],s=t.x,l=t.y;if(r){let u=Lt.calcLabelPosition(r);V.debug("Moving label "+t.label+" from (",s,",",l,") to (",u.x,",",u.y,") abc88"),e.updatedPath&&(s=u.x,l=u.y)}a.attr("transform",`translate(${s}, ${l+i/2})`)}if(t.startLabelLeft){let a=Ta[t.id].startLeft,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_left",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}if(t.startLabelRight){let a=Ta[t.id].startRight,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_right",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}if(t.endLabelLeft){let a=Ta[t.id].endLeft,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_left",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}if(t.endLabelRight){let a=Ta[t.id].endRight,s=t.x,l=t.y;if(r){let u=Lt.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_right",r);s=u.x,l=u.y}a.attr("transform",`translate(${s}, ${l})`)}},"positionEdgeLabel"),uVe=o((t,e)=>{let r=t.x,n=t.y,i=Math.abs(e.x-r),a=Math.abs(e.y-n),s=t.width/2,l=t.height/2;return i>=s||a>=l},"outsideNode"),hVe=o((t,e,r)=>{V.debug(`intersection calc abc89: + outsidePoint: ${JSON.stringify(e)} + insidePoint : ${JSON.stringify(r)} + node : x:${t.x} y:${t.y} w:${t.width} h:${t.height}`);let n=t.x,i=t.y,a=Math.abs(n-r.x),s=t.width/2,l=r.xMath.abs(n-e.x)*u){let d=r.y{V.debug("abc88 cutPathAtIntersect",t,e);let r=[],n=t[0],i=!1;return t.forEach(a=>{if(!uVe(e,a)&&!i){let s=hVe(e,n,a),l=!1;r.forEach(u=>{l=l||u.x===s.x&&u.y===s.y}),r.some(u=>u.x===s.x&&u.y===s.y)||r.push(s),i=!0}else n=a,i||r.push(a)}),r},"cutPathAtIntersect"),PE=o(function(t,e,r,n,i,a,s){let l=r.points;V.debug("abc88 InsertEdge: edge=",r,"e=",e);let u=!1,h=a.node(e.v);var f=a.node(e.w);f?.intersect&&h?.intersect&&(l=l.slice(1,r.points.length-1),l.unshift(h.intersect(l[0])),l.push(f.intersect(l[l.length-1]))),r.toCluster&&(V.debug("to cluster abc88",n[r.toCluster]),l=Zhe(r.points,n[r.toCluster].node),u=!0),r.fromCluster&&(V.debug("from cluster abc88",n[r.fromCluster]),l=Zhe(l.reverse(),n[r.fromCluster].node).reverse(),u=!0);let d=l.filter(S=>!Number.isNaN(S.y)),p=vs;r.curve&&(i==="graph"||i==="flowchart")&&(p=r.curve);let{x:m,y:g}=X5(r),y=ha().x(m).y(g).curve(p),v;switch(r.thickness){case"normal":v="edge-thickness-normal";break;case"thick":v="edge-thickness-thick";break;case"invisible":v="edge-thickness-thick";break;default:v=""}switch(r.pattern){case"solid":v+=" edge-pattern-solid";break;case"dotted":v+=" edge-pattern-dotted";break;case"dashed":v+=" edge-pattern-dashed";break}let x=t.append("path").attr("d",y(d)).attr("id",r.id).attr("class"," "+v+(r.classes?" "+r.classes:"")).attr("style",r.style),b="";(de().flowchart.arrowMarkerAbsolute||de().state.arrowMarkerAbsolute)&&(b=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,b=b.replace(/\(/g,"\\("),b=b.replace(/\)/g,"\\)")),Khe(x,r,b,s,i);let w={};return u&&(w.updatedPath=l),w.originalPath=r.points,w},"insertEdge")});var efe,tfe,rfe=R(()=>{"use strict";Vd();Pv();LO();N5();Hhe();M5();Xhe();DO();ut();_d();_t();efe=o(async(t,e,r,n,i,a)=>{V.info("Graph in recursive render: XXX",zn(e),i);let s=e.graph().rankdir;V.trace("Dir in recursive render - dir:",s);let l=t.insert("g").attr("class","root");e.nodes()?V.info("Recursive render XXX",e.nodes()):V.info("No nodes found for",e),e.edges().length>0&&V.trace("Recursive edges",e.edge(e.edges()[0]));let u=l.insert("g").attr("class","clusters"),h=l.insert("g").attr("class","edgePaths"),f=l.insert("g").attr("class","edgeLabels"),d=l.insert("g").attr("class","nodes");await Promise.all(e.nodes().map(async function(g){let y=e.node(g);if(i!==void 0){let v=JSON.parse(JSON.stringify(i.clusterData));V.info("Setting data for cluster XXX (",g,") ",v,i),e.setNode(i.id,v),e.parent(g)||(V.trace("Setting parent",g,i.id),e.setParent(g,i.id,v))}if(V.info("(Insert) Node XXX"+g+": "+JSON.stringify(e.node(g))),y?.clusterNode){V.info("Cluster identified",g,y.width,e.node(g));let{ranksep:v,nodesep:x}=e.graph();y.graph.setGraph({...y.graph.graph(),ranksep:v,nodesep:x});let b=await efe(d,y.graph,r,n,e.node(g),a),w=b.elem;kn(y,w),y.diff=b.diff||0,V.info("Node bounds (abc123)",g,y,y.width,y.x,y.y),Bj(w,y),V.warn("Recursive render complete ",w,y)}else e.children(g).length>0?(V.info("Cluster - the non recursive path XXX",g,y.id,y,e),V.info(Fg(y.id,e)),tr[y.id]={id:Fg(y.id,e),node:y}):(V.info("Node - the non recursive path",g,y.id,y),await pm(d,e.node(g),s))})),e.edges().forEach(async function(g){let y=e.edge(g.v,g.w,g.name);V.info("Edge "+g.v+" -> "+g.w+": "+JSON.stringify(g)),V.info("Edge "+g.v+" -> "+g.w+": ",g," ",JSON.stringify(e.edge(g))),V.info("Fix",tr,"ids:",g.v,g.w,"Translating: ",tr[g.v],tr[g.w]),await IE(f,y)}),e.edges().forEach(function(g){V.info("Edge "+g.v+" -> "+g.w+": "+JSON.stringify(g))}),V.info("Graph before layout:",JSON.stringify(zn(e))),V.info("#############################################"),V.info("### Layout ###"),V.info("#############################################"),V.info(e),lo(e),V.info("Graph after layout:",JSON.stringify(zn(e)));let p=0,{subGraphTitleTotalMargin:m}=io(a);return Uhe(e).forEach(function(g){let y=e.node(g);V.info("Position "+g+": "+JSON.stringify(e.node(g))),V.info("Position "+g+": ("+y.x,","+y.y,") width: ",y.width," height: ",y.height),y?.clusterNode?(y.y+=m,wv(y)):e.children(g).length>0?(y.height+=m,Whe(u,y),tr[y.id].node=y):(y.y+=m/2,wv(y))}),e.edges().forEach(function(g){let y=e.edge(g);V.info("Edge "+g.v+" -> "+g.w+": "+JSON.stringify(y),y),y.points.forEach(x=>x.y+=m/2);let v=PE(h,g,y,tr,r,e,n);OE(y,v)}),e.nodes().forEach(function(g){let y=e.node(g);V.info(g,y.type,y.diff),y.type==="group"&&(p=y.diff)}),{elem:l,diff:p}},"recursiveRender"),tfe=o(async(t,e,r,n,i)=>{LE(t,r,n,i),Fj(),Jhe(),qhe(),Bhe(),V.warn("Graph at first:",JSON.stringify(zn(e))),Ghe(e),V.warn("Graph after:",JSON.stringify(zn(e)));let a=de();await efe(t,e,n,i,void 0,a)},"render")});function nfe(t){let e;switch(t){case 0:e="aggregation";break;case 1:e="extension";break;case 2:e="composition";break;case 3:e="dependency";break;case 4:e="lollipop";break;default:e="none"}return e}var NO,RO,fVe,ife,dVe,pVe,mVe,gVe,afe,sfe=R(()=>{"use strict";Zt();ya();ut();_t();rfe();xr();xr();Yn();rr();NO=o(t=>We.sanitizeText(t,de()),"sanitizeText"),RO={dividerMargin:10,padding:5,textHeight:10,curve:void 0},fVe=o(function(t,e,r,n){V.info("keys:",[...t.keys()]),V.info(t),t.forEach(function(i){let s={shape:"rect",id:i.id,domId:i.domId,labelText:NO(i.id),labelStyle:"",style:"fill: none; stroke: black",padding:de().flowchart?.padding??de().class?.padding};e.setNode(i.id,s),ife(i.classes,e,r,n,i.id),V.info("setNode",s)})},"addNamespaces"),ife=o(function(t,e,r,n,i){V.info("keys:",[...t.keys()]),V.info(t),[...t.values()].filter(a=>a.parent===i).forEach(function(a){let s=a.cssClasses.join(" "),l=lm(a.styles),u=a.label??a.id,h=0,d={labelStyle:l.labelStyle,shape:"class_box",labelText:NO(u),classData:a,rx:h,ry:h,class:s,style:l.style,id:a.id,domId:a.domId,tooltip:n.db.getTooltip(a.id,i)||"",haveCallback:a.haveCallback,link:a.link,width:a.type==="group"?500:void 0,type:a.type,padding:de().flowchart?.padding??de().class?.padding};e.setNode(a.id,d),i&&e.setParent(a.id,i),V.info("setNode",d)})},"addClasses"),dVe=o(function(t,e,r,n){V.info(t),t.forEach(function(i,a){let s=i,l="",u={labelStyle:"",style:""},h=s.text,f=0,p={labelStyle:u.labelStyle,shape:"note",labelText:NO(h),noteData:s,rx:f,ry:f,class:l,style:u.style,id:s.id,domId:s.id,tooltip:"",type:"note",padding:de().flowchart?.padding??de().class?.padding};if(e.setNode(s.id,p),V.info("setNode",p),!s.class||!n.has(s.class))return;let m=r+a,g={id:`edgeNote${m}`,classes:"relation",pattern:"dotted",arrowhead:"none",startLabelRight:"",endLabelLeft:"",arrowTypeStart:"none",arrowTypeEnd:"none",style:"fill:none",labelStyle:"",curve:om(RO.curve,xu)};e.setEdge(s.id,s.class,g,m)})},"addNotes"),pVe=o(function(t,e){let r=de().flowchart,n=0;t.forEach(function(i){n++;let a={classes:"relation",pattern:i.relation.lineType==1?"dashed":"solid",id:y5(i.id1,i.id2,{prefix:"id",counter:n}),arrowhead:i.type==="arrow_open"?"none":"normal",startLabelRight:i.relationTitle1==="none"?"":i.relationTitle1,endLabelLeft:i.relationTitle2==="none"?"":i.relationTitle2,arrowTypeStart:nfe(i.relation.type1),arrowTypeEnd:nfe(i.relation.type2),style:"fill:none",labelStyle:"",curve:om(r?.curve,xu)};if(V.info(a,i),i.style!==void 0){let s=lm(i.style);a.style=s.style,a.labelStyle=s.labelStyle}i.text=i.title,i.text===void 0?i.style!==void 0&&(a.arrowheadStyle="fill: #333"):(a.arrowheadStyle="fill: #333",a.labelpos="c",de().flowchart?.htmlLabels??de().htmlLabels?(a.labelType="html",a.label=''+i.text+""):(a.labelType="text",a.label=i.text.replace(We.lineBreakRegex,` +`),i.style===void 0&&(a.style=a.style||"stroke: #333; stroke-width: 1.5px;fill:none"),a.labelStyle=a.labelStyle.replace("color:","fill:"))),e.setEdge(i.id1,i.id2,a,n)})},"addRelations"),mVe=o(function(t){RO={...RO,...t}},"setConf"),gVe=o(async function(t,e,r,n){V.info("Drawing class - ",e);let i=de().flowchart??de().class,a=de().securityLevel;V.info("config:",i);let s=i?.nodeSpacing??50,l=i?.rankSpacing??50,u=new lr({multigraph:!0,compound:!0}).setGraph({rankdir:n.db.getDirection(),nodesep:s,ranksep:l,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}}),h=n.db.getNamespaces(),f=n.db.getClasses(),d=n.db.getRelations(),p=n.db.getNotes();V.info(d),fVe(h,u,e,n),ife(f,u,e,n),pVe(d,u),dVe(p,u,d.length+1,f);let m;a==="sandbox"&&(m=$e("#i"+e));let g=a==="sandbox"?$e(m.nodes()[0].contentDocument.body):$e("body"),y=g.select(`[id="${e}"]`),v=g.select("#"+e+" g");if(await tfe(v,u,["aggregation","extension","composition","dependency","lollipop"],"classDiagram",e),Lt.insertTitle(y,"classTitleText",i?.titleTopMargin??5,n.db.getDiagramTitle()),Lo(u,y,i?.diagramPadding,i?.useMaxWidth),!i?.htmlLabels){let x=a==="sandbox"?m.nodes()[0].contentDocument:document,b=x.querySelectorAll('[id="'+e+'"] .edgeLabel .label');for(let w of b){let S=w.getBBox(),T=x.createElementNS("http://www.w3.org/2000/svg","rect");T.setAttribute("rx",0),T.setAttribute("ry",0),T.setAttribute("width",S.width),T.setAttribute("height",S.height),w.insertBefore(T,w.firstChild)}}},"draw");o(nfe,"getArrowMarker");afe={setConf:mVe,draw:gVe}});var ofe={};hr(ofe,{diagram:()=>yVe});var yVe,lfe=R(()=>{"use strict";TO();AO();_O();sfe();yVe={parser:wE,db:Bg,renderer:afe,styles:CE,init:o(t=>{t.class||(t.class={}),t.class.arrowMarkerAbsolute=t.arrowMarkerAbsolute,Bg.clear()},"init")}});var MO,BE,IO=R(()=>{"use strict";MO=function(){var t=o(function(F,B,$,z){for($=$||{},z=F.length;z--;$[F[z]]=B);return $},"o"),e=[1,2],r=[1,3],n=[1,4],i=[2,4],a=[1,9],s=[1,11],l=[1,16],u=[1,17],h=[1,18],f=[1,19],d=[1,32],p=[1,20],m=[1,21],g=[1,22],y=[1,23],v=[1,24],x=[1,26],b=[1,27],w=[1,28],S=[1,29],T=[1,30],E=[1,31],_=[1,34],A=[1,35],L=[1,36],M=[1,37],N=[1,33],k=[1,4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],I=[1,4,5,14,15,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],C=[4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],O={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,SD:6,document:7,line:8,statement:9,classDefStatement:10,styleStatement:11,cssClassStatement:12,idStatement:13,DESCR:14,"-->":15,HIDE_EMPTY:16,scale:17,WIDTH:18,COMPOSIT_STATE:19,STRUCT_START:20,STRUCT_STOP:21,STATE_DESCR:22,AS:23,ID:24,FORK:25,JOIN:26,CHOICE:27,CONCURRENT:28,note:29,notePosition:30,NOTE_TEXT:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,classDef:38,CLASSDEF_ID:39,CLASSDEF_STYLEOPTS:40,DEFAULT:41,style:42,STYLE_IDS:43,STYLEDEF_STYLEOPTS:44,class:45,CLASSENTITY_IDS:46,STYLECLASS:47,direction_tb:48,direction_bt:49,direction_rl:50,direction_lr:51,eol:52,";":53,EDGE_STATE:54,STYLE_SEPARATOR:55,left_of:56,right_of:57,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",6:"SD",14:"DESCR",15:"-->",16:"HIDE_EMPTY",17:"scale",18:"WIDTH",19:"COMPOSIT_STATE",20:"STRUCT_START",21:"STRUCT_STOP",22:"STATE_DESCR",23:"AS",24:"ID",25:"FORK",26:"JOIN",27:"CHOICE",28:"CONCURRENT",29:"note",31:"NOTE_TEXT",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",38:"classDef",39:"CLASSDEF_ID",40:"CLASSDEF_STYLEOPTS",41:"DEFAULT",42:"style",43:"STYLE_IDS",44:"STYLEDEF_STYLEOPTS",45:"class",46:"CLASSENTITY_IDS",47:"STYLECLASS",48:"direction_tb",49:"direction_bt",50:"direction_rl",51:"direction_lr",53:";",54:"EDGE_STATE",55:"STYLE_SEPARATOR",56:"left_of",57:"right_of"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,3],[9,4],[9,1],[9,2],[9,1],[9,4],[9,3],[9,6],[9,1],[9,1],[9,1],[9,1],[9,4],[9,4],[9,1],[9,2],[9,2],[9,1],[10,3],[10,3],[11,3],[12,3],[32,1],[32,1],[32,1],[32,1],[52,1],[52,1],[13,1],[13,1],[13,3],[13,3],[30,1],[30,1]],performAction:o(function(B,$,z,Y,Q,X,ie){var j=X.length-1;switch(Q){case 3:return Y.setRootDoc(X[j]),X[j];break;case 4:this.$=[];break;case 5:X[j]!="nl"&&(X[j-1].push(X[j]),this.$=X[j-1]);break;case 6:case 7:this.$=X[j];break;case 8:this.$="nl";break;case 12:this.$=X[j];break;case 13:let q=X[j-1];q.description=Y.trimColon(X[j]),this.$=q;break;case 14:this.$={stmt:"relation",state1:X[j-2],state2:X[j]};break;case 15:let K=Y.trimColon(X[j]);this.$={stmt:"relation",state1:X[j-3],state2:X[j-1],description:K};break;case 19:this.$={stmt:"state",id:X[j-3],type:"default",description:"",doc:X[j-1]};break;case 20:var J=X[j],Z=X[j-2].trim();if(X[j].match(":")){var H=X[j].split(":");J=H[0],Z=[Z,H[1]]}this.$={stmt:"state",id:J,type:"default",description:Z};break;case 21:this.$={stmt:"state",id:X[j-3],type:"default",description:X[j-5],doc:X[j-1]};break;case 22:this.$={stmt:"state",id:X[j],type:"fork"};break;case 23:this.$={stmt:"state",id:X[j],type:"join"};break;case 24:this.$={stmt:"state",id:X[j],type:"choice"};break;case 25:this.$={stmt:"state",id:Y.getDividerId(),type:"divider"};break;case 26:this.$={stmt:"state",id:X[j-1].trim(),note:{position:X[j-2].trim(),text:X[j].trim()}};break;case 29:this.$=X[j].trim(),Y.setAccTitle(this.$);break;case 30:case 31:this.$=X[j].trim(),Y.setAccDescription(this.$);break;case 32:case 33:this.$={stmt:"classDef",id:X[j-1].trim(),classes:X[j].trim()};break;case 34:this.$={stmt:"style",id:X[j-1].trim(),styleClass:X[j].trim()};break;case 35:this.$={stmt:"applyClass",id:X[j-1].trim(),styleClass:X[j].trim()};break;case 36:Y.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 37:Y.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 38:Y.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 39:Y.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 42:case 43:this.$={stmt:"state",id:X[j].trim(),type:"default",description:""};break;case 44:this.$={stmt:"state",id:X[j-2].trim(),classes:[X[j].trim()],type:"default",description:""};break;case 45:this.$={stmt:"state",id:X[j-2].trim(),classes:[X[j].trim()],type:"default",description:""};break}},"anonymous"),table:[{3:1,4:e,5:r,6:n},{1:[3]},{3:5,4:e,5:r,6:n},{3:6,4:e,5:r,6:n},t([1,4,5,16,17,19,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],i,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:a,5:s,8:8,9:10,10:12,11:13,12:14,13:15,16:l,17:u,19:h,22:f,24:d,25:p,26:m,27:g,28:y,29:v,32:25,33:x,35:b,37:w,38:S,42:T,45:E,48:_,49:A,50:L,51:M,54:N},t(k,[2,5]),{9:38,10:12,11:13,12:14,13:15,16:l,17:u,19:h,22:f,24:d,25:p,26:m,27:g,28:y,29:v,32:25,33:x,35:b,37:w,38:S,42:T,45:E,48:_,49:A,50:L,51:M,54:N},t(k,[2,7]),t(k,[2,8]),t(k,[2,9]),t(k,[2,10]),t(k,[2,11]),t(k,[2,12],{14:[1,39],15:[1,40]}),t(k,[2,16]),{18:[1,41]},t(k,[2,18],{20:[1,42]}),{23:[1,43]},t(k,[2,22]),t(k,[2,23]),t(k,[2,24]),t(k,[2,25]),{30:44,31:[1,45],56:[1,46],57:[1,47]},t(k,[2,28]),{34:[1,48]},{36:[1,49]},t(k,[2,31]),{39:[1,50],41:[1,51]},{43:[1,52]},{46:[1,53]},t(I,[2,42],{55:[1,54]}),t(I,[2,43],{55:[1,55]}),t(k,[2,36]),t(k,[2,37]),t(k,[2,38]),t(k,[2,39]),t(k,[2,6]),t(k,[2,13]),{13:56,24:d,54:N},t(k,[2,17]),t(C,i,{7:57}),{24:[1,58]},{24:[1,59]},{23:[1,60]},{24:[2,46]},{24:[2,47]},t(k,[2,29]),t(k,[2,30]),{40:[1,61]},{40:[1,62]},{44:[1,63]},{47:[1,64]},{24:[1,65]},{24:[1,66]},t(k,[2,14],{14:[1,67]}),{4:a,5:s,8:8,9:10,10:12,11:13,12:14,13:15,16:l,17:u,19:h,21:[1,68],22:f,24:d,25:p,26:m,27:g,28:y,29:v,32:25,33:x,35:b,37:w,38:S,42:T,45:E,48:_,49:A,50:L,51:M,54:N},t(k,[2,20],{20:[1,69]}),{31:[1,70]},{24:[1,71]},t(k,[2,32]),t(k,[2,33]),t(k,[2,34]),t(k,[2,35]),t(I,[2,44]),t(I,[2,45]),t(k,[2,15]),t(k,[2,19]),t(C,i,{7:72}),t(k,[2,26]),t(k,[2,27]),{4:a,5:s,8:8,9:10,10:12,11:13,12:14,13:15,16:l,17:u,19:h,21:[1,73],22:f,24:d,25:p,26:m,27:g,28:y,29:v,32:25,33:x,35:b,37:w,38:S,42:T,45:E,48:_,49:A,50:L,51:M,54:N},t(k,[2,21])],defaultActions:{5:[2,1],6:[2,2],46:[2,46],47:[2,47]},parseError:o(function(B,$){if($.recoverable)this.trace(B);else{var z=new Error(B);throw z.hash=$,z}},"parseError"),parse:o(function(B){var $=this,z=[0],Y=[],Q=[null],X=[],ie=this.table,j="",J=0,Z=0,H=0,q=2,K=1,se=X.slice.call(arguments,1),ce=Object.create(this.lexer),ue={yy:{}};for(var te in this.yy)Object.prototype.hasOwnProperty.call(this.yy,te)&&(ue.yy[te]=this.yy[te]);ce.setInput(B,ue.yy),ue.yy.lexer=ce,ue.yy.parser=this,typeof ce.yylloc>"u"&&(ce.yylloc={});var De=ce.yylloc;X.push(De);var oe=ce.options&&ce.options.ranges;typeof ue.yy.parseError=="function"?this.parseError=ue.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ke(we){z.length=z.length-2*we,Q.length=Q.length-we,X.length=X.length-we}o(ke,"popStack");function Ie(){var we;return we=Y.pop()||ce.lex()||K,typeof we!="number"&&(we instanceof Array&&(Y=we,we=Y.pop()),we=$.symbols_[we]||we),we}o(Ie,"lex");for(var Se,Ue,Pe,_e,me,W,fe={},ge,re,he,ne;;){if(Pe=z[z.length-1],this.defaultActions[Pe]?_e=this.defaultActions[Pe]:((Se===null||typeof Se>"u")&&(Se=Ie()),_e=ie[Pe]&&ie[Pe][Se]),typeof _e>"u"||!_e.length||!_e[0]){var ae="";ne=[];for(ge in ie[Pe])this.terminals_[ge]&&ge>q&&ne.push("'"+this.terminals_[ge]+"'");ce.showPosition?ae="Parse error on line "+(J+1)+`: +`+ce.showPosition()+` +Expecting `+ne.join(", ")+", got '"+(this.terminals_[Se]||Se)+"'":ae="Parse error on line "+(J+1)+": Unexpected "+(Se==K?"end of input":"'"+(this.terminals_[Se]||Se)+"'"),this.parseError(ae,{text:ce.match,token:this.terminals_[Se]||Se,line:ce.yylineno,loc:De,expected:ne})}if(_e[0]instanceof Array&&_e.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Pe+", token: "+Se);switch(_e[0]){case 1:z.push(Se),Q.push(ce.yytext),X.push(ce.yylloc),z.push(_e[1]),Se=null,Ue?(Se=Ue,Ue=null):(Z=ce.yyleng,j=ce.yytext,J=ce.yylineno,De=ce.yylloc,H>0&&H--);break;case 2:if(re=this.productions_[_e[1]][1],fe.$=Q[Q.length-re],fe._$={first_line:X[X.length-(re||1)].first_line,last_line:X[X.length-1].last_line,first_column:X[X.length-(re||1)].first_column,last_column:X[X.length-1].last_column},oe&&(fe._$.range=[X[X.length-(re||1)].range[0],X[X.length-1].range[1]]),W=this.performAction.apply(fe,[j,Z,J,ue.yy,_e[1],Q,X].concat(se)),typeof W<"u")return W;re&&(z=z.slice(0,-1*re*2),Q=Q.slice(0,-1*re),X=X.slice(0,-1*re)),z.push(this.productions_[_e[1]][0]),Q.push(fe.$),X.push(fe._$),he=ie[z[z.length-2]][z[z.length-1]],z.push(he);break;case 3:return!0}}return!0},"parse")},D=function(){var F={EOF:1,parseError:o(function($,z){if(this.yy.parser)this.yy.parser.parseError($,z);else throw new Error($)},"parseError"),setInput:o(function(B,$){return this.yy=$||this.yy||{},this._input=B,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var B=this._input[0];this.yytext+=B,this.yyleng++,this.offset++,this.match+=B,this.matched+=B;var $=B.match(/(?:\r\n?|\n).*/g);return $?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),B},"input"),unput:o(function(B){var $=B.length,z=B.split(/(?:\r\n?|\n)/g);this._input=B+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-$),this.offset-=$;var Y=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),z.length-1&&(this.yylineno-=z.length-1);var Q=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:z?(z.length===Y.length?this.yylloc.first_column:0)+Y[Y.length-z.length].length-z[0].length:this.yylloc.first_column-$},this.options.ranges&&(this.yylloc.range=[Q[0],Q[0]+this.yyleng-$]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(B){this.unput(this.match.slice(B))},"less"),pastInput:o(function(){var B=this.matched.substr(0,this.matched.length-this.match.length);return(B.length>20?"...":"")+B.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var B=this.match;return B.length<20&&(B+=this._input.substr(0,20-B.length)),(B.substr(0,20)+(B.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var B=this.pastInput(),$=new Array(B.length+1).join("-");return B+this.upcomingInput()+` +`+$+"^"},"showPosition"),test_match:o(function(B,$){var z,Y,Q;if(this.options.backtrack_lexer&&(Q={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(Q.yylloc.range=this.yylloc.range.slice(0))),Y=B[0].match(/(?:\r\n?|\n).*/g),Y&&(this.yylineno+=Y.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:Y?Y[Y.length-1].length-Y[Y.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+B[0].length},this.yytext+=B[0],this.match+=B[0],this.matches=B,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(B[0].length),this.matched+=B[0],z=this.performAction.call(this,this.yy,this,$,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),z)return z;if(this._backtrack){for(var X in Q)this[X]=Q[X];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var B,$,z,Y;this._more||(this.yytext="",this.match="");for(var Q=this._currentRules(),X=0;X$[0].length)){if($=z,Y=X,this.options.backtrack_lexer){if(B=this.test_match(z,Q[X]),B!==!1)return B;if(this._backtrack){$=!1;continue}else return!1}else if(!this.options.flex)break}return $?(B=this.test_match($,Q[Y]),B!==!1?B:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var $=this.next();return $||this.lex()},"lex"),begin:o(function($){this.conditionStack.push($)},"begin"),popState:o(function(){var $=this.conditionStack.length-1;return $>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function($){return $=this.conditionStack.length-1-Math.abs($||0),$>=0?this.conditionStack[$]:"INITIAL"},"topState"),pushState:o(function($){this.begin($)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function($,z,Y,Q){var X=Q;switch(Y){case 0:return 41;case 1:return 48;case 2:return 49;case 3:return 50;case 4:return 51;case 5:break;case 6:break;case 7:return 5;case 8:break;case 9:break;case 10:break;case 11:break;case 12:return this.pushState("SCALE"),17;break;case 13:return 18;case 14:this.popState();break;case 15:return this.begin("acc_title"),33;break;case 16:return this.popState(),"acc_title_value";break;case 17:return this.begin("acc_descr"),35;break;case 18:return this.popState(),"acc_descr_value";break;case 19:this.begin("acc_descr_multiline");break;case 20:this.popState();break;case 21:return"acc_descr_multiline_value";case 22:return this.pushState("CLASSDEF"),38;break;case 23:return this.popState(),this.pushState("CLASSDEFID"),"DEFAULT_CLASSDEF_ID";break;case 24:return this.popState(),this.pushState("CLASSDEFID"),39;break;case 25:return this.popState(),40;break;case 26:return this.pushState("CLASS"),45;break;case 27:return this.popState(),this.pushState("CLASS_STYLE"),46;break;case 28:return this.popState(),47;break;case 29:return this.pushState("STYLE"),42;break;case 30:return this.popState(),this.pushState("STYLEDEF_STYLES"),43;break;case 31:return this.popState(),44;break;case 32:return this.pushState("SCALE"),17;break;case 33:return 18;case 34:this.popState();break;case 35:this.pushState("STATE");break;case 36:return this.popState(),z.yytext=z.yytext.slice(0,-8).trim(),25;break;case 37:return this.popState(),z.yytext=z.yytext.slice(0,-8).trim(),26;break;case 38:return this.popState(),z.yytext=z.yytext.slice(0,-10).trim(),27;break;case 39:return this.popState(),z.yytext=z.yytext.slice(0,-8).trim(),25;break;case 40:return this.popState(),z.yytext=z.yytext.slice(0,-8).trim(),26;break;case 41:return this.popState(),z.yytext=z.yytext.slice(0,-10).trim(),27;break;case 42:return 48;case 43:return 49;case 44:return 50;case 45:return 51;case 46:this.pushState("STATE_STRING");break;case 47:return this.pushState("STATE_ID"),"AS";break;case 48:return this.popState(),"ID";break;case 49:this.popState();break;case 50:return"STATE_DESCR";case 51:return 19;case 52:this.popState();break;case 53:return this.popState(),this.pushState("struct"),20;break;case 54:break;case 55:return this.popState(),21;break;case 56:break;case 57:return this.begin("NOTE"),29;break;case 58:return this.popState(),this.pushState("NOTE_ID"),56;break;case 59:return this.popState(),this.pushState("NOTE_ID"),57;break;case 60:this.popState(),this.pushState("FLOATING_NOTE");break;case 61:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";break;case 62:break;case 63:return"NOTE_TEXT";case 64:return this.popState(),"ID";break;case 65:return this.popState(),this.pushState("NOTE_TEXT"),24;break;case 66:return this.popState(),z.yytext=z.yytext.substr(2).trim(),31;break;case 67:return this.popState(),z.yytext=z.yytext.slice(0,-8).trim(),31;break;case 68:return 6;case 69:return 6;case 70:return 16;case 71:return 54;case 72:return 24;case 73:return z.yytext=z.yytext.trim(),14;break;case 74:return 15;case 75:return 28;case 76:return 55;case 77:return 5;case 78:return"INVALID"}},"anonymous"),rules:[/^(?:default\b)/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:classDef\s+)/i,/^(?:DEFAULT\s+)/i,/^(?:\w+\s+)/i,/^(?:[^\n]*)/i,/^(?:class\s+)/i,/^(?:(\w+)+((,\s*\w+)*))/i,/^(?:[^\n]*)/i,/^(?:style\s+)/i,/^(?:[\w,]+\s+)/i,/^(?:[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:state\s+)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:.*\[\[choice\]\])/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:["])/i,/^(?:\s*as\s+)/i,/^(?:[^\n\{]*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n\s\{]+)/i,/^(?:\n)/i,/^(?:\{)/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:\})/i,/^(?:[\n])/i,/^(?:note\s+)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:")/i,/^(?:\s*as\s*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n]*)/i,/^(?:\s*[^:\n\s\-]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:[\s\S]*?end note\b)/i,/^(?:stateDiagram\s+)/i,/^(?:stateDiagram-v2\s+)/i,/^(?:hide empty description\b)/i,/^(?:\[\*\])/i,/^(?:[^:\n\s\-\{]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:-->)/i,/^(?:--)/i,/^(?::::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{LINE:{rules:[9,10],inclusive:!1},struct:{rules:[9,10,22,26,29,35,42,43,44,45,54,55,56,57,71,72,73,74,75],inclusive:!1},FLOATING_NOTE_ID:{rules:[64],inclusive:!1},FLOATING_NOTE:{rules:[61,62,63],inclusive:!1},NOTE_TEXT:{rules:[66,67],inclusive:!1},NOTE_ID:{rules:[65],inclusive:!1},NOTE:{rules:[58,59,60],inclusive:!1},STYLEDEF_STYLEOPTS:{rules:[],inclusive:!1},STYLEDEF_STYLES:{rules:[31],inclusive:!1},STYLE_IDS:{rules:[],inclusive:!1},STYLE:{rules:[30],inclusive:!1},CLASS_STYLE:{rules:[28],inclusive:!1},CLASS:{rules:[27],inclusive:!1},CLASSDEFID:{rules:[25],inclusive:!1},CLASSDEF:{rules:[23,24],inclusive:!1},acc_descr_multiline:{rules:[20,21],inclusive:!1},acc_descr:{rules:[18],inclusive:!1},acc_title:{rules:[16],inclusive:!1},SCALE:{rules:[13,14,33,34],inclusive:!1},ALIAS:{rules:[],inclusive:!1},STATE_ID:{rules:[48],inclusive:!1},STATE_STRING:{rules:[49,50],inclusive:!1},FORK_STATE:{rules:[],inclusive:!1},STATE:{rules:[9,10,36,37,38,39,40,41,46,47,51,52,53],inclusive:!1},ID:{rules:[9,10],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,10,11,12,15,17,19,22,26,29,32,35,53,57,68,69,70,71,72,73,74,76,77,78],inclusive:!0}}};return F}();O.lexer=D;function P(){this.yy={}}return o(P,"Parser"),P.prototype=O,O.Parser=P,new P}();MO.parser=MO;BE=MO});var hfe,FE,zg,Ex,ffe,dfe,pfe,N0,zE,OO,PO,BO,FO,zO,GE,$E,mfe,gfe,GO,$O,yfe,vfe,Gg,wVe,xfe,VO,TVe,kVe,bfe,wfe,EVe,Tfe,CVe,kfe,UO,HO,Efe,VE,Cfe,YO,UE=R(()=>{"use strict";hfe="LR",FE="TB",zg="state",Ex="relation",ffe="classDef",dfe="style",pfe="applyClass",N0="default",zE="divider",OO="fill:none",PO="fill: #333",BO="c",FO="text",zO="normal",GE="rect",$E="rectWithTitle",mfe="stateStart",gfe="stateEnd",GO="divider",$O="roundedWithTitle",yfe="note",vfe="noteGroup",Gg="statediagram",wVe="state",xfe=`${Gg}-${wVe}`,VO="transition",TVe="note",kVe="note-edge",bfe=`${VO} ${kVe}`,wfe=`${Gg}-${TVe}`,EVe="cluster",Tfe=`${Gg}-${EVe}`,CVe="cluster-alt",kfe=`${Gg}-${CVe}`,UO="parent",HO="note",Efe="state",VE="----",Cfe=`${VE}${HO}`,YO=`${VE}${UO}`});function WO(t="",e=0,r="",n=VE){let i=r!==null&&r.length>0?`${n}${r}`:"";return`${Efe}-${t}${i}-${e}`}function HE(t,e,r){if(!e.id||e.id===""||e.id==="")return;e.cssClasses&&(Array.isArray(e.cssCompiledStyles)||(e.cssCompiledStyles=[]),e.cssClasses.split(" ").forEach(i=>{if(r.get(i)){let a=r.get(i);e.cssCompiledStyles=[...e.cssCompiledStyles,...a.styles]}}));let n=t.find(i=>i.id===e.id);n?Object.assign(n,e):t.push(e)}function AVe(t){return t?.classes?.join(" ")??""}function _Ve(t){return t?.styles??[]}var YE,yf,SVe,Sfe,$g,Afe,_fe=R(()=>{"use strict";_t();ut();rr();UE();YE=new Map,yf=0;o(WO,"stateDomId");SVe=o((t,e,r,n,i,a,s,l)=>{V.trace("items",e),e.forEach(u=>{switch(u.stmt){case zg:$g(t,u,r,n,i,a,s,l);break;case N0:$g(t,u,r,n,i,a,s,l);break;case Ex:{$g(t,u.state1,r,n,i,a,s,l),$g(t,u.state2,r,n,i,a,s,l);let h={id:"edge"+yf,start:u.state1.id,end:u.state2.id,arrowhead:"normal",arrowTypeEnd:"arrow_barb",style:OO,labelStyle:"",label:We.sanitizeText(u.description,de()),arrowheadStyle:PO,labelpos:BO,labelType:FO,thickness:zO,classes:VO,look:s};i.push(h),yf++}break}})},"setupDoc"),Sfe=o((t,e=FE)=>{let r=e;if(t.doc)for(let n of t.doc)n.stmt==="dir"&&(r=n.value);return r},"getDir");o(HE,"insertOrUpdateNode");o(AVe,"getClassesFromDbInfo");o(_Ve,"getStylesFromDbInfo");$g=o((t,e,r,n,i,a,s,l)=>{let u=e.id,h=r.get(u),f=AVe(h),d=_Ve(h);if(V.info("dataFetcher parsedItem",e,h,d),u!=="root"){let p=GE;e.start===!0?p=mfe:e.start===!1&&(p=gfe),e.type!==N0&&(p=e.type),YE.get(u)||YE.set(u,{id:u,shape:p,description:We.sanitizeText(u,de()),cssClasses:`${f} ${xfe}`,cssStyles:d});let m=YE.get(u);e.description&&(Array.isArray(m.description)?(m.shape=$E,m.description.push(e.description)):m.description?.length>0?(m.shape=$E,m.description===u?m.description=[e.description]:m.description=[m.description,e.description]):(m.shape=GE,m.description=e.description),m.description=We.sanitizeTextOrArray(m.description,de())),m.description?.length===1&&m.shape===$E&&(m.type==="group"?m.shape=$O:m.shape=GE),!m.type&&e.doc&&(V.info("Setting cluster for XCX",u,Sfe(e)),m.type="group",m.isGroup=!0,m.dir=Sfe(e),m.shape=e.type===zE?GO:$O,m.cssClasses=`${m.cssClasses} ${Tfe} ${a?kfe:""}`);let g={labelStyle:"",shape:m.shape,label:m.description,cssClasses:m.cssClasses,cssCompiledStyles:[],cssStyles:m.cssStyles,id:u,dir:m.dir,domId:WO(u,yf),type:m.type,isGroup:m.type==="group",padding:8,rx:10,ry:10,look:s};if(g.shape===GO&&(g.label=""),t&&t.id!=="root"&&(V.trace("Setting node ",u," to be child of its parent ",t.id),g.parentId=t.id),g.centerLabel=!0,e.note){let y={labelStyle:"",shape:yfe,label:e.note.text,cssClasses:wfe,cssStyles:[],cssCompilesStyles:[],id:u+Cfe+"-"+yf,domId:WO(u,yf,HO),type:m.type,isGroup:m.type==="group",padding:de().flowchart.padding,look:s,position:e.note.position},v=u+YO,x={labelStyle:"",shape:vfe,label:e.note.text,cssClasses:m.cssClasses,cssStyles:[],id:u+YO,domId:WO(u,yf,UO),type:"group",isGroup:!0,padding:16,look:s,position:e.note.position};yf++,x.id=v,y.parentId=v,HE(n,x,l),HE(n,y,l),HE(n,g,l);let b=u,w=y.id;e.note.position==="left of"&&(b=y.id,w=u),i.push({id:b+"-"+w,start:b,end:w,arrowhead:"none",arrowTypeEnd:"",style:OO,labelStyle:"",classes:bfe,arrowheadStyle:PO,labelpos:BO,labelType:FO,thickness:zO,look:s})}else HE(n,g,l)}e.doc&&(V.trace("Adding nodes children "),SVe(e,e.doc,r,n,i,!a,s,l))},"dataFetcher"),Afe=o(()=>{YE.clear(),yf=0},"reset")});var qO,LVe,DVe,Lfe,XO=R(()=>{"use strict";_t();ut();L9();oT();yD();xr();UE();qO=o((t,e=FE)=>{if(!t.doc)return e;let r=e;for(let n of t.doc)n.stmt==="dir"&&(r=n.value);return r},"getDir"),LVe=o(function(t,e){return e.db.extract(e.db.getRootDocV2()),e.db.getClasses()},"getClasses"),DVe=o(async function(t,e,r,n){V.info("REF0:"),V.info("Drawing state diagram (v2)",e);let{securityLevel:i,state:a,layout:s}=de();n.db.extract(n.db.getRootDocV2());let l=n.db.getData(),u=I5(e,i);l.type=n.type,l.layoutAlgorithm=s,l.nodeSpacing=a?.nodeSpacing||50,l.rankSpacing=a?.rankSpacing||50,l.markers=["barb"],l.diagramId=e,await sT(l,u);let h=8;Lt.insertTitle(u,"statediagramTitleText",a?.titleTopMargin??25,n.db.getDiagramTitle()),lT(u,h,Gg,a?.useMaxWidth??!0)},"draw"),Lfe={getClasses:LVe,draw:DVe,getDir:qO}});function Pfe(){return new Map}function jO(t=""){let e=t;return t===ZO&&(Cx++,e=`${Mfe}${Cx}`),e}function KO(t="",e=N0){return t===ZO?Mfe:e}function GVe(t=""){let e=t;return t===Ife&&(Cx++,e=`${Ofe}${Cx}`),e}function $Ve(t="",e=N0){return t===Ife?Ofe:e}function VVe(t,e,r){let n=jO(t.id.trim()),i=KO(t.id.trim(),t.type),a=jO(e.id.trim()),s=KO(e.id.trim(),e.type);vf(n,i,t.doc,t.description,t.note,t.classes,t.styles,t.textStyles),vf(a,s,e.doc,e.description,e.note,e.classes,e.styles,e.textStyles),Fs.relations.push({id1:n,id2:a,relationTitle:We.sanitizeText(r,de())})}var ZO,Mfe,Ife,Ofe,Dfe,Rfe,RVe,NVe,XE,JO,Bfe,jE,Vg,Ffe,KE,Fs,Cx,Nfe,MVe,IVe,WE,OVe,PVe,qE,eP,BVe,vf,zfe,M0,Gfe,FVe,zVe,$fe,QO,UVe,HVe,Vfe,YVe,tP,WVe,qVe,XVe,jVe,KVe,QVe,Qo,QE=R(()=>{"use strict";ut();xr();rr();_t();bi();_fe();XO();UE();ZO="[*]",Mfe="start",Ife=ZO,Ofe="end",Dfe="color",Rfe="fill",RVe="bgFill",NVe=",";o(Pfe,"newClassesList");XE=[],JO=[],Bfe=hfe,jE=[],Vg=Pfe(),Ffe=o(()=>({relations:[],states:new Map,documents:{}}),"newDoc"),KE={root:Ffe()},Fs=KE.root,Cx=0,Nfe=0,MVe={LINE:0,DOTTED_LINE:1},IVe={AGGREGATION:0,EXTENSION:1,COMPOSITION:2,DEPENDENCY:3},WE=o(t=>JSON.parse(JSON.stringify(t)),"clone"),OVe=o(t=>{V.info("Setting root doc",t),jE=t},"setRootDoc"),PVe=o(()=>jE,"getRootDoc"),qE=o((t,e,r)=>{if(e.stmt===Ex)qE(t,e.state1,!0),qE(t,e.state2,!1);else if(e.stmt===zg&&(e.id==="[*]"?(e.id=r?t.id+"_start":t.id+"_end",e.start=r):e.id=e.id.trim()),e.doc){let n=[],i=[],a;for(a=0;a0&&i.length>0){let s={stmt:zg,id:Z_(),type:"divider",doc:WE(i)};n.push(WE(s)),e.doc=n}e.doc.forEach(s=>qE(e,s,!0))}},"docTranslator"),eP=o(()=>(qE({id:"root"},{id:"root",doc:jE},!0),{id:"root",doc:jE}),"getRootDocV2"),BVe=o(t=>{let e;t.doc?e=t.doc:e=t,V.info(e),zfe(!0),V.info("Extract initial document:",e),e.forEach(a=>{switch(V.warn("Statement",a.stmt),a.stmt){case zg:vf(a.id.trim(),a.type,a.doc,a.description,a.note,a.classes,a.styles,a.textStyles);break;case Ex:$fe(a.state1,a.state2,a.description);break;case ffe:Vfe(a.id.trim(),a.classes);break;case dfe:{let s=a.id.trim().split(","),l=a.styleClass.split(",");s.forEach(u=>{let h=M0(u);if(h===void 0){let f=u.trim();vf(f),h=M0(f)}h.styles=l.map(f=>f.replace(/;/g,"")?.trim())})}break;case pfe:tP(a.id.trim(),a.styleClass);break}});let r=Gfe(),i=de().look;Afe(),$g(void 0,eP(),r,XE,JO,!0,i,Vg),XE.forEach(a=>{if(Array.isArray(a.label)){if(a.description=a.label.slice(1),a.isGroup&&a.description.length>0)throw new Error("Group nodes can only have label. Remove the additional description for node ["+a.id+"]");a.label=a.label[0]}})},"extract"),vf=o(function(t,e=N0,r=null,n=null,i=null,a=null,s=null,l=null){let u=t?.trim();if(Fs.states.has(u)?(Fs.states.get(u).doc||(Fs.states.get(u).doc=r),Fs.states.get(u).type||(Fs.states.get(u).type=e)):(V.info("Adding state ",u,n),Fs.states.set(u,{id:u,descriptions:[],type:e,doc:r,note:i,classes:[],styles:[],textStyles:[]})),n&&(V.info("Setting state description",u,n),typeof n=="string"&&QO(u,n.trim()),typeof n=="object"&&n.forEach(h=>QO(u,h.trim()))),i){let h=Fs.states.get(u);h.note=i,h.note.text=We.sanitizeText(h.note.text,de())}a&&(V.info("Setting state classes",u,a),(typeof a=="string"?[a]:a).forEach(f=>tP(u,f.trim()))),s&&(V.info("Setting state styles",u,s),(typeof s=="string"?[s]:s).forEach(f=>WVe(u,f.trim()))),l&&(V.info("Setting state styles",u,s),(typeof l=="string"?[l]:l).forEach(f=>qVe(u,f.trim())))},"addState"),zfe=o(function(t){XE=[],JO=[],KE={root:Ffe()},Fs=KE.root,Cx=0,Vg=Pfe(),t||vr()},"clear"),M0=o(function(t){return Fs.states.get(t)},"getState"),Gfe=o(function(){return Fs.states},"getStates"),FVe=o(function(){V.info("Documents = ",KE)},"logDocuments"),zVe=o(function(){return Fs.relations},"getRelations");o(jO,"startIdIfNeeded");o(KO,"startTypeIfNeeded");o(GVe,"endIdIfNeeded");o($Ve,"endTypeIfNeeded");o(VVe,"addRelationObjs");$fe=o(function(t,e,r){if(typeof t=="object")VVe(t,e,r);else{let n=jO(t.trim()),i=KO(t),a=GVe(e.trim()),s=$Ve(e);vf(n,i),vf(a,s),Fs.relations.push({id1:n,id2:a,title:We.sanitizeText(r,de())})}},"addRelation"),QO=o(function(t,e){let r=Fs.states.get(t),n=e.startsWith(":")?e.replace(":","").trim():e;r.descriptions.push(We.sanitizeText(n,de()))},"addDescription"),UVe=o(function(t){return t.substring(0,1)===":"?t.substr(2).trim():t.trim()},"cleanupLabel"),HVe=o(()=>(Nfe++,"divider-id-"+Nfe),"getDividerId"),Vfe=o(function(t,e=""){Vg.has(t)||Vg.set(t,{id:t,styles:[],textStyles:[]});let r=Vg.get(t);e?.split(NVe).forEach(n=>{let i=n.replace(/([^;]*);/,"$1").trim();if(RegExp(Dfe).exec(n)){let s=i.replace(Rfe,RVe).replace(Dfe,Rfe);r.textStyles.push(s)}r.styles.push(i)})},"addStyleClass"),YVe=o(function(){return Vg},"getClasses"),tP=o(function(t,e){t.split(",").forEach(function(r){let n=M0(r);if(n===void 0){let i=r.trim();vf(i),n=M0(i)}n.classes.push(e)})},"setCssClass"),WVe=o(function(t,e){let r=M0(t);r!==void 0&&r.styles.push(e)},"setStyle"),qVe=o(function(t,e){let r=M0(t);r!==void 0&&r.textStyles.push(e)},"setTextStyle"),XVe=o(()=>Bfe,"getDirection"),jVe=o(t=>{Bfe=t},"setDirection"),KVe=o(t=>t&&t[0]===":"?t.substr(1).trim():t.trim(),"trimColon"),QVe=o(()=>{let t=de();return{nodes:XE,edges:JO,other:{},config:t,direction:qO(eP())}},"getData"),Qo={getConfig:o(()=>de().state,"getConfig"),getData:QVe,addState:vf,clear:zfe,getState:M0,getStates:Gfe,getRelations:zVe,getClasses:YVe,getDirection:XVe,addRelation:$fe,getDividerId:HVe,setDirection:jVe,cleanupLabel:UVe,lineType:MVe,relationType:IVe,logDocuments:FVe,getRootDoc:PVe,setRootDoc:OVe,getRootDocV2:eP,extract:BVe,trimColon:KVe,getAccTitle:Ar,setAccTitle:kr,getAccDescription:Lr,setAccDescription:_r,addStyleClass:Vfe,setCssClass:tP,addDescription:QO,setDiagramTitle:nn,getDiagramTitle:Xr}});var ZVe,ZE,rP=R(()=>{"use strict";ZVe=o(t=>` +defs #statediagram-barbEnd { + fill: ${t.transitionColor}; + stroke: ${t.transitionColor}; + } +g.stateGroup text { + fill: ${t.nodeBorder}; + stroke: none; + font-size: 10px; +} +g.stateGroup text { + fill: ${t.textColor}; + stroke: none; + font-size: 10px; + +} +g.stateGroup .state-title { + font-weight: bolder; + fill: ${t.stateLabelColor}; +} + +g.stateGroup rect { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; +} + +g.stateGroup line { + stroke: ${t.lineColor}; + stroke-width: 1; +} + +.transition { + stroke: ${t.transitionColor}; + stroke-width: 1; + fill: none; +} + +.stateGroup .composit { + fill: ${t.background}; + border-bottom: 1px +} + +.stateGroup .alt-composit { + fill: #e0e0e0; + border-bottom: 1px +} + +.state-note { + stroke: ${t.noteBorderColor}; + fill: ${t.noteBkgColor}; + + text { + fill: ${t.noteTextColor}; + stroke: none; + font-size: 10px; + } +} + +.stateLabel .box { + stroke: none; + stroke-width: 0; + fill: ${t.mainBkg}; + opacity: 0.5; +} + +.edgeLabel .label rect { + fill: ${t.labelBackgroundColor}; + opacity: 0.5; +} +.edgeLabel { + background-color: ${t.edgeLabelBackground}; + p { + background-color: ${t.edgeLabelBackground}; + } + rect { + opacity: 0.5; + background-color: ${t.edgeLabelBackground}; + fill: ${t.edgeLabelBackground}; + } + text-align: center; +} +.edgeLabel .label text { + fill: ${t.transitionLabelColor||t.tertiaryTextColor}; +} +.label div .edgeLabel { + color: ${t.transitionLabelColor||t.tertiaryTextColor}; +} + +.stateLabel text { + fill: ${t.stateLabelColor}; + font-size: 10px; + font-weight: bold; +} + +.node circle.state-start { + fill: ${t.specialStateColor}; + stroke: ${t.specialStateColor}; +} + +.node .fork-join { + fill: ${t.specialStateColor}; + stroke: ${t.specialStateColor}; +} + +.node circle.state-end { + fill: ${t.innerEndBackground}; + stroke: ${t.background}; + stroke-width: 1.5 +} +.end-state-inner { + fill: ${t.compositeBackground||t.background}; + // stroke: ${t.background}; + stroke-width: 1.5 +} + +.node rect { + fill: ${t.stateBkg||t.mainBkg}; + stroke: ${t.stateBorder||t.nodeBorder}; + stroke-width: 1px; +} +.node polygon { + fill: ${t.mainBkg}; + stroke: ${t.stateBorder||t.nodeBorder};; + stroke-width: 1px; +} +#statediagram-barbEnd { + fill: ${t.lineColor}; +} + +.statediagram-cluster rect { + fill: ${t.compositeTitleBackground}; + stroke: ${t.stateBorder||t.nodeBorder}; + stroke-width: 1px; +} + +.cluster-label, .nodeLabel { + color: ${t.stateLabelColor}; + // line-height: 1; +} + +.statediagram-cluster rect.outer { + rx: 5px; + ry: 5px; +} +.statediagram-state .divider { + stroke: ${t.stateBorder||t.nodeBorder}; +} + +.statediagram-state .title-state { + rx: 5px; + ry: 5px; +} +.statediagram-cluster.statediagram-cluster .inner { + fill: ${t.compositeBackground||t.background}; +} +.statediagram-cluster.statediagram-cluster-alt .inner { + fill: ${t.altBackground?t.altBackground:"#efefef"}; +} + +.statediagram-cluster .inner { + rx:0; + ry:0; +} + +.statediagram-state rect.basic { + rx: 5px; + ry: 5px; +} +.statediagram-state rect.divider { + stroke-dasharray: 10,10; + fill: ${t.altBackground?t.altBackground:"#efefef"}; +} + +.note-edge { + stroke-dasharray: 5; +} + +.statediagram-note rect { + fill: ${t.noteBkgColor}; + stroke: ${t.noteBorderColor}; + stroke-width: 1px; + rx: 0; + ry: 0; +} +.statediagram-note rect { + fill: ${t.noteBkgColor}; + stroke: ${t.noteBorderColor}; + stroke-width: 1px; + rx: 0; + ry: 0; +} + +.statediagram-note text { + fill: ${t.noteTextColor}; +} + +.statediagram-note .nodeLabel { + color: ${t.noteTextColor}; +} +.statediagram .edgeLabel { + color: red; // ${t.noteTextColor}; +} + +#dependencyStart, #dependencyEnd { + fill: ${t.lineColor}; + stroke: ${t.lineColor}; + stroke-width: 1; +} + +.statediagramTitleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.textColor}; +} +`,"getStyles"),ZE=ZVe});var nP,JVe,eUe,Ufe,tUe,Hfe,Yfe=R(()=>{"use strict";nP={},JVe=o((t,e)=>{nP[t]=e},"set"),eUe=o(t=>nP[t],"get"),Ufe=o(()=>Object.keys(nP),"keys"),tUe=o(()=>Ufe().length,"size"),Hfe={get:eUe,set:JVe,keys:Ufe,size:tUe}});var rUe,nUe,iUe,aUe,qfe,sUe,oUe,lUe,cUe,iP,Wfe,Xfe,jfe=R(()=>{"use strict";Zt();Yfe();QE();xr();rr();_t();ut();rUe=o(t=>t.append("circle").attr("class","start-state").attr("r",de().state.sizeUnit).attr("cx",de().state.padding+de().state.sizeUnit).attr("cy",de().state.padding+de().state.sizeUnit),"drawStartState"),nUe=o(t=>t.append("line").style("stroke","grey").style("stroke-dasharray","3").attr("x1",de().state.textHeight).attr("class","divider").attr("x2",de().state.textHeight*2).attr("y1",0).attr("y2",0),"drawDivider"),iUe=o((t,e)=>{let r=t.append("text").attr("x",2*de().state.padding).attr("y",de().state.textHeight+2*de().state.padding).attr("font-size",de().state.fontSize).attr("class","state-title").text(e.id),n=r.node().getBBox();return t.insert("rect",":first-child").attr("x",de().state.padding).attr("y",de().state.padding).attr("width",n.width+2*de().state.padding).attr("height",n.height+2*de().state.padding).attr("rx",de().state.radius),r},"drawSimpleState"),aUe=o((t,e)=>{let r=o(function(p,m,g){let y=p.append("tspan").attr("x",2*de().state.padding).text(m);g||y.attr("dy",de().state.textHeight)},"addTspan"),i=t.append("text").attr("x",2*de().state.padding).attr("y",de().state.textHeight+1.3*de().state.padding).attr("font-size",de().state.fontSize).attr("class","state-title").text(e.descriptions[0]).node().getBBox(),a=i.height,s=t.append("text").attr("x",de().state.padding).attr("y",a+de().state.padding*.4+de().state.dividerMargin+de().state.textHeight).attr("class","state-description"),l=!0,u=!0;e.descriptions.forEach(function(p){l||(r(s,p,u),u=!1),l=!1});let h=t.append("line").attr("x1",de().state.padding).attr("y1",de().state.padding+a+de().state.dividerMargin/2).attr("y2",de().state.padding+a+de().state.dividerMargin/2).attr("class","descr-divider"),f=s.node().getBBox(),d=Math.max(f.width,i.width);return h.attr("x2",d+3*de().state.padding),t.insert("rect",":first-child").attr("x",de().state.padding).attr("y",de().state.padding).attr("width",d+2*de().state.padding).attr("height",f.height+a+2*de().state.padding).attr("rx",de().state.radius),t},"drawDescrState"),qfe=o((t,e,r)=>{let n=de().state.padding,i=2*de().state.padding,a=t.node().getBBox(),s=a.width,l=a.x,u=t.append("text").attr("x",0).attr("y",de().state.titleShift).attr("font-size",de().state.fontSize).attr("class","state-title").text(e.id),f=u.node().getBBox().width+i,d=Math.max(f,s);d===s&&(d=d+i);let p,m=t.node().getBBox();e.doc,p=l-n,f>s&&(p=(s-d)/2+n),Math.abs(l-m.x)s&&(p=l-(f-s)/2);let g=1-de().state.textHeight;return t.insert("rect",":first-child").attr("x",p).attr("y",g).attr("class",r?"alt-composit":"composit").attr("width",d).attr("height",m.height+de().state.textHeight+de().state.titleShift+1).attr("rx","0"),u.attr("x",p+n),f<=s&&u.attr("x",l+(d-i)/2-f/2+n),t.insert("rect",":first-child").attr("x",p).attr("y",de().state.titleShift-de().state.textHeight-de().state.padding).attr("width",d).attr("height",de().state.textHeight*3).attr("rx",de().state.radius),t.insert("rect",":first-child").attr("x",p).attr("y",de().state.titleShift-de().state.textHeight-de().state.padding).attr("width",d).attr("height",m.height+3+2*de().state.textHeight).attr("rx",de().state.radius),t},"addTitleAndBox"),sUe=o(t=>(t.append("circle").attr("class","end-state-outer").attr("r",de().state.sizeUnit+de().state.miniPadding).attr("cx",de().state.padding+de().state.sizeUnit+de().state.miniPadding).attr("cy",de().state.padding+de().state.sizeUnit+de().state.miniPadding),t.append("circle").attr("class","end-state-inner").attr("r",de().state.sizeUnit).attr("cx",de().state.padding+de().state.sizeUnit+2).attr("cy",de().state.padding+de().state.sizeUnit+2)),"drawEndState"),oUe=o((t,e)=>{let r=de().state.forkWidth,n=de().state.forkHeight;if(e.parentId){let i=r;r=n,n=i}return t.append("rect").style("stroke","black").style("fill","black").attr("width",r).attr("height",n).attr("x",de().state.padding).attr("y",de().state.padding)},"drawForkJoinState"),lUe=o((t,e,r,n)=>{let i=0,a=n.append("text");a.style("text-anchor","start"),a.attr("class","noteText");let s=t.replace(/\r\n/g,"
    ");s=s.replace(/\n/g,"
    ");let l=s.split(We.lineBreakRegex),u=1.25*de().state.noteMargin;for(let h of l){let f=h.trim();if(f.length>0){let d=a.append("tspan");if(d.text(f),u===0){let p=d.node().getBBox();u+=p.height}i+=u,d.attr("x",e+de().state.noteMargin),d.attr("y",r+i+1.25*de().state.noteMargin)}}return{textWidth:a.node().getBBox().width,textHeight:i}},"_drawLongText"),cUe=o((t,e)=>{e.attr("class","state-note");let r=e.append("rect").attr("x",0).attr("y",de().state.padding),n=e.append("g"),{textWidth:i,textHeight:a}=lUe(t,0,0,n);return r.attr("height",a+2*de().state.noteMargin),r.attr("width",i+de().state.noteMargin*2),r},"drawNote"),iP=o(function(t,e){let r=e.id,n={id:r,label:e.id,width:0,height:0},i=t.append("g").attr("id",r).attr("class","stateGroup");e.type==="start"&&rUe(i),e.type==="end"&&sUe(i),(e.type==="fork"||e.type==="join")&&oUe(i,e),e.type==="note"&&cUe(e.note.text,i),e.type==="divider"&&nUe(i),e.type==="default"&&e.descriptions.length===0&&iUe(i,e),e.type==="default"&&e.descriptions.length>0&&aUe(i,e);let a=i.node().getBBox();return n.width=a.width+2*de().state.padding,n.height=a.height+2*de().state.padding,Hfe.set(r,n),n},"drawState"),Wfe=0,Xfe=o(function(t,e,r){let n=o(function(u){switch(u){case Qo.relationType.AGGREGATION:return"aggregation";case Qo.relationType.EXTENSION:return"extension";case Qo.relationType.COMPOSITION:return"composition";case Qo.relationType.DEPENDENCY:return"dependency"}},"getRelationType");e.points=e.points.filter(u=>!Number.isNaN(u.y));let i=e.points,a=ha().x(function(u){return u.x}).y(function(u){return u.y}).curve(vs),s=t.append("path").attr("d",a(i)).attr("id","edge"+Wfe).attr("class","transition"),l="";if(de().state.arrowMarkerAbsolute&&(l=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,l=l.replace(/\(/g,"\\("),l=l.replace(/\)/g,"\\)")),s.attr("marker-end","url("+l+"#"+n(Qo.relationType.DEPENDENCY)+"End)"),r.title!==void 0){let u=t.append("g").attr("class","stateLabel"),{x:h,y:f}=Lt.calcLabelPosition(e.points),d=We.getRows(r.title),p=0,m=[],g=0,y=0;for(let b=0;b<=d.length;b++){let w=u.append("text").attr("text-anchor","middle").text(d[b]).attr("x",h).attr("y",f+p),S=w.node().getBBox();g=Math.max(g,S.width),y=Math.min(y,S.x),V.info(S.x,h,f+p),p===0&&(p=w.node().getBBox().height,V.info("Title height",p,f)),m.push(w)}let v=p*d.length;if(d.length>1){let b=(d.length-1)*p*.5;m.forEach((w,S)=>w.attr("y",f+S*p-b)),v=p*d.length}let x=u.node().getBBox();u.insert("rect",":first-child").attr("class","box").attr("x",h-g/2-de().state.padding/2).attr("y",f-v/2-de().state.padding/2-3.5).attr("width",g+de().state.padding).attr("height",v+de().state.padding),V.info(x)}Wfe++},"drawEdge")});var vo,aP,uUe,hUe,fUe,dUe,Kfe,Qfe,Zfe=R(()=>{"use strict";Zt();Vd();ya();ut();rr();jfe();_t();Yn();aP={},uUe=o(function(){},"setConf"),hUe=o(function(t){t.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")},"insertMarkers"),fUe=o(function(t,e,r,n){vo=de().state;let i=de().securityLevel,a;i==="sandbox"&&(a=$e("#i"+e));let s=i==="sandbox"?$e(a.nodes()[0].contentDocument.body):$e("body"),l=i==="sandbox"?a.nodes()[0].contentDocument:document;V.debug("Rendering diagram "+t);let u=s.select(`[id='${e}']`);hUe(u);let h=n.db.getRootDoc();Kfe(h,u,void 0,!1,s,l,n);let f=vo.padding,d=u.node().getBBox(),p=d.width+f*2,m=d.height+f*2,g=p*1.75;Sr(u,m,g,vo.useMaxWidth),u.attr("viewBox",`${d.x-vo.padding} ${d.y-vo.padding} `+p+" "+m)},"draw"),dUe=o(t=>t?t.length*vo.fontSizeFactor:1,"getLabelWidth"),Kfe=o((t,e,r,n,i,a,s)=>{let l=new lr({compound:!0,multigraph:!0}),u,h=!0;for(u=0;u{let T=S.parentElement,E=0,_=0;T&&(T.parentElement&&(E=T.parentElement.getBBox().width),_=parseInt(T.getAttribute("data-x-shift"),10),Number.isNaN(_)&&(_=0)),S.setAttribute("x1",0-_+8),S.setAttribute("x2",E-_-8)})):V.debug("No Node "+b+": "+JSON.stringify(l.node(b)))});let v=y.getBBox();l.edges().forEach(function(b){b!==void 0&&l.edge(b)!==void 0&&(V.debug("Edge "+b.v+" -> "+b.w+": "+JSON.stringify(l.edge(b))),Xfe(e,l.edge(b),l.edge(b).relation))}),v=y.getBBox();let x={id:r||"root",label:r||"root",width:0,height:0};return x.width=v.width+2*vo.padding,x.height=v.height+2*vo.padding,V.debug("Doc rendered",x,l),x},"renderDoc"),Qfe={setConf:uUe,draw:fUe}});var Jfe={};hr(Jfe,{diagram:()=>pUe});var pUe,ede=R(()=>{"use strict";IO();QE();rP();Zfe();pUe={parser:BE,db:Qo,renderer:Qfe,styles:ZE,init:o(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute,Qo.clear()},"init")}});var nde={};hr(nde,{diagram:()=>vUe});var vUe,ide=R(()=>{"use strict";IO();QE();rP();XO();vUe={parser:BE,db:Qo,renderer:Lfe,styles:ZE,init:o(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute,Qo.clear()},"init")}});var sP,ode,lde=R(()=>{"use strict";sP=function(){var t=o(function(d,p,m,g){for(m=m||{},g=d.length;g--;m[d[g]]=p);return m},"o"),e=[6,8,10,11,12,14,16,17,18],r=[1,9],n=[1,10],i=[1,11],a=[1,12],s=[1,13],l=[1,14],u={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,taskName:18,taskData:19,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",18:"taskName",19:"taskData"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,2]],performAction:o(function(p,m,g,y,v,x,b){var w=x.length-1;switch(v){case 1:return x[w-1];case 2:this.$=[];break;case 3:x[w-1].push(x[w]),this.$=x[w-1];break;case 4:case 5:this.$=x[w];break;case 6:case 7:this.$=[];break;case 8:y.setDiagramTitle(x[w].substr(6)),this.$=x[w].substr(6);break;case 9:this.$=x[w].trim(),y.setAccTitle(this.$);break;case 10:case 11:this.$=x[w].trim(),y.setAccDescription(this.$);break;case 12:y.addSection(x[w].substr(8)),this.$=x[w].substr(8);break;case 13:y.addTask(x[w-1],x[w]),this.$="task";break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:r,12:n,14:i,16:a,17:s,18:l},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:15,11:r,12:n,14:i,16:a,17:s,18:l},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,16]},{15:[1,17]},t(e,[2,11]),t(e,[2,12]),{19:[1,18]},t(e,[2,4]),t(e,[2,9]),t(e,[2,10]),t(e,[2,13])],defaultActions:{},parseError:o(function(p,m){if(m.recoverable)this.trace(p);else{var g=new Error(p);throw g.hash=m,g}},"parseError"),parse:o(function(p){var m=this,g=[0],y=[],v=[null],x=[],b=this.table,w="",S=0,T=0,E=0,_=2,A=1,L=x.slice.call(arguments,1),M=Object.create(this.lexer),N={yy:{}};for(var k in this.yy)Object.prototype.hasOwnProperty.call(this.yy,k)&&(N.yy[k]=this.yy[k]);M.setInput(p,N.yy),N.yy.lexer=M,N.yy.parser=this,typeof M.yylloc>"u"&&(M.yylloc={});var I=M.yylloc;x.push(I);var C=M.options&&M.options.ranges;typeof N.yy.parseError=="function"?this.parseError=N.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function O(H){g.length=g.length-2*H,v.length=v.length-H,x.length=x.length-H}o(O,"popStack");function D(){var H;return H=y.pop()||M.lex()||A,typeof H!="number"&&(H instanceof Array&&(y=H,H=y.pop()),H=m.symbols_[H]||H),H}o(D,"lex");for(var P,F,B,$,z,Y,Q={},X,ie,j,J;;){if(B=g[g.length-1],this.defaultActions[B]?$=this.defaultActions[B]:((P===null||typeof P>"u")&&(P=D()),$=b[B]&&b[B][P]),typeof $>"u"||!$.length||!$[0]){var Z="";J=[];for(X in b[B])this.terminals_[X]&&X>_&&J.push("'"+this.terminals_[X]+"'");M.showPosition?Z="Parse error on line "+(S+1)+`: +`+M.showPosition()+` +Expecting `+J.join(", ")+", got '"+(this.terminals_[P]||P)+"'":Z="Parse error on line "+(S+1)+": Unexpected "+(P==A?"end of input":"'"+(this.terminals_[P]||P)+"'"),this.parseError(Z,{text:M.match,token:this.terminals_[P]||P,line:M.yylineno,loc:I,expected:J})}if($[0]instanceof Array&&$.length>1)throw new Error("Parse Error: multiple actions possible at state: "+B+", token: "+P);switch($[0]){case 1:g.push(P),v.push(M.yytext),x.push(M.yylloc),g.push($[1]),P=null,F?(P=F,F=null):(T=M.yyleng,w=M.yytext,S=M.yylineno,I=M.yylloc,E>0&&E--);break;case 2:if(ie=this.productions_[$[1]][1],Q.$=v[v.length-ie],Q._$={first_line:x[x.length-(ie||1)].first_line,last_line:x[x.length-1].last_line,first_column:x[x.length-(ie||1)].first_column,last_column:x[x.length-1].last_column},C&&(Q._$.range=[x[x.length-(ie||1)].range[0],x[x.length-1].range[1]]),Y=this.performAction.apply(Q,[w,T,S,N.yy,$[1],v,x].concat(L)),typeof Y<"u")return Y;ie&&(g=g.slice(0,-1*ie*2),v=v.slice(0,-1*ie),x=x.slice(0,-1*ie)),g.push(this.productions_[$[1]][0]),v.push(Q.$),x.push(Q._$),j=b[g[g.length-2]][g[g.length-1]],g.push(j);break;case 3:return!0}}return!0},"parse")},h=function(){var d={EOF:1,parseError:o(function(m,g){if(this.yy.parser)this.yy.parser.parseError(m,g);else throw new Error(m)},"parseError"),setInput:o(function(p,m){return this.yy=m||this.yy||{},this._input=p,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var p=this._input[0];this.yytext+=p,this.yyleng++,this.offset++,this.match+=p,this.matched+=p;var m=p.match(/(?:\r\n?|\n).*/g);return m?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),p},"input"),unput:o(function(p){var m=p.length,g=p.split(/(?:\r\n?|\n)/g);this._input=p+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-m),this.offset-=m;var y=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),g.length-1&&(this.yylineno-=g.length-1);var v=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:g?(g.length===y.length?this.yylloc.first_column:0)+y[y.length-g.length].length-g[0].length:this.yylloc.first_column-m},this.options.ranges&&(this.yylloc.range=[v[0],v[0]+this.yyleng-m]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(p){this.unput(this.match.slice(p))},"less"),pastInput:o(function(){var p=this.matched.substr(0,this.matched.length-this.match.length);return(p.length>20?"...":"")+p.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var p=this.match;return p.length<20&&(p+=this._input.substr(0,20-p.length)),(p.substr(0,20)+(p.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var p=this.pastInput(),m=new Array(p.length+1).join("-");return p+this.upcomingInput()+` +`+m+"^"},"showPosition"),test_match:o(function(p,m){var g,y,v;if(this.options.backtrack_lexer&&(v={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(v.yylloc.range=this.yylloc.range.slice(0))),y=p[0].match(/(?:\r\n?|\n).*/g),y&&(this.yylineno+=y.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:y?y[y.length-1].length-y[y.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+p[0].length},this.yytext+=p[0],this.match+=p[0],this.matches=p,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(p[0].length),this.matched+=p[0],g=this.performAction.call(this,this.yy,this,m,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),g)return g;if(this._backtrack){for(var x in v)this[x]=v[x];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var p,m,g,y;this._more||(this.yytext="",this.match="");for(var v=this._currentRules(),x=0;xm[0].length)){if(m=g,y=x,this.options.backtrack_lexer){if(p=this.test_match(g,v[x]),p!==!1)return p;if(this._backtrack){m=!1;continue}else return!1}else if(!this.options.flex)break}return m?(p=this.test_match(m,v[y]),p!==!1?p:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var m=this.next();return m||this.lex()},"lex"),begin:o(function(m){this.conditionStack.push(m)},"begin"),popState:o(function(){var m=this.conditionStack.length-1;return m>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(m){return m=this.conditionStack.length-1-Math.abs(m||0),m>=0?this.conditionStack[m]:"INITIAL"},"topState"),pushState:o(function(m){this.begin(m)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(m,g,y,v){var x=v;switch(y){case 0:break;case 1:break;case 2:return 10;case 3:break;case 4:break;case 5:return 4;case 6:return 11;case 7:return this.begin("acc_title"),12;break;case 8:return this.popState(),"acc_title_value";break;case 9:return this.begin("acc_descr"),14;break;case 10:return this.popState(),"acc_descr_value";break;case 11:this.begin("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 17;case 15:return 18;case 16:return 19;case 17:return":";case 18:return 6;case 19:return"INVALID"}},"anonymous"),rules:[/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,9,11,14,15,16,17,18,19],inclusive:!0}}};return d}();u.lexer=h;function f(){this.yy={}}return o(f,"Parser"),f.prototype=u,u.Parser=f,new f}();sP.parser=sP;ode=sP});var Ug,oP,Sx,Ax,TUe,kUe,EUe,CUe,SUe,AUe,_Ue,cde,LUe,lP,ude=R(()=>{"use strict";_t();bi();Ug="",oP=[],Sx=[],Ax=[],TUe=o(function(){oP.length=0,Sx.length=0,Ug="",Ax.length=0,vr()},"clear"),kUe=o(function(t){Ug=t,oP.push(t)},"addSection"),EUe=o(function(){return oP},"getSections"),CUe=o(function(){let t=cde(),e=100,r=0;for(;!t&&r{r.people&&t.push(...r.people)}),[...new Set(t)].sort()},"updateActors"),AUe=o(function(t,e){let r=e.substr(1).split(":"),n=0,i=[];r.length===1?(n=Number(r[0]),i=[]):(n=Number(r[0]),i=r[1].split(","));let a=i.map(l=>l.trim()),s={section:Ug,type:Ug,people:a,task:t,score:n};Ax.push(s)},"addTask"),_Ue=o(function(t){let e={section:Ug,type:Ug,description:t,task:t,classes:[]};Sx.push(e)},"addTaskOrg"),cde=o(function(){let t=o(function(r){return Ax[r].processed},"compileTask"),e=!0;for(let[r,n]of Ax.entries())t(r),e=e&&n.processed;return e},"compileTasks"),LUe=o(function(){return SUe()},"getActors"),lP={getConfig:o(()=>de().journey,"getConfig"),clear:TUe,setDiagramTitle:nn,getDiagramTitle:Xr,setAccTitle:kr,getAccTitle:Ar,setAccDescription:_r,getAccDescription:Lr,addSection:kUe,getSections:EUe,getTasks:CUe,addTask:AUe,addTaskOrg:_Ue,getActors:LUe}});var DUe,hde,fde=R(()=>{"use strict";DUe=o(t=>`.label { + font-family: 'trebuchet ms', verdana, arial, sans-serif; + font-family: var(--mermaid-font-family); + color: ${t.textColor}; + } + .mouth { + stroke: #666; + } + + line { + stroke: ${t.textColor} + } + + .legend { + fill: ${t.textColor}; + } + + .label text { + fill: #333; + } + .label { + color: ${t.textColor} + } + + .face { + ${t.faceColor?`fill: ${t.faceColor}`:"fill: #FFF8DC"}; + stroke: #999; + } + + .node rect, + .node circle, + .node ellipse, + .node polygon, + .node path { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; + stroke-width: 1px; + } + + .node .label { + text-align: center; + } + .node.clickable { + cursor: pointer; + } + + .arrowheadPath { + fill: ${t.arrowheadColor}; + } + + .edgePath .path { + stroke: ${t.lineColor}; + stroke-width: 1.5px; + } + + .flowchart-link { + stroke: ${t.lineColor}; + fill: none; + } + + .edgeLabel { + background-color: ${t.edgeLabelBackground}; + rect { + opacity: 0.5; + } + text-align: center; + } + + .cluster rect { + } + + .cluster text { + fill: ${t.titleColor}; + } + + div.mermaidTooltip { + position: absolute; + text-align: center; + max-width: 200px; + padding: 2px; + font-family: 'trebuchet ms', verdana, arial, sans-serif; + font-family: var(--mermaid-font-family); + font-size: 12px; + background: ${t.tertiaryColor}; + border: 1px solid ${t.border2}; + border-radius: 2px; + pointer-events: none; + z-index: 100; + } + + .task-type-0, .section-type-0 { + ${t.fillType0?`fill: ${t.fillType0}`:""}; + } + .task-type-1, .section-type-1 { + ${t.fillType0?`fill: ${t.fillType1}`:""}; + } + .task-type-2, .section-type-2 { + ${t.fillType0?`fill: ${t.fillType2}`:""}; + } + .task-type-3, .section-type-3 { + ${t.fillType0?`fill: ${t.fillType3}`:""}; + } + .task-type-4, .section-type-4 { + ${t.fillType0?`fill: ${t.fillType4}`:""}; + } + .task-type-5, .section-type-5 { + ${t.fillType0?`fill: ${t.fillType5}`:""}; + } + .task-type-6, .section-type-6 { + ${t.fillType0?`fill: ${t.fillType6}`:""}; + } + .task-type-7, .section-type-7 { + ${t.fillType0?`fill: ${t.fillType7}`:""}; + } + + .actor-0 { + ${t.actor0?`fill: ${t.actor0}`:""}; + } + .actor-1 { + ${t.actor1?`fill: ${t.actor1}`:""}; + } + .actor-2 { + ${t.actor2?`fill: ${t.actor2}`:""}; + } + .actor-3 { + ${t.actor3?`fill: ${t.actor3}`:""}; + } + .actor-4 { + ${t.actor4?`fill: ${t.actor4}`:""}; + } + .actor-5 { + ${t.actor5?`fill: ${t.actor5}`:""}; + } +`,"getStyles"),hde=DUe});var cP,RUe,pde,mde,NUe,MUe,dde,IUe,OUe,gde,PUe,Hg,yde=R(()=>{"use strict";Zt();Qy();cP=o(function(t,e){return yd(t,e)},"drawRect"),RUe=o(function(t,e){let n=t.append("circle").attr("cx",e.cx).attr("cy",e.cy).attr("class","face").attr("r",15).attr("stroke-width",2).attr("overflow","visible"),i=t.append("g");i.append("circle").attr("cx",e.cx-15/3).attr("cy",e.cy-15/3).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),i.append("circle").attr("cx",e.cx+15/3).attr("cy",e.cy-15/3).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666");function a(u){let h=bl().startAngle(Math.PI/2).endAngle(3*(Math.PI/2)).innerRadius(7.5).outerRadius(6.8181818181818175);u.append("path").attr("class","mouth").attr("d",h).attr("transform","translate("+e.cx+","+(e.cy+2)+")")}o(a,"smile");function s(u){let h=bl().startAngle(3*Math.PI/2).endAngle(5*(Math.PI/2)).innerRadius(7.5).outerRadius(6.8181818181818175);u.append("path").attr("class","mouth").attr("d",h).attr("transform","translate("+e.cx+","+(e.cy+7)+")")}o(s,"sad");function l(u){u.append("line").attr("class","mouth").attr("stroke",2).attr("x1",e.cx-5).attr("y1",e.cy+7).attr("x2",e.cx+5).attr("y2",e.cy+7).attr("class","mouth").attr("stroke-width","1px").attr("stroke","#666")}return o(l,"ambivalent"),e.score>3?a(i):e.score<3?s(i):l(i),n},"drawFace"),pde=o(function(t,e){let r=t.append("circle");return r.attr("cx",e.cx),r.attr("cy",e.cy),r.attr("class","actor-"+e.pos),r.attr("fill",e.fill),r.attr("stroke",e.stroke),r.attr("r",e.r),r.class!==void 0&&r.attr("class",r.class),e.title!==void 0&&r.append("title").text(e.title),r},"drawCircle"),mde=o(function(t,e){return TW(t,e)},"drawText"),NUe=o(function(t,e){function r(i,a,s,l,u){return i+","+a+" "+(i+s)+","+a+" "+(i+s)+","+(a+l-u)+" "+(i+s-u*1.2)+","+(a+l)+" "+i+","+(a+l)}o(r,"genPoints");let n=t.append("polygon");n.attr("points",r(e.x,e.y,50,20,7)),n.attr("class","labelBox"),e.y=e.y+e.labelMargin,e.x=e.x+.5*e.labelMargin,mde(t,e)},"drawLabel"),MUe=o(function(t,e,r){let n=t.append("g"),i=wl();i.x=e.x,i.y=e.y,i.fill=e.fill,i.width=r.width*e.taskCount+r.diagramMarginX*(e.taskCount-1),i.height=r.height,i.class="journey-section section-type-"+e.num,i.rx=3,i.ry=3,cP(n,i),gde(r)(e.text,n,i.x,i.y,i.width,i.height,{class:"journey-section section-type-"+e.num},r,e.colour)},"drawSection"),dde=-1,IUe=o(function(t,e,r){let n=e.x+r.width/2,i=t.append("g");dde++;let a=300+5*30;i.append("line").attr("id","task"+dde).attr("x1",n).attr("y1",e.y).attr("x2",n).attr("y2",a).attr("class","task-line").attr("stroke-width","1px").attr("stroke-dasharray","4 2").attr("stroke","#666"),RUe(i,{cx:n,cy:300+(5-e.score)*30,score:e.score});let s=wl();s.x=e.x,s.y=e.y,s.fill=e.fill,s.width=r.width,s.height=r.height,s.class="task task-type-"+e.num,s.rx=3,s.ry=3,cP(i,s);let l=e.x+14;e.people.forEach(u=>{let h=e.actors[u].color,f={cx:l,cy:e.y,r:7,fill:h,stroke:"#000",title:u,pos:e.actors[u].position};pde(i,f),l+=10}),gde(r)(e.task,i,s.x,s.y,s.width,s.height,{class:"task"},r,e.colour)},"drawTask"),OUe=o(function(t,e){j3(t,e)},"drawBackgroundRect"),gde=function(){function t(i,a,s,l,u,h,f,d){let p=a.append("text").attr("x",s+u/2).attr("y",l+h/2+5).style("font-color",d).style("text-anchor","middle").text(i);n(p,f)}o(t,"byText");function e(i,a,s,l,u,h,f,d,p){let{taskFontSize:m,taskFontFamily:g}=d,y=i.split(//gi);for(let v=0;v{let i=Xu[n].color,a={cx:20,cy:r,r:7,fill:i,stroke:"#000",pos:Xu[n].position};Hg.drawCircle(t,a);let s={x:40,y:r+7,fill:"#666",text:n,textMargin:e.boxTextMargin|5};Hg.drawText(t,s),r+=20})}var BUe,Xu,JE,I0,zUe,Zo,uP,vde,GUe,hP,xde=R(()=>{"use strict";Zt();yde();_t();Yn();BUe=o(function(t){Object.keys(t).forEach(function(r){JE[r]=t[r]})},"setConf"),Xu={};o(FUe,"drawActorLegend");JE=de().journey,I0=JE.leftMargin,zUe=o(function(t,e,r,n){let i=de().journey,a=de().securityLevel,s;a==="sandbox"&&(s=$e("#i"+e));let l=a==="sandbox"?$e(s.nodes()[0].contentDocument.body):$e("body");Zo.init();let u=l.select("#"+e);Hg.initGraphics(u);let h=n.db.getTasks(),f=n.db.getDiagramTitle(),d=n.db.getActors();for(let x in Xu)delete Xu[x];let p=0;d.forEach(x=>{Xu[x]={color:i.actorColours[p%i.actorColours.length],position:p},p++}),FUe(u),Zo.insert(0,0,I0,Object.keys(Xu).length*50),GUe(u,h,0);let m=Zo.getBounds();f&&u.append("text").text(f).attr("x",I0).attr("font-size","4ex").attr("font-weight","bold").attr("y",25);let g=m.stopy-m.starty+2*i.diagramMarginY,y=I0+m.stopx+2*i.diagramMarginX;Sr(u,g,y,i.useMaxWidth),u.append("line").attr("x1",I0).attr("y1",i.height*4).attr("x2",y-I0-4).attr("y2",i.height*4).attr("stroke-width",4).attr("stroke","black").attr("marker-end","url(#arrowhead)");let v=f?70:0;u.attr("viewBox",`${m.startx} -25 ${y} ${g+v}`),u.attr("preserveAspectRatio","xMinYMin meet"),u.attr("height",g+v+25)},"draw"),Zo={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],init:o(function(){this.sequenceItems=[],this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0},"init"),updateVal:o(function(t,e,r,n){t[e]===void 0?t[e]=r:t[e]=n(r,t[e])},"updateVal"),updateBounds:o(function(t,e,r,n){let i=de().journey,a=this,s=0;function l(u){return o(function(f){s++;let d=a.sequenceItems.length-s+1;a.updateVal(f,"starty",e-d*i.boxMargin,Math.min),a.updateVal(f,"stopy",n+d*i.boxMargin,Math.max),a.updateVal(Zo.data,"startx",t-d*i.boxMargin,Math.min),a.updateVal(Zo.data,"stopx",r+d*i.boxMargin,Math.max),u!=="activation"&&(a.updateVal(f,"startx",t-d*i.boxMargin,Math.min),a.updateVal(f,"stopx",r+d*i.boxMargin,Math.max),a.updateVal(Zo.data,"starty",e-d*i.boxMargin,Math.min),a.updateVal(Zo.data,"stopy",n+d*i.boxMargin,Math.max))},"updateItemBounds")}o(l,"updateFn"),this.sequenceItems.forEach(l())},"updateBounds"),insert:o(function(t,e,r,n){let i=Math.min(t,r),a=Math.max(t,r),s=Math.min(e,n),l=Math.max(e,n);this.updateVal(Zo.data,"startx",i,Math.min),this.updateVal(Zo.data,"starty",s,Math.min),this.updateVal(Zo.data,"stopx",a,Math.max),this.updateVal(Zo.data,"stopy",l,Math.max),this.updateBounds(i,s,a,l)},"insert"),bumpVerticalPos:o(function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=this.verticalPos},"bumpVerticalPos"),getVerticalPos:o(function(){return this.verticalPos},"getVerticalPos"),getBounds:o(function(){return this.data},"getBounds")},uP=JE.sectionFills,vde=JE.sectionColours,GUe=o(function(t,e,r){let n=de().journey,i="",a=n.height*2+n.diagramMarginY,s=r+a,l=0,u="#CCC",h="black",f=0;for(let[d,p]of e.entries()){if(i!==p.section){u=uP[l%uP.length],f=l%uP.length,h=vde[l%vde.length];let g=0,y=p.section;for(let x=d;x(Xu[y]&&(g[y]=Xu[y]),g),{});p.x=d*n.taskMargin+d*n.width+I0,p.y=s,p.width=n.diagramMarginX,p.height=n.diagramMarginY,p.colour=h,p.fill=u,p.num=f,p.actors=m,Hg.drawTask(t,p,n),Zo.insert(p.x,p.y,p.x+p.width+n.taskMargin,300+5*30)}},"drawTasks"),hP={setConf:BUe,draw:zUe}});var bde={};hr(bde,{diagram:()=>$Ue});var $Ue,wde=R(()=>{"use strict";lde();ude();fde();xde();$Ue={parser:ode,db:lP,renderer:hP,styles:hde,init:o(t=>{hP.setConf(t.journey),lP.clear()},"init")}});var dP,_de,Lde=R(()=>{"use strict";dP=function(){var t=o(function(p,m,g,y){for(g=g||{},y=p.length;y--;g[p[y]]=m);return g},"o"),e=[6,8,10,11,12,14,16,17,20,21],r=[1,9],n=[1,10],i=[1,11],a=[1,12],s=[1,13],l=[1,16],u=[1,17],h={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,timeline:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,period_statement:18,event_statement:19,period:20,event:21,$accept:0,$end:1},terminals_:{2:"error",4:"timeline",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",20:"period",21:"event"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,1],[18,1],[19,1]],performAction:o(function(m,g,y,v,x,b,w){var S=b.length-1;switch(x){case 1:return b[S-1];case 2:this.$=[];break;case 3:b[S-1].push(b[S]),this.$=b[S-1];break;case 4:case 5:this.$=b[S];break;case 6:case 7:this.$=[];break;case 8:v.getCommonDb().setDiagramTitle(b[S].substr(6)),this.$=b[S].substr(6);break;case 9:this.$=b[S].trim(),v.getCommonDb().setAccTitle(this.$);break;case 10:case 11:this.$=b[S].trim(),v.getCommonDb().setAccDescription(this.$);break;case 12:v.addSection(b[S].substr(8)),this.$=b[S].substr(8);break;case 15:v.addTask(b[S],0,""),this.$=b[S];break;case 16:v.addEvent(b[S].substr(2)),this.$=b[S];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:r,12:n,14:i,16:a,17:s,18:14,19:15,20:l,21:u},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:18,11:r,12:n,14:i,16:a,17:s,18:14,19:15,20:l,21:u},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,19]},{15:[1,20]},t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),t(e,[2,4]),t(e,[2,9]),t(e,[2,10])],defaultActions:{},parseError:o(function(m,g){if(g.recoverable)this.trace(m);else{var y=new Error(m);throw y.hash=g,y}},"parseError"),parse:o(function(m){var g=this,y=[0],v=[],x=[null],b=[],w=this.table,S="",T=0,E=0,_=0,A=2,L=1,M=b.slice.call(arguments,1),N=Object.create(this.lexer),k={yy:{}};for(var I in this.yy)Object.prototype.hasOwnProperty.call(this.yy,I)&&(k.yy[I]=this.yy[I]);N.setInput(m,k.yy),k.yy.lexer=N,k.yy.parser=this,typeof N.yylloc>"u"&&(N.yylloc={});var C=N.yylloc;b.push(C);var O=N.options&&N.options.ranges;typeof k.yy.parseError=="function"?this.parseError=k.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function D(q){y.length=y.length-2*q,x.length=x.length-q,b.length=b.length-q}o(D,"popStack");function P(){var q;return q=v.pop()||N.lex()||L,typeof q!="number"&&(q instanceof Array&&(v=q,q=v.pop()),q=g.symbols_[q]||q),q}o(P,"lex");for(var F,B,$,z,Y,Q,X={},ie,j,J,Z;;){if($=y[y.length-1],this.defaultActions[$]?z=this.defaultActions[$]:((F===null||typeof F>"u")&&(F=P()),z=w[$]&&w[$][F]),typeof z>"u"||!z.length||!z[0]){var H="";Z=[];for(ie in w[$])this.terminals_[ie]&&ie>A&&Z.push("'"+this.terminals_[ie]+"'");N.showPosition?H="Parse error on line "+(T+1)+`: +`+N.showPosition()+` +Expecting `+Z.join(", ")+", got '"+(this.terminals_[F]||F)+"'":H="Parse error on line "+(T+1)+": Unexpected "+(F==L?"end of input":"'"+(this.terminals_[F]||F)+"'"),this.parseError(H,{text:N.match,token:this.terminals_[F]||F,line:N.yylineno,loc:C,expected:Z})}if(z[0]instanceof Array&&z.length>1)throw new Error("Parse Error: multiple actions possible at state: "+$+", token: "+F);switch(z[0]){case 1:y.push(F),x.push(N.yytext),b.push(N.yylloc),y.push(z[1]),F=null,B?(F=B,B=null):(E=N.yyleng,S=N.yytext,T=N.yylineno,C=N.yylloc,_>0&&_--);break;case 2:if(j=this.productions_[z[1]][1],X.$=x[x.length-j],X._$={first_line:b[b.length-(j||1)].first_line,last_line:b[b.length-1].last_line,first_column:b[b.length-(j||1)].first_column,last_column:b[b.length-1].last_column},O&&(X._$.range=[b[b.length-(j||1)].range[0],b[b.length-1].range[1]]),Q=this.performAction.apply(X,[S,E,T,k.yy,z[1],x,b].concat(M)),typeof Q<"u")return Q;j&&(y=y.slice(0,-1*j*2),x=x.slice(0,-1*j),b=b.slice(0,-1*j)),y.push(this.productions_[z[1]][0]),x.push(X.$),b.push(X._$),J=w[y[y.length-2]][y[y.length-1]],y.push(J);break;case 3:return!0}}return!0},"parse")},f=function(){var p={EOF:1,parseError:o(function(g,y){if(this.yy.parser)this.yy.parser.parseError(g,y);else throw new Error(g)},"parseError"),setInput:o(function(m,g){return this.yy=g||this.yy||{},this._input=m,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var m=this._input[0];this.yytext+=m,this.yyleng++,this.offset++,this.match+=m,this.matched+=m;var g=m.match(/(?:\r\n?|\n).*/g);return g?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),m},"input"),unput:o(function(m){var g=m.length,y=m.split(/(?:\r\n?|\n)/g);this._input=m+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-g),this.offset-=g;var v=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),y.length-1&&(this.yylineno-=y.length-1);var x=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:y?(y.length===v.length?this.yylloc.first_column:0)+v[v.length-y.length].length-y[0].length:this.yylloc.first_column-g},this.options.ranges&&(this.yylloc.range=[x[0],x[0]+this.yyleng-g]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(m){this.unput(this.match.slice(m))},"less"),pastInput:o(function(){var m=this.matched.substr(0,this.matched.length-this.match.length);return(m.length>20?"...":"")+m.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var m=this.match;return m.length<20&&(m+=this._input.substr(0,20-m.length)),(m.substr(0,20)+(m.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var m=this.pastInput(),g=new Array(m.length+1).join("-");return m+this.upcomingInput()+` +`+g+"^"},"showPosition"),test_match:o(function(m,g){var y,v,x;if(this.options.backtrack_lexer&&(x={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(x.yylloc.range=this.yylloc.range.slice(0))),v=m[0].match(/(?:\r\n?|\n).*/g),v&&(this.yylineno+=v.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:v?v[v.length-1].length-v[v.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+m[0].length},this.yytext+=m[0],this.match+=m[0],this.matches=m,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(m[0].length),this.matched+=m[0],y=this.performAction.call(this,this.yy,this,g,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),y)return y;if(this._backtrack){for(var b in x)this[b]=x[b];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var m,g,y,v;this._more||(this.yytext="",this.match="");for(var x=this._currentRules(),b=0;bg[0].length)){if(g=y,v=b,this.options.backtrack_lexer){if(m=this.test_match(y,x[b]),m!==!1)return m;if(this._backtrack){g=!1;continue}else return!1}else if(!this.options.flex)break}return g?(m=this.test_match(g,x[v]),m!==!1?m:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var g=this.next();return g||this.lex()},"lex"),begin:o(function(g){this.conditionStack.push(g)},"begin"),popState:o(function(){var g=this.conditionStack.length-1;return g>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(g){return g=this.conditionStack.length-1-Math.abs(g||0),g>=0?this.conditionStack[g]:"INITIAL"},"topState"),pushState:o(function(g){this.begin(g)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(g,y,v,x){var b=x;switch(v){case 0:break;case 1:break;case 2:return 10;case 3:break;case 4:break;case 5:return 4;case 6:return 11;case 7:return this.begin("acc_title"),12;break;case 8:return this.popState(),"acc_title_value";break;case 9:return this.begin("acc_descr"),14;break;case 10:return this.popState(),"acc_descr_value";break;case 11:this.begin("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 17;case 15:return 21;case 16:return 20;case 17:return 6;case 18:return"INVALID"}},"anonymous"),rules:[/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:timeline\b)/i,/^(?:title\s[^\n]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:section\s[^:\n]+)/i,/^(?::\s[^:\n]+)/i,/^(?:[^#:\n]+)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,9,11,14,15,16,17,18],inclusive:!0}}};return p}();h.lexer=f;function d(){this.yy={}}return o(d,"Parser"),d.prototype=h,h.Parser=d,new d}();dP.parser=dP;_de=dP});var mP={};hr(mP,{addEvent:()=>Fde,addSection:()=>Ide,addTask:()=>Bde,addTaskOrg:()=>zde,clear:()=>Mde,default:()=>KUe,getCommonDb:()=>Nde,getSections:()=>Ode,getTasks:()=>Pde});var Yg,Rde,pP,e6,Wg,Nde,Mde,Ide,Ode,Pde,Bde,Fde,zde,Dde,KUe,Gde=R(()=>{"use strict";bi();Yg="",Rde=0,pP=[],e6=[],Wg=[],Nde=o(()=>ly,"getCommonDb"),Mde=o(function(){pP.length=0,e6.length=0,Yg="",Wg.length=0,vr()},"clear"),Ide=o(function(t){Yg=t,pP.push(t)},"addSection"),Ode=o(function(){return pP},"getSections"),Pde=o(function(){let t=Dde(),e=100,r=0;for(;!t&&rr.id===Rde-1).events.push(t)},"addEvent"),zde=o(function(t){let e={section:Yg,type:Yg,description:t,task:t,classes:[]};e6.push(e)},"addTaskOrg"),Dde=o(function(){let t=o(function(r){return Wg[r].processed},"compileTask"),e=!0;for(let[r,n]of Wg.entries())t(r),e=e&&n.processed;return e},"compileTasks"),KUe={clear:Mde,getCommonDb:Nde,addSection:Ide,getSections:Ode,getTasks:Pde,addTask:Bde,addTaskOrg:zde,addEvent:Fde}});function Hde(t,e){t.each(function(){var r=$e(this),n=r.text().split(/(\s+|
    )/).reverse(),i,a=[],s=1.1,l=r.attr("y"),u=parseFloat(r.attr("dy")),h=r.text(null).append("tspan").attr("x",0).attr("y",l).attr("dy",u+"em");for(let f=0;fe||i==="
    ")&&(a.pop(),h.text(a.join(" ").trim()),i==="
    "?a=[""]:a=[i],h=r.append("tspan").attr("x",0).attr("y",l).attr("dy",s+"em").text(i))})}var QUe,t6,ZUe,JUe,Vde,eHe,tHe,$de,rHe,nHe,iHe,gP,Ude,aHe,sHe,oHe,lHe,xf,Yde=R(()=>{"use strict";Zt();QUe=12,t6=o(function(t,e){let r=t.append("rect");return r.attr("x",e.x),r.attr("y",e.y),r.attr("fill",e.fill),r.attr("stroke",e.stroke),r.attr("width",e.width),r.attr("height",e.height),r.attr("rx",e.rx),r.attr("ry",e.ry),e.class!==void 0&&r.attr("class",e.class),r},"drawRect"),ZUe=o(function(t,e){let n=t.append("circle").attr("cx",e.cx).attr("cy",e.cy).attr("class","face").attr("r",15).attr("stroke-width",2).attr("overflow","visible"),i=t.append("g");i.append("circle").attr("cx",e.cx-15/3).attr("cy",e.cy-15/3).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),i.append("circle").attr("cx",e.cx+15/3).attr("cy",e.cy-15/3).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666");function a(u){let h=bl().startAngle(Math.PI/2).endAngle(3*(Math.PI/2)).innerRadius(7.5).outerRadius(6.8181818181818175);u.append("path").attr("class","mouth").attr("d",h).attr("transform","translate("+e.cx+","+(e.cy+2)+")")}o(a,"smile");function s(u){let h=bl().startAngle(3*Math.PI/2).endAngle(5*(Math.PI/2)).innerRadius(7.5).outerRadius(6.8181818181818175);u.append("path").attr("class","mouth").attr("d",h).attr("transform","translate("+e.cx+","+(e.cy+7)+")")}o(s,"sad");function l(u){u.append("line").attr("class","mouth").attr("stroke",2).attr("x1",e.cx-5).attr("y1",e.cy+7).attr("x2",e.cx+5).attr("y2",e.cy+7).attr("class","mouth").attr("stroke-width","1px").attr("stroke","#666")}return o(l,"ambivalent"),e.score>3?a(i):e.score<3?s(i):l(i),n},"drawFace"),JUe=o(function(t,e){let r=t.append("circle");return r.attr("cx",e.cx),r.attr("cy",e.cy),r.attr("class","actor-"+e.pos),r.attr("fill",e.fill),r.attr("stroke",e.stroke),r.attr("r",e.r),r.class!==void 0&&r.attr("class",r.class),e.title!==void 0&&r.append("title").text(e.title),r},"drawCircle"),Vde=o(function(t,e){let r=e.text.replace(//gi," "),n=t.append("text");n.attr("x",e.x),n.attr("y",e.y),n.attr("class","legend"),n.style("text-anchor",e.anchor),e.class!==void 0&&n.attr("class",e.class);let i=n.append("tspan");return i.attr("x",e.x+e.textMargin*2),i.text(r),n},"drawText"),eHe=o(function(t,e){function r(i,a,s,l,u){return i+","+a+" "+(i+s)+","+a+" "+(i+s)+","+(a+l-u)+" "+(i+s-u*1.2)+","+(a+l)+" "+i+","+(a+l)}o(r,"genPoints");let n=t.append("polygon");n.attr("points",r(e.x,e.y,50,20,7)),n.attr("class","labelBox"),e.y=e.y+e.labelMargin,e.x=e.x+.5*e.labelMargin,Vde(t,e)},"drawLabel"),tHe=o(function(t,e,r){let n=t.append("g"),i=gP();i.x=e.x,i.y=e.y,i.fill=e.fill,i.width=r.width,i.height=r.height,i.class="journey-section section-type-"+e.num,i.rx=3,i.ry=3,t6(n,i),Ude(r)(e.text,n,i.x,i.y,i.width,i.height,{class:"journey-section section-type-"+e.num},r,e.colour)},"drawSection"),$de=-1,rHe=o(function(t,e,r){let n=e.x+r.width/2,i=t.append("g");$de++;let a=300+5*30;i.append("line").attr("id","task"+$de).attr("x1",n).attr("y1",e.y).attr("x2",n).attr("y2",a).attr("class","task-line").attr("stroke-width","1px").attr("stroke-dasharray","4 2").attr("stroke","#666"),ZUe(i,{cx:n,cy:300+(5-e.score)*30,score:e.score});let s=gP();s.x=e.x,s.y=e.y,s.fill=e.fill,s.width=r.width,s.height=r.height,s.class="task task-type-"+e.num,s.rx=3,s.ry=3,t6(i,s),Ude(r)(e.task,i,s.x,s.y,s.width,s.height,{class:"task"},r,e.colour)},"drawTask"),nHe=o(function(t,e){t6(t,{x:e.startx,y:e.starty,width:e.stopx-e.startx,height:e.stopy-e.starty,fill:e.fill,class:"rect"}).lower()},"drawBackgroundRect"),iHe=o(function(){return{x:0,y:0,fill:void 0,"text-anchor":"start",width:100,height:100,textMargin:0,rx:0,ry:0}},"getTextObj"),gP=o(function(){return{x:0,y:0,width:100,anchor:"start",height:100,rx:0,ry:0}},"getNoteRect"),Ude=function(){function t(i,a,s,l,u,h,f,d){let p=a.append("text").attr("x",s+u/2).attr("y",l+h/2+5).style("font-color",d).style("text-anchor","middle").text(i);n(p,f)}o(t,"byText");function e(i,a,s,l,u,h,f,d,p){let{taskFontSize:m,taskFontFamily:g}=d,y=i.split(//gi);for(let v=0;v{"use strict";Zt();Yde();ut();_t();Yn();cHe=o(function(t,e,r,n){let i=de(),a=i.leftMargin??50;V.debug("timeline",n.db);let s=i.securityLevel,l;s==="sandbox"&&(l=$e("#i"+e));let h=(s==="sandbox"?$e(l.nodes()[0].contentDocument.body):$e("body")).select("#"+e);h.append("g");let f=n.db.getTasks(),d=n.db.getCommonDb().getDiagramTitle();V.debug("task",f),xf.initGraphics(h);let p=n.db.getSections();V.debug("sections",p);let m=0,g=0,y=0,v=0,x=50+a,b=50;v=50;let w=0,S=!0;p.forEach(function(L){let M={number:w,descr:L,section:w,width:150,padding:20,maxHeight:m},N=xf.getVirtualNodeHeight(h,M,i);V.debug("sectionHeight before draw",N),m=Math.max(m,N+20)});let T=0,E=0;V.debug("tasks.length",f.length);for(let[L,M]of f.entries()){let N={number:L,descr:M,section:M.section,width:150,padding:20,maxHeight:g},k=xf.getVirtualNodeHeight(h,N,i);V.debug("taskHeight before draw",k),g=Math.max(g,k+20),T=Math.max(T,M.events.length);let I=0;for(let C of M.events){let O={descr:C,section:M.section,number:M.section,width:150,padding:20,maxHeight:50};I+=xf.getVirtualNodeHeight(h,O,i)}E=Math.max(E,I)}V.debug("maxSectionHeight before draw",m),V.debug("maxTaskHeight before draw",g),p&&p.length>0?p.forEach(L=>{let M=f.filter(C=>C.section===L),N={number:w,descr:L,section:w,width:200*Math.max(M.length,1)-50,padding:20,maxHeight:m};V.debug("sectionNode",N);let k=h.append("g"),I=xf.drawNode(k,N,w,i);V.debug("sectionNode output",I),k.attr("transform",`translate(${x}, ${v})`),b+=m+50,M.length>0&&Wde(h,M,w,x,b,g,i,T,E,m,!1),x+=200*Math.max(M.length,1),b=v,w++}):(S=!1,Wde(h,f,w,x,b,g,i,T,E,m,!0));let _=h.node().getBBox();V.debug("bounds",_),d&&h.append("text").text(d).attr("x",_.width/2-a).attr("font-size","4ex").attr("font-weight","bold").attr("y",20),y=S?m+g+150:g+100,h.append("g").attr("class","lineWrapper").append("line").attr("x1",a).attr("y1",y).attr("x2",_.width+3*a).attr("y2",y).attr("stroke-width",4).attr("stroke","black").attr("marker-end","url(#arrowhead)"),Lo(void 0,h,i.timeline?.padding??50,i.timeline?.useMaxWidth??!1)},"draw"),Wde=o(function(t,e,r,n,i,a,s,l,u,h,f){for(let d of e){let p={descr:d.task,section:r,number:r,width:150,padding:20,maxHeight:a};V.debug("taskNode",p);let m=t.append("g").attr("class","taskWrapper"),y=xf.drawNode(m,p,r,s).height;if(V.debug("taskHeight after draw",y),m.attr("transform",`translate(${n}, ${i})`),a=Math.max(a,y),d.events){let v=t.append("g").attr("class","lineWrapper"),x=a;i+=100,x=x+uHe(t,d.events,r,n,i,s),i-=100,v.append("line").attr("x1",n+190/2).attr("y1",i+a).attr("x2",n+190/2).attr("y2",i+a+(f?a:h)+u+120).attr("stroke-width",2).attr("stroke","black").attr("marker-end","url(#arrowhead)").attr("stroke-dasharray","5,5")}n=n+200,f&&!s.timeline?.disableMulticolor&&r++}i=i-10},"drawTasks"),uHe=o(function(t,e,r,n,i,a){let s=0,l=i;i=i+100;for(let u of e){let h={descr:u,section:r,number:r,width:150,padding:20,maxHeight:50};V.debug("eventNode",h);let f=t.append("g").attr("class","eventWrapper"),p=xf.drawNode(f,h,r,a).height;s=s+p,f.attr("transform",`translate(${n}, ${i})`),i=i+10+p}return i=l,s},"drawEvents"),qde={setConf:o(()=>{},"setConf"),draw:cHe}});var hHe,fHe,jde,Kde=R(()=>{"use strict";al();hHe=o(t=>{let e="";for(let r=0;r` + .edge { + stroke-width: 3; + } + ${hHe(t)} + .section-root rect, .section-root path, .section-root circle { + fill: ${t.git0}; + } + .section-root text { + fill: ${t.gitBranchLabel0}; + } + .icon-container { + height:100%; + display: flex; + justify-content: center; + align-items: center; + } + .edge { + fill: none; + } + .eventWrapper { + filter: brightness(120%); + } +`,"getStyles"),jde=fHe});var Qde={};hr(Qde,{diagram:()=>dHe});var dHe,Zde=R(()=>{"use strict";Lde();Gde();Xde();Kde();dHe={db:mP,renderer:qde,parser:_de,styles:jde}});var yP,t0e,r0e=R(()=>{"use strict";yP=function(){var t=o(function(S,T,E,_){for(E=E||{},_=S.length;_--;E[S[_]]=T);return E},"o"),e=[1,4],r=[1,13],n=[1,12],i=[1,15],a=[1,16],s=[1,20],l=[1,19],u=[6,7,8],h=[1,26],f=[1,24],d=[1,25],p=[6,7,11],m=[1,6,13,15,16,19,22],g=[1,33],y=[1,34],v=[1,6,7,11,13,15,16,19,22],x={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mindMap:4,spaceLines:5,SPACELINE:6,NL:7,MINDMAP:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,node:14,ICON:15,CLASS:16,nodeWithId:17,nodeWithoutId:18,NODE_DSTART:19,NODE_DESCR:20,NODE_DEND:21,NODE_ID:22,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"MINDMAP",11:"EOF",13:"SPACELIST",15:"ICON",16:"CLASS",19:"NODE_DSTART",20:"NODE_DESCR",21:"NODE_DEND",22:"NODE_ID"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,2],[12,2],[12,2],[12,1],[12,1],[12,1],[12,1],[12,1],[14,1],[14,1],[18,3],[17,1],[17,4]],performAction:o(function(T,E,_,A,L,M,N){var k=M.length-1;switch(L){case 6:case 7:return A;case 8:A.getLogger().trace("Stop NL ");break;case 9:A.getLogger().trace("Stop EOF ");break;case 11:A.getLogger().trace("Stop NL2 ");break;case 12:A.getLogger().trace("Stop EOF2 ");break;case 15:A.getLogger().info("Node: ",M[k].id),A.addNode(M[k-1].length,M[k].id,M[k].descr,M[k].type);break;case 16:A.getLogger().trace("Icon: ",M[k]),A.decorateNode({icon:M[k]});break;case 17:case 21:A.decorateNode({class:M[k]});break;case 18:A.getLogger().trace("SPACELIST");break;case 19:A.getLogger().trace("Node: ",M[k].id),A.addNode(0,M[k].id,M[k].descr,M[k].type);break;case 20:A.decorateNode({icon:M[k]});break;case 25:A.getLogger().trace("node found ..",M[k-2]),this.$={id:M[k-1],descr:M[k-1],type:A.getType(M[k-2],M[k])};break;case 26:this.$={id:M[k],descr:M[k],type:A.nodeType.DEFAULT};break;case 27:A.getLogger().trace("node found ..",M[k-3]),this.$={id:M[k-3],descr:M[k-1],type:A.getType(M[k-2],M[k])};break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:e},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:e},{6:r,7:[1,10],9:9,12:11,13:n,14:14,15:i,16:a,17:17,18:18,19:s,22:l},t(u,[2,3]),{1:[2,2]},t(u,[2,4]),t(u,[2,5]),{1:[2,6],6:r,12:21,13:n,14:14,15:i,16:a,17:17,18:18,19:s,22:l},{6:r,9:22,12:11,13:n,14:14,15:i,16:a,17:17,18:18,19:s,22:l},{6:h,7:f,10:23,11:d},t(p,[2,22],{17:17,18:18,14:27,15:[1,28],16:[1,29],19:s,22:l}),t(p,[2,18]),t(p,[2,19]),t(p,[2,20]),t(p,[2,21]),t(p,[2,23]),t(p,[2,24]),t(p,[2,26],{19:[1,30]}),{20:[1,31]},{6:h,7:f,10:32,11:d},{1:[2,7],6:r,12:21,13:n,14:14,15:i,16:a,17:17,18:18,19:s,22:l},t(m,[2,14],{7:g,11:y}),t(v,[2,8]),t(v,[2,9]),t(v,[2,10]),t(p,[2,15]),t(p,[2,16]),t(p,[2,17]),{20:[1,35]},{21:[1,36]},t(m,[2,13],{7:g,11:y}),t(v,[2,11]),t(v,[2,12]),{21:[1,37]},t(p,[2,25]),t(p,[2,27])],defaultActions:{2:[2,1],6:[2,2]},parseError:o(function(T,E){if(E.recoverable)this.trace(T);else{var _=new Error(T);throw _.hash=E,_}},"parseError"),parse:o(function(T){var E=this,_=[0],A=[],L=[null],M=[],N=this.table,k="",I=0,C=0,O=0,D=2,P=1,F=M.slice.call(arguments,1),B=Object.create(this.lexer),$={yy:{}};for(var z in this.yy)Object.prototype.hasOwnProperty.call(this.yy,z)&&($.yy[z]=this.yy[z]);B.setInput(T,$.yy),$.yy.lexer=B,$.yy.parser=this,typeof B.yylloc>"u"&&(B.yylloc={});var Y=B.yylloc;M.push(Y);var Q=B.options&&B.options.ranges;typeof $.yy.parseError=="function"?this.parseError=$.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function X(ke){_.length=_.length-2*ke,L.length=L.length-ke,M.length=M.length-ke}o(X,"popStack");function ie(){var ke;return ke=A.pop()||B.lex()||P,typeof ke!="number"&&(ke instanceof Array&&(A=ke,ke=A.pop()),ke=E.symbols_[ke]||ke),ke}o(ie,"lex");for(var j,J,Z,H,q,K,se={},ce,ue,te,De;;){if(Z=_[_.length-1],this.defaultActions[Z]?H=this.defaultActions[Z]:((j===null||typeof j>"u")&&(j=ie()),H=N[Z]&&N[Z][j]),typeof H>"u"||!H.length||!H[0]){var oe="";De=[];for(ce in N[Z])this.terminals_[ce]&&ce>D&&De.push("'"+this.terminals_[ce]+"'");B.showPosition?oe="Parse error on line "+(I+1)+`: +`+B.showPosition()+` +Expecting `+De.join(", ")+", got '"+(this.terminals_[j]||j)+"'":oe="Parse error on line "+(I+1)+": Unexpected "+(j==P?"end of input":"'"+(this.terminals_[j]||j)+"'"),this.parseError(oe,{text:B.match,token:this.terminals_[j]||j,line:B.yylineno,loc:Y,expected:De})}if(H[0]instanceof Array&&H.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Z+", token: "+j);switch(H[0]){case 1:_.push(j),L.push(B.yytext),M.push(B.yylloc),_.push(H[1]),j=null,J?(j=J,J=null):(C=B.yyleng,k=B.yytext,I=B.yylineno,Y=B.yylloc,O>0&&O--);break;case 2:if(ue=this.productions_[H[1]][1],se.$=L[L.length-ue],se._$={first_line:M[M.length-(ue||1)].first_line,last_line:M[M.length-1].last_line,first_column:M[M.length-(ue||1)].first_column,last_column:M[M.length-1].last_column},Q&&(se._$.range=[M[M.length-(ue||1)].range[0],M[M.length-1].range[1]]),K=this.performAction.apply(se,[k,C,I,$.yy,H[1],L,M].concat(F)),typeof K<"u")return K;ue&&(_=_.slice(0,-1*ue*2),L=L.slice(0,-1*ue),M=M.slice(0,-1*ue)),_.push(this.productions_[H[1]][0]),L.push(se.$),M.push(se._$),te=N[_[_.length-2]][_[_.length-1]],_.push(te);break;case 3:return!0}}return!0},"parse")},b=function(){var S={EOF:1,parseError:o(function(E,_){if(this.yy.parser)this.yy.parser.parseError(E,_);else throw new Error(E)},"parseError"),setInput:o(function(T,E){return this.yy=E||this.yy||{},this._input=T,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var T=this._input[0];this.yytext+=T,this.yyleng++,this.offset++,this.match+=T,this.matched+=T;var E=T.match(/(?:\r\n?|\n).*/g);return E?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),T},"input"),unput:o(function(T){var E=T.length,_=T.split(/(?:\r\n?|\n)/g);this._input=T+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-E),this.offset-=E;var A=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),_.length-1&&(this.yylineno-=_.length-1);var L=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:_?(_.length===A.length?this.yylloc.first_column:0)+A[A.length-_.length].length-_[0].length:this.yylloc.first_column-E},this.options.ranges&&(this.yylloc.range=[L[0],L[0]+this.yyleng-E]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(T){this.unput(this.match.slice(T))},"less"),pastInput:o(function(){var T=this.matched.substr(0,this.matched.length-this.match.length);return(T.length>20?"...":"")+T.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var T=this.match;return T.length<20&&(T+=this._input.substr(0,20-T.length)),(T.substr(0,20)+(T.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var T=this.pastInput(),E=new Array(T.length+1).join("-");return T+this.upcomingInput()+` +`+E+"^"},"showPosition"),test_match:o(function(T,E){var _,A,L;if(this.options.backtrack_lexer&&(L={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(L.yylloc.range=this.yylloc.range.slice(0))),A=T[0].match(/(?:\r\n?|\n).*/g),A&&(this.yylineno+=A.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:A?A[A.length-1].length-A[A.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+T[0].length},this.yytext+=T[0],this.match+=T[0],this.matches=T,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(T[0].length),this.matched+=T[0],_=this.performAction.call(this,this.yy,this,E,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),_)return _;if(this._backtrack){for(var M in L)this[M]=L[M];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var T,E,_,A;this._more||(this.yytext="",this.match="");for(var L=this._currentRules(),M=0;ME[0].length)){if(E=_,A=M,this.options.backtrack_lexer){if(T=this.test_match(_,L[M]),T!==!1)return T;if(this._backtrack){E=!1;continue}else return!1}else if(!this.options.flex)break}return E?(T=this.test_match(E,L[A]),T!==!1?T:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var E=this.next();return E||this.lex()},"lex"),begin:o(function(E){this.conditionStack.push(E)},"begin"),popState:o(function(){var E=this.conditionStack.length-1;return E>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(E){return E=this.conditionStack.length-1-Math.abs(E||0),E>=0?this.conditionStack[E]:"INITIAL"},"topState"),pushState:o(function(E){this.begin(E)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(E,_,A,L){var M=L;switch(A){case 0:return E.getLogger().trace("Found comment",_.yytext),6;break;case 1:return 8;case 2:this.begin("CLASS");break;case 3:return this.popState(),16;break;case 4:this.popState();break;case 5:E.getLogger().trace("Begin icon"),this.begin("ICON");break;case 6:return E.getLogger().trace("SPACELINE"),6;break;case 7:return 7;case 8:return 15;case 9:E.getLogger().trace("end icon"),this.popState();break;case 10:return E.getLogger().trace("Exploding node"),this.begin("NODE"),19;break;case 11:return E.getLogger().trace("Cloud"),this.begin("NODE"),19;break;case 12:return E.getLogger().trace("Explosion Bang"),this.begin("NODE"),19;break;case 13:return E.getLogger().trace("Cloud Bang"),this.begin("NODE"),19;break;case 14:return this.begin("NODE"),19;break;case 15:return this.begin("NODE"),19;break;case 16:return this.begin("NODE"),19;break;case 17:return this.begin("NODE"),19;break;case 18:return 13;case 19:return 22;case 20:return 11;case 21:this.begin("NSTR2");break;case 22:return"NODE_DESCR";case 23:this.popState();break;case 24:E.getLogger().trace("Starting NSTR"),this.begin("NSTR");break;case 25:return E.getLogger().trace("description:",_.yytext),"NODE_DESCR";break;case 26:this.popState();break;case 27:return this.popState(),E.getLogger().trace("node end ))"),"NODE_DEND";break;case 28:return this.popState(),E.getLogger().trace("node end )"),"NODE_DEND";break;case 29:return this.popState(),E.getLogger().trace("node end ...",_.yytext),"NODE_DEND";break;case 30:return this.popState(),E.getLogger().trace("node end (("),"NODE_DEND";break;case 31:return this.popState(),E.getLogger().trace("node end (-"),"NODE_DEND";break;case 32:return this.popState(),E.getLogger().trace("node end (-"),"NODE_DEND";break;case 33:return this.popState(),E.getLogger().trace("node end (("),"NODE_DEND";break;case 34:return this.popState(),E.getLogger().trace("node end (("),"NODE_DEND";break;case 35:return E.getLogger().trace("Long description:",_.yytext),20;break;case 36:return E.getLogger().trace("Long description:",_.yytext),20;break}},"anonymous"),rules:[/^(?:\s*%%.*)/i,/^(?:mindmap\b)/i,/^(?::::)/i,/^(?:.+)/i,/^(?:\n)/i,/^(?:::icon\()/i,/^(?:[\s]+[\n])/i,/^(?:[\n]+)/i,/^(?:[^\)]+)/i,/^(?:\))/i,/^(?:-\))/i,/^(?:\(-)/i,/^(?:\)\))/i,/^(?:\))/i,/^(?:\(\()/i,/^(?:\{\{)/i,/^(?:\()/i,/^(?:\[)/i,/^(?:[\s]+)/i,/^(?:[^\(\[\n\)\{\}]+)/i,/^(?:$)/i,/^(?:["][`])/i,/^(?:[^`"]+)/i,/^(?:[`]["])/i,/^(?:["])/i,/^(?:[^"]+)/i,/^(?:["])/i,/^(?:[\)]\))/i,/^(?:[\)])/i,/^(?:[\]])/i,/^(?:\}\})/i,/^(?:\(-)/i,/^(?:-\))/i,/^(?:\(\()/i,/^(?:\()/i,/^(?:[^\)\]\(\}]+)/i,/^(?:.+(?!\(\())/i],conditions:{CLASS:{rules:[3,4],inclusive:!1},ICON:{rules:[8,9],inclusive:!1},NSTR2:{rules:[22,23],inclusive:!1},NSTR:{rules:[25,26],inclusive:!1},NODE:{rules:[21,24,27,28,29,30,31,32,33,34,35,36],inclusive:!1},INITIAL:{rules:[0,1,2,5,6,7,10,11,12,13,14,15,16,17,18,19,20],inclusive:!0}}};return S}();x.lexer=b;function w(){this.yy={}}return o(w,"Parser"),w.prototype=x,x.Parser=w,new w}();yP.parser=yP;t0e=yP});var Gl,n0e,vP,yHe,vHe,xHe,bHe,$i,wHe,THe,kHe,EHe,CHe,SHe,AHe,i0e,a0e=R(()=>{"use strict";_t();rr();ut();sl();Gl=[],n0e=0,vP={},yHe=o(()=>{Gl=[],n0e=0,vP={}},"clear"),vHe=o(function(t){for(let e=Gl.length-1;e>=0;e--)if(Gl[e].levelGl.length>0?Gl[0]:null,"getMindmap"),bHe=o((t,e,r,n)=>{V.info("addNode",t,e,r,n);let i=de(),a=i.mindmap?.padding??mr.mindmap.padding;switch(n){case $i.ROUNDED_RECT:case $i.RECT:case $i.HEXAGON:a*=2}let s={id:n0e++,nodeId:qr(e,i),level:t,descr:qr(r,i),type:n,children:[],width:i.mindmap?.maxNodeWidth??mr.mindmap.maxNodeWidth,padding:a},l=vHe(t);if(l)l.children.push(s),Gl.push(s);else if(Gl.length===0)Gl.push(s);else throw new Error('There can be only one root. No parent could be found for ("'+s.descr+'")')},"addNode"),$i={DEFAULT:0,NO_BORDER:0,ROUNDED_RECT:1,RECT:2,CIRCLE:3,CLOUD:4,BANG:5,HEXAGON:6},wHe=o((t,e)=>{switch(V.debug("In get type",t,e),t){case"[":return $i.RECT;case"(":return e===")"?$i.ROUNDED_RECT:$i.CLOUD;case"((":return $i.CIRCLE;case")":return $i.CLOUD;case"))":return $i.BANG;case"{{":return $i.HEXAGON;default:return $i.DEFAULT}},"getType"),THe=o((t,e)=>{vP[t]=e},"setElementForId"),kHe=o(t=>{if(!t)return;let e=de(),r=Gl[Gl.length-1];t.icon&&(r.icon=qr(t.icon,e)),t.class&&(r.class=qr(t.class,e))},"decorateNode"),EHe=o(t=>{switch(t){case $i.DEFAULT:return"no-border";case $i.RECT:return"rect";case $i.ROUNDED_RECT:return"rounded-rect";case $i.CIRCLE:return"circle";case $i.CLOUD:return"cloud";case $i.BANG:return"bang";case $i.HEXAGON:return"hexgon";default:return"no-border"}},"type2Str"),CHe=o(()=>V,"getLogger"),SHe=o(t=>vP[t],"getElementById"),AHe={clear:yHe,addNode:bHe,getMindmap:xHe,nodeType:$i,getType:wHe,setElementForId:THe,decorateNode:kHe,type2Str:EHe,getLogger:CHe,getElementById:SHe},i0e=AHe});function Hi(t){"@babel/helpers - typeof";return Hi=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Hi(t)}function XP(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s0e(t,e){for(var r=0;rt.length)&&(e=t.length);for(var r=0,n=new Array(e);r=t.length?{done:!0}:{done:!1,value:t[n++]}},"n"),e:o(function(u){throw u},"e"),f:i}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. +In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var a=!0,s=!1,l;return{s:o(function(){r=r.call(t)},"s"),n:o(function(){var u=r.next();return a=u.done,u},"n"),e:o(function(u){s=!0,l=u},"e"),f:o(function(){try{!a&&r.return!=null&&r.return()}finally{if(s)throw l}},"f")}}function eYe(t){var e=typeof t;return t!=null&&(e=="object"||e=="function")}function tYe(t,e){return e={exports:{}},t(e,e.exports),e.exports}function lYe(t){for(var e=t.length;e--&&oYe.test(t.charAt(e)););return e}function hYe(t){return t&&t.slice(0,cYe(t)+1).replace(uYe,"")}function gYe(t){var e=pYe.call(t,_x),r=t[_x];try{t[_x]=void 0;var n=!0}catch{}var i=mYe.call(t);return n&&(e?t[_x]=r:delete t[_x]),i}function bYe(t){return xYe.call(t)}function EYe(t){return t==null?t===void 0?kYe:TYe:u0e&&u0e in Object(t)?yYe(t):wYe(t)}function CYe(t){return t!=null&&typeof t=="object"}function _Ye(t){return typeof t=="symbol"||SYe(t)&&Rpe(t)==AYe}function MYe(t){if(typeof t=="number")return t;if(Jx(t))return h0e;if(V0(t)){var e=typeof t.valueOf=="function"?t.valueOf():t;t=V0(e)?e+"":e}if(typeof t!="string")return t===0?t:+t;t=fYe(t);var r=DYe.test(t);return r||RYe.test(t)?NYe(t.slice(2),r?2:8):LYe.test(t)?h0e:+t}function BYe(t,e,r){var n,i,a,s,l,u,h=0,f=!1,d=!1,p=!0;if(typeof t!="function")throw new TypeError(IYe);e=f0e(e)||0,V0(r)&&(f=!!r.leading,d="maxWait"in r,a=d?OYe(f0e(r.maxWait)||0,e):a,p="trailing"in r?!!r.trailing:p);function m(E){var _=n,A=i;return n=i=void 0,h=E,s=t.apply(A,_),s}o(m,"invokeFunc");function g(E){return h=E,l=setTimeout(x,e),f?m(E):s}o(g,"leadingEdge");function y(E){var _=E-u,A=E-h,L=e-_;return d?PYe(L,a-A):L}o(y,"remainingWait");function v(E){var _=E-u,A=E-h;return u===void 0||_>=e||_<0||d&&A>=a}o(v,"shouldInvoke");function x(){var E=xP();if(v(E))return b(E);l=setTimeout(x,y(E))}o(x,"timerExpired");function b(E){return l=void 0,p&&n?m(E):(n=i=void 0,s)}o(b,"trailingEdge");function w(){l!==void 0&&clearTimeout(l),h=0,n=u=i=l=void 0}o(w,"cancel");function S(){return l===void 0?s:b(xP())}o(S,"flush");function T(){var E=xP(),_=v(E);if(n=arguments,i=this,u=E,_){if(l===void 0)return g(u);if(d)return clearTimeout(l),l=setTimeout(x,e),m(u)}return l===void 0&&(l=setTimeout(x,e)),s}return o(T,"debounced"),T.cancel=w,T.flush=S,T}function z6(t,e,r,n,i,a){var s;return jn(t)?s=t:s=o1[t]||o1.euclidean,e===0&&jn(t)?s(i,a):s(e,r,n,i,a)}function Lqe(t,e){if(G6(t))return!1;var r=typeof t;return r=="number"||r=="symbol"||r=="boolean"||t==null||Jx(t)?!0:_qe.test(t)||!Aqe.test(t)||e!=null&&t in Object(e)}function Oqe(t){if(!V0(t))return!1;var e=Rpe(t);return e==Nqe||e==Mqe||e==Rqe||e==Iqe}function Fqe(t){return!!N0e&&N0e in t}function Vqe(t){if(t!=null){try{return $qe.call(t)}catch{}try{return t+""}catch{}}return""}function Qqe(t){if(!V0(t)||zqe(t))return!1;var e=Pqe(t)?Kqe:Yqe;return e.test(Uqe(t))}function Jqe(t,e){return t?.[e]}function tXe(t,e){var r=eXe(t,e);return Zqe(r)?r:void 0}function nXe(){this.__data__=Wx?Wx(null):{},this.size=0}function aXe(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}function uXe(t){var e=this.__data__;if(Wx){var r=e[t];return r===oXe?void 0:r}return cXe.call(e,t)?e[t]:void 0}function pXe(t){var e=this.__data__;return Wx?e[t]!==void 0:dXe.call(e,t)}function yXe(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=Wx&&e===void 0?gXe:e,this}function h1(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e-1}function RXe(t,e){var r=this.__data__,n=$6(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this}function f1(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e-1&&t%1==0&&t0;){var f=i.shift();e(f),a.add(f.id()),l&&n(i,a,f)}return t}function ume(t,e,r){if(r.isParent())for(var n=r._private.children,i=0;i0&&arguments[0]!==void 0?arguments[0]:mKe,e=arguments.length>1?arguments[1]:void 0,r=0;r0?k=C:N=C;while(Math.abs(I)>s&&++O=a?b(M,O):D===0?O:S(M,N,N+h)}o(T,"getTForX");var E=!1;function _(){E=!0,(t!==e||r!==n)&&w()}o(_,"precompute");var A=o(function(N){return E||_(),t===e&&r===n?N:N===0?0:N===1?1:v(T(N),e,n)},"f");A.getControlPoints=function(){return[{x:t,y:e},{x:r,y:n}]};var L="generateBezier("+[t,e,r,n]+")";return A.toString=function(){return L},A}function Q0e(t,e,r,n,i){if(n===1||e===r)return r;var a=i(e,r,n);return t==null||((t.roundValue||t.color)&&(a=Math.round(a)),t.min!==void 0&&(a=Math.max(a,t.min)),t.max!==void 0&&(a=Math.min(a,t.max))),a}function Z0e(t,e){return t.pfValue!=null||t.value!=null?t.pfValue!=null&&(e==null||e.type.units!=="%")?t.pfValue:t.value:t}function jg(t,e,r,n,i){var a=i!=null?i.type:null;r<0?r=0:r>1&&(r=1);var s=Z0e(t,i),l=Z0e(e,i);if(ft(s)&&ft(l))return Q0e(a,s,l,r,n);if(vn(s)&&vn(l)){for(var u=[],h=0;h0?(m==="spring"&&g.push(s.duration),s.easingImpl=v6[m].apply(null,g)):s.easingImpl=v6[m]}var y=s.easingImpl,v;if(s.duration===0?v=1:v=(r-u)/s.duration,s.applying&&(v=s.progress),v<0?v=0:v>1&&(v=1),s.delay==null){var x=s.startPosition,b=s.position;if(b&&i&&!t.locked()){var w={};Nx(x.x,b.x)&&(w.x=jg(x.x,b.x,v,y)),Nx(x.y,b.y)&&(w.y=jg(x.y,b.y,v,y)),t.position(w)}var S=s.startPan,T=s.pan,E=a.pan,_=T!=null&&n;_&&(Nx(S.x,T.x)&&(E.x=jg(S.x,T.x,v,y)),Nx(S.y,T.y)&&(E.y=jg(S.y,T.y,v,y)),t.emit("pan"));var A=s.startZoom,L=s.zoom,M=L!=null&&n;M&&(Nx(A,L)&&(a.zoom=Hx(a.minZoom,jg(A,L,v,y),a.maxZoom)),t.emit("zoom")),(_||M)&&t.emit("viewport");var N=s.style;if(N&&N.length>0&&i){for(var k=0;k=0;_--){var A=E[_];A()}E.splice(0,E.length)},"callbacks"),b=m.length-1;b>=0;b--){var w=m[b],S=w._private;if(S.stopped){m.splice(b,1),S.hooked=!1,S.playing=!1,S.started=!1,x(S.frames);continue}!S.playing&&!S.applying||(S.playing&&S.applying&&(S.applying=!1),S.started||LKe(f,w,t),_Ke(f,w,t,d),S.applying&&(S.applying=!1),x(S.frames),S.step!=null&&S.step(t),w.completed()&&(m.splice(b,1),S.hooked=!1,S.playing=!1,S.started=!1,x(S.completes)),y=!0)}return!d&&m.length===0&&g.length===0&&n.push(f),y}o(i,"stepOne");for(var a=!1,s=0;s0?e.notify("draw",r):e.notify("draw")),r.unmerge(n),e.emit("step")}function Ame(t){this.options=Wt({},BKe,FKe,t)}function _me(t){this.options=Wt({},zKe,t)}function Lme(t){this.options=Wt({},GKe,t)}function j6(t){this.options=Wt({},$Ke,t),this.options.layout=this;var e=this.options.eles.nodes(),r=this.options.eles.edges(),n=r.filter(function(i){var a=i.source().data("id"),s=i.target().data("id"),l=e.some(function(h){return h.data("id")===a}),u=e.some(function(h){return h.data("id")===s});return!l||!u});this.options.eles=this.options.eles.not(n)}function Rme(t){this.options=Wt({},iQe,t)}function dB(t){this.options=Wt({},aQe,t)}function Nme(t){this.options=Wt({},sQe,t)}function Mme(t){this.options=Wt({},oQe,t)}function Ime(t){this.options=t,this.notifications=0}function Bme(t,e){e.radius===0?t.lineTo(e.cx,e.cy):t.arc(e.cx,e.cy,e.radius,e.startAngle,e.endAngle,e.counterClockwise)}function mB(t,e,r,n){var i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0;return n===0||e.radius===0?{cx:e.x,cy:e.y,radius:0,startX:e.x,startY:e.y,stopX:e.x,stopY:e.y,startAngle:void 0,endAngle:void 0,counterClockwise:void 0}:(uQe(t,e,r,n,i),{cx:GP,cy:$P,radius:z0,startX:Ome,startY:Pme,stopX:VP,stopY:UP,startAngle:Gc.ang+Math.PI/2*G0,endAngle:Jo.ang-Math.PI/2*G0,counterClockwise:w6})}function Fme(t){var e=[];if(t!=null){for(var r=0;r5&&arguments[5]!==void 0?arguments[5]:5,s=arguments.length>6?arguments[6]:void 0;t.beginPath(),t.moveTo(e+a,r),t.lineTo(e+n-a,r),t.quadraticCurveTo(e+n,r,e+n,r+a),t.lineTo(e+n,r+i-a),t.quadraticCurveTo(e+n,r+i,e+n-a,r+i),t.lineTo(e+a,r+i),t.quadraticCurveTo(e,r+i,e,r+i-a),t.lineTo(e,r+a),t.quadraticCurveTo(e,r,e+a,r),t.closePath(),s?t.stroke():t.fill()}function ZQe(t,e){for(var r=atob(t),n=new ArrayBuffer(r.length),i=new Uint8Array(n),a=0;a{"use strict";o(Hi,"_typeof");o(XP,"_classCallCheck");o(s0e,"_defineProperties");o(jP,"_createClass");o(bpe,"_defineProperty$1");o($l,"_slicedToArray");o(_He,"_arrayWithHoles");o(LHe,"_iterableToArrayLimit");o(wpe,"_unsupportedIterableToArray");o(o0e,"_arrayLikeToArray");o(DHe,"_nonIterableRest");o(Tpe,"_createForOfIteratorHelper");Vi=typeof window>"u"?null:window,l0e=Vi?Vi.navigator:null;Vi&&Vi.document;RHe=Hi(""),kpe=Hi({}),NHe=Hi(function(){}),MHe=typeof HTMLElement>"u"?"undefined":Hi(HTMLElement),Qx=o(function(e){return e&&e.instanceString&&jn(e.instanceString)?e.instanceString():null},"instanceStr"),zt=o(function(e){return e!=null&&Hi(e)==RHe},"string"),jn=o(function(e){return e!=null&&Hi(e)===NHe},"fn"),vn=o(function(e){return!xo(e)&&(Array.isArray?Array.isArray(e):e!=null&&e instanceof Array)},"array"),Mr=o(function(e){return e!=null&&Hi(e)===kpe&&!vn(e)&&e.constructor===Object},"plainObject"),IHe=o(function(e){return e!=null&&Hi(e)===kpe},"object"),ft=o(function(e){return e!=null&&Hi(e)===Hi(1)&&!isNaN(e)},"number"),OHe=o(function(e){return ft(e)&&Math.floor(e)===e},"integer"),k6=o(function(e){if(MHe!=="undefined")return e!=null&&e instanceof HTMLElement},"htmlElement"),xo=o(function(e){return Zx(e)||Epe(e)},"elementOrCollection"),Zx=o(function(e){return Qx(e)==="collection"&&e._private.single},"element"),Epe=o(function(e){return Qx(e)==="collection"&&!e._private.single},"collection"),KP=o(function(e){return Qx(e)==="core"},"core"),Cpe=o(function(e){return Qx(e)==="stylesheet"},"stylesheet"),PHe=o(function(e){return Qx(e)==="event"},"event"),Sf=o(function(e){return e==null?!0:!!(e===""||e.match(/^\s+$/))},"emptyString"),BHe=o(function(e){return typeof HTMLElement>"u"?!1:e instanceof HTMLElement},"domElement"),FHe=o(function(e){return Mr(e)&&ft(e.x1)&&ft(e.x2)&&ft(e.y1)&&ft(e.y2)},"boundingBox"),zHe=o(function(e){return IHe(e)&&jn(e.then)},"promise"),GHe=o(function(){return l0e&&l0e.userAgent.match(/msie|trident|edge/i)},"ms"),Gx=o(function(e,r){r||(r=o(function(){if(arguments.length===1)return arguments[0];if(arguments.length===0)return"undefined";for(var a=[],s=0;sr?1:0},"ascending"),qHe=o(function(e,r){return-1*Ape(e,r)},"descending"),Wt=Object.assign!=null?Object.assign.bind(Object):function(t){for(var e=arguments,r=1;r1&&(v-=1),v<1/6?g+(y-g)*6*v:v<1/2?y:v<2/3?g+(y-g)*(2/3-v)*6:g}o(f,"hue2rgb");var d=new RegExp("^"+UHe+"$").exec(e);if(d){if(n=parseInt(d[1]),n<0?n=(360- -1*n%360)%360:n>360&&(n=n%360),n/=360,i=parseFloat(d[2]),i<0||i>100||(i=i/100,a=parseFloat(d[3]),a<0||a>100)||(a=a/100,s=d[4],s!==void 0&&(s=parseFloat(s),s<0||s>1)))return;if(i===0)l=u=h=Math.round(a*255);else{var p=a<.5?a*(1+i):a+i-a*i,m=2*a-p;l=Math.round(255*f(m,p,n+1/3)),u=Math.round(255*f(m,p,n)),h=Math.round(255*f(m,p,n-1/3))}r=[l,u,h,s]}return r},"hsl2tuple"),KHe=o(function(e){var r,n=new RegExp("^"+$He+"$").exec(e);if(n){r=[];for(var i=[],a=1;a<=3;a++){var s=n[a];if(s[s.length-1]==="%"&&(i[a]=!0),s=parseFloat(s),i[a]&&(s=s/100*255),s<0||s>255)return;r.push(Math.floor(s))}var l=i[1]||i[2]||i[3],u=i[1]&&i[2]&&i[3];if(l&&!u)return;var h=n[4];if(h!==void 0){if(h=parseFloat(h),h<0||h>1)return;r.push(h)}}return r},"rgb2tuple"),QHe=o(function(e){return JHe[e.toLowerCase()]},"colorname2tuple"),ZHe=o(function(e){return(vn(e)?e:null)||QHe(e)||XHe(e)||KHe(e)||jHe(e)},"color2tuple"),JHe={transparent:[0,0,0,0],aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],grey:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},_pe=o(function(e){for(var r=e.map,n=e.keys,i=n.length,a=0;a1&&arguments[1]!==void 0?arguments[1]:Zg,n=r,i;i=e.next(),!i.done;)n=n*Mpe+i.value|0;return n},"hashIterableInts"),$x=o(function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Zg;return r*Mpe+e|0},"hashInt"),Vx=o(function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Ix;return(r<<5)+r+e|0},"hashIntAlt"),zYe=o(function(e,r){return e*2097152+r},"combineHashes"),bf=o(function(e){return e[0]*2097152+e[1]},"combineHashesArray"),r6=o(function(e,r){return[$x(e[0],r[0]),Vx(e[1],r[1])]},"hashArrays"),GYe=o(function(e,r){var n={value:0,done:!1},i=0,a=e.length,s={next:o(function(){return i=0&&!(e[i]===r&&(e.splice(i,1),n));i--);},"removeFromArray"),eB=o(function(e){e.splice(0,e.length)},"clearArray"),qYe=o(function(e,r){for(var n=0;n"u"?"undefined":Hi(Set))!==jYe?Set:KYe,B6=o(function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0;if(e===void 0||r===void 0||!KP(e)){oi("An element must have a core reference and parameters set");return}var i=r.group;if(i==null&&(r.data&&r.data.source!=null&&r.data.target!=null?i="edges":i="nodes"),i!=="nodes"&&i!=="edges"){oi("An element must be of type `nodes` or `edges`; you specified `"+i+"`");return}this.length=1,this[0]=this;var a=this._private={cy:e,single:!0,data:r.data||{},position:r.position||{x:0,y:0},autoWidth:void 0,autoHeight:void 0,autoPadding:void 0,compoundBoundsClean:!1,listeners:[],group:i,style:{},rstyle:{},styleCxts:[],styleKeys:{},removed:!0,selected:!!r.selected,selectable:r.selectable===void 0?!0:!!r.selectable,locked:!!r.locked,grabbed:!1,grabbable:r.grabbable===void 0?!0:!!r.grabbable,pannable:r.pannable===void 0?i==="edges":!!r.pannable,active:!1,classes:new c1,animation:{current:[],queue:[]},rscratch:{},scratch:r.scratch||{},edges:[],children:[],parent:r.parent&&r.parent.isNode()?r.parent:null,traversalCache:{},backgrounding:!1,bbCache:null,bbCacheShift:{x:0,y:0},bodyBounds:null,overlayBounds:null,labelBounds:{all:null,source:null,target:null,main:null},arrowBounds:{source:null,target:null,"mid-source":null,"mid-target":null}};if(a.position.x==null&&(a.position.x=0),a.position.y==null&&(a.position.y=0),r.renderedPosition){var s=r.renderedPosition,l=e.pan(),u=e.zoom();a.position={x:(s.x-l.x)/u,y:(s.y-l.y)/u}}var h=[];vn(r.classes)?h=r.classes:zt(r.classes)&&(h=r.classes.split(/\s+/));for(var f=0,d=h.length;fb?1:0},"defaultCmp"),f=o(function(x,b,w,S,T){var E;if(w==null&&(w=0),T==null&&(T=n),w<0)throw new Error("lo must be non-negative");for(S==null&&(S=x.length);wM;0<=M?L++:L--)A.push(L);return A}.apply(this).reverse(),_=[],S=0,T=E.length;SN;0<=N?++A:--A)k.push(s(x,w));return k},"nsmallest"),y=o(function(x,b,w,S){var T,E,_;for(S==null&&(S=n),T=x[w];w>b;){if(_=w-1>>1,E=x[_],S(T,E)<0){x[w]=E,w=_;continue}break}return x[w]=T},"_siftdown"),v=o(function(x,b,w){var S,T,E,_,A;for(w==null&&(w=n),T=x.length,A=b,E=x[b],S=2*b+1;S0;){var E=b.pop(),_=v(E),A=E.id();if(p[A]=_,_!==1/0)for(var L=E.neighborhood().intersect(g),M=0;M0)for(F.unshift(P);d[$];){var z=d[$];F.unshift(z.edge),F.unshift(z.node),B=z.node,$=B.id()}return l.spawn(F)},"pathTo")}},"dijkstra")},eWe={kruskal:o(function(e){e=e||function(w){return 1};for(var r=this.byGroup(),n=r.nodes,i=r.edges,a=n.length,s=new Array(a),l=n,u=o(function(S){for(var T=0;T0;){if(T(),_++,S===f){for(var A=[],L=a,M=f,N=x[M];A.unshift(L),N!=null&&A.unshift(N),L=v[M],L!=null;)M=L.id(),N=x[M];return{found:!0,distance:d[S],path:this.spawn(A),steps:_}}m[S]=!0;for(var k=w._private.edges,I=0;IN&&(g[M]=N,b[M]=L,w[M]=T),!a){var k=L*f+A;!a&&g[k]>N&&(g[k]=N,b[k]=A,w[k]=T)}}}for(var I=0;I1&&arguments[1]!==void 0?arguments[1]:s,Se=w(ke),Ue=[],Pe=Se;;){if(Pe==null)return r.spawn();var _e=b(Pe),me=_e.edge,W=_e.pred;if(Ue.unshift(Pe[0]),Pe.same(Ie)&&Ue.length>0)break;me!=null&&Ue.unshift(me),Pe=W}return u.spawn(Ue)},"pathTo"),E=0;E=0;f--){var d=h[f],p=d[1],m=d[2];(r[p]===l&&r[m]===u||r[p]===u&&r[m]===l)&&h.splice(f,1)}for(var g=0;gi;){var a=Math.floor(Math.random()*r.length);r=lWe(a,e,r),n--}return r},"contractUntil"),cWe={kargerStein:o(function(){var e=this,r=this.byGroup(),n=r.nodes,i=r.edges;i.unmergeBy(function(F){return F.isLoop()});var a=n.length,s=i.length,l=Math.ceil(Math.pow(Math.log(a)/Math.LN2,2)),u=Math.floor(a/oWe);if(a<2){oi("At least 2 nodes are required for Karger-Stein algorithm");return}for(var h=[],f=0;f1&&arguments[1]!==void 0?arguments[1]:0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,i=1/0,a=r;a1&&arguments[1]!==void 0?arguments[1]:0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,i=-1/0,a=r;a1&&arguments[1]!==void 0?arguments[1]:0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,i=0,a=0,s=r;s1&&arguments[1]!==void 0?arguments[1]:0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:e.length,i=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!0,a=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,s=arguments.length>5&&arguments[5]!==void 0?arguments[5]:!0;i?e=e.slice(r,n):(n0&&e.splice(0,r));for(var l=0,u=e.length-1;u>=0;u--){var h=e[u];s?isFinite(h)||(e[u]=-1/0,l++):e.splice(u,1)}a&&e.sort(function(p,m){return p-m});var f=e.length,d=Math.floor(f/2);return f%2!==0?e[d+1+l]:(e[d-1+l]+e[d+l])/2},"median"),mWe=o(function(e){return Math.PI*e/180},"deg2rad"),n6=o(function(e,r){return Math.atan2(r,e)-Math.PI/2},"getAngleFromDisp"),tB=Math.log2||function(t){return Math.log(t)/Math.log(2)},$pe=o(function(e){return e>0?1:e<0?-1:0},"signum"),H0=o(function(e,r){return Math.sqrt(B0(e,r))},"dist"),B0=o(function(e,r){var n=r.x-e.x,i=r.y-e.y;return n*n+i*i},"sqdist"),gWe=o(function(e){for(var r=e.length,n=0,i=0;i=e.x1&&e.y2>=e.y1)return{x1:e.x1,y1:e.y1,x2:e.x2,y2:e.y2,w:e.x2-e.x1,h:e.y2-e.y1};if(e.w!=null&&e.h!=null&&e.w>=0&&e.h>=0)return{x1:e.x1,y1:e.y1,x2:e.x1+e.w,y2:e.y1+e.h,w:e.w,h:e.h}}},"makeBoundingBox"),vWe=o(function(e){return{x1:e.x1,x2:e.x2,w:e.w,y1:e.y1,y2:e.y2,h:e.h}},"copyBoundingBox"),xWe=o(function(e){e.x1=1/0,e.y1=1/0,e.x2=-1/0,e.y2=-1/0,e.w=0,e.h=0},"clearBoundingBox"),bWe=o(function(e,r,n){return{x1:e.x1+r,x2:e.x2+r,y1:e.y1+n,y2:e.y2+n,w:e.w,h:e.h}},"shiftBoundingBox"),Vpe=o(function(e,r){e.x1=Math.min(e.x1,r.x1),e.x2=Math.max(e.x2,r.x2),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,r.y1),e.y2=Math.max(e.y2,r.y2),e.h=e.y2-e.y1},"updateBoundingBox"),wWe=o(function(e,r,n){e.x1=Math.min(e.x1,r),e.x2=Math.max(e.x2,r),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,n),e.y2=Math.max(e.y2,n),e.h=e.y2-e.y1},"expandBoundingBoxByPoint"),p6=o(function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;return e.x1-=r,e.x2+=r,e.y1-=r,e.y2+=r,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},"expandBoundingBox"),m6=o(function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[0],n,i,a,s;if(r.length===1)n=i=a=s=r[0];else if(r.length===2)n=a=r[0],s=i=r[1];else if(r.length===4){var l=$l(r,4);n=l[0],i=l[1],a=l[2],s=l[3]}return e.x1-=s,e.x2+=i,e.y1-=n,e.y2+=a,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},"expandBoundingBoxSides"),g0e=o(function(e,r){e.x1=r.x1,e.y1=r.y1,e.x2=r.x2,e.y2=r.y2,e.w=e.x2-e.x1,e.h=e.y2-e.y1},"assignBoundingBox"),rB=o(function(e,r){return!(e.x1>r.x2||r.x1>e.x2||e.x2r.y2||r.y1>e.y2)},"boundingBoxesIntersect"),s1=o(function(e,r,n){return e.x1<=r&&r<=e.x2&&e.y1<=n&&n<=e.y2},"inBoundingBox"),TWe=o(function(e,r){return s1(e,r.x,r.y)},"pointInBoundingBox"),Upe=o(function(e,r){return s1(e,r.x1,r.y1)&&s1(e,r.x2,r.y2)},"boundingBoxInBoundingBox"),Hpe=o(function(e,r,n,i,a,s,l){var u=arguments.length>7&&arguments[7]!==void 0?arguments[7]:"auto",h=u==="auto"?Y0(a,s):u,f=a/2,d=s/2;h=Math.min(h,f,d);var p=h!==f,m=h!==d,g;if(p){var y=n-f+h-l,v=i-d-l,x=n+f-h+l,b=v;if(g=kf(e,r,n,i,y,v,x,b,!1),g.length>0)return g}if(m){var w=n+f+l,S=i-d+h-l,T=w,E=i+d-h+l;if(g=kf(e,r,n,i,w,S,T,E,!1),g.length>0)return g}if(p){var _=n-f+h-l,A=i+d+l,L=n+f-h+l,M=A;if(g=kf(e,r,n,i,_,A,L,M,!1),g.length>0)return g}if(m){var N=n-f-l,k=i-d+h-l,I=N,C=i+d-h+l;if(g=kf(e,r,n,i,N,k,I,C,!1),g.length>0)return g}var O;{var D=n-f+h,P=i-d+h;if(O=Ox(e,r,n,i,D,P,h+l),O.length>0&&O[0]<=D&&O[1]<=P)return[O[0],O[1]]}{var F=n+f-h,B=i-d+h;if(O=Ox(e,r,n,i,F,B,h+l),O.length>0&&O[0]>=F&&O[1]<=B)return[O[0],O[1]]}{var $=n+f-h,z=i+d-h;if(O=Ox(e,r,n,i,$,z,h+l),O.length>0&&O[0]>=$&&O[1]>=z)return[O[0],O[1]]}{var Y=n-f+h,Q=i+d-h;if(O=Ox(e,r,n,i,Y,Q,h+l),O.length>0&&O[0]<=Y&&O[1]>=Q)return[O[0],O[1]]}return[]},"roundRectangleIntersectLine"),kWe=o(function(e,r,n,i,a,s,l){var u=l,h=Math.min(n,a),f=Math.max(n,a),d=Math.min(i,s),p=Math.max(i,s);return h-u<=e&&e<=f+u&&d-u<=r&&r<=p+u},"inLineVicinity"),EWe=o(function(e,r,n,i,a,s,l,u,h){var f={x1:Math.min(n,l,a)-h,x2:Math.max(n,l,a)+h,y1:Math.min(i,u,s)-h,y2:Math.max(i,u,s)+h};return!(ef.x2||rf.y2)},"inBezierVicinity"),CWe=o(function(e,r,n,i){n-=i;var a=r*r-4*e*n;if(a<0)return[];var s=Math.sqrt(a),l=2*e,u=(-r+s)/l,h=(-r-s)/l;return[u,h]},"solveQuadratic"),SWe=o(function(e,r,n,i,a){var s=1e-5;e===0&&(e=s),r/=e,n/=e,i/=e;var l,u,h,f,d,p,m,g;if(u=(3*n-r*r)/9,h=-(27*i)+r*(9*n-2*(r*r)),h/=54,l=u*u*u+h*h,a[1]=0,m=r/3,l>0){d=h+Math.sqrt(l),d=d<0?-Math.pow(-d,1/3):Math.pow(d,1/3),p=h-Math.sqrt(l),p=p<0?-Math.pow(-p,1/3):Math.pow(p,1/3),a[0]=-m+d+p,m+=(d+p)/2,a[4]=a[2]=-m,m=Math.sqrt(3)*(-p+d)/2,a[3]=m,a[5]=-m;return}if(a[5]=a[3]=0,l===0){g=h<0?-Math.pow(-h,1/3):Math.pow(h,1/3),a[0]=-m+2*g,a[4]=a[2]=-(g+m);return}u=-u,f=u*u*u,f=Math.acos(h/Math.sqrt(f)),g=2*Math.sqrt(u),a[0]=-m+g*Math.cos(f/3),a[2]=-m+g*Math.cos((f+2*Math.PI)/3),a[4]=-m+g*Math.cos((f+4*Math.PI)/3)},"solveCubic"),AWe=o(function(e,r,n,i,a,s,l,u){var h=1*n*n-4*n*a+2*n*l+4*a*a-4*a*l+l*l+i*i-4*i*s+2*i*u+4*s*s-4*s*u+u*u,f=1*9*n*a-3*n*n-3*n*l-6*a*a+3*a*l+9*i*s-3*i*i-3*i*u-6*s*s+3*s*u,d=1*3*n*n-6*n*a+n*l-n*e+2*a*a+2*a*e-l*e+3*i*i-6*i*s+i*u-i*r+2*s*s+2*s*r-u*r,p=1*n*a-n*n+n*e-a*e+i*s-i*i+i*r-s*r,m=[];SWe(h,f,d,p,m);for(var g=1e-7,y=[],v=0;v<6;v+=2)Math.abs(m[v+1])=0&&m[v]<=1&&y.push(m[v]);y.push(1),y.push(0);for(var x=-1,b,w,S,T=0;T=0?Sh?(e-a)*(e-a)+(r-s)*(r-s):f-p},"sqdistToFiniteLine"),zs=o(function(e,r,n){for(var i,a,s,l,u,h=0,f=0;f=e&&e>=s||i<=e&&e<=s)u=(e-i)/(s-i)*(l-a)+a,u>r&&h++;else continue;return h%2!==0},"pointInsidePolygonPoints"),Qu=o(function(e,r,n,i,a,s,l,u,h){var f=new Array(n.length),d;u[0]!=null?(d=Math.atan(u[1]/u[0]),u[0]<0?d=d+Math.PI/2:d=-d-Math.PI/2):d=u;for(var p=Math.cos(-d),m=Math.sin(-d),g=0;g0){var v=A6(f,-h);y=S6(v)}else y=f;return zs(e,r,y)},"pointInsidePolygon"),LWe=o(function(e,r,n,i,a,s,l,u){for(var h=new Array(n.length*2),f=0;f=0&&v<=1&&b.push(v),x>=0&&x<=1&&b.push(x),b.length===0)return[];var w=b[0]*u[0]+e,S=b[0]*u[1]+r;if(b.length>1){if(b[0]==b[1])return[w,S];var T=b[1]*u[0]+e,E=b[1]*u[1]+r;return[w,S,T,E]}else return[w,S]},"intersectLineCircle"),TP=o(function(e,r,n){return r<=e&&e<=n||n<=e&&e<=r?e:e<=r&&r<=n||n<=r&&r<=e?r:n},"midOfThree"),kf=o(function(e,r,n,i,a,s,l,u,h){var f=e-a,d=n-e,p=l-a,m=r-s,g=i-r,y=u-s,v=p*m-y*f,x=d*m-g*f,b=y*d-p*g;if(b!==0){var w=v/b,S=x/b,T=.001,E=0-T,_=1+T;return E<=w&&w<=_&&E<=S&&S<=_?[e+w*d,r+w*g]:h?[e+w*d,r+w*g]:[]}else return v===0||x===0?TP(e,n,l)===l?[l,u]:TP(e,n,a)===a?[a,s]:TP(a,l,n)===n?[n,i]:[]:[]},"finiteLinesIntersect"),Yx=o(function(e,r,n,i,a,s,l,u){var h=[],f,d=new Array(n.length),p=!0;s==null&&(p=!1);var m;if(p){for(var g=0;g0){var y=A6(d,-u);m=S6(y)}else m=d}else m=n;for(var v,x,b,w,S=0;S2){for(var g=[f[0],f[1]],y=Math.pow(g[0]-e,2)+Math.pow(g[1]-r,2),v=1;vf&&(f=S)},"set"),get:o(function(w){return h[w]},"get")},p=0;p0?D=O.edgesTo(C)[0]:D=C.edgesTo(O)[0];var P=i(D);C=C.id(),A[C]>A[k]+P&&(A[C]=A[k]+P,L.nodes.indexOf(C)<0?L.push(C):L.updateItem(C),_[C]=0,E[C]=[]),A[C]==A[k]+P&&(_[C]=_[C]+_[k],E[C].push(k))}else for(var F=0;F0;){for(var Y=T.pop(),Q=0;Q0&&l.push(n[u]);l.length!==0&&a.push(i.collection(l))}return a},"assign"),YWe=o(function(e,r){for(var n=0;n5&&arguments[5]!==void 0?arguments[5]:XWe,l=i,u,h,f=0;f=2?Lx(e,r,n,0,w0e,jWe):Lx(e,r,n,0,b0e)},"euclidean"),squaredEuclidean:o(function(e,r,n){return Lx(e,r,n,0,w0e)},"squaredEuclidean"),manhattan:o(function(e,r,n){return Lx(e,r,n,0,b0e)},"manhattan"),max:o(function(e,r,n){return Lx(e,r,n,-1/0,KWe)},"max")};o1["squared-euclidean"]=o1.squaredEuclidean;o1.squaredeuclidean=o1.squaredEuclidean;o(z6,"clusteringDistance");QWe=Sa({k:2,m:2,sensitivityThreshold:1e-4,distance:"euclidean",maxIterations:10,attributes:[],testMode:!1,testCentroids:null}),iB=o(function(e){return QWe(e)},"setOptions"),_6=o(function(e,r,n,i,a){var s=a!=="kMedoids",l=s?function(d){return n[d]}:function(d){return i[d](n)},u=o(function(p){return i[p](r)},"getQ"),h=n,f=r;return z6(e,i.length,l,u,h,f)},"getDist"),kP=o(function(e,r,n){for(var i=n.length,a=new Array(i),s=new Array(i),l=new Array(r),u=null,h=0;hn)return!1}return!0},"haveMatricesConverged"),eqe=o(function(e,r,n){for(var i=0;il&&(l=r[h][f],u=f);a[u].push(e[h])}for(var d=0;d=a.threshold||a.mode==="dendrogram"&&e.length===1)return!1;var g=r[s],y=r[i[s]],v;a.mode==="dendrogram"?v={left:g,right:y,key:g.key}:v={value:g.value.concat(y.value),key:g.key},e[g.index]=v,e.splice(y.index,1),r[g.key]=v;for(var x=0;xn[y.key][b.key]&&(u=n[y.key][b.key])):a.linkage==="max"?(u=n[g.key][b.key],n[g.key][b.key]0&&i.push(a);return i},"findExemplars"),A0e=o(function(e,r,n){for(var i=[],a=0;al&&(s=h,l=r[a*e+h])}s>0&&i.push(s)}for(var f=0;fh&&(u=f,h=d)}n[a]=s[u]}return i=A0e(e,r,n),i},"assign"),_0e=o(function(e){for(var r=this.cy(),n=this.nodes(),i=pqe(e),a={},s=0;s=N?(k=N,N=C,I=O):C>k&&(k=C);for(var D=0;D0?1:0;_[L%i.minIterations*l+Y]=Q,z+=Q}if(z>0&&(L>=i.minIterations-1||L==i.maxIterations-1)){for(var X=0,ie=0;ie1||E>1)&&(l=!0),d[w]=[],b.outgoers().forEach(function(A){A.isEdge()&&d[w].push(A.id())})}else p[w]=[void 0,b.target().id()]}):s.forEach(function(b){var w=b.id();if(b.isNode()){var S=b.degree(!0);S%2&&(u?h?l=!0:h=w:u=w),d[w]=[],b.connectedEdges().forEach(function(T){return d[w].push(T.id())})}else p[w]=[b.source().id(),b.target().id()]});var m={found:!1,trail:void 0};if(l)return m;if(h&&u)if(a){if(f&&h!=f)return m;f=h}else{if(f&&h!=f&&u!=f)return m;f||(f=h)}else f||(f=s[0].id());var g=o(function(w){for(var S=w,T=[w],E,_,A;d[S].length;)E=d[S].shift(),_=p[E][0],A=p[E][1],S!=A?(d[A]=d[A].filter(function(L){return L!=E}),S=A):!a&&S!=_&&(d[_]=d[_].filter(function(L){return L!=E}),S=_),T.unshift(E),T.unshift(S);return T},"walk"),y=[],v=[];for(v=g(f);v.length!=1;)d[v[0]].length==0?(y.unshift(s.getElementById(v.shift())),y.unshift(s.getElementById(v.shift()))):v=g(v.shift()).concat(v);y.unshift(s.getElementById(v.shift()));for(var x in d)if(d[x].length)return m;return m.found=!0,m.trail=this.spawn(y,!0),m},"hierholzer")},s6=o(function(){var e=this,r={},n=0,i=0,a=[],s=[],l={},u=o(function(p,m){for(var g=s.length-1,y=[],v=e.spawn();s[g].x!=p||s[g].y!=m;)y.push(s.pop().edge),g--;y.push(s.pop().edge),y.forEach(function(x){var b=x.connectedNodes().intersection(e);v.merge(x),b.forEach(function(w){var S=w.id(),T=w.connectedEdges().intersection(e);v.merge(w),r[S].cutVertex?v.merge(T.filter(function(E){return E.isLoop()})):v.merge(T)})}),a.push(v)},"buildComponent"),h=o(function d(p,m,g){p===g&&(i+=1),r[m]={id:n,low:n++,cutVertex:!1};var y=e.getElementById(m).connectedEdges().intersection(e);if(y.size()===0)a.push(e.spawn(e.getElementById(m)));else{var v,x,b,w;y.forEach(function(S){v=S.source().id(),x=S.target().id(),b=v===m?x:v,b!==g&&(w=S.id(),l[w]||(l[w]=!0,s.push({x:m,y:b,edge:S})),b in r?r[m].low=Math.min(r[m].low,r[b].id):(d(p,b,m),r[m].low=Math.min(r[m].low,r[b].low),r[m].id<=r[b].low&&(r[m].cutVertex=!0,u(m,b))))})}},"biconnectedSearch");e.forEach(function(d){if(d.isNode()){var p=d.id();p in r||(i=0,h(p,p),r[p].cutVertex=i>1)}});var f=Object.keys(r).filter(function(d){return r[d].cutVertex}).map(function(d){return e.getElementById(d)});return{cut:e.spawn(f),components:a}},"hopcroftTarjanBiconnected"),Tqe={hopcroftTarjanBiconnected:s6,htbc:s6,htb:s6,hopcroftTarjanBiconnectedComponents:s6},o6=o(function(){var e=this,r={},n=0,i=[],a=[],s=e.spawn(e),l=o(function u(h){a.push(h),r[h]={index:n,low:n++,explored:!1};var f=e.getElementById(h).connectedEdges().intersection(e);if(f.forEach(function(y){var v=y.target().id();v!==h&&(v in r||u(v),r[v].explored||(r[h].low=Math.min(r[h].low,r[v].low)))}),r[h].index===r[h].low){for(var d=e.spawn();;){var p=a.pop();if(d.merge(e.getElementById(p)),r[p].low=r[h].index,r[p].explored=!0,p===h)break}var m=d.edgesWith(d),g=d.merge(m);i.push(g),s=s.difference(g)}},"stronglyConnectedSearch");return e.forEach(function(u){if(u.isNode()){var h=u.id();h in r||l(h)}}),{cut:s,components:i}},"tarjanStronglyConnected"),kqe={tarjanStronglyConnected:o6,tsc:o6,tscc:o6,tarjanStronglyConnectedComponents:o6},Qpe={};[Ux,JYe,eWe,rWe,iWe,sWe,cWe,IWe,r1,n1,IP,qWe,sqe,fqe,xqe,wqe,Tqe,kqe].forEach(function(t){Wt(Qpe,t)});Zpe=0,Jpe=1,eme=2,Zu=o(function t(e){if(!(this instanceof t))return new t(e);this.id="Thenable/1.0.7",this.state=Zpe,this.fulfillValue=void 0,this.rejectReason=void 0,this.onFulfilled=[],this.onRejected=[],this.proxy={then:this.then.bind(this)},typeof e=="function"&&e.call(this,this.fulfill.bind(this),this.reject.bind(this))},"api");Zu.prototype={fulfill:o(function(e){return L0e(this,Jpe,"fulfillValue",e)},"fulfill"),reject:o(function(e){return L0e(this,eme,"rejectReason",e)},"reject"),then:o(function(e,r){var n=this,i=new Zu;return n.onFulfilled.push(R0e(e,i,"fulfill")),n.onRejected.push(R0e(r,i,"reject")),tme(n),i.proxy},"then")};L0e=o(function(e,r,n,i){return e.state===Zpe&&(e.state=r,e[n]=i,tme(e)),e},"deliver"),tme=o(function(e){e.state===Jpe?D0e(e,"onFulfilled",e.fulfillValue):e.state===eme&&D0e(e,"onRejected",e.rejectReason)},"execute"),D0e=o(function(e,r,n){if(e[r].length!==0){var i=e[r];e[r]=[];var a=o(function(){for(var l=0;l0},"animatedImpl")},"animated"),clearQueue:o(function(){return o(function(){var r=this,n=r.length!==void 0,i=n?r:[r],a=this._private.cy||this;if(!a.styleEnabled())return this;for(var s=0;s0&&this.spawn(i).updateStyle().emit("class"),r},"classes"),addClass:o(function(e){return this.toggleClass(e,!0)},"addClass"),hasClass:o(function(e){var r=this[0];return r!=null&&r._private.classes.has(e)},"hasClass"),toggleClass:o(function(e,r){vn(e)||(e=e.match(/\S+/g)||[]);for(var n=this,i=r===void 0,a=[],s=0,l=n.length;s0&&this.spawn(a).updateStyle().emit("class"),n},"toggleClass"),removeClass:o(function(e){return this.toggleClass(e,!1)},"removeClass"),flashClass:o(function(e,r){var n=this;if(r==null)r=250;else if(r===0)return n;return n.addClass(e),setTimeout(function(){n.removeClass(e)},r),n},"flashClass")};g6.className=g6.classNames=g6.classes;Nr={metaChar:"[\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]",comparatorOp:"=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=",boolOp:"\\?|\\!|\\^",string:`"(?:\\\\"|[^"])*"|'(?:\\\\'|[^'])*'`,number:Ui,meta:"degree|indegree|outdegree",separator:"\\s*,\\s*",descendant:"\\s+",child:"\\s+>\\s+",subject:"\\$",group:"node|edge|\\*",directedEdge:"\\s+->\\s+",undirectedEdge:"\\s+<->\\s+"};Nr.variable="(?:[\\w-.]|(?:\\\\"+Nr.metaChar+"))+";Nr.className="(?:[\\w-]|(?:\\\\"+Nr.metaChar+"))+";Nr.value=Nr.string+"|"+Nr.number;Nr.id=Nr.variable;(function(){var t,e,r;for(t=Nr.comparatorOp.split("|"),r=0;r=0)&&e!=="="&&(Nr.comparatorOp+="|\\!"+e)})();un=o(function(){return{checks:[]}},"newQuery"),Ct={GROUP:0,COLLECTION:1,FILTER:2,DATA_COMPARE:3,DATA_EXIST:4,DATA_BOOL:5,META_COMPARE:6,STATE:7,ID:8,CLASS:9,UNDIRECTED_EDGE:10,DIRECTED_EDGE:11,NODE_SOURCE:12,NODE_TARGET:13,NODE_NEIGHBOR:14,CHILD:15,DESCENDANT:16,PARENT:17,ANCESTOR:18,COMPOUND_SPLIT:19,TRUE:20},PP=[{selector:":selected",matches:o(function(e){return e.selected()},"matches")},{selector:":unselected",matches:o(function(e){return!e.selected()},"matches")},{selector:":selectable",matches:o(function(e){return e.selectable()},"matches")},{selector:":unselectable",matches:o(function(e){return!e.selectable()},"matches")},{selector:":locked",matches:o(function(e){return e.locked()},"matches")},{selector:":unlocked",matches:o(function(e){return!e.locked()},"matches")},{selector:":visible",matches:o(function(e){return e.visible()},"matches")},{selector:":hidden",matches:o(function(e){return!e.visible()},"matches")},{selector:":transparent",matches:o(function(e){return e.transparent()},"matches")},{selector:":grabbed",matches:o(function(e){return e.grabbed()},"matches")},{selector:":free",matches:o(function(e){return!e.grabbed()},"matches")},{selector:":removed",matches:o(function(e){return e.removed()},"matches")},{selector:":inside",matches:o(function(e){return!e.removed()},"matches")},{selector:":grabbable",matches:o(function(e){return e.grabbable()},"matches")},{selector:":ungrabbable",matches:o(function(e){return!e.grabbable()},"matches")},{selector:":animated",matches:o(function(e){return e.animated()},"matches")},{selector:":unanimated",matches:o(function(e){return!e.animated()},"matches")},{selector:":parent",matches:o(function(e){return e.isParent()},"matches")},{selector:":childless",matches:o(function(e){return e.isChildless()},"matches")},{selector:":child",matches:o(function(e){return e.isChild()},"matches")},{selector:":orphan",matches:o(function(e){return e.isOrphan()},"matches")},{selector:":nonorphan",matches:o(function(e){return e.isChild()},"matches")},{selector:":compound",matches:o(function(e){return e.isNode()?e.isParent():e.source().isParent()||e.target().isParent()},"matches")},{selector:":loop",matches:o(function(e){return e.isLoop()},"matches")},{selector:":simple",matches:o(function(e){return e.isSimple()},"matches")},{selector:":active",matches:o(function(e){return e.active()},"matches")},{selector:":inactive",matches:o(function(e){return!e.active()},"matches")},{selector:":backgrounding",matches:o(function(e){return e.backgrounding()},"matches")},{selector:":nonbackgrounding",matches:o(function(e){return!e.backgrounding()},"matches")}].sort(function(t,e){return qHe(t.selector,e.selector)}),Pje=function(){for(var t={},e,r=0;r0&&f.edgeCount>0)return tn("The selector `"+e+"` is invalid because it uses both a compound selector and an edge selector"),!1;if(f.edgeCount>1)return tn("The selector `"+e+"` is invalid because it uses multiple edge selectors"),!1;f.edgeCount===1&&tn("The selector `"+e+"` is deprecated. Edge selectors do not take effect on changes to source and target nodes after an edge is added, for performance reasons. Use a class or data selector on edges instead, updating the class or data of an edge when your app detects a change in source or target nodes.")}return!0},"parse"),Vje=o(function(){if(this.toStringCache!=null)return this.toStringCache;for(var e=o(function(f){return f??""},"clean"),r=o(function(f){return zt(f)?'"'+f+'"':e(f)},"cleanVal"),n=o(function(f){return" "+f+" "},"space"),i=o(function(f,d){var p=f.type,m=f.value;switch(p){case Ct.GROUP:{var g=e(m);return g.substring(0,g.length-1)}case Ct.DATA_COMPARE:{var y=f.field,v=f.operator;return"["+y+n(e(v))+r(m)+"]"}case Ct.DATA_BOOL:{var x=f.operator,b=f.field;return"["+e(x)+b+"]"}case Ct.DATA_EXIST:{var w=f.field;return"["+w+"]"}case Ct.META_COMPARE:{var S=f.operator,T=f.field;return"[["+T+n(e(S))+r(m)+"]]"}case Ct.STATE:return m;case Ct.ID:return"#"+m;case Ct.CLASS:return"."+m;case Ct.PARENT:case Ct.CHILD:return a(f.parent,d)+n(">")+a(f.child,d);case Ct.ANCESTOR:case Ct.DESCENDANT:return a(f.ancestor,d)+" "+a(f.descendant,d);case Ct.COMPOUND_SPLIT:{var E=a(f.left,d),_=a(f.subject,d),A=a(f.right,d);return E+(E.length>0?" ":"")+_+A}case Ct.TRUE:return""}},"checkToString"),a=o(function(f,d){return f.checks.reduce(function(p,m,g){return p+(d===f&&g===0?"$":"")+i(m,d)},"")},"queryToString"),s="",l=0;l1&&l=0&&(r=r.replace("!",""),d=!0),r.indexOf("@")>=0&&(r=r.replace("@",""),f=!0),(a||l||f)&&(u=!a&&!s?"":""+e,h=""+n),f&&(e=u=u.toLowerCase(),n=h=h.toLowerCase()),r){case"*=":i=u.indexOf(h)>=0;break;case"$=":i=u.indexOf(h,u.length-h.length)>=0;break;case"^=":i=u.indexOf(h)===0;break;case"=":i=e===n;break;case">":p=!0,i=e>n;break;case">=":p=!0,i=e>=n;break;case"<":p=!0,i=e1&&arguments[1]!==void 0?arguments[1]:!0;return cB(this,t,e,ume)};o(hme,"addParent");l1.forEachUp=function(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return cB(this,t,e,hme)};o(Kje,"addParentAndChildren");l1.forEachUpAndDown=function(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return cB(this,t,e,Kje)};l1.ancestors=l1.parents;qx=fme={data:en.data({field:"data",bindingEvent:"data",allowBinding:!0,allowSetting:!0,settingEvent:"data",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),removeData:en.removeData({field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),scratch:en.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeScratch:en.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0}),rscratch:en.data({field:"rscratch",allowBinding:!1,allowSetting:!0,settingTriggersEvent:!1,allowGetting:!0}),removeRscratch:en.removeData({field:"rscratch",triggerEvent:!1}),id:o(function(){var e=this[0];if(e)return e._private.data.id},"id")};qx.attr=qx.data;qx.removeAttr=qx.removeData;Qje=fme,U6={};o(CP,"defineDegreeFunction");Wt(U6,{degree:CP(function(t,e){return e.source().same(e.target())?2:1}),indegree:CP(function(t,e){return e.target().same(t)?1:0}),outdegree:CP(function(t,e){return e.source().same(t)?1:0})});o(Xg,"defineDegreeBoundsFunction");Wt(U6,{minDegree:Xg("degree",function(t,e){return te}),minIndegree:Xg("indegree",function(t,e){return te}),minOutdegree:Xg("outdegree",function(t,e){return te})});Wt(U6,{totalDegree:o(function(e){for(var r=0,n=this.nodes(),i=0;i0,p=d;d&&(f=f[0]);var m=p?f.position():{x:0,y:0};r!==void 0?h.position(e,r+m[e]):a!==void 0&&h.position({x:a.x+m.x,y:a.y+m.y})}else{var g=n.position(),y=l?n.parent():null,v=y&&y.length>0,x=v;v&&(y=y[0]);var b=x?y.position():{x:0,y:0};return a={x:g.x-b.x,y:g.y-b.y},e===void 0?a:a[e]}else if(!s)return;return this},"relativePosition")};Hl.modelPosition=Hl.point=Hl.position;Hl.modelPositions=Hl.points=Hl.positions;Hl.renderedPoint=Hl.renderedPosition;Hl.relativePoint=Hl.relativePosition;Zje=dme;i1=Rf={};Rf.renderedBoundingBox=function(t){var e=this.boundingBox(t),r=this.cy(),n=r.zoom(),i=r.pan(),a=e.x1*n+i.x,s=e.x2*n+i.x,l=e.y1*n+i.y,u=e.y2*n+i.y;return{x1:a,x2:s,y1:l,y2:u,w:s-a,h:u-l}};Rf.dirtyCompoundBoundsCache=function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,e=this.cy();return!e.styleEnabled()||!e.hasCompoundNodes()?this:(this.forEachUp(function(r){if(r.isParent()){var n=r._private;n.compoundBoundsClean=!1,n.bbCache=null,t||r.emitAndNotify("bounds")}}),this)};Rf.updateCompoundBounds=function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,e=this.cy();if(!e.styleEnabled()||!e.hasCompoundNodes())return this;if(!t&&e.batching())return this;function r(s){if(!s.isParent())return;var l=s._private,u=s.children(),h=s.pstyle("compound-sizing-wrt-labels").value==="include",f={width:{val:s.pstyle("min-width").pfValue,left:s.pstyle("min-width-bias-left"),right:s.pstyle("min-width-bias-right")},height:{val:s.pstyle("min-height").pfValue,top:s.pstyle("min-height-bias-top"),bottom:s.pstyle("min-height-bias-bottom")}},d=u.boundingBox({includeLabels:h,includeOverlays:!1,useCache:!1}),p=l.position;(d.w===0||d.h===0)&&(d={w:s.pstyle("width").pfValue,h:s.pstyle("height").pfValue},d.x1=p.x-d.w/2,d.x2=p.x+d.w/2,d.y1=p.y-d.h/2,d.y2=p.y+d.h/2);function m(L,M,N){var k=0,I=0,C=M+N;return L>0&&C>0&&(k=M/C*L,I=N/C*L),{biasDiff:k,biasComplementDiff:I}}o(m,"computeBiasValues");function g(L,M,N,k){if(N.units==="%")switch(k){case"width":return L>0?N.pfValue*L:0;case"height":return M>0?N.pfValue*M:0;case"average":return L>0&&M>0?N.pfValue*(L+M)/2:0;case"min":return L>0&&M>0?L>M?N.pfValue*M:N.pfValue*L:0;case"max":return L>0&&M>0?L>M?N.pfValue*L:N.pfValue*M:0;default:return 0}else return N.units==="px"?N.pfValue:0}o(g,"computePaddingValues");var y=f.width.left.value;f.width.left.units==="px"&&f.width.val>0&&(y=y*100/f.width.val);var v=f.width.right.value;f.width.right.units==="px"&&f.width.val>0&&(v=v*100/f.width.val);var x=f.height.top.value;f.height.top.units==="px"&&f.height.val>0&&(x=x*100/f.height.val);var b=f.height.bottom.value;f.height.bottom.units==="px"&&f.height.val>0&&(b=b*100/f.height.val);var w=m(f.width.val-d.w,y,v),S=w.biasDiff,T=w.biasComplementDiff,E=m(f.height.val-d.h,x,b),_=E.biasDiff,A=E.biasComplementDiff;l.autoPadding=g(d.w,d.h,s.pstyle("padding"),s.pstyle("padding-relative-to").value),l.autoWidth=Math.max(d.w,f.width.val),p.x=(-S+d.x1+d.x2+T)/2,l.autoHeight=Math.max(d.h,f.height.val),p.y=(-_+d.y1+d.y2+A)/2}o(r,"update");for(var n=0;ne.x2?i:e.x2,e.y1=ne.y2?a:e.y2,e.w=e.x2-e.x1,e.h=e.y2-e.y1)},"updateBounds"),F0=o(function(e,r){return r==null?e:Vl(e,r.x1,r.y1,r.x2,r.y2)},"updateBoundsFromBox"),Dx=o(function(e,r,n){return Ul(e,r,n)},"prefixedProperty"),l6=o(function(e,r,n){if(!r.cy().headless()){var i=r._private,a=i.rstyle,s=a.arrowWidth/2,l=r.pstyle(n+"-arrow-shape").value,u,h;if(l!=="none"){n==="source"?(u=a.srcX,h=a.srcY):n==="target"?(u=a.tgtX,h=a.tgtY):(u=a.midX,h=a.midY);var f=i.arrowBounds=i.arrowBounds||{},d=f[n]=f[n]||{};d.x1=u-s,d.y1=h-s,d.x2=u+s,d.y2=h+s,d.w=d.x2-d.x1,d.h=d.y2-d.y1,p6(d,1),Vl(e,d.x1,d.y1,d.x2,d.y2)}}},"updateBoundsFromArrow"),SP=o(function(e,r,n){if(!r.cy().headless()){var i;n?i=n+"-":i="";var a=r._private,s=a.rstyle,l=r.pstyle(i+"label").strValue;if(l){var u=r.pstyle("text-halign"),h=r.pstyle("text-valign"),f=Dx(s,"labelWidth",n),d=Dx(s,"labelHeight",n),p=Dx(s,"labelX",n),m=Dx(s,"labelY",n),g=r.pstyle(i+"text-margin-x").pfValue,y=r.pstyle(i+"text-margin-y").pfValue,v=r.isEdge(),x=r.pstyle(i+"text-rotation"),b=r.pstyle("text-outline-width").pfValue,w=r.pstyle("text-border-width").pfValue,S=w/2,T=r.pstyle("text-background-padding").pfValue,E=2,_=d,A=f,L=A/2,M=_/2,N,k,I,C;if(v)N=p-L,k=p+L,I=m-M,C=m+M;else{switch(u.value){case"left":N=p-A,k=p;break;case"center":N=p-L,k=p+L;break;case"right":N=p,k=p+A;break}switch(h.value){case"top":I=m-_,C=m;break;case"center":I=m-M,C=m+M;break;case"bottom":I=m,C=m+_;break}}N+=g-Math.max(b,S)-T-E,k+=g+Math.max(b,S)+T+E,I+=y-Math.max(b,S)-T-E,C+=y+Math.max(b,S)+T+E;var O=n||"main",D=a.labelBounds,P=D[O]=D[O]||{};P.x1=N,P.y1=I,P.x2=k,P.y2=C,P.w=k-N,P.h=C-I;var F=v&&x.strValue==="autorotate",B=x.pfValue!=null&&x.pfValue!==0;if(F||B){var $=F?Dx(a.rstyle,"labelAngle",n):x.pfValue,z=Math.cos($),Y=Math.sin($),Q=(N+k)/2,X=(I+C)/2;if(!v){switch(u.value){case"left":Q=k;break;case"right":Q=N;break}switch(h.value){case"top":X=C;break;case"bottom":X=I;break}}var ie=o(function(ce,ue){return ce=ce-Q,ue=ue-X,{x:ce*z-ue*Y+Q,y:ce*Y+ue*z+X}},"rotate"),j=ie(N,I),J=ie(N,C),Z=ie(k,I),H=ie(k,C);N=Math.min(j.x,J.x,Z.x,H.x),k=Math.max(j.x,J.x,Z.x,H.x),I=Math.min(j.y,J.y,Z.y,H.y),C=Math.max(j.y,J.y,Z.y,H.y)}var q=O+"Rot",K=D[q]=D[q]||{};K.x1=N,K.y1=I,K.x2=k,K.y2=C,K.w=k-N,K.h=C-I,Vl(e,N,I,k,C),Vl(a.labelBounds.all,N,I,k,C)}return e}},"updateBoundsFromLabel"),Jje=o(function(e,r){if(!r.cy().headless()){var n=r.pstyle("outline-opacity").value,i=r.pstyle("outline-width").value;if(n>0&&i>0){var a=r.pstyle("outline-offset").value,s=r.pstyle("shape").value,l=i+a,u=(e.w+l*2)/e.w,h=(e.h+l*2)/e.h,f=0,d=0;["diamond","pentagon","round-triangle"].includes(s)?(u=(e.w+l*2.4)/e.w,d=-l/3.6):["concave-hexagon","rhomboid","right-rhomboid"].includes(s)?u=(e.w+l*2.4)/e.w:s==="star"?(u=(e.w+l*2.8)/e.w,h=(e.h+l*2.6)/e.h,d=-l/3.8):s==="triangle"?(u=(e.w+l*2.8)/e.w,h=(e.h+l*2.4)/e.h,d=-l/1.4):s==="vee"&&(u=(e.w+l*4.4)/e.w,h=(e.h+l*3.8)/e.h,d=-l*.5);var p=e.h*h-e.h,m=e.w*u-e.w;if(m6(e,[Math.ceil(p/2),Math.ceil(m/2)]),f!=0||d!==0){var g=bWe(e,f,d);Vpe(e,g)}}}},"updateBoundsFromOutline"),eKe=o(function(e,r){var n=e._private.cy,i=n.styleEnabled(),a=n.headless(),s=Gs(),l=e._private,u=e.isNode(),h=e.isEdge(),f,d,p,m,g,y,v=l.rstyle,x=u&&i?e.pstyle("bounds-expansion").pfValue:[0],b=o(function(De){return De.pstyle("display").value!=="none"},"isDisplayed"),w=!i||b(e)&&(!h||b(e.source())&&b(e.target()));if(w){var S=0,T=0;i&&r.includeOverlays&&(S=e.pstyle("overlay-opacity").value,S!==0&&(T=e.pstyle("overlay-padding").value));var E=0,_=0;i&&r.includeUnderlays&&(E=e.pstyle("underlay-opacity").value,E!==0&&(_=e.pstyle("underlay-padding").value));var A=Math.max(T,_),L=0,M=0;if(i&&(L=e.pstyle("width").pfValue,M=L/2),u&&r.includeNodes){var N=e.position();g=N.x,y=N.y;var k=e.outerWidth(),I=k/2,C=e.outerHeight(),O=C/2;f=g-I,d=g+I,p=y-O,m=y+O,Vl(s,f,p,d,m),i&&r.includeOutlines&&Jje(s,e)}else if(h&&r.includeEdges)if(i&&!a){var D=e.pstyle("curve-style").strValue;if(f=Math.min(v.srcX,v.midX,v.tgtX),d=Math.max(v.srcX,v.midX,v.tgtX),p=Math.min(v.srcY,v.midY,v.tgtY),m=Math.max(v.srcY,v.midY,v.tgtY),f-=M,d+=M,p-=M,m+=M,Vl(s,f,p,d,m),D==="haystack"){var P=v.haystackPts;if(P&&P.length===2){if(f=P[0].x,p=P[0].y,d=P[1].x,m=P[1].y,f>d){var F=f;f=d,d=F}if(p>m){var B=p;p=m,m=B}Vl(s,f-M,p-M,d+M,m+M)}}else if(D==="bezier"||D==="unbundled-bezier"||D.endsWith("segments")||D.endsWith("taxi")){var $;switch(D){case"bezier":case"unbundled-bezier":$=v.bezierPts;break;case"segments":case"taxi":case"round-segments":case"round-taxi":$=v.linePts;break}if($!=null)for(var z=0;z<$.length;z++){var Y=$[z];f=Y.x-M,d=Y.x+M,p=Y.y-M,m=Y.y+M,Vl(s,f,p,d,m)}}}else{var Q=e.source(),X=Q.position(),ie=e.target(),j=ie.position();if(f=X.x,d=j.x,p=X.y,m=j.y,f>d){var J=f;f=d,d=J}if(p>m){var Z=p;p=m,m=Z}f-=M,d+=M,p-=M,m+=M,Vl(s,f,p,d,m)}if(i&&r.includeEdges&&h&&(l6(s,e,"mid-source"),l6(s,e,"mid-target"),l6(s,e,"source"),l6(s,e,"target")),i){var H=e.pstyle("ghost").value==="yes";if(H){var q=e.pstyle("ghost-offset-x").pfValue,K=e.pstyle("ghost-offset-y").pfValue;Vl(s,s.x1+q,s.y1+K,s.x2+q,s.y2+K)}}var se=l.bodyBounds=l.bodyBounds||{};g0e(se,s),m6(se,x),p6(se,1),i&&(f=s.x1,d=s.x2,p=s.y1,m=s.y2,Vl(s,f-A,p-A,d+A,m+A));var ce=l.overlayBounds=l.overlayBounds||{};g0e(ce,s),m6(ce,x),p6(ce,1);var ue=l.labelBounds=l.labelBounds||{};ue.all!=null?xWe(ue.all):ue.all=Gs(),i&&r.includeLabels&&(r.includeMainLabels&&SP(s,e,null),h&&(r.includeSourceLabels&&SP(s,e,"source"),r.includeTargetLabels&&SP(s,e,"target")))}return s.x1=el(s.x1),s.y1=el(s.y1),s.x2=el(s.x2),s.y2=el(s.y2),s.w=el(s.x2-s.x1),s.h=el(s.y2-s.y1),s.w>0&&s.h>0&&w&&(m6(s,x),p6(s,1)),s},"boundingBoxImpl"),mme=o(function(e){var r=0,n=o(function(s){return(s?1:0)<=0;l--)s(l);return this};Df.removeAllListeners=function(){return this.removeListener("*")};Df.emit=Df.trigger=function(t,e,r){var n=this.listeners,i=n.length;return this.emitting++,vn(e)||(e=[e]),gKe(this,function(a,s){r!=null&&(n=[{event:s.event,type:s.type,namespace:s.namespace,callback:r}],i=n.length);for(var l=o(function(f){var d=n[f];if(d.type===s.type&&(!d.namespace||d.namespace===s.namespace||d.namespace===pKe)&&a.eventMatches(a.context,d,s)){var p=[s];e!=null&&qYe(p,e),a.beforeEmit(a.context,d,s),d.conf&&d.conf.one&&(a.listeners=a.listeners.filter(function(y){return y!==d}));var m=a.callbackContext(a.context,d,s),g=d.callback.apply(m,p);a.afterEmit(a.context,d,s),g===!1&&(s.stopPropagation(),s.preventDefault())}},"_loop2"),u=0;u1&&!s){var l=this.length-1,u=this[l],h=u._private.data.id;this[l]=void 0,this[e]=u,a.set(h,{ele:u,index:e})}return this.length--,this},"unmergeAt"),unmergeOne:o(function(e){e=e[0];var r=this._private,n=e._private.data.id,i=r.map,a=i.get(n);if(!a)return this;var s=a.index;return this.unmergeAt(s),this},"unmergeOne"),unmerge:o(function(e){var r=this._private.cy;if(!e)return this;if(e&&zt(e)){var n=e;e=r.mutableElements().filter(n)}for(var i=0;i=0;r--){var n=this[r];e(n)&&this.unmergeAt(r)}return this},"unmergeBy"),map:o(function(e,r){for(var n=[],i=this,a=0;an&&(n=u,i=l)}return{value:n,ele:i}},"max"),min:o(function(e,r){for(var n=1/0,i,a=this,s=0;s=0&&a"u"?"undefined":Hi(Symbol))!=e&&Hi(Symbol.iterator)!=e;r&&(L6[Symbol.iterator]=function(){var n=this,i={value:void 0,done:!1},a=0,s=this.length;return bpe({next:o(function(){return a1&&arguments[1]!==void 0?arguments[1]:!0,n=this[0],i=n.cy();if(i.styleEnabled()&&n){this.cleanStyle();var a=n._private.style[e];return a??(r?i.style().getDefaultProperty(e):null)}},"parsedStyle"),numericStyle:o(function(e){var r=this[0];if(r.cy().styleEnabled()&&r){var n=r.pstyle(e);return n.pfValue!==void 0?n.pfValue:n.value}},"numericStyle"),numericStyleUnits:o(function(e){var r=this[0];if(r.cy().styleEnabled()&&r)return r.pstyle(e).units},"numericStyleUnits"),renderedStyle:o(function(e){var r=this.cy();if(!r.styleEnabled())return this;var n=this[0];if(n)return r.style().getRenderedStyle(n,e)},"renderedStyle"),style:o(function(e,r){var n=this.cy();if(!n.styleEnabled())return this;var i=!1,a=n.style();if(Mr(e)){var s=e;a.applyBypass(this,s,i),this.emitAndNotify("style")}else if(zt(e))if(r===void 0){var l=this[0];return l?a.getStylePropertyValue(l,e):void 0}else a.applyBypass(this,e,r,i),this.emitAndNotify("style");else if(e===void 0){var u=this[0];return u?a.getRawStyle(u):void 0}return this},"style"),removeStyle:o(function(e){var r=this.cy();if(!r.styleEnabled())return this;var n=!1,i=r.style(),a=this;if(e===void 0)for(var s=0;s0&&e.push(f[0]),e.push(l[0])}return this.spawn(e,!0).filter(t)},"neighborhood"),closedNeighborhood:o(function(e){return this.neighborhood().add(this).filter(e)},"closedNeighborhood"),openNeighborhood:o(function(e){return this.neighborhood(e)},"openNeighborhood")});Fa.neighbourhood=Fa.neighborhood;Fa.closedNeighbourhood=Fa.closedNeighborhood;Fa.openNeighbourhood=Fa.openNeighborhood;Wt(Fa,{source:tl(o(function(e){var r=this[0],n;return r&&(n=r._private.source||r.cy().collection()),n&&e?n.filter(e):n},"sourceImpl"),"source"),target:tl(o(function(e){var r=this[0],n;return r&&(n=r._private.target||r.cy().collection()),n&&e?n.filter(e):n},"targetImpl"),"target"),sources:X0e({attr:"source"}),targets:X0e({attr:"target"})});o(X0e,"defineSourceFunction");Wt(Fa,{edgesWith:tl(j0e(),"edgesWith"),edgesTo:tl(j0e({thisIsSrc:!0}),"edgesTo")});o(j0e,"defineEdgesWithFunction");Wt(Fa,{connectedEdges:tl(function(t){for(var e=[],r=this,n=0;n0);return s},"components"),component:o(function(){var e=this[0];return e.cy().mutableElements().components(e)[0]},"component")});Fa.componentsOf=Fa.components;Ca=o(function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1,i=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1;if(e===void 0){oi("A collection must have a reference to the core");return}var a=new Vc,s=!1;if(!r)r=[];else if(r.length>0&&Mr(r[0])&&!Zx(r[0])){s=!0;for(var l=[],u=new c1,h=0,f=r.length;h0&&arguments[0]!==void 0?arguments[0]:!0,e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,r=this,n=r.cy(),i=n._private,a=[],s=[],l,u=0,h=r.length;u0){for(var B=l.length===r.length?r:new Ca(n,l),$=0;$0&&arguments[0]!==void 0?arguments[0]:!0,e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,r=this,n=[],i={},a=r._private.cy;function s(C){for(var O=C._private.edges,D=0;D0&&(t?N.emitAndNotify("remove"):e&&N.emit("remove"));for(var k=0;kf&&Math.abs(g.v)>f;);return p?function(y){return u[y*(u.length-1)|0]}:h},"springRK4Factory")}(),Ln=o(function(e,r,n,i){var a=SKe(e,r,n,i);return function(s,l,u){return s+(l-s)*a(u)}},"cubicBezier"),v6={linear:o(function(e,r,n){return e+(r-e)*n},"linear"),ease:Ln(.25,.1,.25,1),"ease-in":Ln(.42,0,1,1),"ease-out":Ln(0,0,.58,1),"ease-in-out":Ln(.42,0,.58,1),"ease-in-sine":Ln(.47,0,.745,.715),"ease-out-sine":Ln(.39,.575,.565,1),"ease-in-out-sine":Ln(.445,.05,.55,.95),"ease-in-quad":Ln(.55,.085,.68,.53),"ease-out-quad":Ln(.25,.46,.45,.94),"ease-in-out-quad":Ln(.455,.03,.515,.955),"ease-in-cubic":Ln(.55,.055,.675,.19),"ease-out-cubic":Ln(.215,.61,.355,1),"ease-in-out-cubic":Ln(.645,.045,.355,1),"ease-in-quart":Ln(.895,.03,.685,.22),"ease-out-quart":Ln(.165,.84,.44,1),"ease-in-out-quart":Ln(.77,0,.175,1),"ease-in-quint":Ln(.755,.05,.855,.06),"ease-out-quint":Ln(.23,1,.32,1),"ease-in-out-quint":Ln(.86,0,.07,1),"ease-in-expo":Ln(.95,.05,.795,.035),"ease-out-expo":Ln(.19,1,.22,1),"ease-in-out-expo":Ln(1,0,0,1),"ease-in-circ":Ln(.6,.04,.98,.335),"ease-out-circ":Ln(.075,.82,.165,1),"ease-in-out-circ":Ln(.785,.135,.15,.86),spring:o(function(e,r,n){if(n===0)return v6.linear;var i=AKe(e,r,n);return function(a,s,l){return a+(s-a)*i(l)}},"spring"),"cubic-bezier":Ln};o(Q0e,"getEasedValue");o(Z0e,"getValue");o(jg,"ease");o(_Ke,"step$1");o(Nx,"valid");o(LKe,"startAnimation");o(J0e,"stepAll");DKe={animate:en.animate(),animation:en.animation(),animated:en.animated(),clearQueue:en.clearQueue(),delay:en.delay(),delayAnimation:en.delayAnimation(),stop:en.stop(),addToAnimationPool:o(function(e){var r=this;r.styleEnabled()&&r._private.aniEles.merge(e)},"addToAnimationPool"),stopAnimationLoop:o(function(){this._private.animationsRunning=!1},"stopAnimationLoop"),startAnimationLoop:o(function(){var e=this;if(e._private.animationsRunning=!0,!e.styleEnabled())return;function r(){e._private.animationsRunning&&E6(o(function(a){J0e(a,e),r()},"animationStep"))}o(r,"headlessStep");var n=e.renderer();n&&n.beforeRender?n.beforeRender(o(function(a,s){J0e(s,e)},"rendererAnimationStep"),n.beforeRenderPriorities.animations):r()},"startAnimationLoop")},RKe={qualifierCompare:o(function(e,r){return e==null||r==null?e==null&&r==null:e.sameText(r)},"qualifierCompare"),eventMatches:o(function(e,r,n){var i=r.qualifier;return i!=null?e!==n.target&&Zx(n.target)&&i.matches(n.target):!0},"eventMatches"),addEventFields:o(function(e,r){r.cy=e,r.target=e},"addEventFields"),callbackContext:o(function(e,r,n){return r.qualifier!=null?n.target:e},"callbackContext")},h6=o(function(e){return zt(e)?new _f(e):e},"argSelector"),Sme={createEmitter:o(function(){var e=this._private;return e.emitter||(e.emitter=new H6(RKe,this)),this},"createEmitter"),emitter:o(function(){return this._private.emitter},"emitter"),on:o(function(e,r,n){return this.emitter().on(e,h6(r),n),this},"on"),removeListener:o(function(e,r,n){return this.emitter().removeListener(e,h6(r),n),this},"removeListener"),removeAllListeners:o(function(){return this.emitter().removeAllListeners(),this},"removeAllListeners"),one:o(function(e,r,n){return this.emitter().one(e,h6(r),n),this},"one"),once:o(function(e,r,n){return this.emitter().one(e,h6(r),n),this},"once"),emit:o(function(e,r){return this.emitter().emit(e,r),this},"emit"),emitAndNotify:o(function(e,r){return this.emit(e),this.notify(e,r),this},"emitAndNotify")};en.eventAliasesOn(Sme);FP={png:o(function(e){var r=this._private.renderer;return e=e||{},r.png(e)},"png"),jpg:o(function(e){var r=this._private.renderer;return e=e||{},e.bg=e.bg||"#fff",r.jpg(e)},"jpg")};FP.jpeg=FP.jpg;x6={layout:o(function(e){var r=this;if(e==null){oi("Layout options must be specified to make a layout");return}if(e.name==null){oi("A `name` must be specified to make a layout");return}var n=e.name,i=r.extension("layout",n);if(i==null){oi("No such layout `"+n+"` found. Did you forget to import it and `cytoscape.use()` it?");return}var a;zt(e.eles)?a=r.$(e.eles):a=e.eles!=null?e.eles:r.$();var s=new i(Wt({},e,{cy:r,eles:a}));return s},"layout")};x6.createLayout=x6.makeLayout=x6.layout;NKe={notify:o(function(e,r){var n=this._private;if(this.batching()){n.batchNotifications=n.batchNotifications||{};var i=n.batchNotifications[e]=n.batchNotifications[e]||this.collection();r!=null&&i.merge(r);return}if(n.notificationsEnabled){var a=this.renderer();this.destroyed()||!a||a.notify(e,r)}},"notify"),notifications:o(function(e){var r=this._private;return e===void 0?r.notificationsEnabled:(r.notificationsEnabled=!!e,this)},"notifications"),noNotifications:o(function(e){this.notifications(!1),e(),this.notifications(!0)},"noNotifications"),batching:o(function(){return this._private.batchCount>0},"batching"),startBatch:o(function(){var e=this._private;return e.batchCount==null&&(e.batchCount=0),e.batchCount===0&&(e.batchStyleEles=this.collection(),e.batchNotifications={}),e.batchCount++,this},"startBatch"),endBatch:o(function(){var e=this._private;if(e.batchCount===0)return this;if(e.batchCount--,e.batchCount===0){e.batchStyleEles.updateStyle();var r=this.renderer();Object.keys(e.batchNotifications).forEach(function(n){var i=e.batchNotifications[n];i.empty()?r.notify(n):r.notify(n,i)})}return this},"endBatch"),batch:o(function(e){return this.startBatch(),e(),this.endBatch(),this},"batch"),batchData:o(function(e){var r=this;return this.batch(function(){for(var n=Object.keys(e),i=0;i0;)r.removeChild(r.childNodes[0]);e._private.renderer=null,e.mutableElements().forEach(function(n){var i=n._private;i.rscratch={},i.rstyle={},i.animation.current=[],i.animation.queue=[]})},"destroyRenderer"),onRender:o(function(e){return this.on("render",e)},"onRender"),offRender:o(function(e){return this.off("render",e)},"offRender")};zP.invalidateDimensions=zP.resize;b6={collection:o(function(e,r){return zt(e)?this.$(e):xo(e)?e.collection():vn(e)?(r||(r={}),new Ca(this,e,r.unique,r.removed)):new Ca(this)},"collection"),nodes:o(function(e){var r=this.$(function(n){return n.isNode()});return e?r.filter(e):r},"nodes"),edges:o(function(e){var r=this.$(function(n){return n.isEdge()});return e?r.filter(e):r},"edges"),$:o(function(e){var r=this._private.elements;return e?r.filter(e):r.spawnSelf()},"$"),mutableElements:o(function(){return this._private.elements},"mutableElements")};b6.elements=b6.filter=b6.$;Ga={},Fx="t",IKe="f";Ga.apply=function(t){for(var e=this,r=e._private,n=r.cy,i=n.collection(),a=0;a0;if(p||d&&m){var g=void 0;p&&m||p?g=h.properties:m&&(g=h.mappedProperties);for(var y=0;y1&&(S=1),l.color){var E=n.valueMin[0],_=n.valueMax[0],A=n.valueMin[1],L=n.valueMax[1],M=n.valueMin[2],N=n.valueMax[2],k=n.valueMin[3]==null?1:n.valueMin[3],I=n.valueMax[3]==null?1:n.valueMax[3],C=[Math.round(E+(_-E)*S),Math.round(A+(L-A)*S),Math.round(M+(N-M)*S),Math.round(k+(I-k)*S)];a={bypass:n.bypass,name:n.name,value:C,strValue:"rgb("+C[0]+", "+C[1]+", "+C[2]+")"}}else if(l.number){var O=n.valueMin+(n.valueMax-n.valueMin)*S;a=this.parse(n.name,O,n.bypass,p)}else return!1;if(!a)return y(),!1;a.mapping=n,n=a;break}case s.data:{for(var D=n.field.split("."),P=d.data,F=0;F0&&a>0){for(var l={},u=!1,h=0;h0?t.delayAnimation(s).play().promise().then(w):w()}).then(function(){return t.animation({style:l,duration:a,easing:t.pstyle("transition-timing-function").value,queue:!1}).play().promise()}).then(function(){r.removeBypasses(t,i),t.emitAndNotify("style"),n.transitioning=!1})}else n.transitioning&&(this.removeBypasses(t,i),t.emitAndNotify("style"),n.transitioning=!1)};Ga.checkTrigger=function(t,e,r,n,i,a){var s=this.properties[e],l=i(s);l!=null&&l(r,n)&&a(s)};Ga.checkZOrderTrigger=function(t,e,r,n){var i=this;this.checkTrigger(t,e,r,n,function(a){return a.triggersZOrder},function(){i._private.cy.notify("zorder",t)})};Ga.checkBoundsTrigger=function(t,e,r,n){this.checkTrigger(t,e,r,n,function(i){return i.triggersBounds},function(i){t.dirtyCompoundBoundsCache(),t.dirtyBoundingBoxCache(),i.triggersBoundsOfParallelBeziers&&e==="curve-style"&&(r==="bezier"||n==="bezier")&&t.parallelEdges().forEach(function(a){a.isBundledBezier()&&a.dirtyBoundingBoxCache()}),i.triggersBoundsOfConnectedEdges&&e==="display"&&(r==="none"||n==="none")&&t.connectedEdges().forEach(function(a){a.dirtyBoundingBoxCache()})})};Ga.checkTriggers=function(t,e,r,n){t.dirtyStyleCache(),this.checkZOrderTrigger(t,e,r,n),this.checkBoundsTrigger(t,e,r,n)};rb={};rb.applyBypass=function(t,e,r,n){var i=this,a=[],s=!0;if(e==="*"||e==="**"){if(r!==void 0)for(var l=0;li.length?n=n.substr(i.length):n=""}o(l,"removeSelAndBlockFromRemaining");function u(){a.length>s.length?a=a.substr(s.length):a=""}for(o(u,"removePropAndValFromRem");;){var h=n.match(/^\s*$/);if(h)break;var f=n.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/);if(!f){tn("Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: "+n);break}i=f[0];var d=f[1];if(d!=="core"){var p=new _f(d);if(p.invalid){tn("Skipping parsing of block: Invalid selector found in string stylesheet: "+d),l();continue}}var m=f[2],g=!1;a=m;for(var y=[];;){var v=a.match(/^\s*$/);if(v)break;var x=a.match(/^\s*(.+?)\s*:\s*(.+?)(?:\s*;|\s*$)/);if(!x){tn("Skipping parsing of block: Invalid formatting of style property and value definitions found in:"+m),g=!0;break}s=x[0];var b=x[1],w=x[2],S=e.properties[b];if(!S){tn("Skipping property: Invalid property name in: "+s),u();continue}var T=r.parse(b,w);if(!T){tn("Skipping property: Invalid property definition in: "+s),u();continue}y.push({name:b,val:w}),u()}if(g){l();break}r.selector(d);for(var E=0;E=7&&e[0]==="d"&&(f=new RegExp(l.data.regex).exec(e))){if(r)return!1;var p=l.data;return{name:t,value:f,strValue:""+e,mapped:p,field:f[1],bypass:r}}else if(e.length>=10&&e[0]==="m"&&(d=new RegExp(l.mapData.regex).exec(e))){if(r||h.multiple)return!1;var m=l.mapData;if(!(h.color||h.number))return!1;var g=this.parse(t,d[4]);if(!g||g.mapped)return!1;var y=this.parse(t,d[5]);if(!y||y.mapped)return!1;if(g.pfValue===y.pfValue||g.strValue===y.strValue)return tn("`"+t+": "+e+"` is not a valid mapper because the output range is zero; converting to `"+t+": "+g.strValue+"`"),this.parse(t,g.strValue);if(h.color){var v=g.value,x=y.value,b=v[0]===x[0]&&v[1]===x[1]&&v[2]===x[2]&&(v[3]===x[3]||(v[3]==null||v[3]===1)&&(x[3]==null||x[3]===1));if(b)return!1}return{name:t,value:d,strValue:""+e,mapped:m,field:d[1],fieldMin:parseFloat(d[2]),fieldMax:parseFloat(d[3]),valueMin:g.value,valueMax:y.value,bypass:r}}}if(h.multiple&&n!=="multiple"){var w;if(u?w=e.split(/\s+/):vn(e)?w=e:w=[e],h.evenMultiple&&w.length%2!==0)return null;for(var S=[],T=[],E=[],_="",A=!1,L=0;L0?" ":"")+M.strValue}return h.validate&&!h.validate(S,T)?null:h.singleEnum&&A?S.length===1&&zt(S[0])?{name:t,value:S[0],strValue:S[0],bypass:r}:null:{name:t,value:S,pfValue:E,strValue:_,bypass:r,units:T}}var N=o(function(){for(var H=0;Hh.max||h.strictMax&&e===h.max))return null;var D={name:t,value:e,strValue:""+e+(k||""),units:k,bypass:r};return h.unitless||k!=="px"&&k!=="em"?D.pfValue=e:D.pfValue=k==="px"||!k?e:this.getEmSizeInPixels()*e,(k==="ms"||k==="s")&&(D.pfValue=k==="ms"?e:1e3*e),(k==="deg"||k==="rad")&&(D.pfValue=k==="rad"?e:mWe(e)),k==="%"&&(D.pfValue=e/100),D}else if(h.propList){var P=[],F=""+e;if(F!=="none"){for(var B=F.split(/\s*,\s*|\s+/),$=0;$0&&l>0&&!isNaN(n.w)&&!isNaN(n.h)&&n.w>0&&n.h>0){u=Math.min((s-2*r)/n.w,(l-2*r)/n.h),u=u>this._private.maxZoom?this._private.maxZoom:u,u=u=n.minZoom&&(n.maxZoom=r),this},"zoomRange"),minZoom:o(function(e){return e===void 0?this._private.minZoom:this.zoomRange({min:e})},"minZoom"),maxZoom:o(function(e){return e===void 0?this._private.maxZoom:this.zoomRange({max:e})},"maxZoom"),getZoomedViewport:o(function(e){var r=this._private,n=r.pan,i=r.zoom,a,s,l=!1;if(r.zoomingEnabled||(l=!0),ft(e)?s=e:Mr(e)&&(s=e.level,e.position!=null?a=F6(e.position,i,n):e.renderedPosition!=null&&(a=e.renderedPosition),a!=null&&!r.panningEnabled&&(l=!0)),s=s>r.maxZoom?r.maxZoom:s,s=sr.maxZoom||!r.zoomingEnabled?s=!0:(r.zoom=u,a.push("zoom"))}if(i&&(!s||!e.cancelOnFailedZoom)&&r.panningEnabled){var h=e.pan;ft(h.x)&&(r.pan.x=h.x,l=!1),ft(h.y)&&(r.pan.y=h.y,l=!1),l||a.push("pan")}return a.length>0&&(a.push("viewport"),this.emit(a.join(" ")),this.notify("viewport")),this},"viewport"),center:o(function(e){var r=this.getCenterPan(e);return r&&(this._private.pan=r,this.emit("pan viewport"),this.notify("viewport")),this},"center"),getCenterPan:o(function(e,r){if(this._private.panningEnabled){if(zt(e)){var n=e;e=this.mutableElements().filter(n)}else xo(e)||(e=this.mutableElements());if(e.length!==0){var i=e.boundingBox(),a=this.width(),s=this.height();r=r===void 0?this._private.zoom:r;var l={x:(a-r*(i.x1+i.x2))/2,y:(s-r*(i.y1+i.y2))/2};return l}}},"getCenterPan"),reset:o(function(){return!this._private.panningEnabled||!this._private.zoomingEnabled?this:(this.viewport({pan:{x:0,y:0},zoom:1}),this)},"reset"),invalidateSize:o(function(){this._private.sizeCache=null},"invalidateSize"),size:o(function(){var e=this._private,r=e.container,n=this;return e.sizeCache=e.sizeCache||(r?function(){var i=n.window().getComputedStyle(r),a=o(function(l){return parseFloat(i.getPropertyValue(l))},"val");return{width:r.clientWidth-a("padding-left")-a("padding-right"),height:r.clientHeight-a("padding-top")-a("padding-bottom")}}():{width:1,height:1})},"size"),width:o(function(){return this.size().width},"width"),height:o(function(){return this.size().height},"height"),extent:o(function(){var e=this._private.pan,r=this._private.zoom,n=this.renderedExtent(),i={x1:(n.x1-e.x)/r,x2:(n.x2-e.x)/r,y1:(n.y1-e.y)/r,y2:(n.y2-e.y)/r};return i.w=i.x2-i.x1,i.h=i.y2-i.y1,i},"extent"),renderedExtent:o(function(){var e=this.width(),r=this.height();return{x1:0,y1:0,x2:e,y2:r,w:e,h:r}},"renderedExtent"),multiClickDebounceTime:o(function(e){if(e)this._private.multiClickDebounceTime=e;else return this._private.multiClickDebounceTime;return this},"multiClickDebounceTime")};q0.centre=q0.center;q0.autolockNodes=q0.autolock;q0.autoungrabifyNodes=q0.autoungrabify;jx={data:en.data({field:"data",bindingEvent:"data",allowBinding:!0,allowSetting:!0,settingEvent:"data",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeData:en.removeData({field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0}),scratch:en.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeScratch:en.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0})};jx.attr=jx.data;jx.removeAttr=jx.removeData;Kx=o(function(e){var r=this;e=Wt({},e);var n=e.container;n&&!k6(n)&&k6(n[0])&&(n=n[0]);var i=n?n._cyreg:null;i=i||{},i&&i.cy&&(i.cy.destroy(),i={});var a=i.readies=i.readies||[];n&&(n._cyreg=i),i.cy=r;var s=Vi!==void 0&&n!==void 0&&!e.headless,l=e;l.layout=Wt({name:s?"grid":"null"},l.layout),l.renderer=Wt({name:s?"canvas":"null"},l.renderer);var u=o(function(g,y,v){return y!==void 0?y:v!==void 0?v:g},"defVal"),h=this._private={container:n,ready:!1,options:l,elements:new Ca(this),listeners:[],aniEles:new Ca(this),data:l.data||{},scratch:{},layout:null,renderer:null,destroyed:!1,notificationsEnabled:!0,minZoom:1e-50,maxZoom:1e50,zoomingEnabled:u(!0,l.zoomingEnabled),userZoomingEnabled:u(!0,l.userZoomingEnabled),panningEnabled:u(!0,l.panningEnabled),userPanningEnabled:u(!0,l.userPanningEnabled),boxSelectionEnabled:u(!0,l.boxSelectionEnabled),autolock:u(!1,l.autolock,l.autolockNodes),autoungrabify:u(!1,l.autoungrabify,l.autoungrabifyNodes),autounselectify:u(!1,l.autounselectify),styleEnabled:l.styleEnabled===void 0?s:l.styleEnabled,zoom:ft(l.zoom)?l.zoom:1,pan:{x:Mr(l.pan)&&ft(l.pan.x)?l.pan.x:0,y:Mr(l.pan)&&ft(l.pan.y)?l.pan.y:0},animation:{current:[],queue:[]},hasCompoundNodes:!1,multiClickDebounceTime:u(250,l.multiClickDebounceTime)};this.createEmitter(),this.selectionType(l.selectionType),this.zoomRange({min:l.minZoom,max:l.maxZoom});var f=o(function(g,y){var v=g.some(zHe);if(v)return u1.all(g).then(y);y(g)},"loadExtData");h.styleEnabled&&r.setStyle([]);var d=Wt({},l,l.renderer);r.initRenderer(d);var p=o(function(g,y,v){r.notifications(!1);var x=r.mutableElements();x.length>0&&x.remove(),g!=null&&(Mr(g)||vn(g))&&r.add(g),r.one("layoutready",function(w){r.notifications(!0),r.emit(w),r.one("load",y),r.emitAndNotify("load")}).one("layoutstop",function(){r.one("done",v),r.emit("done")});var b=Wt({},r._private.options.layout);b.eles=r.elements(),r.layout(b).run()},"setElesAndLayout");f([l.style,l.elements],function(m){var g=m[0],y=m[1];h.styleEnabled&&r.style().append(g),p(y,function(){r.startAnimationLoop(),h.ready=!0,jn(l.ready)&&r.on("ready",l.ready);for(var v=0;v0,u=Gs(e.boundingBox?e.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()}),h;if(xo(e.roots))h=e.roots;else if(vn(e.roots)){for(var f=[],d=0;d0;){var O=C(),D=M(O,k);if(D)O.outgoers().filter(function(ue){return ue.isNode()&&n.has(ue)}).forEach(I);else if(D===null){tn("Detected double maximal shift for node `"+O.id()+"`. Bailing maximal adjustment due to cycle. Use `options.maximal: true` only on DAGs.");break}}}L();var P=0;if(e.avoidOverlap)for(var F=0;F0&&x[0].length<=3?Pe/2:0),W=2*Math.PI/x[oe].length*ke;return oe===0&&x[0].length===1&&(me=1),{x:K.x+me*Math.cos(W),y:K.y+me*Math.sin(W)}}else{var _e={x:K.x+(ke+1-(Ie+1)/2)*Se,y:(oe+1)*Ue};return _e}},"getPosition");return n.nodes().layoutPositions(this,e,ce),this};zKe={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,nodeDimensionsIncludeLabels:!1,spacingFactor:void 0,radius:void 0,startAngle:3/2*Math.PI,sweep:void 0,clockwise:!0,sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:o(function(e,r){return!0},"animateFilter"),ready:void 0,stop:void 0,transform:o(function(e,r){return r},"transform")};o(_me,"CircleLayout");_me.prototype.run=function(){var t=this.options,e=t,r=t.cy,n=e.eles,i=e.counterclockwise!==void 0?!e.counterclockwise:e.clockwise,a=n.nodes().not(":parent");e.sort&&(a=a.sort(e.sort));for(var s=Gs(e.boundingBox?e.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()}),l={x:s.x1+s.w/2,y:s.y1+s.h/2},u=e.sweep===void 0?2*Math.PI-2*Math.PI/a.length:e.sweep,h=u/Math.max(1,a.length-1),f,d=0,p=0;p1&&e.avoidOverlap){d*=1.75;var x=Math.cos(h)-Math.cos(0),b=Math.sin(h)-Math.sin(0),w=Math.sqrt(d*d/(x*x+b*b));f=Math.max(w,f)}var S=o(function(E,_){var A=e.startAngle+_*h*(i?1:-1),L=f*Math.cos(A),M=f*Math.sin(A),N={x:l.x+L,y:l.y+M};return N},"getPos");return n.nodes().layoutPositions(this,e,S),this};GKe={fit:!0,padding:30,startAngle:3/2*Math.PI,sweep:void 0,clockwise:!0,equidistant:!1,minNodeSpacing:10,boundingBox:void 0,avoidOverlap:!0,nodeDimensionsIncludeLabels:!1,height:void 0,width:void 0,spacingFactor:void 0,concentric:o(function(e){return e.degree()},"concentric"),levelWidth:o(function(e){return e.maxDegree()/4},"levelWidth"),animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:o(function(e,r){return!0},"animateFilter"),ready:void 0,stop:void 0,transform:o(function(e,r){return r},"transform")};o(Lme,"ConcentricLayout");Lme.prototype.run=function(){for(var t=this.options,e=t,r=e.counterclockwise!==void 0?!e.counterclockwise:e.clockwise,n=t.cy,i=e.eles,a=i.nodes().not(":parent"),s=Gs(e.boundingBox?e.boundingBox:{x1:0,y1:0,w:n.width(),h:n.height()}),l={x:s.x1+s.w/2,y:s.y1+s.h/2},u=[],h=0,f=0;f0){var T=Math.abs(b[0].value-S.value);T>=v&&(b=[],x.push(b))}b.push(S)}var E=h+e.minNodeSpacing;if(!e.avoidOverlap){var _=x.length>0&&x[0].length>1,A=Math.min(s.w,s.h)/2-E,L=A/(x.length+_?1:0);E=Math.min(E,L)}for(var M=0,N=0;N1&&e.avoidOverlap){var O=Math.cos(C)-Math.cos(0),D=Math.sin(C)-Math.sin(0),P=Math.sqrt(E*E/(O*O+D*D));M=Math.max(P,M)}k.r=M,M+=E}if(e.equidistant){for(var F=0,B=0,$=0;$=t.numIter||(XKe(n,t),n.temperature=n.temperature*t.coolingFactor,n.temperature=t.animationThreshold&&a(),E6(d)}},"frame");f()}else{for(;h;)h=s(u),u++;rpe(n,t),l()}return this};j6.prototype.stop=function(){return this.stopped=!0,this.thread&&this.thread.stop(),this.emit("layoutstop"),this};j6.prototype.destroy=function(){return this.thread&&this.thread.stop(),this};VKe=o(function(e,r,n){for(var i=n.eles.edges(),a=n.eles.nodes(),s=Gs(n.boundingBox?n.boundingBox:{x1:0,y1:0,w:e.width(),h:e.height()}),l={isCompound:e.hasCompoundNodes(),layoutNodes:[],idToIndex:{},nodeSize:a.size(),graphSet:[],indexToGraph:[],layoutEdges:[],edgeSize:i.size(),temperature:n.initialTemp,clientWidth:s.w,clientHeight:s.h,boundingBox:s},u=n.eles.components(),h={},f=0;f0){l.graphSet.push(A);for(var f=0;fi.count?0:i.graph},"findLCA"),HKe=o(function t(e,r,n,i){var a=i.graphSet[n];if(-10)var d=i.nodeOverlap*f,p=Math.sqrt(l*l+u*u),m=d*l/p,g=d*u/p;else var y=R6(e,l,u),v=R6(r,-1*l,-1*u),x=v.x-y.x,b=v.y-y.y,w=x*x+b*b,p=Math.sqrt(w),d=(e.nodeRepulsion+r.nodeRepulsion)/w,m=d*x/p,g=d*b/p;e.isLocked||(e.offsetX-=m,e.offsetY-=g),r.isLocked||(r.offsetX+=m,r.offsetY+=g)}},"nodeRepulsion"),QKe=o(function(e,r,n,i){if(n>0)var a=e.maxX-r.minX;else var a=r.maxX-e.minX;if(i>0)var s=e.maxY-r.minY;else var s=r.maxY-e.minY;return a>=0&&s>=0?Math.sqrt(a*a+s*s):0},"nodesOverlap"),R6=o(function(e,r,n){var i=e.positionX,a=e.positionY,s=e.height||1,l=e.width||1,u=n/r,h=s/l,f={};return r===0&&0n?(f.x=i,f.y=a+s/2,f):0r&&-1*h<=u&&u<=h?(f.x=i-l/2,f.y=a-l*n/2/r,f):0=h)?(f.x=i+s*r/2/n,f.y=a+s/2,f):(0>n&&(u<=-1*h||u>=h)&&(f.x=i-s*r/2/n,f.y=a-s/2),f)},"findClippingPoint"),ZKe=o(function(e,r){for(var n=0;nn){var v=r.gravity*m/y,x=r.gravity*g/y;p.offsetX+=v,p.offsetY+=x}}}}},"calculateGravityForces"),eQe=o(function(e,r){var n=[],i=0,a=-1;for(n.push.apply(n,e.graphSet[0]),a+=e.graphSet[0].length;i<=a;){var s=n[i++],l=e.idToIndex[s],u=e.layoutNodes[l],h=u.children;if(0n)var a={x:n*e/i,y:n*r/i};else var a={x:e,y:r};return a},"limitForce"),nQe=o(function t(e,r){var n=e.parentId;if(n!=null){var i=r.layoutNodes[r.idToIndex[n]],a=!1;if((i.maxX==null||e.maxX+i.padRight>i.maxX)&&(i.maxX=e.maxX+i.padRight,a=!0),(i.minX==null||e.minX-i.padLefti.maxY)&&(i.maxY=e.maxY+i.padBottom,a=!0),(i.minY==null||e.minY-i.padTopx&&(g+=v+r.componentSpacing,m=0,y=0,v=0)}}},"separateComponents"),iQe={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,avoidOverlapPadding:10,nodeDimensionsIncludeLabels:!1,spacingFactor:void 0,condense:!1,rows:void 0,cols:void 0,position:o(function(e){},"position"),sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:o(function(e,r){return!0},"animateFilter"),ready:void 0,stop:void 0,transform:o(function(e,r){return r},"transform")};o(Rme,"GridLayout");Rme.prototype.run=function(){var t=this.options,e=t,r=t.cy,n=e.eles,i=n.nodes().not(":parent");e.sort&&(i=i.sort(e.sort));var a=Gs(e.boundingBox?e.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()});if(a.h===0||a.w===0)n.nodes().layoutPositions(this,e,function(Q){return{x:a.x1,y:a.y1}});else{var s=i.size(),l=Math.sqrt(s*a.h/a.w),u=Math.round(l),h=Math.round(a.w/a.h*l),f=o(function(X){if(X==null)return Math.min(u,h);var ie=Math.min(u,h);ie==u?u=X:h=X},"small"),d=o(function(X){if(X==null)return Math.max(u,h);var ie=Math.max(u,h);ie==u?u=X:h=X},"large"),p=e.rows,m=e.cols!=null?e.cols:e.columns;if(p!=null&&m!=null)u=p,h=m;else if(p!=null&&m==null)u=p,h=Math.ceil(s/u);else if(p==null&&m!=null)h=m,u=Math.ceil(s/h);else if(h*u>s){var g=f(),y=d();(g-1)*y>=s?f(g-1):(y-1)*g>=s&&d(y-1)}else for(;h*u=s?d(x+1):f(v+1)}var b=a.w/h,w=a.h/u;if(e.condense&&(b=0,w=0),e.avoidOverlap)for(var S=0;S=h&&(O=0,C++)},"moveToNextCell"),P={},F=0;F(O=_We(t,e,D[P],D[P+1],D[P+2],D[P+3])))return v(_,O),!0}else if(L.edgeType==="bezier"||L.edgeType==="multibezier"||L.edgeType==="self"||L.edgeType==="compound"){for(var D=L.allpts,P=0;P+5(O=AWe(t,e,D[P],D[P+1],D[P+2],D[P+3],D[P+4],D[P+5])))return v(_,O),!0}for(var F=F||A.source,B=B||A.target,$=i.getArrowWidth(M,N),z=[{name:"source",x:L.arrowStartX,y:L.arrowStartY,angle:L.srcArrowAngle},{name:"target",x:L.arrowEndX,y:L.arrowEndY,angle:L.tgtArrowAngle},{name:"mid-source",x:L.midX,y:L.midY,angle:L.midsrcArrowAngle},{name:"mid-target",x:L.midX,y:L.midY,angle:L.midtgtArrowAngle}],P=0;P0&&(x(F),x(B))}o(b,"checkEdge");function w(_,A,L){return Ul(_,A,L)}o(w,"preprop");function S(_,A){var L=_._private,M=p,N;A?N=A+"-":N="",_.boundingBox();var k=L.labelBounds[A||"main"],I=_.pstyle(N+"label").value,C=_.pstyle("text-events").strValue==="yes";if(!(!C||!I)){var O=w(L.rscratch,"labelX",A),D=w(L.rscratch,"labelY",A),P=w(L.rscratch,"labelAngle",A),F=_.pstyle(N+"text-margin-x").pfValue,B=_.pstyle(N+"text-margin-y").pfValue,$=k.x1-M-F,z=k.x2+M-F,Y=k.y1-M-B,Q=k.y2+M-B;if(P){var X=Math.cos(P),ie=Math.sin(P),j=o(function(ce,ue){return ce=ce-O,ue=ue-D,{x:ce*X-ue*ie+O,y:ce*ie+ue*X+D}},"rotate"),J=j($,Y),Z=j($,Q),H=j(z,Y),q=j(z,Q),K=[J.x+F,J.y+B,H.x+F,H.y+B,q.x+F,q.y+B,Z.x+F,Z.y+B];if(zs(t,e,K))return v(_),!0}else if(s1(k,t,e))return v(_),!0}}o(S,"checkLabel");for(var T=s.length-1;T>=0;T--){var E=s[T];E.isNode()?x(E)||S(E):b(E)||S(E)||S(E,"source")||S(E,"target")}return l};j0.getAllInBox=function(t,e,r,n){var i=this.getCachedZSortedEles().interactive,a=[],s=Math.min(t,r),l=Math.max(t,r),u=Math.min(e,n),h=Math.max(e,n);t=s,r=l,e=u,n=h;for(var f=Gs({x1:t,y1:e,x2:r,y2:n}),d=0;d0?-(Math.PI-e.ang):Math.PI+e.ang},"invertVec"),uQe=o(function(e,r,n,i,a){if(e!==ope?lpe(r,e,Gc):cQe(Jo,Gc),lpe(r,n,Jo),ape=Gc.nx*Jo.ny-Gc.ny*Jo.nx,spe=Gc.nx*Jo.nx-Gc.ny*-Jo.ny,ju=Math.asin(Math.max(-1,Math.min(1,ape))),Math.abs(ju)<1e-6){GP=r.x,$P=r.y,z0=Qg=0;return}G0=1,w6=!1,spe<0?ju<0?ju=Math.PI+ju:(ju=Math.PI-ju,G0=-1,w6=!0):ju>0&&(G0=-1,w6=!0),r.radius!==void 0?Qg=r.radius:Qg=i,O0=ju/2,f6=Math.min(Gc.len/2,Jo.len/2),a?(zc=Math.abs(Math.cos(O0)*Qg/Math.sin(O0)),zc>f6?(zc=f6,z0=Math.abs(zc*Math.sin(O0)/Math.cos(O0))):z0=Qg):(zc=Math.min(f6,Qg),z0=Math.abs(zc*Math.sin(O0)/Math.cos(O0))),VP=r.x+Jo.nx*zc,UP=r.y+Jo.ny*zc,GP=VP-Jo.ny*z0*G0,$P=UP+Jo.nx*z0*G0,Ome=r.x+Gc.nx*zc,Pme=r.y+Gc.ny*zc,ope=r},"calcCornerArc");o(Bme,"drawPreparedRoundCorner");o(mB,"getRoundCorner");$a={};$a.findMidptPtsEtc=function(t,e){var r=e.posPts,n=e.intersectionPts,i=e.vectorNormInverse,a,s=t.pstyle("source-endpoint"),l=t.pstyle("target-endpoint"),u=s.units!=null&&l.units!=null,h=o(function(T,E,_,A){var L=A-E,M=_-T,N=Math.sqrt(M*M+L*L);return{x:-L/N,y:M/N}},"recalcVectorNormInverse"),f=t.pstyle("edge-distances").value;switch(f){case"node-position":a=r;break;case"intersection":a=n;break;case"endpoints":{if(u){var d=this.manualEndptToPx(t.source()[0],s),p=$l(d,2),m=p[0],g=p[1],y=this.manualEndptToPx(t.target()[0],l),v=$l(y,2),x=v[0],b=v[1],w={x1:m,y1:g,x2:x,y2:b};i=h(m,g,x,b),a=w}else tn("Edge ".concat(t.id()," has edge-distances:endpoints specified without manual endpoints specified via source-endpoint and target-endpoint. Falling back on edge-distances:intersection (default).")),a=n;break}}return{midptPts:a,vectorNormInverse:i}};$a.findHaystackPoints=function(t){for(var e=0;e0?Math.max(Te-Ce,0):Math.min(Te+Ce,0)},"subDWH"),I=k(M,A),C=k(N,L),O=!1;b===h?x=Math.abs(I)>Math.abs(C)?i:n:b===u||b===l?(x=n,O=!0):(b===a||b===s)&&(x=i,O=!0);var D=x===n,P=D?C:I,F=D?N:M,B=$pe(F),$=!1;!(O&&(S||E))&&(b===l&&F<0||b===u&&F>0||b===a&&F>0||b===s&&F<0)&&(B*=-1,P=B*Math.abs(P),$=!0);var z;if(S){var Y=T<0?1+T:T;z=Y*P}else{var Q=T<0?P:0;z=Q+T*B}var X=o(function(Te){return Math.abs(Te)<_||Math.abs(Te)>=Math.abs(P)},"getIsTooClose"),ie=X(z),j=X(Math.abs(P)-Math.abs(z)),J=ie||j;if(J&&!$)if(D){var Z=Math.abs(F)<=p/2,H=Math.abs(M)<=m/2;if(Z){var q=(f.x1+f.x2)/2,K=f.y1,se=f.y2;r.segpts=[q,K,q,se]}else if(H){var ce=(f.y1+f.y2)/2,ue=f.x1,te=f.x2;r.segpts=[ue,ce,te,ce]}else r.segpts=[f.x1,f.y2]}else{var De=Math.abs(F)<=d/2,oe=Math.abs(N)<=g/2;if(De){var ke=(f.y1+f.y2)/2,Ie=f.x1,Se=f.x2;r.segpts=[Ie,ke,Se,ke]}else if(oe){var Ue=(f.x1+f.x2)/2,Pe=f.y1,_e=f.y2;r.segpts=[Ue,Pe,Ue,_e]}else r.segpts=[f.x2,f.y1]}else if(D){var me=f.y1+z+(v?p/2*B:0),W=f.x1,fe=f.x2;r.segpts=[W,me,fe,me]}else{var ge=f.x1+z+(v?d/2*B:0),re=f.y1,he=f.y2;r.segpts=[ge,re,ge,he]}if(r.isRound){var ne=t.pstyle("taxi-radius").value,ae=t.pstyle("radius-type").value[0]==="arc-radius";r.radii=new Array(r.segpts.length/2).fill(ne),r.isArcRadius=new Array(r.segpts.length/2).fill(ae)}};$a.tryToCorrectInvalidPoints=function(t,e){var r=t._private.rscratch;if(r.edgeType==="bezier"){var n=e.srcPos,i=e.tgtPos,a=e.srcW,s=e.srcH,l=e.tgtW,u=e.tgtH,h=e.srcShape,f=e.tgtShape,d=e.srcCornerRadius,p=e.tgtCornerRadius,m=e.srcRs,g=e.tgtRs,y=!ft(r.startX)||!ft(r.startY),v=!ft(r.arrowStartX)||!ft(r.arrowStartY),x=!ft(r.endX)||!ft(r.endY),b=!ft(r.arrowEndX)||!ft(r.arrowEndY),w=3,S=this.getArrowWidth(t.pstyle("width").pfValue,t.pstyle("arrow-scale").value)*this.arrowShapeWidth,T=w*S,E=H0({x:r.ctrlpts[0],y:r.ctrlpts[1]},{x:r.startX,y:r.startY}),_=EC.poolIndex()){var O=I;I=C,C=O}var D=L.srcPos=I.position(),P=L.tgtPos=C.position(),F=L.srcW=I.outerWidth(),B=L.srcH=I.outerHeight(),$=L.tgtW=C.outerWidth(),z=L.tgtH=C.outerHeight(),Y=L.srcShape=r.nodeShapes[e.getNodeShape(I)],Q=L.tgtShape=r.nodeShapes[e.getNodeShape(C)],X=L.srcCornerRadius=I.pstyle("corner-radius").value==="auto"?"auto":I.pstyle("corner-radius").pfValue,ie=L.tgtCornerRadius=C.pstyle("corner-radius").value==="auto"?"auto":C.pstyle("corner-radius").pfValue,j=L.tgtRs=C._private.rscratch,J=L.srcRs=I._private.rscratch;L.dirCounts={north:0,west:0,south:0,east:0,northwest:0,southwest:0,northeast:0,southeast:0};for(var Z=0;Z0){var se=a,ce=B0(se,Jg(r)),ue=B0(se,Jg(K)),te=ce;if(ue2){var De=B0(se,{x:K[2],y:K[3]});De0){var he=s,ne=B0(he,Jg(r)),ae=B0(he,Jg(re)),we=ne;if(ae2){var Te=B0(he,{x:re[2],y:re[3]});Te=g||_){v={cp:S,segment:E};break}}if(v)break}var A=v.cp,L=v.segment,M=(g-x)/L.length,N=L.t1-L.t0,k=m?L.t0+N*M:L.t1-N*M;k=Hx(0,k,1),e=t1(A.p0,A.p1,A.p2,k),p=fQe(A.p0,A.p1,A.p2,k);break}case"straight":case"segments":case"haystack":{for(var I=0,C,O,D,P,F=n.allpts.length,B=0;B+3=g));B+=2);var $=g-O,z=$/C;z=Hx(0,z,1),e=yWe(D,P,z),p=Gme(D,P);break}}s("labelX",d,e.x),s("labelY",d,e.y),s("labelAutoAngle",d,p)}},"calculateEndProjection");h("source"),h("target"),this.applyLabelDimensions(t)}};Hc.applyLabelDimensions=function(t){this.applyPrefixedLabelDimensions(t),t.isEdge()&&(this.applyPrefixedLabelDimensions(t,"source"),this.applyPrefixedLabelDimensions(t,"target"))};Hc.applyPrefixedLabelDimensions=function(t,e){var r=t._private,n=this.getLabelText(t,e),i=this.calculateLabelDimensions(t,n),a=t.pstyle("line-height").pfValue,s=t.pstyle("text-wrap").strValue,l=Ul(r.rscratch,"labelWrapCachedLines",e)||[],u=s!=="wrap"?1:Math.max(l.length,1),h=i.height/u,f=h*a,d=i.width,p=i.height+(u-1)*(a-1)*h;Tf(r.rstyle,"labelWidth",e,d),Tf(r.rscratch,"labelWidth",e,d),Tf(r.rstyle,"labelHeight",e,p),Tf(r.rscratch,"labelHeight",e,p),Tf(r.rscratch,"labelLineHeight",e,f)};Hc.getLabelText=function(t,e){var r=t._private,n=e?e+"-":"",i=t.pstyle(n+"label").strValue,a=t.pstyle("text-transform").value,s=o(function(Q,X){return X?(Tf(r.rscratch,Q,e,X),X):Ul(r.rscratch,Q,e)},"rscratch");if(!i)return"";a=="none"||(a=="uppercase"?i=i.toUpperCase():a=="lowercase"&&(i=i.toLowerCase()));var l=t.pstyle("text-wrap").value;if(l==="wrap"){var u=s("labelKey");if(u!=null&&s("labelWrapKey")===u)return s("labelWrapCachedText");for(var h="\u200B",f=i.split(` +`),d=t.pstyle("text-max-width").pfValue,p=t.pstyle("text-overflow-wrap").value,m=p==="anywhere",g=[],y=/[\s\u200b]+|$/g,v=0;vd){var T=x.matchAll(y),E="",_=0,A=Tpe(T),L;try{for(A.s();!(L=A.n()).done;){var M=L.value,N=M[0],k=x.substring(_,M.index);_=M.index+N.length;var I=E.length===0?k:E+k+N,C=this.calculateLabelDimensions(t,I),O=C.width;O<=d?E+=k+N:(E&&g.push(E),E=k+N)}}catch(Y){A.e(Y)}finally{A.f()}E.match(/^[\s\u200b]+$/)||g.push(E)}else g.push(x)}s("labelWrapCachedLines",g),i=s("labelWrapCachedText",g.join(` +`)),s("labelWrapKey",u)}else if(l==="ellipsis"){var D=t.pstyle("text-max-width").pfValue,P="",F="\u2026",B=!1;if(this.calculateLabelDimensions(t,i).widthD)break;P+=i[$],$===i.length-1&&(B=!0)}return B||(P+=F),P}return i};Hc.getLabelJustification=function(t){var e=t.pstyle("text-justification").strValue,r=t.pstyle("text-halign").strValue;if(e==="auto")if(t.isNode())switch(r){case"left":return"right";case"right":return"left";default:return"center"}else return"center";else return e};Hc.calculateLabelDimensions=function(t,e){var r=this,n=r.cy.window(),i=n.document,a=U0(e,t._private.labelDimsKey),s=r.labelDimCache||(r.labelDimCache=[]),l=s[a];if(l!=null)return l;var u=0,h=t.pstyle("font-style").strValue,f=t.pstyle("font-size").pfValue,d=t.pstyle("font-family").strValue,p=t.pstyle("font-weight").strValue,m=this.labelCalcCanvas,g=this.labelCalcCanvasContext;if(!m){m=this.labelCalcCanvas=i.createElement("canvas"),g=this.labelCalcCanvasContext=m.getContext("2d");var y=m.style;y.position="absolute",y.left="-9999px",y.top="-9999px",y.zIndex="-1",y.visibility="hidden",y.pointerEvents="none"}g.font="".concat(h," ").concat(p," ").concat(f,"px ").concat(d);for(var v=0,x=0,b=e.split(` +`),w=0;w1&&arguments[1]!==void 0?arguments[1]:!0;if(e.merge(s),l)for(var u=0;u=t.desktopTapThreshold2}var Je=i(W);ze&&(t.hoverData.tapholdCancelled=!0);var Ve=o(function(){var St=t.hoverData.dragDelta=t.hoverData.dragDelta||[];St.length===0?(St.push(ye[0]),St.push(ye[1])):(St[0]+=ye[0],St[1]+=ye[1])},"updateDragDelta");ge=!0,n(Ae,["mousemove","vmousemove","tapdrag"],W,{x:ae[0],y:ae[1]});var je=o(function(){t.data.bgActivePosistion=void 0,t.hoverData.selecting||re.emit({originalEvent:W,type:"boxstart",position:{x:ae[0],y:ae[1]}}),Ce[4]=1,t.hoverData.selecting=!0,t.redrawHint("select",!0),t.redraw()},"goIntoBoxMode");if(t.hoverData.which===3){if(ze){var kt={originalEvent:W,type:"cxtdrag",position:{x:ae[0],y:ae[1]}};Me?Me.emit(kt):re.emit(kt),t.hoverData.cxtDragged=!0,(!t.hoverData.cxtOver||Ae!==t.hoverData.cxtOver)&&(t.hoverData.cxtOver&&t.hoverData.cxtOver.emit({originalEvent:W,type:"cxtdragout",position:{x:ae[0],y:ae[1]}}),t.hoverData.cxtOver=Ae,Ae&&Ae.emit({originalEvent:W,type:"cxtdragover",position:{x:ae[0],y:ae[1]}}))}}else if(t.hoverData.dragging){if(ge=!0,re.panningEnabled()&&re.userPanningEnabled()){var at;if(t.hoverData.justStartedPan){var xt=t.hoverData.mdownPos;at={x:(ae[0]-xt[0])*he,y:(ae[1]-xt[1])*he},t.hoverData.justStartedPan=!1}else at={x:ye[0]*he,y:ye[1]*he};re.panBy(at),re.emit("dragpan"),t.hoverData.dragged=!0}ae=t.projectIntoViewport(W.clientX,W.clientY)}else if(Ce[4]==1&&(Me==null||Me.pannable())){if(ze){if(!t.hoverData.dragging&&re.boxSelectionEnabled()&&(Je||!re.panningEnabled()||!re.userPanningEnabled()))je();else if(!t.hoverData.selecting&&re.panningEnabled()&&re.userPanningEnabled()){var it=a(Me,t.hoverData.downs);it&&(t.hoverData.dragging=!0,t.hoverData.justStartedPan=!0,Ce[4]=0,t.data.bgActivePosistion=Jg(we),t.redrawHint("select",!0),t.redraw())}Me&&Me.pannable()&&Me.active()&&Me.unactivate()}}else{if(Me&&Me.pannable()&&Me.active()&&Me.unactivate(),(!Me||!Me.grabbed())&&Ae!=Ge&&(Ge&&n(Ge,["mouseout","tapdragout"],W,{x:ae[0],y:ae[1]}),Ae&&n(Ae,["mouseover","tapdragover"],W,{x:ae[0],y:ae[1]}),t.hoverData.last=Ae),Me)if(ze){if(re.boxSelectionEnabled()&&Je)Me&&Me.grabbed()&&(v(He),Me.emit("freeon"),He.emit("free"),t.dragData.didDrag&&(Me.emit("dragfreeon"),He.emit("dragfree"))),je();else if(Me&&Me.grabbed()&&t.nodeIsDraggable(Me)){var dt=!t.dragData.didDrag;dt&&t.redrawHint("eles",!0),t.dragData.didDrag=!0,t.hoverData.draggingEles||g(He,{inDragLayer:!0});var lt={x:0,y:0};if(ft(ye[0])&&ft(ye[1])&&(lt.x+=ye[0],lt.y+=ye[1],dt)){var It=t.hoverData.dragDelta;It&&ft(It[0])&&ft(It[1])&&(lt.x+=It[0],lt.y+=It[1])}t.hoverData.draggingEles=!0,He.silentShift(lt).emit("position drag"),t.redrawHint("drag",!0),t.redraw()}}else Ve();ge=!0}if(Ce[2]=ae[0],Ce[3]=ae[1],ge)return W.stopPropagation&&W.stopPropagation(),W.preventDefault&&W.preventDefault(),!1}},"mousemoveHandler"),!1);var M,N,k;t.registerBinding(e,"mouseup",o(function(W){if(!(t.hoverData.which===1&&W.which!==1&&t.hoverData.capture)){var fe=t.hoverData.capture;if(fe){t.hoverData.capture=!1;var ge=t.cy,re=t.projectIntoViewport(W.clientX,W.clientY),he=t.selection,ne=t.findNearestElement(re[0],re[1],!0,!1),ae=t.dragData.possibleDragElements,we=t.hoverData.down,Te=i(W);if(t.data.bgActivePosistion&&(t.redrawHint("select",!0),t.redraw()),t.hoverData.tapholdCancelled=!0,t.data.bgActivePosistion=void 0,we&&we.unactivate(),t.hoverData.which===3){var Ce={originalEvent:W,type:"cxttapend",position:{x:re[0],y:re[1]}};if(we?we.emit(Ce):ge.emit(Ce),!t.hoverData.cxtDragged){var Ae={originalEvent:W,type:"cxttap",position:{x:re[0],y:re[1]}};we?we.emit(Ae):ge.emit(Ae)}t.hoverData.cxtDragged=!1,t.hoverData.which=null}else if(t.hoverData.which===1){if(n(ne,["mouseup","tapend","vmouseup"],W,{x:re[0],y:re[1]}),!t.dragData.didDrag&&!t.hoverData.dragged&&!t.hoverData.selecting&&!t.hoverData.isOverThresholdDrag&&(n(we,["click","tap","vclick"],W,{x:re[0],y:re[1]}),N=!1,W.timeStamp-k<=ge.multiClickDebounceTime()?(M&&clearTimeout(M),N=!0,k=null,n(we,["dblclick","dbltap","vdblclick"],W,{x:re[0],y:re[1]})):(M=setTimeout(function(){N||n(we,["oneclick","onetap","voneclick"],W,{x:re[0],y:re[1]})},ge.multiClickDebounceTime()),k=W.timeStamp)),we==null&&!t.dragData.didDrag&&!t.hoverData.selecting&&!t.hoverData.dragged&&!i(W)&&(ge.$(r).unselect(["tapunselect"]),ae.length>0&&t.redrawHint("eles",!0),t.dragData.possibleDragElements=ae=ge.collection()),ne==we&&!t.dragData.didDrag&&!t.hoverData.selecting&&ne!=null&&ne._private.selectable&&(t.hoverData.dragging||(ge.selectionType()==="additive"||Te?ne.selected()?ne.unselect(["tapunselect"]):ne.select(["tapselect"]):Te||(ge.$(r).unmerge(ne).unselect(["tapunselect"]),ne.select(["tapselect"]))),t.redrawHint("eles",!0)),t.hoverData.selecting){var Ge=ge.collection(t.getAllInBox(he[0],he[1],he[2],he[3]));t.redrawHint("select",!0),Ge.length>0&&t.redrawHint("eles",!0),ge.emit({type:"boxend",originalEvent:W,position:{x:re[0],y:re[1]}});var Me=o(function(ze){return ze.selectable()&&!ze.selected()},"eleWouldBeSelected");ge.selectionType()==="additive"||Te||ge.$(r).unmerge(Ge).unselect(),Ge.emit("box").stdFilter(Me).select().emit("boxselect"),t.redraw()}if(t.hoverData.dragging&&(t.hoverData.dragging=!1,t.redrawHint("select",!0),t.redrawHint("eles",!0),t.redraw()),!he[4]){t.redrawHint("drag",!0),t.redrawHint("eles",!0);var ye=we&&we.grabbed();v(ae),ye&&(we.emit("freeon"),ae.emit("free"),t.dragData.didDrag&&(we.emit("dragfreeon"),ae.emit("dragfree")))}}he[4]=0,t.hoverData.down=null,t.hoverData.cxtStarted=!1,t.hoverData.draggingEles=!1,t.hoverData.selecting=!1,t.hoverData.isOverThresholdDrag=!1,t.dragData.didDrag=!1,t.hoverData.dragged=!1,t.hoverData.dragDelta=[],t.hoverData.mdownPos=null,t.hoverData.mdownGPos=null}}},"mouseupHandler"),!1);var I=o(function(W){if(!t.scrollingPage){var fe=t.cy,ge=fe.zoom(),re=fe.pan(),he=t.projectIntoViewport(W.clientX,W.clientY),ne=[he[0]*ge+re.x,he[1]*ge+re.y];if(t.hoverData.draggingEles||t.hoverData.dragging||t.hoverData.cxtStarted||A()){W.preventDefault();return}if(fe.panningEnabled()&&fe.userPanningEnabled()&&fe.zoomingEnabled()&&fe.userZoomingEnabled()){W.preventDefault(),t.data.wheelZooming=!0,clearTimeout(t.data.wheelTimeout),t.data.wheelTimeout=setTimeout(function(){t.data.wheelZooming=!1,t.redrawHint("eles",!0),t.redraw()},150);var ae;W.deltaY!=null?ae=W.deltaY/-250:W.wheelDeltaY!=null?ae=W.wheelDeltaY/1e3:ae=W.wheelDelta/1e3,ae=ae*t.wheelSensitivity;var we=W.deltaMode===1;we&&(ae*=33);var Te=fe.zoom()*Math.pow(10,ae);W.type==="gesturechange"&&(Te=t.gestureStartZoom*W.scale),fe.zoom({level:Te,renderedPosition:{x:ne[0],y:ne[1]}}),fe.emit(W.type==="gesturechange"?"pinchzoom":"scrollzoom")}}},"wheelHandler");t.registerBinding(t.container,"wheel",I,!0),t.registerBinding(e,"scroll",o(function(W){t.scrollingPage=!0,clearTimeout(t.scrollingPageTimeout),t.scrollingPageTimeout=setTimeout(function(){t.scrollingPage=!1},250)},"scrollHandler"),!0),t.registerBinding(t.container,"gesturestart",o(function(W){t.gestureStartZoom=t.cy.zoom(),t.hasTouchStarted||W.preventDefault()},"gestureStartHandler"),!0),t.registerBinding(t.container,"gesturechange",function(me){t.hasTouchStarted||I(me)},!0),t.registerBinding(t.container,"mouseout",o(function(W){var fe=t.projectIntoViewport(W.clientX,W.clientY);t.cy.emit({originalEvent:W,type:"mouseout",position:{x:fe[0],y:fe[1]}})},"mouseOutHandler"),!1),t.registerBinding(t.container,"mouseover",o(function(W){var fe=t.projectIntoViewport(W.clientX,W.clientY);t.cy.emit({originalEvent:W,type:"mouseover",position:{x:fe[0],y:fe[1]}})},"mouseOverHandler"),!1);var C,O,D,P,F,B,$,z,Y,Q,X,ie,j,J=o(function(W,fe,ge,re){return Math.sqrt((ge-W)*(ge-W)+(re-fe)*(re-fe))},"distance"),Z=o(function(W,fe,ge,re){return(ge-W)*(ge-W)+(re-fe)*(re-fe)},"distanceSq"),H;t.registerBinding(t.container,"touchstart",H=o(function(W){if(t.hasTouchStarted=!0,!!L(W)){b(),t.touchData.capture=!0,t.data.bgActivePosistion=void 0;var fe=t.cy,ge=t.touchData.now,re=t.touchData.earlier;if(W.touches[0]){var he=t.projectIntoViewport(W.touches[0].clientX,W.touches[0].clientY);ge[0]=he[0],ge[1]=he[1]}if(W.touches[1]){var he=t.projectIntoViewport(W.touches[1].clientX,W.touches[1].clientY);ge[2]=he[0],ge[3]=he[1]}if(W.touches[2]){var he=t.projectIntoViewport(W.touches[2].clientX,W.touches[2].clientY);ge[4]=he[0],ge[5]=he[1]}if(W.touches[1]){t.touchData.singleTouchMoved=!0,v(t.dragData.touchDragEles);var ne=t.findContainerClientCoords();Y=ne[0],Q=ne[1],X=ne[2],ie=ne[3],C=W.touches[0].clientX-Y,O=W.touches[0].clientY-Q,D=W.touches[1].clientX-Y,P=W.touches[1].clientY-Q,j=0<=C&&C<=X&&0<=D&&D<=X&&0<=O&&O<=ie&&0<=P&&P<=ie;var ae=fe.pan(),we=fe.zoom();F=J(C,O,D,P),B=Z(C,O,D,P),$=[(C+D)/2,(O+P)/2],z=[($[0]-ae.x)/we,($[1]-ae.y)/we];var Te=200,Ce=Te*Te;if(B=1){for(var gt=t.touchData.startPosition=[null,null,null,null,null,null],yt=0;yt=t.touchTapThreshold2}if(fe&&t.touchData.cxt){W.preventDefault();var gt=W.touches[0].clientX-Y,yt=W.touches[0].clientY-Q,tt=W.touches[1].clientX-Y,Ye=W.touches[1].clientY-Q,Je=Z(gt,yt,tt,Ye),Ve=Je/B,je=150,kt=je*je,at=1.5,xt=at*at;if(Ve>=xt||Je>=kt){t.touchData.cxt=!1,t.data.bgActivePosistion=void 0,t.redrawHint("select",!0);var it={originalEvent:W,type:"cxttapend",position:{x:he[0],y:he[1]}};t.touchData.start?(t.touchData.start.unactivate().emit(it),t.touchData.start=null):re.emit(it)}}if(fe&&t.touchData.cxt){var it={originalEvent:W,type:"cxtdrag",position:{x:he[0],y:he[1]}};t.data.bgActivePosistion=void 0,t.redrawHint("select",!0),t.touchData.start?t.touchData.start.emit(it):re.emit(it),t.touchData.start&&(t.touchData.start._private.grabbed=!1),t.touchData.cxtDragged=!0;var dt=t.findNearestElement(he[0],he[1],!0,!0);(!t.touchData.cxtOver||dt!==t.touchData.cxtOver)&&(t.touchData.cxtOver&&t.touchData.cxtOver.emit({originalEvent:W,type:"cxtdragout",position:{x:he[0],y:he[1]}}),t.touchData.cxtOver=dt,dt&&dt.emit({originalEvent:W,type:"cxtdragover",position:{x:he[0],y:he[1]}}))}else if(fe&&W.touches[2]&&re.boxSelectionEnabled())W.preventDefault(),t.data.bgActivePosistion=void 0,this.lastThreeTouch=+new Date,t.touchData.selecting||re.emit({originalEvent:W,type:"boxstart",position:{x:he[0],y:he[1]}}),t.touchData.selecting=!0,t.touchData.didSelect=!0,ge[4]=1,!ge||ge.length===0||ge[0]===void 0?(ge[0]=(he[0]+he[2]+he[4])/3,ge[1]=(he[1]+he[3]+he[5])/3,ge[2]=(he[0]+he[2]+he[4])/3+1,ge[3]=(he[1]+he[3]+he[5])/3+1):(ge[2]=(he[0]+he[2]+he[4])/3,ge[3]=(he[1]+he[3]+he[5])/3),t.redrawHint("select",!0),t.redraw();else if(fe&&W.touches[1]&&!t.touchData.didSelect&&re.zoomingEnabled()&&re.panningEnabled()&&re.userZoomingEnabled()&&re.userPanningEnabled()){W.preventDefault(),t.data.bgActivePosistion=void 0,t.redrawHint("select",!0);var lt=t.dragData.touchDragEles;if(lt){t.redrawHint("drag",!0);for(var It=0;It0&&!t.hoverData.draggingEles&&!t.swipePanning&&t.data.bgActivePosistion!=null&&(t.data.bgActivePosistion=void 0,t.redrawHint("select",!0),t.redraw())}},"touchmoveHandler"),!1);var K;t.registerBinding(e,"touchcancel",K=o(function(W){var fe=t.touchData.start;t.touchData.capture=!1,fe&&fe.unactivate()},"touchcancelHandler"));var se,ce,ue,te;if(t.registerBinding(e,"touchend",se=o(function(W){var fe=t.touchData.start,ge=t.touchData.capture;if(ge)W.touches.length===0&&(t.touchData.capture=!1),W.preventDefault();else return;var re=t.selection;t.swipePanning=!1,t.hoverData.draggingEles=!1;var he=t.cy,ne=he.zoom(),ae=t.touchData.now,we=t.touchData.earlier;if(W.touches[0]){var Te=t.projectIntoViewport(W.touches[0].clientX,W.touches[0].clientY);ae[0]=Te[0],ae[1]=Te[1]}if(W.touches[1]){var Te=t.projectIntoViewport(W.touches[1].clientX,W.touches[1].clientY);ae[2]=Te[0],ae[3]=Te[1]}if(W.touches[2]){var Te=t.projectIntoViewport(W.touches[2].clientX,W.touches[2].clientY);ae[4]=Te[0],ae[5]=Te[1]}fe&&fe.unactivate();var Ce;if(t.touchData.cxt){if(Ce={originalEvent:W,type:"cxttapend",position:{x:ae[0],y:ae[1]}},fe?fe.emit(Ce):he.emit(Ce),!t.touchData.cxtDragged){var Ae={originalEvent:W,type:"cxttap",position:{x:ae[0],y:ae[1]}};fe?fe.emit(Ae):he.emit(Ae)}t.touchData.start&&(t.touchData.start._private.grabbed=!1),t.touchData.cxt=!1,t.touchData.start=null,t.redraw();return}if(!W.touches[2]&&he.boxSelectionEnabled()&&t.touchData.selecting){t.touchData.selecting=!1;var Ge=he.collection(t.getAllInBox(re[0],re[1],re[2],re[3]));re[0]=void 0,re[1]=void 0,re[2]=void 0,re[3]=void 0,re[4]=0,t.redrawHint("select",!0),he.emit({type:"boxend",originalEvent:W,position:{x:ae[0],y:ae[1]}});var Me=o(function(kt){return kt.selectable()&&!kt.selected()},"eleWouldBeSelected");Ge.emit("box").stdFilter(Me).select().emit("boxselect"),Ge.nonempty()&&t.redrawHint("eles",!0),t.redraw()}if(fe?.unactivate(),W.touches[2])t.data.bgActivePosistion=void 0,t.redrawHint("select",!0);else if(!W.touches[1]){if(!W.touches[0]){if(!W.touches[0]){t.data.bgActivePosistion=void 0,t.redrawHint("select",!0);var ye=t.dragData.touchDragEles;if(fe!=null){var He=fe._private.grabbed;v(ye),t.redrawHint("drag",!0),t.redrawHint("eles",!0),He&&(fe.emit("freeon"),ye.emit("free"),t.dragData.didDrag&&(fe.emit("dragfreeon"),ye.emit("dragfree"))),n(fe,["touchend","tapend","vmouseup","tapdragout"],W,{x:ae[0],y:ae[1]}),fe.unactivate(),t.touchData.start=null}else{var ze=t.findNearestElement(ae[0],ae[1],!0,!0);n(ze,["touchend","tapend","vmouseup","tapdragout"],W,{x:ae[0],y:ae[1]})}var Ze=t.touchData.startPosition[0]-ae[0],gt=Ze*Ze,yt=t.touchData.startPosition[1]-ae[1],tt=yt*yt,Ye=gt+tt,Je=Ye*ne*ne;t.touchData.singleTouchMoved||(fe||he.$(":selected").unselect(["tapunselect"]),n(fe,["tap","vclick"],W,{x:ae[0],y:ae[1]}),ce=!1,W.timeStamp-te<=he.multiClickDebounceTime()?(ue&&clearTimeout(ue),ce=!0,te=null,n(fe,["dbltap","vdblclick"],W,{x:ae[0],y:ae[1]})):(ue=setTimeout(function(){ce||n(fe,["onetap","voneclick"],W,{x:ae[0],y:ae[1]})},he.multiClickDebounceTime()),te=W.timeStamp)),fe!=null&&!t.dragData.didDrag&&fe._private.selectable&&Je"u"){var De=[],oe=o(function(W){return{clientX:W.clientX,clientY:W.clientY,force:1,identifier:W.pointerId,pageX:W.pageX,pageY:W.pageY,radiusX:W.width/2,radiusY:W.height/2,screenX:W.screenX,screenY:W.screenY,target:W.target}},"makeTouch"),ke=o(function(W){return{event:W,touch:oe(W)}},"makePointer"),Ie=o(function(W){De.push(ke(W))},"addPointer"),Se=o(function(W){for(var fe=0;fe0)return Y[0]}return null},"getCurveT"),g=Object.keys(p),y=0;y0?m:Hpe(a,s,e,r,n,i,l,u)},"intersectLine"),checkPoint:o(function(e,r,n,i,a,s,l,u){u=u==="auto"?Y0(i,a):u;var h=2*u;if(Qu(e,r,this.points,s,l,i,a-h,[0,-1],n)||Qu(e,r,this.points,s,l,i-h,a,[0,-1],n))return!0;var f=i/2+2*n,d=a/2+2*n,p=[s-f,l-d,s-f,l,s+f,l,s+f,l-d];return!!(zs(e,r,p)||$0(e,r,h,h,s+i/2-u,l+a/2-u,n)||$0(e,r,h,h,s-i/2+u,l+a/2-u,n))},"checkPoint")}};Ju.registerNodeShapes=function(){var t=this.nodeShapes={},e=this;this.generateEllipse(),this.generatePolygon("triangle",ls(3,0)),this.generateRoundPolygon("round-triangle",ls(3,0)),this.generatePolygon("rectangle",ls(4,0)),t.square=t.rectangle,this.generateRoundRectangle(),this.generateCutRectangle(),this.generateBarrel(),this.generateBottomRoundrectangle();{var r=[0,1,1,0,0,-1,-1,0];this.generatePolygon("diamond",r),this.generateRoundPolygon("round-diamond",r)}this.generatePolygon("pentagon",ls(5,0)),this.generateRoundPolygon("round-pentagon",ls(5,0)),this.generatePolygon("hexagon",ls(6,0)),this.generateRoundPolygon("round-hexagon",ls(6,0)),this.generatePolygon("heptagon",ls(7,0)),this.generateRoundPolygon("round-heptagon",ls(7,0)),this.generatePolygon("octagon",ls(8,0)),this.generateRoundPolygon("round-octagon",ls(8,0));var n=new Array(20);{var i=NP(5,0),a=NP(5,Math.PI/5),s=.5*(3-Math.sqrt(5));s*=1.57;for(var l=0;l=e.deqFastCost*S)break}else if(h){if(b>=e.deqCost*m||b>=e.deqAvgCost*p)break}else if(w>=e.deqNoDrawCost*LP)break;var T=e.deq(n,v,y);if(T.length>0)for(var E=0;E0&&(e.onDeqd(n,g),!h&&e.shouldRedraw(n,g,v,y)&&a())},"dequeue"),l=e.priority||JP;i.beforeRender(s,l(n))}},"setupDequeueingImpl")},"setupDequeueing")},pQe=function(){function t(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:C6;XP(this,t),this.idsByKey=new Vc,this.keyForId=new Vc,this.cachesByLvl=new Vc,this.lvls=[],this.getKey=e,this.doesEleInvalidateKey=r}return o(t,"ElementTextureCacheLookup"),jP(t,[{key:"getIdsFor",value:o(function(r){r==null&&oi("Can not get id list for null key");var n=this.idsByKey,i=this.idsByKey.get(r);return i||(i=new c1,n.set(r,i)),i},"getIdsFor")},{key:"addIdForKey",value:o(function(r,n){r!=null&&this.getIdsFor(r).add(n)},"addIdForKey")},{key:"deleteIdForKey",value:o(function(r,n){r!=null&&this.getIdsFor(r).delete(n)},"deleteIdForKey")},{key:"getNumberOfIdsForKey",value:o(function(r){return r==null?0:this.getIdsFor(r).size},"getNumberOfIdsForKey")},{key:"updateKeyMappingFor",value:o(function(r){var n=r.id(),i=this.keyForId.get(n),a=this.getKey(r);this.deleteIdForKey(i,n),this.addIdForKey(a,n),this.keyForId.set(n,a)},"updateKeyMappingFor")},{key:"deleteKeyMappingFor",value:o(function(r){var n=r.id(),i=this.keyForId.get(n);this.deleteIdForKey(i,n),this.keyForId.delete(n)},"deleteKeyMappingFor")},{key:"keyHasChangedFor",value:o(function(r){var n=r.id(),i=this.keyForId.get(n),a=this.getKey(r);return i!==a},"keyHasChangedFor")},{key:"isInvalid",value:o(function(r){return this.keyHasChangedFor(r)||this.doesEleInvalidateKey(r)},"isInvalid")},{key:"getCachesAt",value:o(function(r){var n=this.cachesByLvl,i=this.lvls,a=n.get(r);return a||(a=new Vc,n.set(r,a),i.push(r)),a},"getCachesAt")},{key:"getCache",value:o(function(r,n){return this.getCachesAt(n).get(r)},"getCache")},{key:"get",value:o(function(r,n){var i=this.getKey(r),a=this.getCache(i,n);return a!=null&&this.updateKeyMappingFor(r),a},"get")},{key:"getForCachedKey",value:o(function(r,n){var i=this.keyForId.get(r.id()),a=this.getCache(i,n);return a},"getForCachedKey")},{key:"hasCache",value:o(function(r,n){return this.getCachesAt(n).has(r)},"hasCache")},{key:"has",value:o(function(r,n){var i=this.getKey(r);return this.hasCache(i,n)},"has")},{key:"setCache",value:o(function(r,n,i){i.key=r,this.getCachesAt(n).set(r,i)},"setCache")},{key:"set",value:o(function(r,n,i){var a=this.getKey(r);this.setCache(a,n,i),this.updateKeyMappingFor(r)},"set")},{key:"deleteCache",value:o(function(r,n){this.getCachesAt(n).delete(r)},"deleteCache")},{key:"delete",value:o(function(r,n){var i=this.getKey(r);this.deleteCache(i,n)},"_delete")},{key:"invalidateKey",value:o(function(r){var n=this;this.lvls.forEach(function(i){return n.deleteCache(r,i)})},"invalidateKey")},{key:"invalidate",value:o(function(r){var n=r.id(),i=this.keyForId.get(n);this.deleteKeyMappingFor(r);var a=this.doesEleInvalidateKey(r);return a&&this.invalidateKey(i),a||this.getNumberOfIdsForKey(i)===0},"invalidate")}]),t}(),fpe=25,d6=50,T6=-4,HP=3,mQe=7.99,gQe=8,yQe=1024,vQe=1024,xQe=1024,bQe=.2,wQe=.8,TQe=10,kQe=.15,EQe=.1,CQe=.9,SQe=.9,AQe=100,_Qe=1,e1={dequeue:"dequeue",downscale:"downscale",highQuality:"highQuality"},LQe=Sa({getKey:null,doesEleInvalidateKey:C6,drawElement:null,getBoundingBox:null,getRotationPoint:null,getRotationOffset:null,isVisible:Ppe,allowEdgeTxrCaching:!0,allowParentTxrCaching:!0}),Bx=o(function(e,r){var n=this;n.renderer=e,n.onDequeues=[];var i=LQe(r);Wt(n,i),n.lookup=new pQe(i.getKey,i.doesEleInvalidateKey),n.setupDequeueing()},"ElementTextureCache"),Yi=Bx.prototype;Yi.reasons=e1;Yi.getTextureQueue=function(t){var e=this;return e.eleImgCaches=e.eleImgCaches||{},e.eleImgCaches[t]=e.eleImgCaches[t]||[]};Yi.getRetiredTextureQueue=function(t){var e=this,r=e.eleImgCaches.retired=e.eleImgCaches.retired||{},n=r[t]=r[t]||[];return n};Yi.getElementQueue=function(){var t=this,e=t.eleCacheQueue=t.eleCacheQueue||new eb(function(r,n){return n.reqs-r.reqs});return e};Yi.getElementKeyToQueue=function(){var t=this,e=t.eleKeyToCacheQueue=t.eleKeyToCacheQueue||{};return e};Yi.getElement=function(t,e,r,n,i){var a=this,s=this.renderer,l=s.cy.zoom(),u=this.lookup;if(!e||e.w===0||e.h===0||isNaN(e.w)||isNaN(e.h)||!t.visible()||t.removed()||!a.allowEdgeTxrCaching&&t.isEdge()||!a.allowParentTxrCaching&&t.isParent())return null;if(n==null&&(n=Math.ceil(tB(l*r))),n=mQe||n>HP)return null;var h=Math.pow(2,n),f=e.h*h,d=e.w*h,p=s.eleTextBiggerThanMin(t,h);if(!this.isVisible(t,p))return null;var m=u.get(t,n);if(m&&m.invalidated&&(m.invalidated=!1,m.texture.invalidatedWidth-=m.width),m)return m;var g;if(f<=fpe?g=fpe:f<=d6?g=d6:g=Math.ceil(f/d6)*d6,f>xQe||d>vQe)return null;var y=a.getTextureQueue(g),v=y[y.length-2],x=o(function(){return a.recycleTexture(g,d)||a.addTexture(g,d)},"addNewTxr");v||(v=y[y.length-1]),v||(v=x()),v.width-v.usedWidthn;N--)L=a.getElement(t,e,r,N,e1.downscale);M()}else return a.queueElement(t,E.level-1),E;else{var k;if(!w&&!S&&!T)for(var I=n-1;I>=T6;I--){var C=u.get(t,I);if(C){k=C;break}}if(b(k))return a.queueElement(t,n),k;v.context.translate(v.usedWidth,0),v.context.scale(h,h),this.drawElement(v.context,t,e,p,!1),v.context.scale(1/h,1/h),v.context.translate(-v.usedWidth,0)}return m={x:v.usedWidth,texture:v,level:n,scale:h,width:d,height:f,scaledLabelShown:p},v.usedWidth+=Math.ceil(d+gQe),v.eleCaches.push(m),u.set(t,n,m),a.checkTextureFullness(v),m};Yi.invalidateElements=function(t){for(var e=0;e=bQe*t.width&&this.retireTexture(t)};Yi.checkTextureFullness=function(t){var e=this,r=e.getTextureQueue(t.height);t.usedWidth/t.width>wQe&&t.fullnessChecks>=TQe?Af(r,t):t.fullnessChecks++};Yi.retireTexture=function(t){var e=this,r=t.height,n=e.getTextureQueue(r),i=this.lookup;Af(n,t),t.retired=!0;for(var a=t.eleCaches,s=0;s=e)return s.retired=!1,s.usedWidth=0,s.invalidatedWidth=0,s.fullnessChecks=0,eB(s.eleCaches),s.context.setTransform(1,0,0,1,0,0),s.context.clearRect(0,0,s.width,s.height),Af(i,s),n.push(s),s}};Yi.queueElement=function(t,e){var r=this,n=r.getElementQueue(),i=r.getElementKeyToQueue(),a=this.getKey(t),s=i[a];if(s)s.level=Math.max(s.level,e),s.eles.merge(t),s.reqs++,n.updateItem(s);else{var l={eles:t.spawn().merge(t),level:e,reqs:1,key:a};n.push(l),i[a]=l}};Yi.dequeue=function(t){for(var e=this,r=e.getElementQueue(),n=e.getElementKeyToQueue(),i=[],a=e.lookup,s=0;s<_Qe&&r.size()>0;s++){var l=r.pop(),u=l.key,h=l.eles[0],f=a.hasCache(h,l.level);if(n[u]=null,f)continue;i.push(l);var d=e.getBoundingBox(h);e.getElement(h,d,t,l.level,e1.dequeue)}return i};Yi.removeFromQueue=function(t){var e=this,r=e.getElementQueue(),n=e.getElementKeyToQueue(),i=this.getKey(t),a=n[i];a!=null&&(a.eles.length===1?(a.reqs=ZP,r.updateItem(a),r.pop(),n[i]=null):a.eles.unmerge(t))};Yi.onDequeue=function(t){this.onDequeues.push(t)};Yi.offDequeue=function(t){Af(this.onDequeues,t)};Yi.setupDequeueing=Yme.setupDequeueing({deqRedrawThreshold:AQe,deqCost:kQe,deqAvgCost:EQe,deqNoDrawCost:CQe,deqFastCost:SQe,deq:o(function(e,r,n){return e.dequeue(r,n)},"deq"),onDeqd:o(function(e,r){for(var n=0;n=RQe||r>M6)return null}n.validateLayersElesOrdering(r,t);var u=n.layersByLevel,h=Math.pow(2,r),f=u[r]=u[r]||[],d,p=n.levelIsComplete(r,t),m,g=o(function(){var M=o(function(O){if(n.validateLayersElesOrdering(O,t),n.levelIsComplete(O,t))return m=u[O],!0},"canUseAsTmpLvl"),N=o(function(O){if(!m)for(var D=r+O;zx<=D&&D<=M6&&!M(D);D+=O);},"checkLvls");N(1),N(-1);for(var k=f.length-1;k>=0;k--){var I=f[k];I.invalid&&Af(f,I)}},"checkTempLevels");if(!p)g();else return f;var y=o(function(){if(!d){d=Gs();for(var M=0;MzQe)return null;var I=n.makeLayer(d,r);if(N!=null){var C=f.indexOf(N)+1;f.splice(C,0,I)}else(M.insert===void 0||M.insert)&&f.unshift(I);return I},"makeLayer");if(n.skipping&&!l)return null;for(var x=null,b=t.length/DQe,w=!l,S=0;S=b||!Upe(x.bb,T.boundingBox()))&&(x=v({insert:!0,after:x}),!x))return null;m||w?n.queueLayer(x,T):n.drawEleInLayer(x,T,r,e),x.eles.push(T),_[r]=x}return m||(w?null:f)};Aa.getEleLevelForLayerLevel=function(t,e){return t};Aa.drawEleInLayer=function(t,e,r,n){var i=this,a=this.renderer,s=t.context,l=e.boundingBox();l.w===0||l.h===0||!e.visible()||(r=i.getEleLevelForLayerLevel(r,n),a.setImgSmoothing(s,!1),a.drawCachedElement(s,e,null,null,r,GQe),a.setImgSmoothing(s,!0))};Aa.levelIsComplete=function(t,e){var r=this,n=r.layersByLevel[t];if(!n||n.length===0)return!1;for(var i=0,a=0;a0||s.invalid)return!1;i+=s.eles.length}return i===e.length};Aa.validateLayersElesOrdering=function(t,e){var r=this.layersByLevel[t];if(r)for(var n=0;n0){e=!0;break}}return e};Aa.invalidateElements=function(t){var e=this;t.length!==0&&(e.lastInvalidationTime=Ku(),!(t.length===0||!e.haveLayers())&&e.updateElementsInLayers(t,o(function(n,i,a){e.invalidateLayer(n)},"invalAssocLayers")))};Aa.invalidateLayer=function(t){if(this.lastInvalidationTime=Ku(),!t.invalid){var e=t.level,r=t.eles,n=this.layersByLevel[e];Af(n,t),t.elesQueue=[],t.invalid=!0,t.replacement&&(t.replacement.invalid=!0);for(var i=0;i3&&arguments[3]!==void 0?arguments[3]:!0,i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:!0,s=this,l=e._private.rscratch;if(!(a&&!e.visible())&&!(l.badLine||l.allpts==null||isNaN(l.allpts[0]))){var u;r&&(u=r,t.translate(-u.x1,-u.y1));var h=a?e.pstyle("opacity").value:1,f=a?e.pstyle("line-opacity").value:1,d=e.pstyle("curve-style").value,p=e.pstyle("line-style").value,m=e.pstyle("width").pfValue,g=e.pstyle("line-cap").value,y=e.pstyle("line-outline-width").value,v=e.pstyle("line-outline-color").value,x=h*f,b=h*f,w=o(function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:x;d==="straight-triangle"?(s.eleStrokeStyle(t,e,O),s.drawEdgeTrianglePath(e,t,l.allpts)):(t.lineWidth=m,t.lineCap=g,s.eleStrokeStyle(t,e,O),s.drawEdgePath(e,t,l.allpts,p),t.lineCap="butt")},"drawLine"),S=o(function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:x;if(t.lineWidth=m+y,t.lineCap=g,y>0)s.colorStrokeStyle(t,v[0],v[1],v[2],O);else{t.lineCap="butt";return}d==="straight-triangle"?s.drawEdgeTrianglePath(e,t,l.allpts):(s.drawEdgePath(e,t,l.allpts,p),t.lineCap="butt")},"drawLineOutline"),T=o(function(){i&&s.drawEdgeOverlay(t,e)},"drawOverlay"),E=o(function(){i&&s.drawEdgeUnderlay(t,e)},"drawUnderlay"),_=o(function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:b;s.drawArrowheads(t,e,O)},"drawArrows"),A=o(function(){s.drawElementText(t,e,null,n)},"drawText");t.lineJoin="round";var L=e.pstyle("ghost").value==="yes";if(L){var M=e.pstyle("ghost-offset-x").pfValue,N=e.pstyle("ghost-offset-y").pfValue,k=e.pstyle("ghost-opacity").value,I=x*k;t.translate(M,N),w(I),_(I),t.translate(-M,-N)}else S();E(),w(),_(),T(),A(),r&&t.translate(u.x1,u.y1)}};Xme=o(function(e){if(!["overlay","underlay"].includes(e))throw new Error("Invalid state");return function(r,n){if(n.visible()){var i=n.pstyle("".concat(e,"-opacity")).value;if(i!==0){var a=this,s=a.usePaths(),l=n._private.rscratch,u=n.pstyle("".concat(e,"-padding")).pfValue,h=2*u,f=n.pstyle("".concat(e,"-color")).value;r.lineWidth=h,l.edgeType==="self"&&!s?r.lineCap="butt":r.lineCap="round",a.colorStrokeStyle(r,f[0],f[1],f[2],i),a.drawEdgePath(n,r,l.allpts,"solid")}}}},"drawEdgeOverlayUnderlay");eh.drawEdgeOverlay=Xme("overlay");eh.drawEdgeUnderlay=Xme("underlay");eh.drawEdgePath=function(t,e,r,n){var i=t._private.rscratch,a=e,s,l=!1,u=this.usePaths(),h=t.pstyle("line-dash-pattern").pfValue,f=t.pstyle("line-dash-offset").pfValue;if(u){var d=r.join("$"),p=i.pathCacheKey&&i.pathCacheKey===d;p?(s=e=i.pathCache,l=!0):(s=e=new Path2D,i.pathCacheKey=d,i.pathCache=s)}if(a.setLineDash)switch(n){case"dotted":a.setLineDash([1,1]);break;case"dashed":a.setLineDash(h),a.lineDashOffset=f;break;case"solid":a.setLineDash([]);break}if(!l&&!i.badLine)switch(e.beginPath&&e.beginPath(),e.moveTo(r[0],r[1]),i.edgeType){case"bezier":case"self":case"compound":case"multibezier":for(var m=2;m+35&&arguments[5]!==void 0?arguments[5]:!0,s=this;if(n==null){if(a&&!s.eleTextBiggerThanMin(e))return}else if(n===!1)return;if(e.isNode()){var l=e.pstyle("label");if(!l||!l.value)return;var u=s.getLabelJustification(e);t.textAlign=u,t.textBaseline="bottom"}else{var h=e.element()._private.rscratch.badLine,f=e.pstyle("label"),d=e.pstyle("source-label"),p=e.pstyle("target-label");if(h||(!f||!f.value)&&(!d||!d.value)&&(!p||!p.value))return;t.textAlign="center",t.textBaseline="bottom"}var m=!r,g;r&&(g=r,t.translate(-g.x1,-g.y1)),i==null?(s.drawText(t,e,null,m,a),e.isEdge()&&(s.drawText(t,e,"source",m,a),s.drawText(t,e,"target",m,a))):s.drawText(t,e,i,m,a),r&&t.translate(g.x1,g.y1)};K0.getFontCache=function(t){var e;this.fontCaches=this.fontCaches||[];for(var r=0;r2&&arguments[2]!==void 0?arguments[2]:!0,n=e.pstyle("font-style").strValue,i=e.pstyle("font-size").pfValue+"px",a=e.pstyle("font-family").strValue,s=e.pstyle("font-weight").strValue,l=r?e.effectiveOpacity()*e.pstyle("text-opacity").value:1,u=e.pstyle("text-outline-opacity").value*l,h=e.pstyle("color").value,f=e.pstyle("text-outline-color").value;t.font=n+" "+s+" "+i+" "+a,t.lineJoin="round",this.colorFillStyle(t,h[0],h[1],h[2],l),this.colorStrokeStyle(t,f[0],f[1],f[2],u)};o(RP,"roundRect");K0.getTextAngle=function(t,e){var r,n=t._private,i=n.rscratch,a=e?e+"-":"",s=t.pstyle(a+"text-rotation"),l=Ul(i,"labelAngle",e);return s.strValue==="autorotate"?r=t.isEdge()?l:0:s.strValue==="none"?r=0:r=s.pfValue,r};K0.drawText=function(t,e,r){var n=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!0,i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,a=e._private,s=a.rscratch,l=i?e.effectiveOpacity():1;if(!(i&&(l===0||e.pstyle("text-opacity").value===0))){r==="main"&&(r=null);var u=Ul(s,"labelX",r),h=Ul(s,"labelY",r),f,d,p=this.getLabelText(e,r);if(p!=null&&p!==""&&!isNaN(u)&&!isNaN(h)){this.setupTextStyle(t,e,i);var m=r?r+"-":"",g=Ul(s,"labelWidth",r),y=Ul(s,"labelHeight",r),v=e.pstyle(m+"text-margin-x").pfValue,x=e.pstyle(m+"text-margin-y").pfValue,b=e.isEdge(),w=e.pstyle("text-halign").value,S=e.pstyle("text-valign").value;b&&(w="center",S="center"),u+=v,h+=x;var T;switch(n?T=this.getTextAngle(e,r):T=0,T!==0&&(f=u,d=h,t.translate(f,d),t.rotate(T),u=0,h=0),S){case"top":break;case"center":h+=y/2;break;case"bottom":h+=y;break}var E=e.pstyle("text-background-opacity").value,_=e.pstyle("text-border-opacity").value,A=e.pstyle("text-border-width").pfValue,L=e.pstyle("text-background-padding").pfValue,M=e.pstyle("text-background-shape").strValue,N=M.indexOf("round")===0,k=2;if(E>0||A>0&&_>0){var I=u-L;switch(w){case"left":I-=g;break;case"center":I-=g/2;break}var C=h-y-L,O=g+2*L,D=y+2*L;if(E>0){var P=t.fillStyle,F=e.pstyle("text-background-color").value;t.fillStyle="rgba("+F[0]+","+F[1]+","+F[2]+","+E*l+")",N?RP(t,I,C,O,D,k):t.fillRect(I,C,O,D),t.fillStyle=P}if(A>0&&_>0){var B=t.strokeStyle,$=t.lineWidth,z=e.pstyle("text-border-color").value,Y=e.pstyle("text-border-style").value;if(t.strokeStyle="rgba("+z[0]+","+z[1]+","+z[2]+","+_*l+")",t.lineWidth=A,t.setLineDash)switch(Y){case"dotted":t.setLineDash([1,1]);break;case"dashed":t.setLineDash([4,2]);break;case"double":t.lineWidth=A/4,t.setLineDash([]);break;case"solid":t.setLineDash([]);break}if(N?RP(t,I,C,O,D,k,"stroke"):t.strokeRect(I,C,O,D),Y==="double"){var Q=A/2;N?RP(t,I+Q,C+Q,O-Q*2,D-Q*2,k,"stroke"):t.strokeRect(I+Q,C+Q,O-Q*2,D-Q*2)}t.setLineDash&&t.setLineDash([]),t.lineWidth=$,t.strokeStyle=B}}var X=2*e.pstyle("text-outline-width").pfValue;if(X>0&&(t.lineWidth=X),e.pstyle("text-wrap").value==="wrap"){var ie=Ul(s,"labelWrapCachedLines",r),j=Ul(s,"labelLineHeight",r),J=g/2,Z=this.getLabelJustification(e);switch(Z==="auto"||(w==="left"?Z==="left"?u+=-g:Z==="center"&&(u+=-J):w==="center"?Z==="left"?u+=-J:Z==="right"&&(u+=J):w==="right"&&(Z==="center"?u+=J:Z==="right"&&(u+=g))),S){case"top":h-=(ie.length-1)*j;break;case"center":case"bottom":h-=(ie.length-1)*j;break}for(var H=0;H0&&t.strokeText(ie[H],u,h),t.fillText(ie[H],u,h),h+=j}else X>0&&t.strokeText(p,u,h),t.fillText(p,u,h);T!==0&&(t.rotate(-T),t.translate(-f,-d))}}};v1={};v1.drawNode=function(t,e,r){var n=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!0,i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:!0,s=this,l,u,h=e._private,f=h.rscratch,d=e.position();if(!(!ft(d.x)||!ft(d.y))&&!(a&&!e.visible())){var p=a?e.effectiveOpacity():1,m=s.usePaths(),g,y=!1,v=e.padding();l=e.width()+2*v,u=e.height()+2*v;var x;r&&(x=r,t.translate(-x.x1,-x.y1));for(var b=e.pstyle("background-image"),w=b.value,S=new Array(w.length),T=new Array(w.length),E=0,_=0;_0&&arguments[0]!==void 0?arguments[0]:I;s.eleFillStyle(t,e,ne)},"setupShapeColor"),H=o(function(){var ne=arguments.length>0&&arguments[0]!==void 0?arguments[0]:z;s.colorStrokeStyle(t,C[0],C[1],C[2],ne)},"setupBorderColor"),q=o(function(){var ne=arguments.length>0&&arguments[0]!==void 0?arguments[0]:ie;s.colorStrokeStyle(t,Q[0],Q[1],Q[2],ne)},"setupOutlineColor"),K=o(function(ne,ae,we,Te){var Ce=s.nodePathCache=s.nodePathCache||[],Ae=Ope(we==="polygon"?we+","+Te.join(","):we,""+ae,""+ne,""+J),Ge=Ce[Ae],Me,ye=!1;return Ge!=null?(Me=Ge,ye=!0,f.pathCache=Me):(Me=new Path2D,Ce[Ae]=f.pathCache=Me),{path:Me,cacheHit:ye}},"getPath"),se=e.pstyle("shape").strValue,ce=e.pstyle("shape-polygon-points").pfValue;if(m){t.translate(d.x,d.y);var ue=K(l,u,se,ce);g=ue.path,y=ue.cacheHit}var te=o(function(){if(!y){var ne=d;m&&(ne={x:0,y:0}),s.nodeShapes[s.getNodeShape(e)].draw(g||t,ne.x,ne.y,l,u,J,f)}m?t.fill(g):t.fill()},"drawShape"),De=o(function(){for(var ne=arguments.length>0&&arguments[0]!==void 0?arguments[0]:p,ae=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,we=h.backgrounding,Te=0,Ce=0;Ce0&&arguments[0]!==void 0?arguments[0]:!1,ae=arguments.length>1&&arguments[1]!==void 0?arguments[1]:p;s.hasPie(e)&&(s.drawPie(t,e,ae),ne&&(m||s.nodeShapes[s.getNodeShape(e)].draw(t,d.x,d.y,l,u,J,f)))},"drawPie"),ke=o(function(){var ne=arguments.length>0&&arguments[0]!==void 0?arguments[0]:p,ae=(N>0?N:-N)*ne,we=N>0?0:255;N!==0&&(s.colorFillStyle(t,we,we,we,ae),m?t.fill(g):t.fill())},"darken"),Ie=o(function(){if(k>0){if(t.lineWidth=k,t.lineCap=P,t.lineJoin=D,t.setLineDash)switch(O){case"dotted":t.setLineDash([1,1]);break;case"dashed":t.setLineDash(B),t.lineDashOffset=$;break;case"solid":case"double":t.setLineDash([]);break}if(F!=="center"){if(t.save(),t.lineWidth*=2,F==="inside")m?t.clip(g):t.clip();else{var ne=new Path2D;ne.rect(-l/2-k,-u/2-k,l+2*k,u+2*k),ne.addPath(g),t.clip(ne,"evenodd")}m?t.stroke(g):t.stroke(),t.restore()}else m?t.stroke(g):t.stroke();if(O==="double"){t.lineWidth=k/3;var ae=t.globalCompositeOperation;t.globalCompositeOperation="destination-out",m?t.stroke(g):t.stroke(),t.globalCompositeOperation=ae}t.setLineDash&&t.setLineDash([])}},"drawBorder"),Se=o(function(){if(Y>0){if(t.lineWidth=Y,t.lineCap="butt",t.setLineDash)switch(X){case"dotted":t.setLineDash([1,1]);break;case"dashed":t.setLineDash([4,2]);break;case"solid":case"double":t.setLineDash([]);break}var ne=d;m&&(ne={x:0,y:0});var ae=s.getNodeShape(e),we=k;F==="inside"&&(we=0),F==="outside"&&(we*=2);var Te=(l+we+(Y+j))/l,Ce=(u+we+(Y+j))/u,Ae=l*Te,Ge=u*Ce,Me=s.nodeShapes[ae].points,ye;if(m){var He=K(Ae,Ge,ae,Me);ye=He.path}if(ae==="ellipse")s.drawEllipsePath(ye||t,ne.x,ne.y,Ae,Ge);else if(["round-diamond","round-heptagon","round-hexagon","round-octagon","round-pentagon","round-polygon","round-triangle","round-tag"].includes(ae)){var ze=0,Ze=0,gt=0;ae==="round-diamond"?ze=(we+j+Y)*1.4:ae==="round-heptagon"?(ze=(we+j+Y)*1.075,gt=-(we/2+j+Y)/35):ae==="round-hexagon"?ze=(we+j+Y)*1.12:ae==="round-pentagon"?(ze=(we+j+Y)*1.13,gt=-(we/2+j+Y)/15):ae==="round-tag"?(ze=(we+j+Y)*1.12,Ze=(we/2+Y+j)*.07):ae==="round-triangle"&&(ze=(we+j+Y)*(Math.PI/2),gt=-(we+j/2+Y)/Math.PI),ze!==0&&(Te=(l+ze)/l,Ae=l*Te,["round-hexagon","round-tag"].includes(ae)||(Ce=(u+ze)/u,Ge=u*Ce)),J=J==="auto"?Wpe(Ae,Ge):J;for(var yt=Ae/2,tt=Ge/2,Ye=J+(we+Y+j)/2,Je=new Array(Me.length/2),Ve=new Array(Me.length/2),je=0;je0){if(i=i||n.position(),a==null||s==null){var m=n.padding();a=n.width()+2*m,s=n.height()+2*m}l.colorFillStyle(r,f[0],f[1],f[2],h),l.nodeShapes[d].draw(r,i.x,i.y,a+u*2,s+u*2,p),r.fill()}}}},"drawNodeOverlayUnderlay");v1.drawNodeOverlay=jme("overlay");v1.drawNodeUnderlay=jme("underlay");v1.hasPie=function(t){return t=t[0],t._private.hasPie};v1.drawPie=function(t,e,r,n){e=e[0],n=n||e.position();var i=e.cy().style(),a=e.pstyle("pie-size"),s=n.x,l=n.y,u=e.width(),h=e.height(),f=Math.min(u,h)/2,d=0,p=this.usePaths();p&&(s=0,l=0),a.units==="%"?f=f*a.pfValue:a.pfValue!==void 0&&(f=a.pfValue/2);for(var m=1;m<=i.pieBackgroundN;m++){var g=e.pstyle("pie-"+m+"-background-size").value,y=e.pstyle("pie-"+m+"-background-color").value,v=e.pstyle("pie-"+m+"-background-opacity").value*r,x=g/100;x+d>1&&(x=1-d);var b=1.5*Math.PI+2*Math.PI*d,w=2*Math.PI*x,S=b+w;g===0||d>=1||d+x>1||(t.beginPath(),t.moveTo(s,l),t.arc(s,l,f,b,S),t.closePath(),this.colorFillStyle(t,y[0],y[1],y[2],v),t.fill(),d+=x)}};bo={},QQe=100;bo.getPixelRatio=function(){var t=this.data.contexts[0];if(this.forcedPixelRatio!=null)return this.forcedPixelRatio;var e=this.cy.window(),r=t.backingStorePixelRatio||t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1;return(e.devicePixelRatio||1)/r};bo.paintCache=function(t){for(var e=this.paintCaches=this.paintCaches||[],r=!0,n,i=0;is.minMbLowQualFrames&&(s.motionBlurPxRatio=s.mbPxRBlurry)),s.clearingMotionBlur&&(s.motionBlurPxRatio=1),s.textureDrawLastFrame&&!d&&(f[s.NODE]=!0,f[s.SELECT_BOX]=!0);var b=u.style(),w=u.zoom(),S=i!==void 0?i:w,T=u.pan(),E={x:T.x,y:T.y},_={zoom:w,pan:{x:T.x,y:T.y}},A=s.prevViewport,L=A===void 0||_.zoom!==A.zoom||_.pan.x!==A.pan.x||_.pan.y!==A.pan.y;!L&&!(y&&!g)&&(s.motionBlurPxRatio=1),a&&(E=a),S*=l,E.x*=l,E.y*=l;var M=s.getCachedZSortedEles();function N(ue,te,De,oe,ke){var Ie=ue.globalCompositeOperation;ue.globalCompositeOperation="destination-out",s.colorFillStyle(ue,255,255,255,s.motionBlurTransparency),ue.fillRect(te,De,oe,ke),ue.globalCompositeOperation=Ie}o(N,"mbclear");function k(ue,te){var De,oe,ke,Ie;!s.clearingMotionBlur&&(ue===h.bufferContexts[s.MOTIONBLUR_BUFFER_NODE]||ue===h.bufferContexts[s.MOTIONBLUR_BUFFER_DRAG])?(De={x:T.x*m,y:T.y*m},oe=w*m,ke=s.canvasWidth*m,Ie=s.canvasHeight*m):(De=E,oe=S,ke=s.canvasWidth,Ie=s.canvasHeight),ue.setTransform(1,0,0,1,0,0),te==="motionBlur"?N(ue,0,0,ke,Ie):!e&&(te===void 0||te)&&ue.clearRect(0,0,ke,Ie),r||(ue.translate(De.x,De.y),ue.scale(oe,oe)),a&&ue.translate(a.x,a.y),i&&ue.scale(i,i)}if(o(k,"setContextTransform"),d||(s.textureDrawLastFrame=!1),d){if(s.textureDrawLastFrame=!0,!s.textureCache){s.textureCache={},s.textureCache.bb=u.mutableElements().boundingBox(),s.textureCache.texture=s.data.bufferCanvases[s.TEXTURE_BUFFER];var I=s.data.bufferContexts[s.TEXTURE_BUFFER];I.setTransform(1,0,0,1,0,0),I.clearRect(0,0,s.canvasWidth*s.textureMult,s.canvasHeight*s.textureMult),s.render({forcedContext:I,drawOnlyNodeLayer:!0,forcedPxRatio:l*s.textureMult});var _=s.textureCache.viewport={zoom:u.zoom(),pan:u.pan(),width:s.canvasWidth,height:s.canvasHeight};_.mpan={x:(0-_.pan.x)/_.zoom,y:(0-_.pan.y)/_.zoom}}f[s.DRAG]=!1,f[s.NODE]=!1;var C=h.contexts[s.NODE],O=s.textureCache.texture,_=s.textureCache.viewport;C.setTransform(1,0,0,1,0,0),p?N(C,0,0,_.width,_.height):C.clearRect(0,0,_.width,_.height);var D=b.core("outside-texture-bg-color").value,P=b.core("outside-texture-bg-opacity").value;s.colorFillStyle(C,D[0],D[1],D[2],P),C.fillRect(0,0,_.width,_.height);var w=u.zoom();k(C,!1),C.clearRect(_.mpan.x,_.mpan.y,_.width/_.zoom/l,_.height/_.zoom/l),C.drawImage(O,_.mpan.x,_.mpan.y,_.width/_.zoom/l,_.height/_.zoom/l)}else s.textureOnViewport&&!e&&(s.textureCache=null);var F=u.extent(),B=s.pinching||s.hoverData.dragging||s.swipePanning||s.data.wheelZooming||s.hoverData.draggingEles||s.cy.animated(),$=s.hideEdgesOnViewport&&B,z=[];if(z[s.NODE]=!f[s.NODE]&&p&&!s.clearedForMotionBlur[s.NODE]||s.clearingMotionBlur,z[s.NODE]&&(s.clearedForMotionBlur[s.NODE]=!0),z[s.DRAG]=!f[s.DRAG]&&p&&!s.clearedForMotionBlur[s.DRAG]||s.clearingMotionBlur,z[s.DRAG]&&(s.clearedForMotionBlur[s.DRAG]=!0),f[s.NODE]||r||n||z[s.NODE]){var Y=p&&!z[s.NODE]&&m!==1,C=e||(Y?s.data.bufferContexts[s.MOTIONBLUR_BUFFER_NODE]:h.contexts[s.NODE]),Q=p&&!Y?"motionBlur":void 0;k(C,Q),$?s.drawCachedNodes(C,M.nondrag,l,F):s.drawLayeredElements(C,M.nondrag,l,F),s.debug&&s.drawDebugPoints(C,M.nondrag),!r&&!p&&(f[s.NODE]=!1)}if(!n&&(f[s.DRAG]||r||z[s.DRAG])){var Y=p&&!z[s.DRAG]&&m!==1,C=e||(Y?s.data.bufferContexts[s.MOTIONBLUR_BUFFER_DRAG]:h.contexts[s.DRAG]);k(C,p&&!Y?"motionBlur":void 0),$?s.drawCachedNodes(C,M.drag,l,F):s.drawCachedElements(C,M.drag,l,F),s.debug&&s.drawDebugPoints(C,M.drag),!r&&!p&&(f[s.DRAG]=!1)}if(s.showFps||!n&&f[s.SELECT_BOX]&&!r){var C=e||h.contexts[s.SELECT_BOX];if(k(C),s.selection[4]==1&&(s.hoverData.selecting||s.touchData.selecting)){var w=s.cy.zoom(),X=b.core("selection-box-border-width").value/w;C.lineWidth=X,C.fillStyle="rgba("+b.core("selection-box-color").value[0]+","+b.core("selection-box-color").value[1]+","+b.core("selection-box-color").value[2]+","+b.core("selection-box-opacity").value+")",C.fillRect(s.selection[0],s.selection[1],s.selection[2]-s.selection[0],s.selection[3]-s.selection[1]),X>0&&(C.strokeStyle="rgba("+b.core("selection-box-border-color").value[0]+","+b.core("selection-box-border-color").value[1]+","+b.core("selection-box-border-color").value[2]+","+b.core("selection-box-opacity").value+")",C.strokeRect(s.selection[0],s.selection[1],s.selection[2]-s.selection[0],s.selection[3]-s.selection[1]))}if(h.bgActivePosistion&&!s.hoverData.selecting){var w=s.cy.zoom(),ie=h.bgActivePosistion;C.fillStyle="rgba("+b.core("active-bg-color").value[0]+","+b.core("active-bg-color").value[1]+","+b.core("active-bg-color").value[2]+","+b.core("active-bg-opacity").value+")",C.beginPath(),C.arc(ie.x,ie.y,b.core("active-bg-size").pfValue/w,0,2*Math.PI),C.fill()}var j=s.lastRedrawTime;if(s.showFps&&j){j=Math.round(j);var J=Math.round(1e3/j);C.setTransform(1,0,0,1,0,0),C.fillStyle="rgba(255, 0, 0, 0.75)",C.strokeStyle="rgba(255, 0, 0, 0.75)",C.lineWidth=1,C.fillText("1 frame = "+j+" ms = "+J+" fps",0,20);var Z=60;C.strokeRect(0,30,250,20),C.fillRect(0,30,250*Math.min(J/Z,1),20)}r||(f[s.SELECT_BOX]=!1)}if(p&&m!==1){var H=h.contexts[s.NODE],q=s.data.bufferCanvases[s.MOTIONBLUR_BUFFER_NODE],K=h.contexts[s.DRAG],se=s.data.bufferCanvases[s.MOTIONBLUR_BUFFER_DRAG],ce=o(function(te,De,oe){te.setTransform(1,0,0,1,0,0),oe||!x?te.clearRect(0,0,s.canvasWidth,s.canvasHeight):N(te,0,0,s.canvasWidth,s.canvasHeight);var ke=m;te.drawImage(De,0,0,s.canvasWidth*ke,s.canvasHeight*ke,0,0,s.canvasWidth,s.canvasHeight)},"drawMotionBlur");(f[s.NODE]||z[s.NODE])&&(ce(H,q,z[s.NODE]),f[s.NODE]=!1),(f[s.DRAG]||z[s.DRAG])&&(ce(K,se,z[s.DRAG]),f[s.DRAG]=!1)}s.prevViewport=_,s.clearingMotionBlur&&(s.clearingMotionBlur=!1,s.motionBlurCleared=!0,s.motionBlur=!0),p&&(s.motionBlurTimeout=setTimeout(function(){s.motionBlurTimeout=null,s.clearedForMotionBlur[s.NODE]=!1,s.clearedForMotionBlur[s.DRAG]=!1,s.motionBlur=!1,s.clearingMotionBlur=!d,s.mbFrames=0,f[s.NODE]=!0,f[s.DRAG]=!0,s.redraw()},QQe)),e||u.emit("render")};Nf={};Nf.drawPolygonPath=function(t,e,r,n,i,a){var s=n/2,l=i/2;t.beginPath&&t.beginPath(),t.moveTo(e+s*a[0],r+l*a[1]);for(var u=1;u0&&s>0){m.clearRect(0,0,a,s),m.globalCompositeOperation="source-over";var g=this.getCachedZSortedEles();if(t.full)m.translate(-n.x1*h,-n.y1*h),m.scale(h,h),this.drawElements(m,g),m.scale(1/h,1/h),m.translate(n.x1*h,n.y1*h);else{var y=e.pan(),v={x:y.x*h,y:y.y*h};h*=e.zoom(),m.translate(v.x,v.y),m.scale(h,h),this.drawElements(m,g),m.scale(1/h,1/h),m.translate(-v.x,-v.y)}t.bg&&(m.globalCompositeOperation="destination-over",m.fillStyle=t.bg,m.rect(0,0,a,s),m.fill())}return p};o(ZQe,"b64ToBlob");o(xpe,"b64UriToB64");o(Qme,"output");ab.png=function(t){return Qme(t,this.bufferCanvasImage(t),"image/png")};ab.jpg=function(t){return Qme(t,this.bufferCanvasImage(t),"image/jpeg")};Zme={};Zme.nodeShapeImpl=function(t,e,r,n,i,a,s,l){switch(t){case"ellipse":return this.drawEllipsePath(e,r,n,i,a);case"polygon":return this.drawPolygonPath(e,r,n,i,a,s);case"round-polygon":return this.drawRoundPolygonPath(e,r,n,i,a,s,l);case"roundrectangle":case"round-rectangle":return this.drawRoundRectanglePath(e,r,n,i,a,l);case"cutrectangle":case"cut-rectangle":return this.drawCutRectanglePath(e,r,n,i,a,s,l);case"bottomroundrectangle":case"bottom-round-rectangle":return this.drawBottomRoundRectanglePath(e,r,n,i,a,l);case"barrel":return this.drawBarrelPath(e,r,n,i,a)}};JQe=Jme,Yr=Jme.prototype;Yr.CANVAS_LAYERS=3;Yr.SELECT_BOX=0;Yr.DRAG=1;Yr.NODE=2;Yr.BUFFER_COUNT=3;Yr.TEXTURE_BUFFER=0;Yr.MOTIONBLUR_BUFFER_NODE=1;Yr.MOTIONBLUR_BUFFER_DRAG=2;o(Jme,"CanvasRenderer");Yr.redrawHint=function(t,e){var r=this;switch(t){case"eles":r.data.canvasNeedsRedraw[Yr.NODE]=e;break;case"drag":r.data.canvasNeedsRedraw[Yr.DRAG]=e;break;case"select":r.data.canvasNeedsRedraw[Yr.SELECT_BOX]=e;break}};eZe=typeof Path2D<"u";Yr.path2dEnabled=function(t){if(t===void 0)return this.pathsEnabled;this.pathsEnabled=!!t};Yr.usePaths=function(){return eZe&&this.pathsEnabled};Yr.setImgSmoothing=function(t,e){t.imageSmoothingEnabled!=null?t.imageSmoothingEnabled=e:(t.webkitImageSmoothingEnabled=e,t.mozImageSmoothingEnabled=e,t.msImageSmoothingEnabled=e)};Yr.getImgSmoothing=function(t){return t.imageSmoothingEnabled!=null?t.imageSmoothingEnabled:t.webkitImageSmoothingEnabled||t.mozImageSmoothingEnabled||t.msImageSmoothingEnabled};Yr.makeOffscreenCanvas=function(t,e){var r;if((typeof OffscreenCanvas>"u"?"undefined":Hi(OffscreenCanvas))!=="undefined")r=new OffscreenCanvas(t,e);else{var n=this.cy.window(),i=n.document;r=i.createElement("canvas"),r.width=t,r.height=e}return r};[qme,Yc,eh,yB,K0,v1,bo,Nf,ab,Zme].forEach(function(t){Wt(Yr,t)});tZe=[{name:"null",impl:Ime},{name:"base",impl:Hme},{name:"canvas",impl:JQe}],rZe=[{type:"layout",extensions:lQe},{type:"renderer",extensions:tZe}],ege={},tge={};o(rge,"setExtension");o(nge,"getExtension");o(nZe,"setModule");o(iZe,"getModule");qP=o(function(){if(arguments.length===2)return nge.apply(null,arguments);if(arguments.length===3)return rge.apply(null,arguments);if(arguments.length===4)return iZe.apply(null,arguments);if(arguments.length===5)return nZe.apply(null,arguments);oi("Invalid extension access syntax")},"extension");Kx.prototype.extension=qP;rZe.forEach(function(t){t.extensions.forEach(function(e){rge(t.type,e.name,e.impl)})});ige=o(function t(){if(!(this instanceof t))return new t;this.length=0},"Stylesheet"),X0=ige.prototype;X0.instanceString=function(){return"stylesheet"};X0.selector=function(t){var e=this.length++;return this[e]={selector:t,properties:[]},this};X0.css=function(t,e){var r=this.length-1;if(zt(t))this[r].properties.push({name:t,value:e});else if(Mr(t))for(var n=t,i=Object.keys(n),a=0;a{"use strict";o(function(e,r){typeof sb=="object"&&typeof xB=="object"?xB.exports=r():typeof define=="function"&&define.amd?define([],r):typeof sb=="object"?sb.layoutBase=r():e.layoutBase=r()},"webpackUniversalModuleDefinition")(sb,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return o(r,"__webpack_require__"),r.m=t,r.c=e,r.i=function(n){return n},r.d=function(n,i,a){r.o(n,i)||Object.defineProperty(n,i,{configurable:!1,enumerable:!0,get:a})},r.n=function(n){var i=n&&n.__esModule?o(function(){return n.default},"getDefault"):o(function(){return n},"getModuleExports");return r.d(i,"a",i),i},r.o=function(n,i){return Object.prototype.hasOwnProperty.call(n,i)},r.p="",r(r.s=26)}([function(t,e,r){"use strict";function n(){}o(n,"LayoutConstants"),n.QUALITY=1,n.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,n.DEFAULT_INCREMENTAL=!1,n.DEFAULT_ANIMATION_ON_LAYOUT=!0,n.DEFAULT_ANIMATION_DURING_LAYOUT=!1,n.DEFAULT_ANIMATION_PERIOD=50,n.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,n.DEFAULT_GRAPH_MARGIN=15,n.NODE_DIMENSIONS_INCLUDE_LABELS=!1,n.SIMPLE_NODE_SIZE=40,n.SIMPLE_NODE_HALF_SIZE=n.SIMPLE_NODE_SIZE/2,n.EMPTY_COMPOUND_NODE_SIZE=40,n.MIN_EDGE_LENGTH=1,n.WORLD_BOUNDARY=1e6,n.INITIAL_WORLD_BOUNDARY=n.WORLD_BOUNDARY/1e3,n.WORLD_CENTER_X=1200,n.WORLD_CENTER_Y=900,t.exports=n},function(t,e,r){"use strict";var n=r(2),i=r(8),a=r(9);function s(u,h,f){n.call(this,f),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=f,this.bendpoints=[],this.source=u,this.target=h}o(s,"LEdge"),s.prototype=Object.create(n.prototype);for(var l in n)s[l]=n[l];s.prototype.getSource=function(){return this.source},s.prototype.getTarget=function(){return this.target},s.prototype.isInterGraph=function(){return this.isInterGraph},s.prototype.getLength=function(){return this.length},s.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},s.prototype.getBendpoints=function(){return this.bendpoints},s.prototype.getLca=function(){return this.lca},s.prototype.getSourceInLca=function(){return this.sourceInLca},s.prototype.getTargetInLca=function(){return this.targetInLca},s.prototype.getOtherEnd=function(u){if(this.source===u)return this.target;if(this.target===u)return this.source;throw"Node is not incident with this edge"},s.prototype.getOtherEndInGraph=function(u,h){for(var f=this.getOtherEnd(u),d=h.getGraphManager().getRoot();;){if(f.getOwner()==h)return f;if(f.getOwner()==d)break;f=f.getOwner().getParent()}return null},s.prototype.updateLength=function(){var u=new Array(4);this.isOverlapingSourceAndTarget=i.getIntersection(this.target.getRect(),this.source.getRect(),u),this.isOverlapingSourceAndTarget||(this.lengthX=u[0]-u[2],this.lengthY=u[1]-u[3],Math.abs(this.lengthX)<1&&(this.lengthX=a.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=a.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},s.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=a.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=a.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},t.exports=s},function(t,e,r){"use strict";function n(i){this.vGraphObject=i}o(n,"LGraphObject"),t.exports=n},function(t,e,r){"use strict";var n=r(2),i=r(10),a=r(13),s=r(0),l=r(16),u=r(4);function h(d,p,m,g){m==null&&g==null&&(g=p),n.call(this,g),d.graphManager!=null&&(d=d.graphManager),this.estimatedSize=i.MIN_VALUE,this.inclusionTreeDepth=i.MAX_VALUE,this.vGraphObject=g,this.edges=[],this.graphManager=d,m!=null&&p!=null?this.rect=new a(p.x,p.y,m.width,m.height):this.rect=new a}o(h,"LNode"),h.prototype=Object.create(n.prototype);for(var f in n)h[f]=n[f];h.prototype.getEdges=function(){return this.edges},h.prototype.getChild=function(){return this.child},h.prototype.getOwner=function(){return this.owner},h.prototype.getWidth=function(){return this.rect.width},h.prototype.setWidth=function(d){this.rect.width=d},h.prototype.getHeight=function(){return this.rect.height},h.prototype.setHeight=function(d){this.rect.height=d},h.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},h.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},h.prototype.getCenter=function(){return new u(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},h.prototype.getLocation=function(){return new u(this.rect.x,this.rect.y)},h.prototype.getRect=function(){return this.rect},h.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},h.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},h.prototype.setRect=function(d,p){this.rect.x=d.x,this.rect.y=d.y,this.rect.width=p.width,this.rect.height=p.height},h.prototype.setCenter=function(d,p){this.rect.x=d-this.rect.width/2,this.rect.y=p-this.rect.height/2},h.prototype.setLocation=function(d,p){this.rect.x=d,this.rect.y=p},h.prototype.moveBy=function(d,p){this.rect.x+=d,this.rect.y+=p},h.prototype.getEdgeListToNode=function(d){var p=[],m,g=this;return g.edges.forEach(function(y){if(y.target==d){if(y.source!=g)throw"Incorrect edge source!";p.push(y)}}),p},h.prototype.getEdgesBetween=function(d){var p=[],m,g=this;return g.edges.forEach(function(y){if(!(y.source==g||y.target==g))throw"Incorrect edge source and/or target";(y.target==d||y.source==d)&&p.push(y)}),p},h.prototype.getNeighborsList=function(){var d=new Set,p=this;return p.edges.forEach(function(m){if(m.source==p)d.add(m.target);else{if(m.target!=p)throw"Incorrect incidency!";d.add(m.source)}}),d},h.prototype.withChildren=function(){var d=new Set,p,m;if(d.add(this),this.child!=null)for(var g=this.child.getNodes(),y=0;yp&&(this.rect.x-=(this.labelWidth-p)/2,this.setWidth(this.labelWidth)),this.labelHeight>m&&(this.labelPos=="center"?this.rect.y-=(this.labelHeight-m)/2:this.labelPos=="top"&&(this.rect.y-=this.labelHeight-m),this.setHeight(this.labelHeight))}}},h.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==i.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},h.prototype.transform=function(d){var p=this.rect.x;p>s.WORLD_BOUNDARY?p=s.WORLD_BOUNDARY:p<-s.WORLD_BOUNDARY&&(p=-s.WORLD_BOUNDARY);var m=this.rect.y;m>s.WORLD_BOUNDARY?m=s.WORLD_BOUNDARY:m<-s.WORLD_BOUNDARY&&(m=-s.WORLD_BOUNDARY);var g=new u(p,m),y=d.inverseTransformPoint(g);this.setLocation(y.x,y.y)},h.prototype.getLeft=function(){return this.rect.x},h.prototype.getRight=function(){return this.rect.x+this.rect.width},h.prototype.getTop=function(){return this.rect.y},h.prototype.getBottom=function(){return this.rect.y+this.rect.height},h.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},t.exports=h},function(t,e,r){"use strict";function n(i,a){i==null&&a==null?(this.x=0,this.y=0):(this.x=i,this.y=a)}o(n,"PointD"),n.prototype.getX=function(){return this.x},n.prototype.getY=function(){return this.y},n.prototype.setX=function(i){this.x=i},n.prototype.setY=function(i){this.y=i},n.prototype.getDifference=function(i){return new DimensionD(this.x-i.x,this.y-i.y)},n.prototype.getCopy=function(){return new n(this.x,this.y)},n.prototype.translate=function(i){return this.x+=i.width,this.y+=i.height,this},t.exports=n},function(t,e,r){"use strict";var n=r(2),i=r(10),a=r(0),s=r(6),l=r(3),u=r(1),h=r(13),f=r(12),d=r(11);function p(g,y,v){n.call(this,v),this.estimatedSize=i.MIN_VALUE,this.margin=a.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=g,y!=null&&y instanceof s?this.graphManager=y:y!=null&&y instanceof Layout&&(this.graphManager=y.graphManager)}o(p,"LGraph"),p.prototype=Object.create(n.prototype);for(var m in n)p[m]=n[m];p.prototype.getNodes=function(){return this.nodes},p.prototype.getEdges=function(){return this.edges},p.prototype.getGraphManager=function(){return this.graphManager},p.prototype.getParent=function(){return this.parent},p.prototype.getLeft=function(){return this.left},p.prototype.getRight=function(){return this.right},p.prototype.getTop=function(){return this.top},p.prototype.getBottom=function(){return this.bottom},p.prototype.isConnected=function(){return this.isConnected},p.prototype.add=function(g,y,v){if(y==null&&v==null){var x=g;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(x)>-1)throw"Node already in graph!";return x.owner=this,this.getNodes().push(x),x}else{var b=g;if(!(this.getNodes().indexOf(y)>-1&&this.getNodes().indexOf(v)>-1))throw"Source or target not in graph!";if(!(y.owner==v.owner&&y.owner==this))throw"Both owners must be this graph!";return y.owner!=v.owner?null:(b.source=y,b.target=v,b.isInterGraph=!1,this.getEdges().push(b),y.edges.push(b),v!=y&&v.edges.push(b),b)}},p.prototype.remove=function(g){var y=g;if(g instanceof l){if(y==null)throw"Node is null!";if(!(y.owner!=null&&y.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var v=y.edges.slice(),x,b=v.length,w=0;w-1&&E>-1))throw"Source and/or target doesn't know this edge!";x.source.edges.splice(T,1),x.target!=x.source&&x.target.edges.splice(E,1);var S=x.source.owner.getEdges().indexOf(x);if(S==-1)throw"Not in owner's edge list!";x.source.owner.getEdges().splice(S,1)}},p.prototype.updateLeftTop=function(){for(var g=i.MAX_VALUE,y=i.MAX_VALUE,v,x,b,w=this.getNodes(),S=w.length,T=0;Tv&&(g=v),y>x&&(y=x)}return g==i.MAX_VALUE?null:(w[0].getParent().paddingLeft!=null?b=w[0].getParent().paddingLeft:b=this.margin,this.left=y-b,this.top=g-b,new f(this.left,this.top))},p.prototype.updateBounds=function(g){for(var y=i.MAX_VALUE,v=-i.MAX_VALUE,x=i.MAX_VALUE,b=-i.MAX_VALUE,w,S,T,E,_,A=this.nodes,L=A.length,M=0;Mw&&(y=w),vT&&(x=T),bw&&(y=w),vT&&(x=T),b=this.nodes.length){var L=0;v.forEach(function(M){M.owner==g&&L++}),L==this.nodes.length&&(this.isConnected=!0)}},t.exports=p},function(t,e,r){"use strict";var n,i=r(1);function a(s){n=r(5),this.layout=s,this.graphs=[],this.edges=[]}o(a,"LGraphManager"),a.prototype.addRoot=function(){var s=this.layout.newGraph(),l=this.layout.newNode(null),u=this.add(s,l);return this.setRootGraph(u),this.rootGraph},a.prototype.add=function(s,l,u,h,f){if(u==null&&h==null&&f==null){if(s==null)throw"Graph is null!";if(l==null)throw"Parent node is null!";if(this.graphs.indexOf(s)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(s),s.parent!=null)throw"Already has a parent!";if(l.child!=null)throw"Already has a child!";return s.parent=l,l.child=s,s}else{f=u,h=l,u=s;var d=h.getOwner(),p=f.getOwner();if(!(d!=null&&d.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(p!=null&&p.getGraphManager()==this))throw"Target not in this graph mgr!";if(d==p)return u.isInterGraph=!1,d.add(u,h,f);if(u.isInterGraph=!0,u.source=h,u.target=f,this.edges.indexOf(u)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(u),!(u.source!=null&&u.target!=null))throw"Edge source and/or target is null!";if(!(u.source.edges.indexOf(u)==-1&&u.target.edges.indexOf(u)==-1))throw"Edge already in source and/or target incidency list!";return u.source.edges.push(u),u.target.edges.push(u),u}},a.prototype.remove=function(s){if(s instanceof n){var l=s;if(l.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(l==this.rootGraph||l.parent!=null&&l.parent.graphManager==this))throw"Invalid parent node!";var u=[];u=u.concat(l.getEdges());for(var h,f=u.length,d=0;d=s.getRight()?l[0]+=Math.min(s.getX()-a.getX(),a.getRight()-s.getRight()):s.getX()<=a.getX()&&s.getRight()>=a.getRight()&&(l[0]+=Math.min(a.getX()-s.getX(),s.getRight()-a.getRight())),a.getY()<=s.getY()&&a.getBottom()>=s.getBottom()?l[1]+=Math.min(s.getY()-a.getY(),a.getBottom()-s.getBottom()):s.getY()<=a.getY()&&s.getBottom()>=a.getBottom()&&(l[1]+=Math.min(a.getY()-s.getY(),s.getBottom()-a.getBottom()));var f=Math.abs((s.getCenterY()-a.getCenterY())/(s.getCenterX()-a.getCenterX()));s.getCenterY()===a.getCenterY()&&s.getCenterX()===a.getCenterX()&&(f=1);var d=f*l[0],p=l[1]/f;l[0]d)return l[0]=u,l[1]=m,l[2]=f,l[3]=A,!1;if(hf)return l[0]=p,l[1]=h,l[2]=E,l[3]=d,!1;if(uf?(l[0]=y,l[1]=v,k=!0):(l[0]=g,l[1]=m,k=!0):C===D&&(u>f?(l[0]=p,l[1]=m,k=!0):(l[0]=x,l[1]=v,k=!0)),-O===D?f>u?(l[2]=_,l[3]=A,I=!0):(l[2]=E,l[3]=T,I=!0):O===D&&(f>u?(l[2]=S,l[3]=T,I=!0):(l[2]=L,l[3]=A,I=!0)),k&&I)return!1;if(u>f?h>d?(P=this.getCardinalDirection(C,D,4),F=this.getCardinalDirection(O,D,2)):(P=this.getCardinalDirection(-C,D,3),F=this.getCardinalDirection(-O,D,1)):h>d?(P=this.getCardinalDirection(-C,D,1),F=this.getCardinalDirection(-O,D,3)):(P=this.getCardinalDirection(C,D,2),F=this.getCardinalDirection(O,D,4)),!k)switch(P){case 1:$=m,B=u+-w/D,l[0]=B,l[1]=$;break;case 2:B=x,$=h+b*D,l[0]=B,l[1]=$;break;case 3:$=v,B=u+w/D,l[0]=B,l[1]=$;break;case 4:B=y,$=h+-b*D,l[0]=B,l[1]=$;break}if(!I)switch(F){case 1:Y=T,z=f+-N/D,l[2]=z,l[3]=Y;break;case 2:z=L,Y=d+M*D,l[2]=z,l[3]=Y;break;case 3:Y=A,z=f+N/D,l[2]=z,l[3]=Y;break;case 4:z=_,Y=d+-M*D,l[2]=z,l[3]=Y;break}}return!1},i.getCardinalDirection=function(a,s,l){return a>s?l:1+l%4},i.getIntersection=function(a,s,l,u){if(u==null)return this.getIntersection2(a,s,l);var h=a.x,f=a.y,d=s.x,p=s.y,m=l.x,g=l.y,y=u.x,v=u.y,x=void 0,b=void 0,w=void 0,S=void 0,T=void 0,E=void 0,_=void 0,A=void 0,L=void 0;return w=p-f,T=h-d,_=d*f-h*p,S=v-g,E=m-y,A=y*g-m*v,L=w*E-S*T,L===0?null:(x=(T*A-E*_)/L,b=(S*_-w*A)/L,new n(x,b))},i.angleOfVector=function(a,s,l,u){var h=void 0;return a!==l?(h=Math.atan((u-s)/(l-a)),l0?1:i<0?-1:0},n.floor=function(i){return i<0?Math.ceil(i):Math.floor(i)},n.ceil=function(i){return i<0?Math.floor(i):Math.ceil(i)},t.exports=n},function(t,e,r){"use strict";function n(){}o(n,"Integer"),n.MAX_VALUE=2147483647,n.MIN_VALUE=-2147483648,t.exports=n},function(t,e,r){"use strict";var n=function(){function h(f,d){for(var p=0;p"u"?"undefined":n(a);return a==null||s!="object"&&s!="function"},t.exports=i},function(t,e,r){"use strict";function n(m){if(Array.isArray(m)){for(var g=0,y=Array(m.length);g0&&g;){for(w.push(T[0]);w.length>0&&g;){var E=w[0];w.splice(0,1),b.add(E);for(var _=E.getEdges(),x=0;x<_.length;x++){var A=_[x].getOtherEnd(E);if(S.get(E)!=A)if(!b.has(A))w.push(A),S.set(A,E);else{g=!1;break}}}if(!g)m=[];else{var L=[].concat(n(b));m.push(L);for(var x=0;x-1&&T.splice(N,1)}b=new Set,S=new Map}}return m},p.prototype.createDummyNodesForBendpoints=function(m){for(var g=[],y=m.source,v=this.graphManager.calcLowestCommonAncestor(m.source,m.target),x=0;x0){for(var v=this.edgeToDummyNodes.get(y),x=0;x=0&&g.splice(A,1);var L=S.getNeighborsList();L.forEach(function(k){if(y.indexOf(k)<0){var I=v.get(k),C=I-1;C==1&&E.push(k),v.set(k,C)}})}y=y.concat(E),(g.length==1||g.length==2)&&(x=!0,b=g[0])}return b},p.prototype.setGraphManager=function(m){this.graphManager=m},t.exports=p},function(t,e,r){"use strict";function n(){}o(n,"RandomSeed"),n.seed=1,n.x=0,n.nextDouble=function(){return n.x=Math.sin(n.seed++)*1e4,n.x-Math.floor(n.x)},t.exports=n},function(t,e,r){"use strict";var n=r(4);function i(a,s){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}o(i,"Transform"),i.prototype.getWorldOrgX=function(){return this.lworldOrgX},i.prototype.setWorldOrgX=function(a){this.lworldOrgX=a},i.prototype.getWorldOrgY=function(){return this.lworldOrgY},i.prototype.setWorldOrgY=function(a){this.lworldOrgY=a},i.prototype.getWorldExtX=function(){return this.lworldExtX},i.prototype.setWorldExtX=function(a){this.lworldExtX=a},i.prototype.getWorldExtY=function(){return this.lworldExtY},i.prototype.setWorldExtY=function(a){this.lworldExtY=a},i.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},i.prototype.setDeviceOrgX=function(a){this.ldeviceOrgX=a},i.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},i.prototype.setDeviceOrgY=function(a){this.ldeviceOrgY=a},i.prototype.getDeviceExtX=function(){return this.ldeviceExtX},i.prototype.setDeviceExtX=function(a){this.ldeviceExtX=a},i.prototype.getDeviceExtY=function(){return this.ldeviceExtY},i.prototype.setDeviceExtY=function(a){this.ldeviceExtY=a},i.prototype.transformX=function(a){var s=0,l=this.lworldExtX;return l!=0&&(s=this.ldeviceOrgX+(a-this.lworldOrgX)*this.ldeviceExtX/l),s},i.prototype.transformY=function(a){var s=0,l=this.lworldExtY;return l!=0&&(s=this.ldeviceOrgY+(a-this.lworldOrgY)*this.ldeviceExtY/l),s},i.prototype.inverseTransformX=function(a){var s=0,l=this.ldeviceExtX;return l!=0&&(s=this.lworldOrgX+(a-this.ldeviceOrgX)*this.lworldExtX/l),s},i.prototype.inverseTransformY=function(a){var s=0,l=this.ldeviceExtY;return l!=0&&(s=this.lworldOrgY+(a-this.ldeviceOrgY)*this.lworldExtY/l),s},i.prototype.inverseTransformPoint=function(a){var s=new n(this.inverseTransformX(a.x),this.inverseTransformY(a.y));return s},t.exports=i},function(t,e,r){"use strict";function n(d){if(Array.isArray(d)){for(var p=0,m=Array(d.length);pa.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*a.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(d-a.ADAPTATION_LOWER_NODE_LIMIT)/(a.ADAPTATION_UPPER_NODE_LIMIT-a.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-a.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=a.MAX_NODE_DISPLACEMENT_INCREMENTAL):(d>a.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(a.COOLING_ADAPTATION_FACTOR,1-(d-a.ADAPTATION_LOWER_NODE_LIMIT)/(a.ADAPTATION_UPPER_NODE_LIMIT-a.ADAPTATION_LOWER_NODE_LIMIT)*(1-a.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=a.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},h.prototype.calcSpringForces=function(){for(var d=this.getAllEdges(),p,m=0;m0&&arguments[0]!==void 0?arguments[0]:!0,p=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,m,g,y,v,x=this.getAllNodes(),b;if(this.useFRGridVariant)for(this.totalIterations%a.GRID_CALCULATION_CHECK_PERIOD==1&&d&&this.updateGrid(),b=new Set,m=0;mw||b>w)&&(d.gravitationForceX=-this.gravityConstant*y,d.gravitationForceY=-this.gravityConstant*v)):(w=p.getEstimatedSize()*this.compoundGravityRangeFactor,(x>w||b>w)&&(d.gravitationForceX=-this.gravityConstant*y*this.compoundGravityConstant,d.gravitationForceY=-this.gravityConstant*v*this.compoundGravityConstant))},h.prototype.isConverged=function(){var d,p=!1;return this.totalIterations>this.maxIterations/3&&(p=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),d=this.totalDisplacement=x.length||w>=x[0].length)){for(var S=0;Sh},"_defaultCompareFunction")}]),l}();t.exports=s},function(t,e,r){"use strict";var n=function(){function s(l,u){for(var h=0;h2&&arguments[2]!==void 0?arguments[2]:1,f=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,d=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;i(this,s),this.sequence1=l,this.sequence2=u,this.match_score=h,this.mismatch_penalty=f,this.gap_penalty=d,this.iMax=l.length+1,this.jMax=u.length+1,this.grid=new Array(this.iMax);for(var p=0;p=0;l--){var u=this.listeners[l];u.event===a&&u.callback===s&&this.listeners.splice(l,1)}},i.emit=function(a,s){for(var l=0;l{"use strict";o(function(e,r){typeof ob=="object"&&typeof wB=="object"?wB.exports=r(bB()):typeof define=="function"&&define.amd?define(["layout-base"],r):typeof ob=="object"?ob.coseBase=r(bB()):e.coseBase=r(e.layoutBase)},"webpackUniversalModuleDefinition")(ob,function(t){return function(e){var r={};function n(i){if(r[i])return r[i].exports;var a=r[i]={i,l:!1,exports:{}};return e[i].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return o(n,"__webpack_require__"),n.m=e,n.c=r,n.i=function(i){return i},n.d=function(i,a,s){n.o(i,a)||Object.defineProperty(i,a,{configurable:!1,enumerable:!0,get:s})},n.n=function(i){var a=i&&i.__esModule?o(function(){return i.default},"getDefault"):o(function(){return i},"getModuleExports");return n.d(a,"a",a),a},n.o=function(i,a){return Object.prototype.hasOwnProperty.call(i,a)},n.p="",n(n.s=7)}([function(e,r){e.exports=t},function(e,r,n){"use strict";var i=n(0).FDLayoutConstants;function a(){}o(a,"CoSEConstants");for(var s in i)a[s]=i[s];a.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,a.DEFAULT_RADIAL_SEPARATION=i.DEFAULT_EDGE_LENGTH,a.DEFAULT_COMPONENT_SEPERATION=60,a.TILE=!0,a.TILING_PADDING_VERTICAL=10,a.TILING_PADDING_HORIZONTAL=10,a.TREE_REDUCTION_ON_INCREMENTAL=!1,e.exports=a},function(e,r,n){"use strict";var i=n(0).FDLayoutEdge;function a(l,u,h){i.call(this,l,u,h)}o(a,"CoSEEdge"),a.prototype=Object.create(i.prototype);for(var s in i)a[s]=i[s];e.exports=a},function(e,r,n){"use strict";var i=n(0).LGraph;function a(l,u,h){i.call(this,l,u,h)}o(a,"CoSEGraph"),a.prototype=Object.create(i.prototype);for(var s in i)a[s]=i[s];e.exports=a},function(e,r,n){"use strict";var i=n(0).LGraphManager;function a(l){i.call(this,l)}o(a,"CoSEGraphManager"),a.prototype=Object.create(i.prototype);for(var s in i)a[s]=i[s];e.exports=a},function(e,r,n){"use strict";var i=n(0).FDLayoutNode,a=n(0).IMath;function s(u,h,f,d){i.call(this,u,h,f,d)}o(s,"CoSENode"),s.prototype=Object.create(i.prototype);for(var l in i)s[l]=i[l];s.prototype.move=function(){var u=this.graphManager.getLayout();this.displacementX=u.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY=u.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren,Math.abs(this.displacementX)>u.coolingFactor*u.maxNodeDisplacement&&(this.displacementX=u.coolingFactor*u.maxNodeDisplacement*a.sign(this.displacementX)),Math.abs(this.displacementY)>u.coolingFactor*u.maxNodeDisplacement&&(this.displacementY=u.coolingFactor*u.maxNodeDisplacement*a.sign(this.displacementY)),this.child==null?this.moveBy(this.displacementX,this.displacementY):this.child.getNodes().length==0?this.moveBy(this.displacementX,this.displacementY):this.propogateDisplacementToChildren(this.displacementX,this.displacementY),u.totalDisplacement+=Math.abs(this.displacementX)+Math.abs(this.displacementY),this.springForceX=0,this.springForceY=0,this.repulsionForceX=0,this.repulsionForceY=0,this.gravitationForceX=0,this.gravitationForceY=0,this.displacementX=0,this.displacementY=0},s.prototype.propogateDisplacementToChildren=function(u,h){for(var f=this.getChild().getNodes(),d,p=0;p0)this.positionNodesRadially(T);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var E=new Set(this.getAllNodes()),_=this.nodesWithGravity.filter(function(A){return E.has(A)});this.graphManager.setAllNodesToApplyGravitation(_),this.positionNodesRandomly()}}return this.initSpringEmbedder(),this.runSpringEmbedder(),!0},w.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%f.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var T=new Set(this.getAllNodes()),E=this.nodesWithGravity.filter(function(L){return T.has(L)});this.graphManager.setAllNodesToApplyGravitation(E),this.graphManager.updateBounds(),this.updateGrid(),this.coolingFactor=f.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),this.coolingFactor=f.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var _=!this.isTreeGrowing&&!this.isGrowthFinished,A=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(_,A),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},w.prototype.getPositionsData=function(){for(var T=this.graphManager.getAllNodes(),E={},_=0;_1){var k;for(k=0;kA&&(A=Math.floor(N.y)),M=Math.floor(N.x+h.DEFAULT_COMPONENT_SEPERATION)}this.transform(new m(d.WORLD_CENTER_X-N.x/2,d.WORLD_CENTER_Y-N.y/2))},w.radialLayout=function(T,E,_){var A=Math.max(this.maxDiagonalInTree(T),h.DEFAULT_RADIAL_SEPARATION);w.branchRadialLayout(E,null,0,359,0,A);var L=x.calculateBounds(T),M=new b;M.setDeviceOrgX(L.getMinX()),M.setDeviceOrgY(L.getMinY()),M.setWorldOrgX(_.x),M.setWorldOrgY(_.y);for(var N=0;N1;){var Q=Y[0];Y.splice(0,1);var X=P.indexOf(Q);X>=0&&P.splice(X,1),$--,F--}E!=null?z=(P.indexOf(Y[0])+1)%$:z=0;for(var ie=Math.abs(A-_)/F,j=z;B!=F;j=++j%$){var J=P[j].getOtherEnd(T);if(J!=E){var Z=(_+B*ie)%360,H=(Z+ie)%360;w.branchRadialLayout(J,T,Z,H,L+M,M),B++}}},w.maxDiagonalInTree=function(T){for(var E=y.MIN_VALUE,_=0;_E&&(E=L)}return E},w.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},w.prototype.groupZeroDegreeMembers=function(){var T=this,E={};this.memberGroups={},this.idToDummyNode={};for(var _=[],A=this.graphManager.getAllNodes(),L=0;L"u"&&(E[k]=[]),E[k]=E[k].concat(M)}Object.keys(E).forEach(function(I){if(E[I].length>1){var C="DummyCompound_"+I;T.memberGroups[C]=E[I];var O=E[I][0].getParent(),D=new l(T.graphManager);D.id=C,D.paddingLeft=O.paddingLeft||0,D.paddingRight=O.paddingRight||0,D.paddingBottom=O.paddingBottom||0,D.paddingTop=O.paddingTop||0,T.idToDummyNode[C]=D;var P=T.getGraphManager().add(T.newGraph(),D),F=O.getChild();F.add(D);for(var B=0;B=0;T--){var E=this.compoundOrder[T],_=E.id,A=E.paddingLeft,L=E.paddingTop;this.adjustLocations(this.tiledMemberPack[_],E.rect.x,E.rect.y,A,L)}},w.prototype.repopulateZeroDegreeMembers=function(){var T=this,E=this.tiledZeroDegreePack;Object.keys(E).forEach(function(_){var A=T.idToDummyNode[_],L=A.paddingLeft,M=A.paddingTop;T.adjustLocations(E[_],A.rect.x,A.rect.y,L,M)})},w.prototype.getToBeTiled=function(T){var E=T.id;if(this.toBeTiled[E]!=null)return this.toBeTiled[E];var _=T.getChild();if(_==null)return this.toBeTiled[E]=!1,!1;for(var A=_.getNodes(),L=0;L0)return this.toBeTiled[E]=!1,!1;if(M.getChild()==null){this.toBeTiled[M.id]=!1;continue}if(!this.getToBeTiled(M))return this.toBeTiled[E]=!1,!1}return this.toBeTiled[E]=!0,!0},w.prototype.getNodeDegree=function(T){for(var E=T.id,_=T.getEdges(),A=0,L=0;L<_.length;L++){var M=_[L];M.getSource().id!==M.getTarget().id&&(A=A+1)}return A},w.prototype.getNodeDegreeWithChildren=function(T){var E=this.getNodeDegree(T);if(T.getChild()==null)return E;for(var _=T.getChild().getNodes(),A=0;A<_.length;A++){var L=_[A];E+=this.getNodeDegreeWithChildren(L)}return E},w.prototype.performDFSOnCompounds=function(){this.compoundOrder=[],this.fillCompexOrderByDFS(this.graphManager.getRoot().getNodes())},w.prototype.fillCompexOrderByDFS=function(T){for(var E=0;EI&&(I=O.rect.height)}_+=I+T.verticalPadding}},w.prototype.tileCompoundMembers=function(T,E){var _=this;this.tiledMemberPack=[],Object.keys(T).forEach(function(A){var L=E[A];_.tiledMemberPack[A]=_.tileNodes(T[A],L.paddingLeft+L.paddingRight),L.rect.width=_.tiledMemberPack[A].width,L.rect.height=_.tiledMemberPack[A].height})},w.prototype.tileNodes=function(T,E){var _=h.TILING_PADDING_VERTICAL,A=h.TILING_PADDING_HORIZONTAL,L={rows:[],rowWidth:[],rowHeight:[],width:0,height:E,verticalPadding:_,horizontalPadding:A};T.sort(function(k,I){return k.rect.width*k.rect.height>I.rect.width*I.rect.height?-1:k.rect.width*k.rect.height0&&(N+=T.horizontalPadding),T.rowWidth[_]=N,T.width0&&(k+=T.verticalPadding);var I=0;k>T.rowHeight[_]&&(I=T.rowHeight[_],T.rowHeight[_]=k,I=T.rowHeight[_]-I),T.height+=I,T.rows[_].push(E)},w.prototype.getShortestRowIndex=function(T){for(var E=-1,_=Number.MAX_VALUE,A=0;A_&&(E=A,_=T.rowWidth[A]);return E},w.prototype.canAddHorizontal=function(T,E,_){var A=this.getShortestRowIndex(T);if(A<0)return!0;var L=T.rowWidth[A];if(L+T.horizontalPadding+E<=T.width)return!0;var M=0;T.rowHeight[A]<_&&A>0&&(M=_+T.verticalPadding-T.rowHeight[A]);var N;T.width-L>=E+T.horizontalPadding?N=(T.height+M)/(L+E+T.horizontalPadding):N=(T.height+M)/T.width,M=_+T.verticalPadding;var k;return T.widthM&&E!=_){A.splice(-1,1),T.rows[_].push(L),T.rowWidth[E]=T.rowWidth[E]-M,T.rowWidth[_]=T.rowWidth[_]+M,T.width=T.rowWidth[instance.getLongestRowIndex(T)];for(var N=Number.MIN_VALUE,k=0;kN&&(N=A[k].height);E>0&&(N+=T.verticalPadding);var I=T.rowHeight[E]+T.rowHeight[_];T.rowHeight[E]=N,T.rowHeight[_]0)for(var F=L;F<=M;F++)P[0]+=this.grid[F][N-1].length+this.grid[F][N].length-1;if(M0)for(var F=N;F<=k;F++)P[3]+=this.grid[L-1][F].length+this.grid[L][F].length-1;for(var B=y.MAX_VALUE,$,z,Y=0;Y{"use strict";o(function(e,r){typeof lb=="object"&&typeof kB=="object"?kB.exports=r(TB()):typeof define=="function"&&define.amd?define(["cose-base"],r):typeof lb=="object"?lb.cytoscapeCoseBilkent=r(TB()):e.cytoscapeCoseBilkent=r(e.coseBase)},"webpackUniversalModuleDefinition")(lb,function(t){return function(e){var r={};function n(i){if(r[i])return r[i].exports;var a=r[i]={i,l:!1,exports:{}};return e[i].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return o(n,"__webpack_require__"),n.m=e,n.c=r,n.i=function(i){return i},n.d=function(i,a,s){n.o(i,a)||Object.defineProperty(i,a,{configurable:!1,enumerable:!0,get:s})},n.n=function(i){var a=i&&i.__esModule?o(function(){return i.default},"getDefault"):o(function(){return i},"getModuleExports");return n.d(a,"a",a),a},n.o=function(i,a){return Object.prototype.hasOwnProperty.call(i,a)},n.p="",n(n.s=1)}([function(e,r){e.exports=t},function(e,r,n){"use strict";var i=n(0).layoutBase.LayoutConstants,a=n(0).layoutBase.FDLayoutConstants,s=n(0).CoSEConstants,l=n(0).CoSELayout,u=n(0).CoSENode,h=n(0).layoutBase.PointD,f=n(0).layoutBase.DimensionD,d={ready:o(function(){},"ready"),stop:o(function(){},"stop"),quality:"default",nodeDimensionsIncludeLabels:!1,refresh:30,fit:!0,padding:10,randomize:!0,nodeRepulsion:4500,idealEdgeLength:50,edgeElasticity:.45,nestingFactor:.1,gravity:.25,numIter:2500,tile:!0,animate:"end",animationDuration:500,tilingPaddingVertical:10,tilingPaddingHorizontal:10,gravityRangeCompound:1.5,gravityCompound:1,gravityRange:3.8,initialEnergyOnIncremental:.5};function p(v,x){var b={};for(var w in v)b[w]=v[w];for(var w in x)b[w]=x[w];return b}o(p,"extend");function m(v){this.options=p(d,v),g(this.options)}o(m,"_CoSELayout");var g=o(function(x){x.nodeRepulsion!=null&&(s.DEFAULT_REPULSION_STRENGTH=a.DEFAULT_REPULSION_STRENGTH=x.nodeRepulsion),x.idealEdgeLength!=null&&(s.DEFAULT_EDGE_LENGTH=a.DEFAULT_EDGE_LENGTH=x.idealEdgeLength),x.edgeElasticity!=null&&(s.DEFAULT_SPRING_STRENGTH=a.DEFAULT_SPRING_STRENGTH=x.edgeElasticity),x.nestingFactor!=null&&(s.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=a.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=x.nestingFactor),x.gravity!=null&&(s.DEFAULT_GRAVITY_STRENGTH=a.DEFAULT_GRAVITY_STRENGTH=x.gravity),x.numIter!=null&&(s.MAX_ITERATIONS=a.MAX_ITERATIONS=x.numIter),x.gravityRange!=null&&(s.DEFAULT_GRAVITY_RANGE_FACTOR=a.DEFAULT_GRAVITY_RANGE_FACTOR=x.gravityRange),x.gravityCompound!=null&&(s.DEFAULT_COMPOUND_GRAVITY_STRENGTH=a.DEFAULT_COMPOUND_GRAVITY_STRENGTH=x.gravityCompound),x.gravityRangeCompound!=null&&(s.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=a.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=x.gravityRangeCompound),x.initialEnergyOnIncremental!=null&&(s.DEFAULT_COOLING_FACTOR_INCREMENTAL=a.DEFAULT_COOLING_FACTOR_INCREMENTAL=x.initialEnergyOnIncremental),x.quality=="draft"?i.QUALITY=0:x.quality=="proof"?i.QUALITY=2:i.QUALITY=1,s.NODE_DIMENSIONS_INCLUDE_LABELS=a.NODE_DIMENSIONS_INCLUDE_LABELS=i.NODE_DIMENSIONS_INCLUDE_LABELS=x.nodeDimensionsIncludeLabels,s.DEFAULT_INCREMENTAL=a.DEFAULT_INCREMENTAL=i.DEFAULT_INCREMENTAL=!x.randomize,s.ANIMATE=a.ANIMATE=i.ANIMATE=x.animate,s.TILE=x.tile,s.TILING_PADDING_VERTICAL=typeof x.tilingPaddingVertical=="function"?x.tilingPaddingVertical.call():x.tilingPaddingVertical,s.TILING_PADDING_HORIZONTAL=typeof x.tilingPaddingHorizontal=="function"?x.tilingPaddingHorizontal.call():x.tilingPaddingHorizontal},"getUserOptions");m.prototype.run=function(){var v,x,b=this.options,w=this.idToLNode={},S=this.layout=new l,T=this;T.stopped=!1,this.cy=this.options.cy,this.cy.trigger({type:"layoutstart",layout:this});var E=S.newGraphManager();this.gm=E;var _=this.options.eles.nodes(),A=this.options.eles.edges();this.root=E.addRoot(),this.processChildrenList(this.root,this.getTopMostNodes(_),S);for(var L=0;L0){var k;k=b.getGraphManager().add(b.newGraph(),_),this.processChildrenList(k,E,b)}}},m.prototype.stop=function(){return this.stopped=!0,this};var y=o(function(x){x("layout","cose-bilkent",m)},"register");typeof cytoscape<"u"&&y(cytoscape),e.exports=y}])})});function fZe(t,e,r,n,i){return t.insert("polygon",":first-child").attr("points",n.map(function(a){return a.x+","+a.y}).join(" ")).attr("transform","translate("+(i.width-e)/2+", "+r+")")}var sZe,oZe,lZe,cZe,uZe,hZe,dZe,pZe,sge,oge,lge=R(()=>{"use strict";Al();xr();sZe=12,oZe=o(function(t,e,r,n){e.append("path").attr("id","node-"+r.id).attr("class","node-bkg node-"+t.type2Str(r.type)).attr("d",`M0 ${r.height-5} v${-r.height+2*5} q0,-5 5,-5 h${r.width-2*5} q5,0 5,5 v${r.height-5} H0 Z`),e.append("line").attr("class","node-line-"+n).attr("x1",0).attr("y1",r.height).attr("x2",r.width).attr("y2",r.height)},"defaultBkg"),lZe=o(function(t,e,r){e.append("rect").attr("id","node-"+r.id).attr("class","node-bkg node-"+t.type2Str(r.type)).attr("height",r.height).attr("width",r.width)},"rectBkg"),cZe=o(function(t,e,r){let n=r.width,i=r.height,a=.15*n,s=.25*n,l=.35*n,u=.2*n;e.append("path").attr("id","node-"+r.id).attr("class","node-bkg node-"+t.type2Str(r.type)).attr("d",`M0 0 a${a},${a} 0 0,1 ${n*.25},${-1*n*.1} + a${l},${l} 1 0,1 ${n*.4},${-1*n*.1} + a${s},${s} 1 0,1 ${n*.35},${1*n*.2} + + a${a},${a} 1 0,1 ${n*.15},${1*i*.35} + a${u},${u} 1 0,1 ${-1*n*.15},${1*i*.65} + + a${s},${a} 1 0,1 ${-1*n*.25},${n*.15} + a${l},${l} 1 0,1 ${-1*n*.5},0 + a${a},${a} 1 0,1 ${-1*n*.25},${-1*n*.15} + + a${a},${a} 1 0,1 ${-1*n*.1},${-1*i*.35} + a${u},${u} 1 0,1 ${n*.1},${-1*i*.65} + + H0 V0 Z`)},"cloudBkg"),uZe=o(function(t,e,r){let n=r.width,i=r.height,a=.15*n;e.append("path").attr("id","node-"+r.id).attr("class","node-bkg node-"+t.type2Str(r.type)).attr("d",`M0 0 a${a},${a} 1 0,0 ${n*.25},${-1*i*.1} + a${a},${a} 1 0,0 ${n*.25},0 + a${a},${a} 1 0,0 ${n*.25},0 + a${a},${a} 1 0,0 ${n*.25},${1*i*.1} + + a${a},${a} 1 0,0 ${n*.15},${1*i*.33} + a${a*.8},${a*.8} 1 0,0 0,${1*i*.34} + a${a},${a} 1 0,0 ${-1*n*.15},${1*i*.33} + + a${a},${a} 1 0,0 ${-1*n*.25},${i*.15} + a${a},${a} 1 0,0 ${-1*n*.25},0 + a${a},${a} 1 0,0 ${-1*n*.25},0 + a${a},${a} 1 0,0 ${-1*n*.25},${-1*i*.15} + + a${a},${a} 1 0,0 ${-1*n*.1},${-1*i*.33} + a${a*.8},${a*.8} 1 0,0 0,${-1*i*.34} + a${a},${a} 1 0,0 ${n*.1},${-1*i*.33} + + H0 V0 Z`)},"bangBkg"),hZe=o(function(t,e,r){e.append("circle").attr("id","node-"+r.id).attr("class","node-bkg node-"+t.type2Str(r.type)).attr("r",r.width/2)},"circleBkg");o(fZe,"insertPolygonShape");dZe=o(function(t,e,r){let n=r.height,a=n/4,s=r.width-r.padding+2*a,l=[{x:a,y:0},{x:s-a,y:0},{x:s,y:-n/2},{x:s-a,y:-n},{x:a,y:-n},{x:0,y:-n/2}];fZe(e,s,n,l,r)},"hexagonBkg"),pZe=o(function(t,e,r){e.append("rect").attr("id","node-"+r.id).attr("class","node-bkg node-"+t.type2Str(r.type)).attr("height",r.height).attr("rx",r.padding).attr("ry",r.padding).attr("width",r.width)},"roundedRectBkg"),sge=o(async function(t,e,r,n,i){let a=i.htmlLabels,s=n%(sZe-1),l=e.append("g");r.section=s;let u="section-"+s;s<0&&(u+=" section-root"),l.attr("class",(r.class?r.class+" ":"")+"mindmap-node "+u);let h=l.append("g"),f=l.append("g"),d=r.descr.replace(/()/g,` +`);await ta(f,d,{useHtmlLabels:a,width:r.width,classes:"mindmap-node-label"},i),a||f.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle");let p=f.node().getBBox(),[m]=mc(i.fontSize);if(r.height=p.height+m*1.1*.5+r.padding,r.width=p.width+2*r.padding,r.icon)if(r.type===t.nodeType.CIRCLE)r.height+=50,r.width+=50,l.append("foreignObject").attr("height","50px").attr("width",r.width).attr("style","text-align: center;").append("div").attr("class","icon-container").append("i").attr("class","node-icon-"+s+" "+r.icon),f.attr("transform","translate("+r.width/2+", "+(r.height/2-1.5*r.padding)+")");else{r.width+=50;let g=r.height;r.height=Math.max(g,60);let y=Math.abs(r.height-g);l.append("foreignObject").attr("width","60px").attr("height",r.height).attr("style","text-align: center;margin-top:"+y/2+"px;").append("div").attr("class","icon-container").append("i").attr("class","node-icon-"+s+" "+r.icon),f.attr("transform","translate("+(25+r.width/2)+", "+(y/2+r.padding/2)+")")}else if(a){let g=(r.width-p.width)/2,y=(r.height-p.height)/2;f.attr("transform","translate("+g+", "+y+")")}else{let g=r.width/2,y=r.padding/2;f.attr("transform","translate("+g+", "+y+")")}switch(r.type){case t.nodeType.DEFAULT:oZe(t,h,r,s);break;case t.nodeType.ROUNDED_RECT:pZe(t,h,r,s);break;case t.nodeType.RECT:lZe(t,h,r,s);break;case t.nodeType.CIRCLE:h.attr("transform","translate("+r.width/2+", "+ +r.height/2+")"),hZe(t,h,r,s);break;case t.nodeType.CLOUD:cZe(t,h,r,s);break;case t.nodeType.BANG:uZe(t,h,r,s);break;case t.nodeType.HEXAGON:dZe(t,h,r,s);break}return t.setElementForId(r.id,l),r.height},"drawNode"),oge=o(function(t,e){let r=t.getElementById(e.id),n=e.x||0,i=e.y||0;r.attr("transform","translate("+n+","+i+")")},"positionNode")});async function uge(t,e,r,n,i){await sge(t,e,r,n,i),r.children&&await Promise.all(r.children.map((a,s)=>uge(t,e,a,n<0?s:n,i)))}function mZe(t,e){e.edges().map((r,n)=>{let i=r.data();if(r[0]._private.bodyBounds){let a=r[0]._private.rscratch;V.trace("Edge: ",n,i),t.insert("path").attr("d",`M ${a.startX},${a.startY} L ${a.midX},${a.midY} L${a.endX},${a.endY} `).attr("class","edge section-edge-"+i.section+" edge-depth-"+i.depth)}})}function hge(t,e,r,n){e.add({group:"nodes",data:{id:t.id.toString(),labelText:t.descr,height:t.height,width:t.width,level:n,nodeId:t.id,padding:t.padding,type:t.type},position:{x:t.x,y:t.y}}),t.children&&t.children.forEach(i=>{hge(i,e,r,n+1),e.add({group:"edges",data:{id:`${t.id}_${i.id}`,source:t.id,target:i.id,depth:n,section:i.section}})})}function gZe(t,e){return new Promise(r=>{let n=$e("body").append("div").attr("id","cy").attr("style","display:none"),i=rl({container:document.getElementById("cy"),style:[{selector:"edge",style:{"curve-style":"bezier"}}]});n.remove(),hge(t,i,e,0),i.nodes().forEach(function(a){a.layoutDimensions=()=>{let s=a.data();return{w:s.width,h:s.height}}}),i.layout({name:"cose-bilkent",quality:"proof",styleEnabled:!1,animate:!1}).run(),i.ready(a=>{V.info("Ready",a),r(i)})})}function yZe(t,e){e.nodes().map((r,n)=>{let i=r.data();i.x=r.position().x,i.y=r.position().y,oge(t,i);let a=t.getElementById(i.nodeId);V.info("Id:",n,"Position: (",r.position().x,", ",r.position().y,")",i),a.attr("transform",`translate(${r.position().x-i.width/2}, ${r.position().y-i.height/2})`),a.attr("attr",`apa-${n})`)})}var cge,vZe,fge,dge=R(()=>{"use strict";vB();cge=Xi(age(),1);Zt();_t();ut();pf();Yn();lge();sl();rl.use(cge.default);o(uge,"drawNodes");o(mZe,"drawEdges");o(hge,"addNodes");o(gZe,"layoutMindmap");o(yZe,"positionNodes");vZe=o(async(t,e,r,n)=>{V.debug(`Rendering mindmap diagram +`+t);let i=n.db,a=i.getMindmap();if(!a)return;let s=de();s.htmlLabels=!1;let l=Ps(e),u=l.append("g");u.attr("class","mindmap-edges");let h=l.append("g");h.attr("class","mindmap-nodes"),await uge(i,h,a,-1,s);let f=await gZe(a,s);mZe(u,f),yZe(i,f),Lo(void 0,l,s.mindmap?.padding??mr.mindmap.padding,s.mindmap?.useMaxWidth??mr.mindmap.useMaxWidth)},"draw"),fge={draw:vZe}});var xZe,bZe,pge,mge=R(()=>{"use strict";al();xZe=o(t=>{let e="";for(let r=0;r` + .edge { + stroke-width: 3; + } + ${xZe(t)} + .section-root rect, .section-root path, .section-root circle, .section-root polygon { + fill: ${t.git0}; + } + .section-root text { + fill: ${t.gitBranchLabel0}; + } + .icon-container { + height:100%; + display: flex; + justify-content: center; + align-items: center; + } + .edge { + fill: none; + } + .mindmap-node-label { + dy: 1em; + alignment-baseline: middle; + text-anchor: middle; + dominant-baseline: middle; + text-align: center; + } +`,"getStyles"),pge=bZe});var gge={};hr(gge,{diagram:()=>wZe});var wZe,yge=R(()=>{"use strict";r0e();a0e();dge();mge();wZe={db:i0e,renderer:fge,parser:t0e,styles:pge}});var EB,cb,bge=R(()=>{"use strict";EB=function(){var t=o(function(l,u,h,f){for(h=h||{},f=l.length;f--;h[l[f]]=u);return h},"o"),e=[1,9],r=[1,10],n=[1,5,10,12],i={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SANKEY:4,NEWLINE:5,csv:6,opt_eof:7,record:8,csv_tail:9,EOF:10,"field[source]":11,COMMA:12,"field[target]":13,"field[value]":14,field:15,escaped:16,non_escaped:17,DQUOTE:18,ESCAPED_TEXT:19,NON_ESCAPED_TEXT:20,$accept:0,$end:1},terminals_:{2:"error",4:"SANKEY",5:"NEWLINE",10:"EOF",11:"field[source]",12:"COMMA",13:"field[target]",14:"field[value]",18:"DQUOTE",19:"ESCAPED_TEXT",20:"NON_ESCAPED_TEXT"},productions_:[0,[3,4],[6,2],[9,2],[9,0],[7,1],[7,0],[8,5],[15,1],[15,1],[16,3],[17,1]],performAction:o(function(u,h,f,d,p,m,g){var y=m.length-1;switch(p){case 7:let v=d.findOrCreateNode(m[y-4].trim().replaceAll('""','"')),x=d.findOrCreateNode(m[y-2].trim().replaceAll('""','"')),b=parseFloat(m[y].trim());d.addLink(v,x,b);break;case 8:case 9:case 11:this.$=m[y];break;case 10:this.$=m[y-1];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3]},{6:4,8:5,15:6,16:7,17:8,18:e,20:r},{1:[2,6],7:11,10:[1,12]},t(r,[2,4],{9:13,5:[1,14]}),{12:[1,15]},t(n,[2,8]),t(n,[2,9]),{19:[1,16]},t(n,[2,11]),{1:[2,1]},{1:[2,5]},t(r,[2,2]),{6:17,8:5,15:6,16:7,17:8,18:e,20:r},{15:18,16:7,17:8,18:e,20:r},{18:[1,19]},t(r,[2,3]),{12:[1,20]},t(n,[2,10]),{15:21,16:7,17:8,18:e,20:r},t([1,5,10],[2,7])],defaultActions:{11:[2,1],12:[2,5]},parseError:o(function(u,h){if(h.recoverable)this.trace(u);else{var f=new Error(u);throw f.hash=h,f}},"parseError"),parse:o(function(u){var h=this,f=[0],d=[],p=[null],m=[],g=this.table,y="",v=0,x=0,b=0,w=2,S=1,T=m.slice.call(arguments,1),E=Object.create(this.lexer),_={yy:{}};for(var A in this.yy)Object.prototype.hasOwnProperty.call(this.yy,A)&&(_.yy[A]=this.yy[A]);E.setInput(u,_.yy),_.yy.lexer=E,_.yy.parser=this,typeof E.yylloc>"u"&&(E.yylloc={});var L=E.yylloc;m.push(L);var M=E.options&&E.options.ranges;typeof _.yy.parseError=="function"?this.parseError=_.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function N(ie){f.length=f.length-2*ie,p.length=p.length-ie,m.length=m.length-ie}o(N,"popStack");function k(){var ie;return ie=d.pop()||E.lex()||S,typeof ie!="number"&&(ie instanceof Array&&(d=ie,ie=d.pop()),ie=h.symbols_[ie]||ie),ie}o(k,"lex");for(var I,C,O,D,P,F,B={},$,z,Y,Q;;){if(O=f[f.length-1],this.defaultActions[O]?D=this.defaultActions[O]:((I===null||typeof I>"u")&&(I=k()),D=g[O]&&g[O][I]),typeof D>"u"||!D.length||!D[0]){var X="";Q=[];for($ in g[O])this.terminals_[$]&&$>w&&Q.push("'"+this.terminals_[$]+"'");E.showPosition?X="Parse error on line "+(v+1)+`: +`+E.showPosition()+` +Expecting `+Q.join(", ")+", got '"+(this.terminals_[I]||I)+"'":X="Parse error on line "+(v+1)+": Unexpected "+(I==S?"end of input":"'"+(this.terminals_[I]||I)+"'"),this.parseError(X,{text:E.match,token:this.terminals_[I]||I,line:E.yylineno,loc:L,expected:Q})}if(D[0]instanceof Array&&D.length>1)throw new Error("Parse Error: multiple actions possible at state: "+O+", token: "+I);switch(D[0]){case 1:f.push(I),p.push(E.yytext),m.push(E.yylloc),f.push(D[1]),I=null,C?(I=C,C=null):(x=E.yyleng,y=E.yytext,v=E.yylineno,L=E.yylloc,b>0&&b--);break;case 2:if(z=this.productions_[D[1]][1],B.$=p[p.length-z],B._$={first_line:m[m.length-(z||1)].first_line,last_line:m[m.length-1].last_line,first_column:m[m.length-(z||1)].first_column,last_column:m[m.length-1].last_column},M&&(B._$.range=[m[m.length-(z||1)].range[0],m[m.length-1].range[1]]),F=this.performAction.apply(B,[y,x,v,_.yy,D[1],p,m].concat(T)),typeof F<"u")return F;z&&(f=f.slice(0,-1*z*2),p=p.slice(0,-1*z),m=m.slice(0,-1*z)),f.push(this.productions_[D[1]][0]),p.push(B.$),m.push(B._$),Y=g[f[f.length-2]][f[f.length-1]],f.push(Y);break;case 3:return!0}}return!0},"parse")},a=function(){var l={EOF:1,parseError:o(function(h,f){if(this.yy.parser)this.yy.parser.parseError(h,f);else throw new Error(h)},"parseError"),setInput:o(function(u,h){return this.yy=h||this.yy||{},this._input=u,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var u=this._input[0];this.yytext+=u,this.yyleng++,this.offset++,this.match+=u,this.matched+=u;var h=u.match(/(?:\r\n?|\n).*/g);return h?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),u},"input"),unput:o(function(u){var h=u.length,f=u.split(/(?:\r\n?|\n)/g);this._input=u+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-h),this.offset-=h;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),f.length-1&&(this.yylineno-=f.length-1);var p=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:f?(f.length===d.length?this.yylloc.first_column:0)+d[d.length-f.length].length-f[0].length:this.yylloc.first_column-h},this.options.ranges&&(this.yylloc.range=[p[0],p[0]+this.yyleng-h]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(u){this.unput(this.match.slice(u))},"less"),pastInput:o(function(){var u=this.matched.substr(0,this.matched.length-this.match.length);return(u.length>20?"...":"")+u.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var u=this.match;return u.length<20&&(u+=this._input.substr(0,20-u.length)),(u.substr(0,20)+(u.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var u=this.pastInput(),h=new Array(u.length+1).join("-");return u+this.upcomingInput()+` +`+h+"^"},"showPosition"),test_match:o(function(u,h){var f,d,p;if(this.options.backtrack_lexer&&(p={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(p.yylloc.range=this.yylloc.range.slice(0))),d=u[0].match(/(?:\r\n?|\n).*/g),d&&(this.yylineno+=d.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:d?d[d.length-1].length-d[d.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+u[0].length},this.yytext+=u[0],this.match+=u[0],this.matches=u,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(u[0].length),this.matched+=u[0],f=this.performAction.call(this,this.yy,this,h,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),f)return f;if(this._backtrack){for(var m in p)this[m]=p[m];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var u,h,f,d;this._more||(this.yytext="",this.match="");for(var p=this._currentRules(),m=0;mh[0].length)){if(h=f,d=m,this.options.backtrack_lexer){if(u=this.test_match(f,p[m]),u!==!1)return u;if(this._backtrack){h=!1;continue}else return!1}else if(!this.options.flex)break}return h?(u=this.test_match(h,p[d]),u!==!1?u:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var h=this.next();return h||this.lex()},"lex"),begin:o(function(h){this.conditionStack.push(h)},"begin"),popState:o(function(){var h=this.conditionStack.length-1;return h>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(h){return h=this.conditionStack.length-1-Math.abs(h||0),h>=0?this.conditionStack[h]:"INITIAL"},"topState"),pushState:o(function(h){this.begin(h)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:o(function(h,f,d,p){var m=p;switch(d){case 0:return this.pushState("csv"),4;break;case 1:return 10;case 2:return 5;case 3:return 12;case 4:return this.pushState("escaped_text"),18;break;case 5:return 20;case 6:return this.popState("escaped_text"),18;break;case 7:return 19}},"anonymous"),rules:[/^(?:sankey-beta\b)/i,/^(?:$)/i,/^(?:((\u000D\u000A)|(\u000A)))/i,/^(?:(\u002C))/i,/^(?:(\u0022))/i,/^(?:([\u0020-\u0021\u0023-\u002B\u002D-\u007E])*)/i,/^(?:(\u0022)(?!(\u0022)))/i,/^(?:(([\u0020-\u0021\u0023-\u002B\u002D-\u007E])|(\u002C)|(\u000D)|(\u000A)|(\u0022)(\u0022))*)/i],conditions:{csv:{rules:[1,2,3,4,5,6,7],inclusive:!1},escaped_text:{rules:[6,7],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7],inclusive:!0}}};return l}();i.lexer=a;function s(){this.yy={}}return o(s,"Parser"),s.prototype=i,i.Parser=s,new s}();EB.parser=EB;cb=EB});var J6,eC,Z6,CZe,CB,SZe,SB,AZe,_Ze,LZe,DZe,wge,Tge=R(()=>{"use strict";_t();rr();bi();J6=[],eC=[],Z6=new Map,CZe=o(()=>{J6=[],eC=[],Z6=new Map,vr()},"clear"),CB=class{constructor(e,r,n=0){this.source=e;this.target=r;this.value=n}static{o(this,"SankeyLink")}},SZe=o((t,e,r)=>{J6.push(new CB(t,e,r))},"addLink"),SB=class{constructor(e){this.ID=e}static{o(this,"SankeyNode")}},AZe=o(t=>{t=We.sanitizeText(t,de());let e=Z6.get(t);return e===void 0&&(e=new SB(t),Z6.set(t,e),eC.push(e)),e},"findOrCreateNode"),_Ze=o(()=>eC,"getNodes"),LZe=o(()=>J6,"getLinks"),DZe=o(()=>({nodes:eC.map(t=>({id:t.ID})),links:J6.map(t=>({source:t.source.ID,target:t.target.ID,value:t.value}))}),"getGraph"),wge={nodesMap:Z6,getConfig:o(()=>de().sankey,"getConfig"),getNodes:_Ze,getLinks:LZe,getGraph:DZe,addLink:SZe,findOrCreateNode:AZe,getAccTitle:Ar,setAccTitle:kr,getAccDescription:Lr,setAccDescription:_r,getDiagramTitle:Xr,setDiagramTitle:nn,clear:CZe}});function ub(t,e){let r;if(e===void 0)for(let n of t)n!=null&&(r=n)&&(r=n);else{let n=-1;for(let i of t)(i=e(i,++n,t))!=null&&(r=i)&&(r=i)}return r}var kge=R(()=>{"use strict";o(ub,"max")});function x1(t,e){let r;if(e===void 0)for(let n of t)n!=null&&(r>n||r===void 0&&n>=n)&&(r=n);else{let n=-1;for(let i of t)(i=e(i,++n,t))!=null&&(r>i||r===void 0&&i>=i)&&(r=i)}return r}var Ege=R(()=>{"use strict";o(x1,"min")});function b1(t,e){let r=0;if(e===void 0)for(let n of t)(n=+n)&&(r+=n);else{let n=-1;for(let i of t)(i=+e(i,++n,t))&&(r+=i)}return r}var Cge=R(()=>{"use strict";o(b1,"sum")});var AB=R(()=>{"use strict";kge();Ege();Cge()});function RZe(t){return t.target.depth}function _B(t){return t.depth}function LB(t,e){return e-1-t.height}function hb(t,e){return t.sourceLinks.length?t.depth:e-1}function DB(t){return t.targetLinks.length?t.depth:t.sourceLinks.length?x1(t.sourceLinks,RZe)-1:0}var RB=R(()=>{"use strict";AB();o(RZe,"targetDepth");o(_B,"left");o(LB,"right");o(hb,"justify");o(DB,"center")});function w1(t){return function(){return t}}var Sge=R(()=>{"use strict";o(w1,"constant")});function Age(t,e){return tC(t.source,e.source)||t.index-e.index}function _ge(t,e){return tC(t.target,e.target)||t.index-e.index}function tC(t,e){return t.y0-e.y0}function NB(t){return t.value}function NZe(t){return t.index}function MZe(t){return t.nodes}function IZe(t){return t.links}function Lge(t,e){let r=t.get(e);if(!r)throw new Error("missing: "+e);return r}function Dge({nodes:t}){for(let e of t){let r=e.y0,n=r;for(let i of e.sourceLinks)i.y0=r+i.width/2,r+=i.width;for(let i of e.targetLinks)i.y1=n+i.width/2,n+=i.width}}function rC(){let t=0,e=0,r=1,n=1,i=24,a=8,s,l=NZe,u=hb,h,f,d=MZe,p=IZe,m=6;function g(){let O={nodes:d.apply(null,arguments),links:p.apply(null,arguments)};return y(O),v(O),x(O),b(O),T(O),Dge(O),O}o(g,"sankey"),g.update=function(O){return Dge(O),O},g.nodeId=function(O){return arguments.length?(l=typeof O=="function"?O:w1(O),g):l},g.nodeAlign=function(O){return arguments.length?(u=typeof O=="function"?O:w1(O),g):u},g.nodeSort=function(O){return arguments.length?(h=O,g):h},g.nodeWidth=function(O){return arguments.length?(i=+O,g):i},g.nodePadding=function(O){return arguments.length?(a=s=+O,g):a},g.nodes=function(O){return arguments.length?(d=typeof O=="function"?O:w1(O),g):d},g.links=function(O){return arguments.length?(p=typeof O=="function"?O:w1(O),g):p},g.linkSort=function(O){return arguments.length?(f=O,g):f},g.size=function(O){return arguments.length?(t=e=0,r=+O[0],n=+O[1],g):[r-t,n-e]},g.extent=function(O){return arguments.length?(t=+O[0][0],r=+O[1][0],e=+O[0][1],n=+O[1][1],g):[[t,e],[r,n]]},g.iterations=function(O){return arguments.length?(m=+O,g):m};function y({nodes:O,links:D}){for(let[F,B]of O.entries())B.index=F,B.sourceLinks=[],B.targetLinks=[];let P=new Map(O.map((F,B)=>[l(F,B,O),F]));for(let[F,B]of D.entries()){B.index=F;let{source:$,target:z}=B;typeof $!="object"&&($=B.source=Lge(P,$)),typeof z!="object"&&(z=B.target=Lge(P,z)),$.sourceLinks.push(B),z.targetLinks.push(B)}if(f!=null)for(let{sourceLinks:F,targetLinks:B}of O)F.sort(f),B.sort(f)}o(y,"computeNodeLinks");function v({nodes:O}){for(let D of O)D.value=D.fixedValue===void 0?Math.max(b1(D.sourceLinks,NB),b1(D.targetLinks,NB)):D.fixedValue}o(v,"computeNodeValues");function x({nodes:O}){let D=O.length,P=new Set(O),F=new Set,B=0;for(;P.size;){for(let $ of P){$.depth=B;for(let{target:z}of $.sourceLinks)F.add(z)}if(++B>D)throw new Error("circular link");P=F,F=new Set}}o(x,"computeNodeDepths");function b({nodes:O}){let D=O.length,P=new Set(O),F=new Set,B=0;for(;P.size;){for(let $ of P){$.height=B;for(let{source:z}of $.targetLinks)F.add(z)}if(++B>D)throw new Error("circular link");P=F,F=new Set}}o(b,"computeNodeHeights");function w({nodes:O}){let D=ub(O,B=>B.depth)+1,P=(r-t-i)/(D-1),F=new Array(D);for(let B of O){let $=Math.max(0,Math.min(D-1,Math.floor(u.call(null,B,D))));B.layer=$,B.x0=t+$*P,B.x1=B.x0+i,F[$]?F[$].push(B):F[$]=[B]}if(h)for(let B of F)B.sort(h);return F}o(w,"computeNodeLayers");function S(O){let D=x1(O,P=>(n-e-(P.length-1)*s)/b1(P,NB));for(let P of O){let F=e;for(let B of P){B.y0=F,B.y1=F+B.value*D,F=B.y1+s;for(let $ of B.sourceLinks)$.width=$.value*D}F=(n-F+s)/(P.length+1);for(let B=0;BP.length)-1)),S(D);for(let P=0;P0))continue;let X=(Y/Q-z.y0)*D;z.y0+=X,z.y1+=X,N(z)}h===void 0&&$.sort(tC),A($,P)}}o(E,"relaxLeftToRight");function _(O,D,P){for(let F=O.length,B=F-2;B>=0;--B){let $=O[B];for(let z of $){let Y=0,Q=0;for(let{target:ie,value:j}of z.sourceLinks){let J=j*(ie.layer-z.layer);Y+=C(z,ie)*J,Q+=J}if(!(Q>0))continue;let X=(Y/Q-z.y0)*D;z.y0+=X,z.y1+=X,N(z)}h===void 0&&$.sort(tC),A($,P)}}o(_,"relaxRightToLeft");function A(O,D){let P=O.length>>1,F=O[P];M(O,F.y0-s,P-1,D),L(O,F.y1+s,P+1,D),M(O,n,O.length-1,D),L(O,e,0,D)}o(A,"resolveCollisions");function L(O,D,P,F){for(;P1e-6&&(B.y0+=$,B.y1+=$),D=B.y1+s}}o(L,"resolveCollisionsTopToBottom");function M(O,D,P,F){for(;P>=0;--P){let B=O[P],$=(B.y1-D)*F;$>1e-6&&(B.y0-=$,B.y1-=$),D=B.y0-s}}o(M,"resolveCollisionsBottomToTop");function N({sourceLinks:O,targetLinks:D}){if(f===void 0){for(let{source:{sourceLinks:P}}of D)P.sort(_ge);for(let{target:{targetLinks:P}}of O)P.sort(Age)}}o(N,"reorderNodeLinks");function k(O){if(f===void 0)for(let{sourceLinks:D,targetLinks:P}of O)D.sort(_ge),P.sort(Age)}o(k,"reorderLinks");function I(O,D){let P=O.y0-(O.sourceLinks.length-1)*s/2;for(let{target:F,width:B}of O.sourceLinks){if(F===D)break;P+=B+s}for(let{source:F,width:B}of D.targetLinks){if(F===O)break;P-=B}return P}o(I,"targetTop");function C(O,D){let P=D.y0-(D.targetLinks.length-1)*s/2;for(let{source:F,width:B}of D.targetLinks){if(F===O)break;P+=B+s}for(let{target:F,width:B}of O.sourceLinks){if(F===D)break;P-=B}return P}return o(C,"sourceTop"),g}var Rge=R(()=>{"use strict";AB();RB();Sge();o(Age,"ascendingSourceBreadth");o(_ge,"ascendingTargetBreadth");o(tC,"ascendingBreadth");o(NB,"value");o(NZe,"defaultId");o(MZe,"defaultNodes");o(IZe,"defaultLinks");o(Lge,"find");o(Dge,"computeLinkBreadths");o(rC,"Sankey")});function OB(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function Nge(){return new OB}var MB,IB,Q0,OZe,PB,Mge=R(()=>{"use strict";MB=Math.PI,IB=2*MB,Q0=1e-6,OZe=IB-Q0;o(OB,"Path");o(Nge,"path");OB.prototype=Nge.prototype={constructor:OB,moveTo:o(function(t,e){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)},"moveTo"),closePath:o(function(){this._x1!==null&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},"closePath"),lineTo:o(function(t,e){this._+="L"+(this._x1=+t)+","+(this._y1=+e)},"lineTo"),quadraticCurveTo:o(function(t,e,r,n){this._+="Q"+ +t+","+ +e+","+(this._x1=+r)+","+(this._y1=+n)},"quadraticCurveTo"),bezierCurveTo:o(function(t,e,r,n,i,a){this._+="C"+ +t+","+ +e+","+ +r+","+ +n+","+(this._x1=+i)+","+(this._y1=+a)},"bezierCurveTo"),arcTo:o(function(t,e,r,n,i){t=+t,e=+e,r=+r,n=+n,i=+i;var a=this._x1,s=this._y1,l=r-t,u=n-e,h=a-t,f=s-e,d=h*h+f*f;if(i<0)throw new Error("negative radius: "+i);if(this._x1===null)this._+="M"+(this._x1=t)+","+(this._y1=e);else if(d>Q0)if(!(Math.abs(f*l-u*h)>Q0)||!i)this._+="L"+(this._x1=t)+","+(this._y1=e);else{var p=r-a,m=n-s,g=l*l+u*u,y=p*p+m*m,v=Math.sqrt(g),x=Math.sqrt(d),b=i*Math.tan((MB-Math.acos((g+d-y)/(2*v*x)))/2),w=b/x,S=b/v;Math.abs(w-1)>Q0&&(this._+="L"+(t+w*h)+","+(e+w*f)),this._+="A"+i+","+i+",0,0,"+ +(f*p>h*m)+","+(this._x1=t+S*l)+","+(this._y1=e+S*u)}},"arcTo"),arc:o(function(t,e,r,n,i,a){t=+t,e=+e,r=+r,a=!!a;var s=r*Math.cos(n),l=r*Math.sin(n),u=t+s,h=e+l,f=1^a,d=a?n-i:i-n;if(r<0)throw new Error("negative radius: "+r);this._x1===null?this._+="M"+u+","+h:(Math.abs(this._x1-u)>Q0||Math.abs(this._y1-h)>Q0)&&(this._+="L"+u+","+h),r&&(d<0&&(d=d%IB+IB),d>OZe?this._+="A"+r+","+r+",0,1,"+f+","+(t-s)+","+(e-l)+"A"+r+","+r+",0,1,"+f+","+(this._x1=u)+","+(this._y1=h):d>Q0&&(this._+="A"+r+","+r+",0,"+ +(d>=MB)+","+f+","+(this._x1=t+r*Math.cos(i))+","+(this._y1=e+r*Math.sin(i))))},"arc"),rect:o(function(t,e,r,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +r+"v"+ +n+"h"+-r+"Z"},"rect"),toString:o(function(){return this._},"toString")};PB=Nge});var Ige=R(()=>{"use strict";Mge()});function nC(t){return o(function(){return t},"constant")}var Oge=R(()=>{"use strict";o(nC,"default")});function Pge(t){return t[0]}function Bge(t){return t[1]}var Fge=R(()=>{"use strict";o(Pge,"x");o(Bge,"y")});var zge,Gge=R(()=>{"use strict";zge=Array.prototype.slice});function PZe(t){return t.source}function BZe(t){return t.target}function FZe(t){var e=PZe,r=BZe,n=Pge,i=Bge,a=null;function s(){var l,u=zge.call(arguments),h=e.apply(this,u),f=r.apply(this,u);if(a||(a=l=PB()),t(a,+n.apply(this,(u[0]=h,u)),+i.apply(this,u),+n.apply(this,(u[0]=f,u)),+i.apply(this,u)),l)return a=null,l+""||null}return o(s,"link"),s.source=function(l){return arguments.length?(e=l,s):e},s.target=function(l){return arguments.length?(r=l,s):r},s.x=function(l){return arguments.length?(n=typeof l=="function"?l:nC(+l),s):n},s.y=function(l){return arguments.length?(i=typeof l=="function"?l:nC(+l),s):i},s.context=function(l){return arguments.length?(a=l??null,s):a},s}function zZe(t,e,r,n,i){t.moveTo(e,r),t.bezierCurveTo(e=(e+n)/2,r,e,i,n,i)}function BB(){return FZe(zZe)}var $ge=R(()=>{"use strict";Ige();Gge();Oge();Fge();o(PZe,"linkSource");o(BZe,"linkTarget");o(FZe,"link");o(zZe,"curveHorizontal");o(BB,"linkHorizontal")});var Vge=R(()=>{"use strict";$ge()});function GZe(t){return[t.source.x1,t.y0]}function $Ze(t){return[t.target.x0,t.y1]}function iC(){return BB().source(GZe).target($Ze)}var Uge=R(()=>{"use strict";Vge();o(GZe,"horizontalSource");o($Ze,"horizontalTarget");o(iC,"default")});var Hge=R(()=>{"use strict";Rge();RB();Uge()});var fb,Yge=R(()=>{"use strict";fb=class t{static{o(this,"Uid")}static{this.count=0}static next(e){return new t(e+ ++t.count)}constructor(e){this.id=e,this.href=`#${e}`}toString(){return"url("+this.href+")"}}});var VZe,UZe,Wge,qge=R(()=>{"use strict";_t();Zt();Hge();Yn();Yge();VZe={left:_B,right:LB,center:DB,justify:hb},UZe=o(function(t,e,r,n){let{securityLevel:i,sankey:a}=de(),s=_4.sankey,l;i==="sandbox"&&(l=$e("#i"+e));let u=i==="sandbox"?$e(l.nodes()[0].contentDocument.body):$e("body"),h=i==="sandbox"?u.select(`[id="${e}"]`):$e(`[id="${e}"]`),f=a?.width??s.width,d=a?.height??s.width,p=a?.useMaxWidth??s.useMaxWidth,m=a?.nodeAlignment??s.nodeAlignment,g=a?.prefix??s.prefix,y=a?.suffix??s.suffix,v=a?.showValues??s.showValues,x=n.db.getGraph(),b=VZe[m];rC().nodeId(M=>M.id).nodeWidth(10).nodePadding(10+(v?15:0)).nodeAlign(b).extent([[0,0],[f,d]])(x);let T=pu(Z8);h.append("g").attr("class","nodes").selectAll(".node").data(x.nodes).join("g").attr("class","node").attr("id",M=>(M.uid=fb.next("node-")).id).attr("transform",function(M){return"translate("+M.x0+","+M.y0+")"}).attr("x",M=>M.x0).attr("y",M=>M.y0).append("rect").attr("height",M=>M.y1-M.y0).attr("width",M=>M.x1-M.x0).attr("fill",M=>T(M.id));let E=o(({id:M,value:N})=>v?`${M} +${g}${Math.round(N*100)/100}${y}`:M,"getText");h.append("g").attr("class","node-labels").attr("font-family","sans-serif").attr("font-size",14).selectAll("text").data(x.nodes).join("text").attr("x",M=>M.x0(M.y1+M.y0)/2).attr("dy",`${v?"0":"0.35"}em`).attr("text-anchor",M=>M.x0(N.uid=fb.next("linearGradient-")).id).attr("gradientUnits","userSpaceOnUse").attr("x1",N=>N.source.x1).attr("x2",N=>N.target.x0);M.append("stop").attr("offset","0%").attr("stop-color",N=>T(N.source.id)),M.append("stop").attr("offset","100%").attr("stop-color",N=>T(N.target.id))}let L;switch(A){case"gradient":L=o(M=>M.uid,"coloring");break;case"source":L=o(M=>T(M.source.id),"coloring");break;case"target":L=o(M=>T(M.target.id),"coloring");break;default:L=A}_.append("path").attr("d",iC()).attr("stroke",L).attr("stroke-width",M=>Math.max(1,M.width)),Lo(void 0,h,0,p)},"draw"),Wge={draw:UZe}});var Xge,jge=R(()=>{"use strict";Xge=o(t=>t.replaceAll(/^[^\S\n\r]+|[^\S\n\r]+$/g,"").replaceAll(/([\n\r])+/g,` +`).trim(),"prepareTextForParsing")});var Kge={};hr(Kge,{diagram:()=>YZe});var HZe,YZe,Qge=R(()=>{"use strict";bge();Tge();qge();jge();HZe=cb.parse.bind(cb);cb.parse=t=>HZe(Xge(t));YZe={parser:cb,db:wge,renderer:Wge}});var e1e,FB,jZe,KZe,QZe,ZZe,JZe,Mf,zB=R(()=>{"use strict";qs();sl();xr();bi();e1e={packet:[]},FB=structuredClone(e1e),jZe=mr.packet,KZe=o(()=>{let t=Ts({...jZe,...Or().packet});return t.showBits&&(t.paddingY+=10),t},"getConfig"),QZe=o(()=>FB.packet,"getPacket"),ZZe=o(t=>{t.length>0&&FB.packet.push(t)},"pushWord"),JZe=o(()=>{vr(),FB=structuredClone(e1e)},"clear"),Mf={pushWord:ZZe,getPacket:QZe,getConfig:KZe,clear:JZe,setAccTitle:kr,getAccTitle:Ar,setDiagramTitle:nn,getDiagramTitle:Xr,getAccDescription:Lr,setAccDescription:_r}});var eJe,tJe,rJe,t1e,r1e=R(()=>{"use strict";Lg();ut();sx();zB();eJe=1e4,tJe=o(t=>{cf(t,Mf);let e=-1,r=[],n=1,{bitsPerRow:i}=Mf.getConfig();for(let{start:a,end:s,label:l}of t.blocks){if(s&&s{if(t.end===void 0&&(t.end=t.start),t.start>t.end)throw new Error(`Block start ${t.start} is greater than block end ${t.end}.`);return t.end+1<=e*r?[t,void 0]:[{start:t.start,end:e*r-1,label:t.label},{start:e*r,end:t.end,label:t.label}]},"getNextFittingBlock"),t1e={parse:o(async t=>{let e=await Fl("packet",t);V.debug(e),tJe(e)},"parse")}});var nJe,iJe,n1e,i1e=R(()=>{"use strict";pf();Yn();nJe=o((t,e,r,n)=>{let i=n.db,a=i.getConfig(),{rowHeight:s,paddingY:l,bitWidth:u,bitsPerRow:h}=a,f=i.getPacket(),d=i.getDiagramTitle(),p=s+l,m=p*(f.length+1)-(d?0:s),g=u*h+2,y=Ps(e);y.attr("viewbox",`0 0 ${g} ${m}`),Sr(y,m,g,a.useMaxWidth);for(let[v,x]of f.entries())iJe(y,x,v,a);y.append("text").text(d).attr("x",g/2).attr("y",m-p/2).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("class","packetTitle")},"draw"),iJe=o((t,e,r,{rowHeight:n,paddingX:i,paddingY:a,bitWidth:s,bitsPerRow:l,showBits:u})=>{let h=t.append("g"),f=r*(n+a)+a;for(let d of e){let p=d.start%l*s+1,m=(d.end-d.start+1)*s-i;if(h.append("rect").attr("x",p).attr("y",f).attr("width",m).attr("height",n).attr("class","packetBlock"),h.append("text").attr("x",p+m/2).attr("y",f+n/2).attr("class","packetLabel").attr("dominant-baseline","middle").attr("text-anchor","middle").text(d.label),!u)continue;let g=d.end===d.start,y=f-2;h.append("text").attr("x",p+(g?m/2:0)).attr("y",y).attr("class","packetByte start").attr("dominant-baseline","auto").attr("text-anchor",g?"middle":"start").text(d.start),g||h.append("text").attr("x",p+m).attr("y",y).attr("class","packetByte end").attr("dominant-baseline","auto").attr("text-anchor","end").text(d.end)}},"drawWord"),n1e={draw:nJe}});var aJe,a1e,s1e=R(()=>{"use strict";xr();aJe={byteFontSize:"10px",startByteColor:"black",endByteColor:"black",labelColor:"black",labelFontSize:"12px",titleColor:"black",titleFontSize:"14px",blockStrokeColor:"black",blockStrokeWidth:"1",blockFillColor:"#efefef"},a1e=o(({packet:t}={})=>{let e=Ts(aJe,t);return` + .packetByte { + font-size: ${e.byteFontSize}; + } + .packetByte.start { + fill: ${e.startByteColor}; + } + .packetByte.end { + fill: ${e.endByteColor}; + } + .packetLabel { + fill: ${e.labelColor}; + font-size: ${e.labelFontSize}; + } + .packetTitle { + fill: ${e.titleColor}; + font-size: ${e.titleFontSize}; + } + .packetBlock { + stroke: ${e.blockStrokeColor}; + stroke-width: ${e.blockStrokeWidth}; + fill: ${e.blockFillColor}; + } + `},"styles")});var o1e={};hr(o1e,{diagram:()=>sJe});var sJe,l1e=R(()=>{"use strict";zB();r1e();i1e();s1e();sJe={parser:t1e,db:Mf,renderer:n1e,styles:a1e}});var GB,h1e,f1e=R(()=>{"use strict";GB=function(){var t=o(function(w,S,T,E){for(T=T||{},E=w.length;E--;T[w[E]]=S);return T},"o"),e=[1,7],r=[1,13],n=[1,14],i=[1,15],a=[1,19],s=[1,16],l=[1,17],u=[1,18],h=[8,30],f=[8,21,28,29,30,31,32,40,44,47],d=[1,23],p=[1,24],m=[8,15,16,21,28,29,30,31,32,40,44,47],g=[8,15,16,21,27,28,29,30,31,32,40,44,47],y=[1,49],v={trace:o(function(){},"trace"),yy:{},symbols_:{error:2,spaceLines:3,SPACELINE:4,NL:5,separator:6,SPACE:7,EOF:8,start:9,BLOCK_DIAGRAM_KEY:10,document:11,stop:12,statement:13,link:14,LINK:15,START_LINK:16,LINK_LABEL:17,STR:18,nodeStatement:19,columnsStatement:20,SPACE_BLOCK:21,blockStatement:22,classDefStatement:23,cssClassStatement:24,styleStatement:25,node:26,SIZE:27,COLUMNS:28,"id-block":29,end:30,block:31,NODE_ID:32,nodeShapeNLabel:33,dirList:34,DIR:35,NODE_DSTART:36,NODE_DEND:37,BLOCK_ARROW_START:38,BLOCK_ARROW_END:39,classDef:40,CLASSDEF_ID:41,CLASSDEF_STYLEOPTS:42,DEFAULT:43,class:44,CLASSENTITY_IDS:45,STYLECLASS:46,style:47,STYLE_ENTITY_IDS:48,STYLE_DEFINITION_DATA:49,$accept:0,$end:1},terminals_:{2:"error",4:"SPACELINE",5:"NL",7:"SPACE",8:"EOF",10:"BLOCK_DIAGRAM_KEY",15:"LINK",16:"START_LINK",17:"LINK_LABEL",18:"STR",21:"SPACE_BLOCK",27:"SIZE",28:"COLUMNS",29:"id-block",30:"end",31:"block",32:"NODE_ID",35:"DIR",36:"NODE_DSTART",37:"NODE_DEND",38:"BLOCK_ARROW_START",39:"BLOCK_ARROW_END",40:"classDef",41:"CLASSDEF_ID",42:"CLASSDEF_STYLEOPTS",43:"DEFAULT",44:"class",45:"CLASSENTITY_IDS",46:"STYLECLASS",47:"style",48:"STYLE_ENTITY_IDS",49:"STYLE_DEFINITION_DATA"},productions_:[0,[3,1],[3,2],[3,2],[6,1],[6,1],[6,1],[9,3],[12,1],[12,1],[12,2],[12,2],[11,1],[11,2],[14,1],[14,4],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[19,3],[19,2],[19,1],[20,1],[22,4],[22,3],[26,1],[26,2],[34,1],[34,2],[33,3],[33,4],[23,3],[23,3],[24,3],[25,3]],performAction:o(function(S,T,E,_,A,L,M){var N=L.length-1;switch(A){case 4:_.getLogger().debug("Rule: separator (NL) ");break;case 5:_.getLogger().debug("Rule: separator (Space) ");break;case 6:_.getLogger().debug("Rule: separator (EOF) ");break;case 7:_.getLogger().debug("Rule: hierarchy: ",L[N-1]),_.setHierarchy(L[N-1]);break;case 8:_.getLogger().debug("Stop NL ");break;case 9:_.getLogger().debug("Stop EOF ");break;case 10:_.getLogger().debug("Stop NL2 ");break;case 11:_.getLogger().debug("Stop EOF2 ");break;case 12:_.getLogger().debug("Rule: statement: ",L[N]),typeof L[N].length=="number"?this.$=L[N]:this.$=[L[N]];break;case 13:_.getLogger().debug("Rule: statement #2: ",L[N-1]),this.$=[L[N-1]].concat(L[N]);break;case 14:_.getLogger().debug("Rule: link: ",L[N],S),this.$={edgeTypeStr:L[N],label:""};break;case 15:_.getLogger().debug("Rule: LABEL link: ",L[N-3],L[N-1],L[N]),this.$={edgeTypeStr:L[N],label:L[N-1]};break;case 18:let k=parseInt(L[N]),I=_.generateId();this.$={id:I,type:"space",label:"",width:k,children:[]};break;case 23:_.getLogger().debug("Rule: (nodeStatement link node) ",L[N-2],L[N-1],L[N]," typestr: ",L[N-1].edgeTypeStr);let C=_.edgeStrToEdgeData(L[N-1].edgeTypeStr);this.$=[{id:L[N-2].id,label:L[N-2].label,type:L[N-2].type,directions:L[N-2].directions},{id:L[N-2].id+"-"+L[N].id,start:L[N-2].id,end:L[N].id,label:L[N-1].label,type:"edge",directions:L[N].directions,arrowTypeEnd:C,arrowTypeStart:"arrow_open"},{id:L[N].id,label:L[N].label,type:_.typeStr2Type(L[N].typeStr),directions:L[N].directions}];break;case 24:_.getLogger().debug("Rule: nodeStatement (abc88 node size) ",L[N-1],L[N]),this.$={id:L[N-1].id,label:L[N-1].label,type:_.typeStr2Type(L[N-1].typeStr),directions:L[N-1].directions,widthInColumns:parseInt(L[N],10)};break;case 25:_.getLogger().debug("Rule: nodeStatement (node) ",L[N]),this.$={id:L[N].id,label:L[N].label,type:_.typeStr2Type(L[N].typeStr),directions:L[N].directions,widthInColumns:1};break;case 26:_.getLogger().debug("APA123",this?this:"na"),_.getLogger().debug("COLUMNS: ",L[N]),this.$={type:"column-setting",columns:L[N]==="auto"?-1:parseInt(L[N])};break;case 27:_.getLogger().debug("Rule: id-block statement : ",L[N-2],L[N-1]);let O=_.generateId();this.$={...L[N-2],type:"composite",children:L[N-1]};break;case 28:_.getLogger().debug("Rule: blockStatement : ",L[N-2],L[N-1],L[N]);let D=_.generateId();this.$={id:D,type:"composite",label:"",children:L[N-1]};break;case 29:_.getLogger().debug("Rule: node (NODE_ID separator): ",L[N]),this.$={id:L[N]};break;case 30:_.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel separator): ",L[N-1],L[N]),this.$={id:L[N-1],label:L[N].label,typeStr:L[N].typeStr,directions:L[N].directions};break;case 31:_.getLogger().debug("Rule: dirList: ",L[N]),this.$=[L[N]];break;case 32:_.getLogger().debug("Rule: dirList: ",L[N-1],L[N]),this.$=[L[N-1]].concat(L[N]);break;case 33:_.getLogger().debug("Rule: nodeShapeNLabel: ",L[N-2],L[N-1],L[N]),this.$={typeStr:L[N-2]+L[N],label:L[N-1]};break;case 34:_.getLogger().debug("Rule: BLOCK_ARROW nodeShapeNLabel: ",L[N-3],L[N-2]," #3:",L[N-1],L[N]),this.$={typeStr:L[N-3]+L[N],label:L[N-2],directions:L[N-1]};break;case 35:case 36:this.$={type:"classDef",id:L[N-1].trim(),css:L[N].trim()};break;case 37:this.$={type:"applyClass",id:L[N-1].trim(),styleClass:L[N].trim()};break;case 38:this.$={type:"applyStyles",id:L[N-1].trim(),stylesStr:L[N].trim()};break}},"anonymous"),table:[{9:1,10:[1,2]},{1:[3]},{11:3,13:4,19:5,20:6,21:e,22:8,23:9,24:10,25:11,26:12,28:r,29:n,31:i,32:a,40:s,44:l,47:u},{8:[1,20]},t(h,[2,12],{13:4,19:5,20:6,22:8,23:9,24:10,25:11,26:12,11:21,21:e,28:r,29:n,31:i,32:a,40:s,44:l,47:u}),t(f,[2,16],{14:22,15:d,16:p}),t(f,[2,17]),t(f,[2,18]),t(f,[2,19]),t(f,[2,20]),t(f,[2,21]),t(f,[2,22]),t(m,[2,25],{27:[1,25]}),t(f,[2,26]),{19:26,26:12,32:a},{11:27,13:4,19:5,20:6,21:e,22:8,23:9,24:10,25:11,26:12,28:r,29:n,31:i,32:a,40:s,44:l,47:u},{41:[1,28],43:[1,29]},{45:[1,30]},{48:[1,31]},t(g,[2,29],{33:32,36:[1,33],38:[1,34]}),{1:[2,7]},t(h,[2,13]),{26:35,32:a},{32:[2,14]},{17:[1,36]},t(m,[2,24]),{11:37,13:4,14:22,15:d,16:p,19:5,20:6,21:e,22:8,23:9,24:10,25:11,26:12,28:r,29:n,31:i,32:a,40:s,44:l,47:u},{30:[1,38]},{42:[1,39]},{42:[1,40]},{46:[1,41]},{49:[1,42]},t(g,[2,30]),{18:[1,43]},{18:[1,44]},t(m,[2,23]),{18:[1,45]},{30:[1,46]},t(f,[2,28]),t(f,[2,35]),t(f,[2,36]),t(f,[2,37]),t(f,[2,38]),{37:[1,47]},{34:48,35:y},{15:[1,50]},t(f,[2,27]),t(g,[2,33]),{39:[1,51]},{34:52,35:y,39:[2,31]},{32:[2,15]},t(g,[2,34]),{39:[2,32]}],defaultActions:{20:[2,7],23:[2,14],50:[2,15],52:[2,32]},parseError:o(function(S,T){if(T.recoverable)this.trace(S);else{var E=new Error(S);throw E.hash=T,E}},"parseError"),parse:o(function(S){var T=this,E=[0],_=[],A=[null],L=[],M=this.table,N="",k=0,I=0,C=0,O=2,D=1,P=L.slice.call(arguments,1),F=Object.create(this.lexer),B={yy:{}};for(var $ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,$)&&(B.yy[$]=this.yy[$]);F.setInput(S,B.yy),B.yy.lexer=F,B.yy.parser=this,typeof F.yylloc>"u"&&(F.yylloc={});var z=F.yylloc;L.push(z);var Y=F.options&&F.options.ranges;typeof B.yy.parseError=="function"?this.parseError=B.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Q(oe){E.length=E.length-2*oe,A.length=A.length-oe,L.length=L.length-oe}o(Q,"popStack");function X(){var oe;return oe=_.pop()||F.lex()||D,typeof oe!="number"&&(oe instanceof Array&&(_=oe,oe=_.pop()),oe=T.symbols_[oe]||oe),oe}o(X,"lex");for(var ie,j,J,Z,H,q,K={},se,ce,ue,te;;){if(J=E[E.length-1],this.defaultActions[J]?Z=this.defaultActions[J]:((ie===null||typeof ie>"u")&&(ie=X()),Z=M[J]&&M[J][ie]),typeof Z>"u"||!Z.length||!Z[0]){var De="";te=[];for(se in M[J])this.terminals_[se]&&se>O&&te.push("'"+this.terminals_[se]+"'");F.showPosition?De="Parse error on line "+(k+1)+`: +`+F.showPosition()+` +Expecting `+te.join(", ")+", got '"+(this.terminals_[ie]||ie)+"'":De="Parse error on line "+(k+1)+": Unexpected "+(ie==D?"end of input":"'"+(this.terminals_[ie]||ie)+"'"),this.parseError(De,{text:F.match,token:this.terminals_[ie]||ie,line:F.yylineno,loc:z,expected:te})}if(Z[0]instanceof Array&&Z.length>1)throw new Error("Parse Error: multiple actions possible at state: "+J+", token: "+ie);switch(Z[0]){case 1:E.push(ie),A.push(F.yytext),L.push(F.yylloc),E.push(Z[1]),ie=null,j?(ie=j,j=null):(I=F.yyleng,N=F.yytext,k=F.yylineno,z=F.yylloc,C>0&&C--);break;case 2:if(ce=this.productions_[Z[1]][1],K.$=A[A.length-ce],K._$={first_line:L[L.length-(ce||1)].first_line,last_line:L[L.length-1].last_line,first_column:L[L.length-(ce||1)].first_column,last_column:L[L.length-1].last_column},Y&&(K._$.range=[L[L.length-(ce||1)].range[0],L[L.length-1].range[1]]),q=this.performAction.apply(K,[N,I,k,B.yy,Z[1],A,L].concat(P)),typeof q<"u")return q;ce&&(E=E.slice(0,-1*ce*2),A=A.slice(0,-1*ce),L=L.slice(0,-1*ce)),E.push(this.productions_[Z[1]][0]),A.push(K.$),L.push(K._$),ue=M[E[E.length-2]][E[E.length-1]],E.push(ue);break;case 3:return!0}}return!0},"parse")},x=function(){var w={EOF:1,parseError:o(function(T,E){if(this.yy.parser)this.yy.parser.parseError(T,E);else throw new Error(T)},"parseError"),setInput:o(function(S,T){return this.yy=T||this.yy||{},this._input=S,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:o(function(){var S=this._input[0];this.yytext+=S,this.yyleng++,this.offset++,this.match+=S,this.matched+=S;var T=S.match(/(?:\r\n?|\n).*/g);return T?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),S},"input"),unput:o(function(S){var T=S.length,E=S.split(/(?:\r\n?|\n)/g);this._input=S+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-T),this.offset-=T;var _=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),E.length-1&&(this.yylineno-=E.length-1);var A=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:E?(E.length===_.length?this.yylloc.first_column:0)+_[_.length-E.length].length-E[0].length:this.yylloc.first_column-T},this.options.ranges&&(this.yylloc.range=[A[0],A[0]+this.yyleng-T]),this.yyleng=this.yytext.length,this},"unput"),more:o(function(){return this._more=!0,this},"more"),reject:o(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:o(function(S){this.unput(this.match.slice(S))},"less"),pastInput:o(function(){var S=this.matched.substr(0,this.matched.length-this.match.length);return(S.length>20?"...":"")+S.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:o(function(){var S=this.match;return S.length<20&&(S+=this._input.substr(0,20-S.length)),(S.substr(0,20)+(S.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:o(function(){var S=this.pastInput(),T=new Array(S.length+1).join("-");return S+this.upcomingInput()+` +`+T+"^"},"showPosition"),test_match:o(function(S,T){var E,_,A;if(this.options.backtrack_lexer&&(A={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(A.yylloc.range=this.yylloc.range.slice(0))),_=S[0].match(/(?:\r\n?|\n).*/g),_&&(this.yylineno+=_.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:_?_[_.length-1].length-_[_.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+S[0].length},this.yytext+=S[0],this.match+=S[0],this.matches=S,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(S[0].length),this.matched+=S[0],E=this.performAction.call(this,this.yy,this,T,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),E)return E;if(this._backtrack){for(var L in A)this[L]=A[L];return!1}return!1},"test_match"),next:o(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var S,T,E,_;this._more||(this.yytext="",this.match="");for(var A=this._currentRules(),L=0;LT[0].length)){if(T=E,_=L,this.options.backtrack_lexer){if(S=this.test_match(E,A[L]),S!==!1)return S;if(this._backtrack){T=!1;continue}else return!1}else if(!this.options.flex)break}return T?(S=this.test_match(T,A[_]),S!==!1?S:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:o(function(){var T=this.next();return T||this.lex()},"lex"),begin:o(function(T){this.conditionStack.push(T)},"begin"),popState:o(function(){var T=this.conditionStack.length-1;return T>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:o(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:o(function(T){return T=this.conditionStack.length-1-Math.abs(T||0),T>=0?this.conditionStack[T]:"INITIAL"},"topState"),pushState:o(function(T){this.begin(T)},"pushState"),stateStackSize:o(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:o(function(T,E,_,A){var L=A;switch(_){case 0:return 10;case 1:return T.getLogger().debug("Found space-block"),31;break;case 2:return T.getLogger().debug("Found nl-block"),31;break;case 3:return T.getLogger().debug("Found space-block"),29;break;case 4:T.getLogger().debug(".",E.yytext);break;case 5:T.getLogger().debug("_",E.yytext);break;case 6:return 5;case 7:return E.yytext=-1,28;break;case 8:return E.yytext=E.yytext.replace(/columns\s+/,""),T.getLogger().debug("COLUMNS (LEX)",E.yytext),28;break;case 9:this.pushState("md_string");break;case 10:return"MD_STR";case 11:this.popState();break;case 12:this.pushState("string");break;case 13:T.getLogger().debug("LEX: POPPING STR:",E.yytext),this.popState();break;case 14:return T.getLogger().debug("LEX: STR end:",E.yytext),"STR";break;case 15:return E.yytext=E.yytext.replace(/space\:/,""),T.getLogger().debug("SPACE NUM (LEX)",E.yytext),21;break;case 16:return E.yytext="1",T.getLogger().debug("COLUMNS (LEX)",E.yytext),21;break;case 17:return 43;case 18:return"LINKSTYLE";case 19:return"INTERPOLATE";case 20:return this.pushState("CLASSDEF"),40;break;case 21:return this.popState(),this.pushState("CLASSDEFID"),"DEFAULT_CLASSDEF_ID";break;case 22:return this.popState(),this.pushState("CLASSDEFID"),41;break;case 23:return this.popState(),42;break;case 24:return this.pushState("CLASS"),44;break;case 25:return this.popState(),this.pushState("CLASS_STYLE"),45;break;case 26:return this.popState(),46;break;case 27:return this.pushState("STYLE_STMNT"),47;break;case 28:return this.popState(),this.pushState("STYLE_DEFINITION"),48;break;case 29:return this.popState(),49;break;case 30:return this.pushState("acc_title"),"acc_title";break;case 31:return this.popState(),"acc_title_value";break;case 32:return this.pushState("acc_descr"),"acc_descr";break;case 33:return this.popState(),"acc_descr_value";break;case 34:this.pushState("acc_descr_multiline");break;case 35:this.popState();break;case 36:return"acc_descr_multiline_value";case 37:return 30;case 38:return this.popState(),T.getLogger().debug("Lex: (("),"NODE_DEND";break;case 39:return this.popState(),T.getLogger().debug("Lex: (("),"NODE_DEND";break;case 40:return this.popState(),T.getLogger().debug("Lex: ))"),"NODE_DEND";break;case 41:return this.popState(),T.getLogger().debug("Lex: (("),"NODE_DEND";break;case 42:return this.popState(),T.getLogger().debug("Lex: (("),"NODE_DEND";break;case 43:return this.popState(),T.getLogger().debug("Lex: (-"),"NODE_DEND";break;case 44:return this.popState(),T.getLogger().debug("Lex: -)"),"NODE_DEND";break;case 45:return this.popState(),T.getLogger().debug("Lex: (("),"NODE_DEND";break;case 46:return this.popState(),T.getLogger().debug("Lex: ]]"),"NODE_DEND";break;case 47:return this.popState(),T.getLogger().debug("Lex: ("),"NODE_DEND";break;case 48:return this.popState(),T.getLogger().debug("Lex: ])"),"NODE_DEND";break;case 49:return this.popState(),T.getLogger().debug("Lex: /]"),"NODE_DEND";break;case 50:return this.popState(),T.getLogger().debug("Lex: /]"),"NODE_DEND";break;case 51:return this.popState(),T.getLogger().debug("Lex: )]"),"NODE_DEND";break;case 52:return this.popState(),T.getLogger().debug("Lex: )"),"NODE_DEND";break;case 53:return this.popState(),T.getLogger().debug("Lex: ]>"),"NODE_DEND";break;case 54:return this.popState(),T.getLogger().debug("Lex: ]"),"NODE_DEND";break;case 55:return T.getLogger().debug("Lexa: -)"),this.pushState("NODE"),36;break;case 56:return T.getLogger().debug("Lexa: (-"),this.pushState("NODE"),36;break;case 57:return T.getLogger().debug("Lexa: ))"),this.pushState("NODE"),36;break;case 58:return T.getLogger().debug("Lexa: )"),this.pushState("NODE"),36;break;case 59:return T.getLogger().debug("Lex: ((("),this.pushState("NODE"),36;break;case 60:return T.getLogger().debug("Lexa: )"),this.pushState("NODE"),36;break;case 61:return T.getLogger().debug("Lexa: )"),this.pushState("NODE"),36;break;case 62:return T.getLogger().debug("Lexa: )"),this.pushState("NODE"),36;break;case 63:return T.getLogger().debug("Lexc: >"),this.pushState("NODE"),36;break;case 64:return T.getLogger().debug("Lexa: (["),this.pushState("NODE"),36;break;case 65:return T.getLogger().debug("Lexa: )"),this.pushState("NODE"),36;break;case 66:return this.pushState("NODE"),36;break;case 67:return this.pushState("NODE"),36;break;case 68:return this.pushState("NODE"),36;break;case 69:return this.pushState("NODE"),36;break;case 70:return this.pushState("NODE"),36;break;case 71:return this.pushState("NODE"),36;break;case 72:return this.pushState("NODE"),36;break;case 73:return T.getLogger().debug("Lexa: ["),this.pushState("NODE"),36;break;case 74:return this.pushState("BLOCK_ARROW"),T.getLogger().debug("LEX ARR START"),38;break;case 75:return T.getLogger().debug("Lex: NODE_ID",E.yytext),32;break;case 76:return T.getLogger().debug("Lex: EOF",E.yytext),8;break;case 77:this.pushState("md_string");break;case 78:this.pushState("md_string");break;case 79:return"NODE_DESCR";case 80:this.popState();break;case 81:T.getLogger().debug("Lex: Starting string"),this.pushState("string");break;case 82:T.getLogger().debug("LEX ARR: Starting string"),this.pushState("string");break;case 83:return T.getLogger().debug("LEX: NODE_DESCR:",E.yytext),"NODE_DESCR";break;case 84:T.getLogger().debug("LEX POPPING"),this.popState();break;case 85:T.getLogger().debug("Lex: =>BAE"),this.pushState("ARROW_DIR");break;case 86:return E.yytext=E.yytext.replace(/^,\s*/,""),T.getLogger().debug("Lex (right): dir:",E.yytext),"DIR";break;case 87:return E.yytext=E.yytext.replace(/^,\s*/,""),T.getLogger().debug("Lex (left):",E.yytext),"DIR";break;case 88:return E.yytext=E.yytext.replace(/^,\s*/,""),T.getLogger().debug("Lex (x):",E.yytext),"DIR";break;case 89:return E.yytext=E.yytext.replace(/^,\s*/,""),T.getLogger().debug("Lex (y):",E.yytext),"DIR";break;case 90:return E.yytext=E.yytext.replace(/^,\s*/,""),T.getLogger().debug("Lex (up):",E.yytext),"DIR";break;case 91:return E.yytext=E.yytext.replace(/^,\s*/,""),T.getLogger().debug("Lex (down):",E.yytext),"DIR";break;case 92:return E.yytext="]>",T.getLogger().debug("Lex (ARROW_DIR end):",E.yytext),this.popState(),this.popState(),"BLOCK_ARROW_END";break;case 93:return T.getLogger().debug("Lex: LINK","#"+E.yytext+"#"),15;break;case 94:return T.getLogger().debug("Lex: LINK",E.yytext),15;break;case 95:return T.getLogger().debug("Lex: LINK",E.yytext),15;break;case 96:return T.getLogger().debug("Lex: LINK",E.yytext),15;break;case 97:return T.getLogger().debug("Lex: START_LINK",E.yytext),this.pushState("LLABEL"),16;break;case 98:return T.getLogger().debug("Lex: START_LINK",E.yytext),this.pushState("LLABEL"),16;break;case 99:return T.getLogger().debug("Lex: START_LINK",E.yytext),this.pushState("LLABEL"),16;break;case 100:this.pushState("md_string");break;case 101:return T.getLogger().debug("Lex: Starting string"),this.pushState("string"),"LINK_LABEL";break;case 102:return this.popState(),T.getLogger().debug("Lex: LINK","#"+E.yytext+"#"),15;break;case 103:return this.popState(),T.getLogger().debug("Lex: LINK",E.yytext),15;break;case 104:return this.popState(),T.getLogger().debug("Lex: LINK",E.yytext),15;break;case 105:return T.getLogger().debug("Lex: COLON",E.yytext),E.yytext=E.yytext.slice(1),27;break}},"anonymous"),rules:[/^(?:block-beta\b)/,/^(?:block\s+)/,/^(?:block\n+)/,/^(?:block:)/,/^(?:[\s]+)/,/^(?:[\n]+)/,/^(?:((\u000D\u000A)|(\u000A)))/,/^(?:columns\s+auto\b)/,/^(?:columns\s+[\d]+)/,/^(?:["][`])/,/^(?:[^`"]+)/,/^(?:[`]["])/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:space[:]\d+)/,/^(?:space\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\s+)/,/^(?:DEFAULT\s+)/,/^(?:\w+\s+)/,/^(?:[^\n]*)/,/^(?:class\s+)/,/^(?:(\w+)+((,\s*\w+)*))/,/^(?:[^\n]*)/,/^(?:style\s+)/,/^(?:(\w+)+((,\s*\w+)*))/,/^(?:[^\n]*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:end\b\s*)/,/^(?:\(\(\()/,/^(?:\)\)\))/,/^(?:[\)]\))/,/^(?:\}\})/,/^(?:\})/,/^(?:\(-)/,/^(?:-\))/,/^(?:\(\()/,/^(?:\]\])/,/^(?:\()/,/^(?:\]\))/,/^(?:\\\])/,/^(?:\/\])/,/^(?:\)\])/,/^(?:[\)])/,/^(?:\]>)/,/^(?:[\]])/,/^(?:-\))/,/^(?:\(-)/,/^(?:\)\))/,/^(?:\))/,/^(?:\(\(\()/,/^(?:\(\()/,/^(?:\{\{)/,/^(?:\{)/,/^(?:>)/,/^(?:\(\[)/,/^(?:\()/,/^(?:\[\[)/,/^(?:\[\|)/,/^(?:\[\()/,/^(?:\)\)\))/,/^(?:\[\\)/,/^(?:\[\/)/,/^(?:\[\\)/,/^(?:\[)/,/^(?:<\[)/,/^(?:[^\(\[\n\-\)\{\}\s\<\>:]+)/,/^(?:$)/,/^(?:["][`])/,/^(?:["][`])/,/^(?:[^`"]+)/,/^(?:[`]["])/,/^(?:["])/,/^(?:["])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:\]>\s*\()/,/^(?:,?\s*right\s*)/,/^(?:,?\s*left\s*)/,/^(?:,?\s*x\s*)/,/^(?:,?\s*y\s*)/,/^(?:,?\s*up\s*)/,/^(?:,?\s*down\s*)/,/^(?:\)\s*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*~~[\~]+\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:["][`])/,/^(?:["])/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?::\d+)/],conditions:{STYLE_DEFINITION:{rules:[29],inclusive:!1},STYLE_STMNT:{rules:[28],inclusive:!1},CLASSDEFID:{rules:[23],inclusive:!1},CLASSDEF:{rules:[21,22],inclusive:!1},CLASS_STYLE:{rules:[26],inclusive:!1},CLASS:{rules:[25],inclusive:!1},LLABEL:{rules:[100,101,102,103,104],inclusive:!1},ARROW_DIR:{rules:[86,87,88,89,90,91,92],inclusive:!1},BLOCK_ARROW:{rules:[77,82,85],inclusive:!1},NODE:{rules:[38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,78,81],inclusive:!1},md_string:{rules:[10,11,79,80],inclusive:!1},space:{rules:[],inclusive:!1},string:{rules:[13,14,83,84],inclusive:!1},acc_descr_multiline:{rules:[35,36],inclusive:!1},acc_descr:{rules:[33],inclusive:!1},acc_title:{rules:[31],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,12,15,16,17,18,19,20,24,27,30,32,34,37,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,93,94,95,96,97,98,99,105],inclusive:!0}}};return w}();v.lexer=x;function b(){this.yy={}}return o(b,"Parser"),b.prototype=v,v.Parser=b,new b}();GB.parser=GB;h1e=GB});function gJe(t){switch(V.debug("typeStr2Type",t),t){case"[]":return"square";case"()":return V.debug("we have a round"),"round";case"(())":return"circle";case">]":return"rect_left_inv_arrow";case"{}":return"diamond";case"{{}}":return"hexagon";case"([])":return"stadium";case"[[]]":return"subroutine";case"[()]":return"cylinder";case"((()))":return"doublecircle";case"[//]":return"lean_right";case"[\\\\]":return"lean_left";case"[/\\]":return"trapezoid";case"[\\/]":return"inv_trapezoid";case"<[]>":return"block_arrow";default:return"na"}}function yJe(t){switch(V.debug("typeStr2Type",t),t){case"==":return"thick";default:return"normal"}}function vJe(t){switch(t.trim()){case"--x":return"arrow_cross";case"--o":return"arrow_circle";default:return"arrow_point"}}var Yl,VB,$B,d1e,p1e,cJe,g1e,uJe,aC,hJe,fJe,dJe,pJe,y1e,UB,db,mJe,m1e,xJe,bJe,wJe,TJe,kJe,EJe,CJe,SJe,AJe,_Je,LJe,v1e,x1e=R(()=>{"use strict";gL();qs();_t();ut();rr();bi();Yl=new Map,VB=[],$B=new Map,d1e="color",p1e="fill",cJe="bgFill",g1e=",",uJe=de(),aC=new Map,hJe=o(t=>We.sanitizeText(t,uJe),"sanitizeText"),fJe=o(function(t,e=""){let r=aC.get(t);r||(r={id:t,styles:[],textStyles:[]},aC.set(t,r)),e?.split(g1e).forEach(n=>{let i=n.replace(/([^;]*);/,"$1").trim();if(RegExp(d1e).exec(n)){let s=i.replace(p1e,cJe).replace(d1e,p1e);r.textStyles.push(s)}r.styles.push(i)})},"addStyleClass"),dJe=o(function(t,e=""){let r=Yl.get(t);e!=null&&(r.styles=e.split(g1e))},"addStyle2Node"),pJe=o(function(t,e){t.split(",").forEach(function(r){let n=Yl.get(r);if(n===void 0){let i=r.trim();n={id:i,type:"na",children:[]},Yl.set(i,n)}n.classes||(n.classes=[]),n.classes.push(e)})},"setCssClass"),y1e=o((t,e)=>{let r=t.flat(),n=[];for(let i of r){if(i.label&&(i.label=hJe(i.label)),i.type==="classDef"){fJe(i.id,i.css);continue}if(i.type==="applyClass"){pJe(i.id,i?.styleClass??"");continue}if(i.type==="applyStyles"){i?.stylesStr&&dJe(i.id,i?.stylesStr);continue}if(i.type==="column-setting")e.columns=i.columns??-1;else if(i.type==="edge"){let a=($B.get(i.id)??0)+1;$B.set(i.id,a),i.id=a+"-"+i.id,VB.push(i)}else{i.label||(i.type==="composite"?i.label="":i.label=i.id);let a=Yl.get(i.id);if(a===void 0?Yl.set(i.id,i):(i.type!=="na"&&(a.type=i.type),i.label!==i.id&&(a.label=i.label)),i.children&&y1e(i.children,i),i.type==="space"){let s=i.width??1;for(let l=0;l{V.debug("Clear called"),vr(),db={id:"root",type:"composite",children:[],columns:-1},Yl=new Map([["root",db]]),UB=[],aC=new Map,VB=[],$B=new Map},"clear");o(gJe,"typeStr2Type");o(yJe,"edgeTypeStr2Type");o(vJe,"edgeStrToEdgeData");m1e=0,xJe=o(()=>(m1e++,"id-"+Math.random().toString(36).substr(2,12)+"-"+m1e),"generateId"),bJe=o(t=>{db.children=t,y1e(t,db),UB=db.children},"setHierarchy"),wJe=o(t=>{let e=Yl.get(t);return e?e.columns?e.columns:e.children?e.children.length:-1:-1},"getColumns"),TJe=o(()=>[...Yl.values()],"getBlocksFlat"),kJe=o(()=>UB||[],"getBlocks"),EJe=o(()=>VB,"getEdges"),CJe=o(t=>Yl.get(t),"getBlock"),SJe=o(t=>{Yl.set(t.id,t)},"setBlock"),AJe=o(()=>console,"getLogger"),_Je=o(function(){return aC},"getClasses"),LJe={getConfig:o(()=>Or().block,"getConfig"),typeStr2Type:gJe,edgeTypeStr2Type:yJe,edgeStrToEdgeData:vJe,getLogger:AJe,getBlocksFlat:TJe,getBlocks:kJe,getEdges:EJe,setHierarchy:bJe,getBlock:CJe,setBlock:SJe,getColumns:wJe,getClasses:_Je,clear:mJe,generateId:xJe},v1e=LJe});var sC,DJe,b1e,w1e=R(()=>{"use strict";al();sC=o((t,e)=>{let r=X1,n=r(t,"r"),i=r(t,"g"),a=r(t,"b");return Ws(n,i,a,e)},"fade"),DJe=o(t=>`.label { + font-family: ${t.fontFamily}; + color: ${t.nodeTextColor||t.textColor}; + } + .cluster-label text { + fill: ${t.titleColor}; + } + .cluster-label span,p { + color: ${t.titleColor}; + } + + + + .label text,span,p { + fill: ${t.nodeTextColor||t.textColor}; + color: ${t.nodeTextColor||t.textColor}; + } + + .node rect, + .node circle, + .node ellipse, + .node polygon, + .node path { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; + stroke-width: 1px; + } + .flowchart-label text { + text-anchor: middle; + } + // .flowchart-label .text-outer-tspan { + // text-anchor: middle; + // } + // .flowchart-label .text-inner-tspan { + // text-anchor: start; + // } + + .node .label { + text-align: center; + } + .node.clickable { + cursor: pointer; + } + + .arrowheadPath { + fill: ${t.arrowheadColor}; + } + + .edgePath .path { + stroke: ${t.lineColor}; + stroke-width: 2.0px; + } + + .flowchart-link { + stroke: ${t.lineColor}; + fill: none; + } + + .edgeLabel { + background-color: ${t.edgeLabelBackground}; + rect { + opacity: 0.5; + background-color: ${t.edgeLabelBackground}; + fill: ${t.edgeLabelBackground}; + } + text-align: center; + } + + /* For html labels only */ + .labelBkg { + background-color: ${sC(t.edgeLabelBackground,.5)}; + // background-color: + } + + .node .cluster { + // fill: ${sC(t.mainBkg,.5)}; + fill: ${sC(t.clusterBkg,.5)}; + stroke: ${sC(t.clusterBorder,.2)}; + box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; + stroke-width: 1px; + } + + .cluster text { + fill: ${t.titleColor}; + } + + .cluster span,p { + color: ${t.titleColor}; + } + /* .cluster div { + color: ${t.titleColor}; + } */ + + div.mermaidTooltip { + position: absolute; + text-align: center; + max-width: 200px; + padding: 2px; + font-family: ${t.fontFamily}; + font-size: 12px; + background: ${t.tertiaryColor}; + border: 1px solid ${t.border2}; + border-radius: 2px; + pointer-events: none; + z-index: 100; + } + + .flowchartTitleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.textColor}; + } +`,"getStyles"),b1e=DJe});function RJe(t,e){if(t===0||!Number.isInteger(t))throw new Error("Columns must be an integer !== 0.");if(e<0||!Number.isInteger(e))throw new Error("Position must be a non-negative integer."+e);if(t<0)return{px:e,py:0};if(t===1)return{px:0,py:e};let r=e%t,n=Math.floor(e/t);return{px:r,py:n}}function HB(t,e,r=0,n=0){V.debug("setBlockSizes abc95 (start)",t.id,t?.size?.x,"block width =",t?.size,"sieblingWidth",r),t?.size?.width||(t.size={width:r,height:n,x:0,y:0});let i=0,a=0;if(t.children?.length>0){for(let m of t.children)HB(m,e);let s=NJe(t);i=s.width,a=s.height,V.debug("setBlockSizes abc95 maxWidth of",t.id,":s children is ",i,a);for(let m of t.children)m.size&&(V.debug(`abc95 Setting size of children of ${t.id} id=${m.id} ${i} ${a} ${JSON.stringify(m.size)}`),m.size.width=i*(m.widthInColumns??1)+mi*((m.widthInColumns??1)-1),m.size.height=a,m.size.x=0,m.size.y=0,V.debug(`abc95 updating size of ${t.id} children child:${m.id} maxWidth:${i} maxHeight:${a}`));for(let m of t.children)HB(m,e,i,a);let l=t.columns??-1,u=0;for(let m of t.children)u+=m.widthInColumns??1;let h=t.children.length;l>0&&l0?Math.min(t.children.length,l):t.children.length;if(m>0){let g=(d-m*mi-mi)/m;V.debug("abc95 (growing to fit) width",t.id,d,t.size?.width,g);for(let y of t.children)y.size&&(y.size.width=g)}}t.size={width:d,height:p,x:0,y:0}}V.debug("setBlockSizes abc94 (done)",t.id,t?.size?.x,t?.size?.width,t?.size?.y,t?.size?.height)}function T1e(t,e){V.debug(`abc85 layout blocks (=>layoutBlocks) ${t.id} x: ${t?.size?.x} y: ${t?.size?.y} width: ${t?.size?.width}`);let r=t.columns??-1;if(V.debug("layoutBlocks columns abc95",t.id,"=>",r,t),t.children&&t.children.length>0){let n=t?.children[0]?.size?.width??0,i=t.children.length*n+(t.children.length-1)*mi;V.debug("widthOfChildren 88",i,"posX");let a=0;V.debug("abc91 block?.size?.x",t.id,t?.size?.x);let s=t?.size?.x?t?.size?.x+(-t?.size?.width/2||0):-mi,l=0;for(let u of t.children){let h=t;if(!u.size)continue;let{width:f,height:d}=u.size,{px:p,py:m}=RJe(r,a);if(m!=l&&(l=m,s=t?.size?.x?t?.size?.x+(-t?.size?.width/2||0):-mi,V.debug("New row in layout for block",t.id," and child ",u.id,l)),V.debug(`abc89 layout blocks (child) id: ${u.id} Pos: ${a} (px, py) ${p},${m} (${h?.size?.x},${h?.size?.y}) parent: ${h.id} width: ${f}${mi}`),h.size){let g=f/2;u.size.x=s+mi+g,V.debug(`abc91 layout blocks (calc) px, pyid:${u.id} startingPos=X${s} new startingPosX${u.size.x} ${g} padding=${mi} width=${f} halfWidth=${g} => x:${u.size.x} y:${u.size.y} ${u.widthInColumns} (width * (child?.w || 1)) / 2 ${f*(u?.widthInColumns??1)/2}`),s=u.size.x+g,u.size.y=h.size.y-h.size.height/2+m*(d+mi)+d/2+mi,V.debug(`abc88 layout blocks (calc) px, pyid:${u.id}startingPosX${s}${mi}${g}=>x:${u.size.x}y:${u.size.y}${u.widthInColumns}(width * (child?.w || 1)) / 2${f*(u?.widthInColumns??1)/2}`)}u.children&&T1e(u,e),a+=u?.widthInColumns??1,V.debug("abc88 columnsPos",u,a)}}V.debug(`layout blocks (<==layoutBlocks) ${t.id} x: ${t?.size?.x} y: ${t?.size?.y} width: ${t?.size?.width}`)}function k1e(t,{minX:e,minY:r,maxX:n,maxY:i}={minX:0,minY:0,maxX:0,maxY:0}){if(t.size&&t.id!=="root"){let{x:a,y:s,width:l,height:u}=t.size;a-l/2n&&(n=a+l/2),s+u/2>i&&(i=s+u/2)}if(t.children)for(let a of t.children)({minX:e,minY:r,maxX:n,maxY:i}=k1e(a,{minX:e,minY:r,maxX:n,maxY:i}));return{minX:e,minY:r,maxX:n,maxY:i}}function E1e(t){let e=t.getBlock("root");if(!e)return;HB(e,t,0,0),T1e(e,t),V.debug("getBlocks",JSON.stringify(e,null,2));let{minX:r,minY:n,maxX:i,maxY:a}=k1e(e),s=a-n,l=i-r;return{x:r,y:n,width:l,height:s}}var mi,NJe,C1e=R(()=>{"use strict";ut();_t();mi=de()?.block?.padding??8;o(RJe,"calculateBlockPosition");NJe=o(t=>{let e=0,r=0;for(let n of t.children){let{width:i,height:a,x:s,y:l}=n.size??{width:0,height:0,x:0,y:0};V.debug("getMaxChildSize abc95 child:",n.id,"width:",i,"height:",a,"x:",s,"y:",l,n.type),n.type!=="space"&&(i>e&&(e=i/(t.widthInColumns??1)),a>r&&(r=a))}return{width:e,height:r}},"getMaxChildSize");o(HB,"setBlockSizes");o(T1e,"layoutBlocks");o(k1e,"findBounds");o(E1e,"layout")});function S1e(t,e,r=!1){let n=t,i="default";(n?.classes?.length||0)>0&&(i=(n?.classes??[]).join(" ")),i=i+" flowchart-label";let a=0,s="",l;switch(n.type){case"round":a=5,s="rect";break;case"composite":a=0,s="composite",l=0;break;case"square":s="rect";break;case"diamond":s="question";break;case"hexagon":s="hexagon";break;case"block_arrow":s="block_arrow";break;case"odd":s="rect_left_inv_arrow";break;case"lean_right":s="lean_right";break;case"lean_left":s="lean_left";break;case"trapezoid":s="trapezoid";break;case"inv_trapezoid":s="inv_trapezoid";break;case"rect_left_inv_arrow":s="rect_left_inv_arrow";break;case"circle":s="circle";break;case"ellipse":s="ellipse";break;case"stadium":s="stadium";break;case"subroutine":s="subroutine";break;case"cylinder":s="cylinder";break;case"group":s="rect";break;case"doublecircle":s="doublecircle";break;default:s="rect"}let u=lm(n?.styles??[]),h=n.label,f=n.size??{width:0,height:0,x:0,y:0};return{labelStyle:u.labelStyle,shape:s,labelText:h,rx:a,ry:a,class:i,style:u.style,id:n.id,directions:n.directions,width:f.width,height:f.height,x:f.x,y:f.y,positioned:r,intersect:void 0,type:n.type,padding:l??Or()?.block?.padding??0}}async function MJe(t,e,r){let n=S1e(e,r,!1);if(n.type==="group")return;let i=await pm(t,n),a=i.node().getBBox(),s=r.getBlock(n.id);s.size={width:a.width,height:a.height,x:0,y:0,node:i},r.setBlock(s),i.remove()}async function IJe(t,e,r){let n=S1e(e,r,!0);r.getBlock(n.id).type!=="space"&&(await pm(t,n),e.intersect=n?.intersect,wv(n))}async function YB(t,e,r,n){for(let i of e)await n(t,i,r),i.children&&await YB(t,i.children,r,n)}async function A1e(t,e,r){await YB(t,e,r,MJe)}async function _1e(t,e,r){await YB(t,e,r,IJe)}async function L1e(t,e,r,n,i){let a=new lr({multigraph:!0,compound:!0});a.setGraph({rankdir:"TB",nodesep:10,ranksep:10,marginx:8,marginy:8});for(let s of r)s.size&&a.setNode(s.id,{width:s.size.width,height:s.size.height,intersect:s.intersect});for(let s of e)if(s.start&&s.end){let l=n.getBlock(s.start),u=n.getBlock(s.end);if(l?.size&&u?.size){let h=l.size,f=u.size,d=[{x:h.x,y:h.y},{x:h.x+(f.x-h.x)/2,y:h.y+(f.y-h.y)/2},{x:f.x,y:f.y}];PE(t,{v:s.start,w:s.end,name:s.id},{...s,arrowTypeEnd:s.arrowTypeEnd,arrowTypeStart:s.arrowTypeStart,points:d,classes:"edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1"},void 0,"block",a,i),s.label&&(await IE(t,{...s,label:s.label,labelStyle:"stroke: #333; stroke-width: 1.5px;fill:none;",arrowTypeEnd:s.arrowTypeEnd,arrowTypeStart:s.arrowTypeStart,points:d,classes:"edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1"}),OE({...s,x:d[1].x,y:d[1].y},{originalPath:d}))}}}var D1e=R(()=>{"use strict";ya();qs();DO();M5();xr();o(S1e,"getNodeFromBlock");o(MJe,"calculateBlockSize");o(IJe,"insertBlockPositioned");o(YB,"performOperations");o(A1e,"calculateBlockSizes");o(_1e,"insertBlocks");o(L1e,"insertEdges")});var OJe,PJe,R1e,N1e=R(()=>{"use strict";Zt();qs();LO();ut();Yn();C1e();D1e();OJe=o(function(t,e){return e.db.getClasses()},"getClasses"),PJe=o(async function(t,e,r,n){let{securityLevel:i,block:a}=Or(),s=n.db,l;i==="sandbox"&&(l=$e("#i"+e));let u=i==="sandbox"?$e(l.nodes()[0].contentDocument.body):$e("body"),h=i==="sandbox"?u.select(`[id="${e}"]`):$e(`[id="${e}"]`);LE(h,["point","circle","cross"],n.type,e);let d=s.getBlocks(),p=s.getBlocksFlat(),m=s.getEdges(),g=h.insert("g").attr("class","block");await A1e(g,d,s);let y=E1e(s);if(await _1e(g,d,s),await L1e(g,m,p,s,e),y){let v=y,x=Math.max(1,Math.round(.125*(v.width/v.height))),b=v.height+x+10,w=v.width+10,{useMaxWidth:S}=a;Sr(h,b,w,!!S),V.debug("Here Bounds",y,v),h.attr("viewBox",`${v.x-5} ${v.y-5} ${v.width+10} ${v.height+10}`)}},"draw"),R1e={draw:PJe,getClasses:OJe}});var M1e={};hr(M1e,{diagram:()=>BJe});var BJe,I1e=R(()=>{"use strict";f1e();x1e();w1e();N1e();BJe={parser:h1e,db:v1e,renderer:R1e,styles:b1e}});var WB,qB,pb,B1e,XB,cs,Wc,oC,F1e,$Je,mb,z1e,G1e,$1e,V1e,lC,If,cC=R(()=>{"use strict";WB={L:"left",R:"right",T:"top",B:"bottom"},qB={L:o(t=>`${t},${t/2} 0,${t} 0,0`,"L"),R:o(t=>`0,${t/2} ${t},0 ${t},${t}`,"R"),T:o(t=>`0,0 ${t},0 ${t/2},${t}`,"T"),B:o(t=>`${t/2},0 ${t},${t} 0,${t}`,"B")},pb={L:o((t,e)=>t-e+2,"L"),R:o((t,e)=>t-2,"R"),T:o((t,e)=>t-e+2,"T"),B:o((t,e)=>t-2,"B")},B1e=o(function(t){return cs(t)?t==="L"?"R":"L":t==="T"?"B":"T"},"getOppositeArchitectureDirection"),XB=o(function(t){let e=t;return e==="L"||e==="R"||e==="T"||e==="B"},"isArchitectureDirection"),cs=o(function(t){let e=t;return e==="L"||e==="R"},"isArchitectureDirectionX"),Wc=o(function(t){let e=t;return e==="T"||e==="B"},"isArchitectureDirectionY"),oC=o(function(t,e){let r=cs(t)&&Wc(e),n=Wc(t)&&cs(e);return r||n},"isArchitectureDirectionXY"),F1e=o(function(t){let e=t[0],r=t[1],n=cs(e)&&Wc(r),i=Wc(e)&&cs(r);return n||i},"isArchitecturePairXY"),$Je=o(function(t){return t!=="LL"&&t!=="RR"&&t!=="TT"&&t!=="BB"},"isValidArchitectureDirectionPair"),mb=o(function(t,e){let r=`${t}${e}`;return $Je(r)?r:void 0},"getArchitectureDirectionPair"),z1e=o(function([t,e],r){let n=r[0],i=r[1];return cs(n)?Wc(i)?[t+(n==="L"?-1:1),e+(i==="T"?1:-1)]:[t+(n==="L"?-1:1),e]:cs(i)?[t+(i==="L"?1:-1),e+(n==="T"?1:-1)]:[t,e+(n==="T"?1:-1)]},"shiftPositionByArchitectureDirectionPair"),G1e=o(function(t){return t==="LT"||t==="TL"?[1,1]:t==="BL"||t==="LB"?[1,-1]:t==="BR"||t==="RB"?[-1,-1]:[-1,1]},"getArchitectureDirectionXYFactors"),$1e=o(function(t){return t.type==="service"},"isArchitectureService"),V1e=o(function(t){return t.type==="junction"},"isArchitectureJunction"),lC=o(t=>t.data(),"edgeData"),If=o(t=>t.data(),"nodeData")});function Ci(t){let e=de().architecture;return e?.[t]?e[t]:U1e[t]}var U1e,nr,VJe,UJe,HJe,YJe,WJe,qJe,XJe,jJe,KJe,QJe,ZJe,JJe,eet,tet,Z0,gb=R(()=>{"use strict";sl();_t();Jk();bi();cC();U1e=mr.architecture,nr=new uf(()=>({nodes:{},groups:{},edges:[],registeredIds:{},config:U1e,dataStructures:void 0,elements:{}})),VJe=o(()=>{nr.reset(),vr()},"clear"),UJe=o(function({id:t,icon:e,in:r,title:n,iconText:i}){if(nr.records.registeredIds[t]!==void 0)throw new Error(`The service id [${t}] is already in use by another ${nr.records.registeredIds[t]}`);if(r!==void 0){if(t===r)throw new Error(`The service [${t}] cannot be placed within itself`);if(nr.records.registeredIds[r]===void 0)throw new Error(`The service [${t}]'s parent does not exist. Please make sure the parent is created before this service`);if(nr.records.registeredIds[r]==="node")throw new Error(`The service [${t}]'s parent is not a group`)}nr.records.registeredIds[t]="node",nr.records.nodes[t]={id:t,type:"service",icon:e,iconText:i,title:n,edges:[],in:r}},"addService"),HJe=o(()=>Object.values(nr.records.nodes).filter($1e),"getServices"),YJe=o(function({id:t,in:e}){nr.records.registeredIds[t]="node",nr.records.nodes[t]={id:t,type:"junction",edges:[],in:e}},"addJunction"),WJe=o(()=>Object.values(nr.records.nodes).filter(V1e),"getJunctions"),qJe=o(()=>Object.values(nr.records.nodes),"getNodes"),XJe=o(t=>nr.records.nodes[t],"getNode"),jJe=o(function({id:t,icon:e,in:r,title:n}){if(nr.records.registeredIds[t]!==void 0)throw new Error(`The group id [${t}] is already in use by another ${nr.records.registeredIds[t]}`);if(r!==void 0){if(t===r)throw new Error(`The group [${t}] cannot be placed within itself`);if(nr.records.registeredIds[r]===void 0)throw new Error(`The group [${t}]'s parent does not exist. Please make sure the parent is created before this group`);if(nr.records.registeredIds[r]==="node")throw new Error(`The group [${t}]'s parent is not a group`)}nr.records.registeredIds[t]="group",nr.records.groups[t]={id:t,icon:e,title:n,in:r}},"addGroup"),KJe=o(()=>Object.values(nr.records.groups),"getGroups"),QJe=o(function({lhsId:t,rhsId:e,lhsDir:r,rhsDir:n,lhsInto:i,rhsInto:a,lhsGroup:s,rhsGroup:l,title:u}){if(!XB(r))throw new Error(`Invalid direction given for left hand side of edge ${t}--${e}. Expected (L,R,T,B) got ${r}`);if(!XB(n))throw new Error(`Invalid direction given for right hand side of edge ${t}--${e}. Expected (L,R,T,B) got ${n}`);if(nr.records.nodes[t]===void 0&&nr.records.groups[t]===void 0)throw new Error(`The left-hand id [${t}] does not yet exist. Please create the service/group before declaring an edge to it.`);if(nr.records.nodes[e]===void 0&&nr.records.groups[t]===void 0)throw new Error(`The right-hand id [${e}] does not yet exist. Please create the service/group before declaring an edge to it.`);let h=nr.records.nodes[t].in,f=nr.records.nodes[e].in;if(s&&h&&f&&h==f)throw new Error(`The left-hand id [${t}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);if(l&&h&&f&&h==f)throw new Error(`The right-hand id [${e}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);let d={lhsId:t,lhsDir:r,lhsInto:i,lhsGroup:s,rhsId:e,rhsDir:n,rhsInto:a,rhsGroup:l,title:u};nr.records.edges.push(d),nr.records.nodes[t]&&nr.records.nodes[e]&&(nr.records.nodes[t].edges.push(nr.records.edges[nr.records.edges.length-1]),nr.records.nodes[e].edges.push(nr.records.edges[nr.records.edges.length-1]))},"addEdge"),ZJe=o(()=>nr.records.edges,"getEdges"),JJe=o(()=>{if(nr.records.dataStructures===void 0){let t=Object.entries(nr.records.nodes).reduce((s,[l,u])=>(s[l]=u.edges.reduce((h,f)=>{if(f.lhsId===l){let d=mb(f.lhsDir,f.rhsDir);d&&(h[d]=f.rhsId)}else{let d=mb(f.rhsDir,f.lhsDir);d&&(h[d]=f.lhsId)}return h},{}),s),{}),e=Object.keys(t)[0],r={[e]:1},n=Object.keys(t).reduce((s,l)=>l===e?s:{...s,[l]:1},{}),i=o(s=>{let l={[s]:[0,0]},u=[s];for(;u.length>0;){let h=u.shift();if(h){r[h]=1,delete n[h];let f=t[h],[d,p]=l[h];Object.entries(f).forEach(([m,g])=>{r[g]||(l[g]=z1e([d,p],m),u.push(g))})}}return l},"BFS"),a=[i(e)];for(;Object.keys(n).length>0;)a.push(i(Object.keys(n)[0]));nr.records.dataStructures={adjList:t,spatialMaps:a}}return nr.records.dataStructures},"getDataStructures"),eet=o((t,e)=>{nr.records.elements[t]=e},"setElementForId"),tet=o(t=>nr.records.elements[t],"getElementById"),Z0={clear:VJe,setDiagramTitle:nn,getDiagramTitle:Xr,setAccTitle:kr,getAccTitle:Ar,setAccDescription:_r,getAccDescription:Lr,addService:UJe,getServices:HJe,addJunction:YJe,getJunctions:WJe,getNodes:qJe,getNode:XJe,addGroup:jJe,getGroups:KJe,addEdge:QJe,getEdges:ZJe,setElementForId:eet,getElementById:tet,getDataStructures:JJe};o(Ci,"getConfigField")});var ret,H1e,Y1e=R(()=>{"use strict";Lg();ut();sx();gb();ret=o((t,e)=>{cf(t,e),t.groups.map(e.addGroup),t.services.map(r=>e.addService({...r,type:"service"})),t.junctions.map(r=>e.addJunction({...r,type:"junction"})),t.edges.map(e.addEdge)},"populateDb"),H1e={parse:o(async t=>{let e=await Fl("architecture",t);V.debug(e),ret(e,Z0)},"parse")}});var net,W1e,q1e=R(()=>{"use strict";net=o(t=>` + .edge { + stroke-width: ${t.archEdgeWidth}; + stroke: ${t.archEdgeColor}; + fill: none; + } + + .arrow { + fill: ${t.archEdgeArrowColor}; + } + + .node-bkg { + fill: none; + stroke: ${t.archGroupBorderColor}; + stroke-width: ${t.archGroupBorderWidth}; + stroke-dasharray: 8; + } + .node-icon-text { + display: flex; + align-items: center; + } + + .node-icon-text > div { + color: #fff; + margin: 1px; + height: fit-content; + text-align: center; + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + } +`,"getStyles"),W1e=net});var KB=gi((yb,jB)=>{"use strict";o(function(e,r){typeof yb=="object"&&typeof jB=="object"?jB.exports=r():typeof define=="function"&&define.amd?define([],r):typeof yb=="object"?yb.layoutBase=r():e.layoutBase=r()},"webpackUniversalModuleDefinition")(yb,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return o(r,"__webpack_require__"),r.m=t,r.c=e,r.i=function(n){return n},r.d=function(n,i,a){r.o(n,i)||Object.defineProperty(n,i,{configurable:!1,enumerable:!0,get:a})},r.n=function(n){var i=n&&n.__esModule?o(function(){return n.default},"getDefault"):o(function(){return n},"getModuleExports");return r.d(i,"a",i),i},r.o=function(n,i){return Object.prototype.hasOwnProperty.call(n,i)},r.p="",r(r.s=28)}([function(t,e,r){"use strict";function n(){}o(n,"LayoutConstants"),n.QUALITY=1,n.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,n.DEFAULT_INCREMENTAL=!1,n.DEFAULT_ANIMATION_ON_LAYOUT=!0,n.DEFAULT_ANIMATION_DURING_LAYOUT=!1,n.DEFAULT_ANIMATION_PERIOD=50,n.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,n.DEFAULT_GRAPH_MARGIN=15,n.NODE_DIMENSIONS_INCLUDE_LABELS=!1,n.SIMPLE_NODE_SIZE=40,n.SIMPLE_NODE_HALF_SIZE=n.SIMPLE_NODE_SIZE/2,n.EMPTY_COMPOUND_NODE_SIZE=40,n.MIN_EDGE_LENGTH=1,n.WORLD_BOUNDARY=1e6,n.INITIAL_WORLD_BOUNDARY=n.WORLD_BOUNDARY/1e3,n.WORLD_CENTER_X=1200,n.WORLD_CENTER_Y=900,t.exports=n},function(t,e,r){"use strict";var n=r(2),i=r(8),a=r(9);function s(u,h,f){n.call(this,f),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=f,this.bendpoints=[],this.source=u,this.target=h}o(s,"LEdge"),s.prototype=Object.create(n.prototype);for(var l in n)s[l]=n[l];s.prototype.getSource=function(){return this.source},s.prototype.getTarget=function(){return this.target},s.prototype.isInterGraph=function(){return this.isInterGraph},s.prototype.getLength=function(){return this.length},s.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},s.prototype.getBendpoints=function(){return this.bendpoints},s.prototype.getLca=function(){return this.lca},s.prototype.getSourceInLca=function(){return this.sourceInLca},s.prototype.getTargetInLca=function(){return this.targetInLca},s.prototype.getOtherEnd=function(u){if(this.source===u)return this.target;if(this.target===u)return this.source;throw"Node is not incident with this edge"},s.prototype.getOtherEndInGraph=function(u,h){for(var f=this.getOtherEnd(u),d=h.getGraphManager().getRoot();;){if(f.getOwner()==h)return f;if(f.getOwner()==d)break;f=f.getOwner().getParent()}return null},s.prototype.updateLength=function(){var u=new Array(4);this.isOverlapingSourceAndTarget=i.getIntersection(this.target.getRect(),this.source.getRect(),u),this.isOverlapingSourceAndTarget||(this.lengthX=u[0]-u[2],this.lengthY=u[1]-u[3],Math.abs(this.lengthX)<1&&(this.lengthX=a.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=a.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},s.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=a.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=a.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},t.exports=s},function(t,e,r){"use strict";function n(i){this.vGraphObject=i}o(n,"LGraphObject"),t.exports=n},function(t,e,r){"use strict";var n=r(2),i=r(10),a=r(13),s=r(0),l=r(16),u=r(5);function h(d,p,m,g){m==null&&g==null&&(g=p),n.call(this,g),d.graphManager!=null&&(d=d.graphManager),this.estimatedSize=i.MIN_VALUE,this.inclusionTreeDepth=i.MAX_VALUE,this.vGraphObject=g,this.edges=[],this.graphManager=d,m!=null&&p!=null?this.rect=new a(p.x,p.y,m.width,m.height):this.rect=new a}o(h,"LNode"),h.prototype=Object.create(n.prototype);for(var f in n)h[f]=n[f];h.prototype.getEdges=function(){return this.edges},h.prototype.getChild=function(){return this.child},h.prototype.getOwner=function(){return this.owner},h.prototype.getWidth=function(){return this.rect.width},h.prototype.setWidth=function(d){this.rect.width=d},h.prototype.getHeight=function(){return this.rect.height},h.prototype.setHeight=function(d){this.rect.height=d},h.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},h.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},h.prototype.getCenter=function(){return new u(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},h.prototype.getLocation=function(){return new u(this.rect.x,this.rect.y)},h.prototype.getRect=function(){return this.rect},h.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},h.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},h.prototype.setRect=function(d,p){this.rect.x=d.x,this.rect.y=d.y,this.rect.width=p.width,this.rect.height=p.height},h.prototype.setCenter=function(d,p){this.rect.x=d-this.rect.width/2,this.rect.y=p-this.rect.height/2},h.prototype.setLocation=function(d,p){this.rect.x=d,this.rect.y=p},h.prototype.moveBy=function(d,p){this.rect.x+=d,this.rect.y+=p},h.prototype.getEdgeListToNode=function(d){var p=[],m,g=this;return g.edges.forEach(function(y){if(y.target==d){if(y.source!=g)throw"Incorrect edge source!";p.push(y)}}),p},h.prototype.getEdgesBetween=function(d){var p=[],m,g=this;return g.edges.forEach(function(y){if(!(y.source==g||y.target==g))throw"Incorrect edge source and/or target";(y.target==d||y.source==d)&&p.push(y)}),p},h.prototype.getNeighborsList=function(){var d=new Set,p=this;return p.edges.forEach(function(m){if(m.source==p)d.add(m.target);else{if(m.target!=p)throw"Incorrect incidency!";d.add(m.source)}}),d},h.prototype.withChildren=function(){var d=new Set,p,m;if(d.add(this),this.child!=null)for(var g=this.child.getNodes(),y=0;yp?(this.rect.x-=(this.labelWidth-p)/2,this.setWidth(this.labelWidth)):this.labelPosHorizontal=="right"&&this.setWidth(p+this.labelWidth)),this.labelHeight&&(this.labelPosVertical=="top"?(this.rect.y-=this.labelHeight,this.setHeight(m+this.labelHeight)):this.labelPosVertical=="center"&&this.labelHeight>m?(this.rect.y-=(this.labelHeight-m)/2,this.setHeight(this.labelHeight)):this.labelPosVertical=="bottom"&&this.setHeight(m+this.labelHeight))}}},h.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==i.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},h.prototype.transform=function(d){var p=this.rect.x;p>s.WORLD_BOUNDARY?p=s.WORLD_BOUNDARY:p<-s.WORLD_BOUNDARY&&(p=-s.WORLD_BOUNDARY);var m=this.rect.y;m>s.WORLD_BOUNDARY?m=s.WORLD_BOUNDARY:m<-s.WORLD_BOUNDARY&&(m=-s.WORLD_BOUNDARY);var g=new u(p,m),y=d.inverseTransformPoint(g);this.setLocation(y.x,y.y)},h.prototype.getLeft=function(){return this.rect.x},h.prototype.getRight=function(){return this.rect.x+this.rect.width},h.prototype.getTop=function(){return this.rect.y},h.prototype.getBottom=function(){return this.rect.y+this.rect.height},h.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},t.exports=h},function(t,e,r){"use strict";var n=r(0);function i(){}o(i,"FDLayoutConstants");for(var a in n)i[a]=n[a];i.MAX_ITERATIONS=2500,i.DEFAULT_EDGE_LENGTH=50,i.DEFAULT_SPRING_STRENGTH=.45,i.DEFAULT_REPULSION_STRENGTH=4500,i.DEFAULT_GRAVITY_STRENGTH=.4,i.DEFAULT_COMPOUND_GRAVITY_STRENGTH=1,i.DEFAULT_GRAVITY_RANGE_FACTOR=3.8,i.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=1.5,i.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION=!0,i.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION=!0,i.DEFAULT_COOLING_FACTOR_INCREMENTAL=.3,i.COOLING_ADAPTATION_FACTOR=.33,i.ADAPTATION_LOWER_NODE_LIMIT=1e3,i.ADAPTATION_UPPER_NODE_LIMIT=5e3,i.MAX_NODE_DISPLACEMENT_INCREMENTAL=100,i.MAX_NODE_DISPLACEMENT=i.MAX_NODE_DISPLACEMENT_INCREMENTAL*3,i.MIN_REPULSION_DIST=i.DEFAULT_EDGE_LENGTH/10,i.CONVERGENCE_CHECK_PERIOD=100,i.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=.1,i.MIN_EDGE_LENGTH=1,i.GRID_CALCULATION_CHECK_PERIOD=10,t.exports=i},function(t,e,r){"use strict";function n(i,a){i==null&&a==null?(this.x=0,this.y=0):(this.x=i,this.y=a)}o(n,"PointD"),n.prototype.getX=function(){return this.x},n.prototype.getY=function(){return this.y},n.prototype.setX=function(i){this.x=i},n.prototype.setY=function(i){this.y=i},n.prototype.getDifference=function(i){return new DimensionD(this.x-i.x,this.y-i.y)},n.prototype.getCopy=function(){return new n(this.x,this.y)},n.prototype.translate=function(i){return this.x+=i.width,this.y+=i.height,this},t.exports=n},function(t,e,r){"use strict";var n=r(2),i=r(10),a=r(0),s=r(7),l=r(3),u=r(1),h=r(13),f=r(12),d=r(11);function p(g,y,v){n.call(this,v),this.estimatedSize=i.MIN_VALUE,this.margin=a.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=g,y!=null&&y instanceof s?this.graphManager=y:y!=null&&y instanceof Layout&&(this.graphManager=y.graphManager)}o(p,"LGraph"),p.prototype=Object.create(n.prototype);for(var m in n)p[m]=n[m];p.prototype.getNodes=function(){return this.nodes},p.prototype.getEdges=function(){return this.edges},p.prototype.getGraphManager=function(){return this.graphManager},p.prototype.getParent=function(){return this.parent},p.prototype.getLeft=function(){return this.left},p.prototype.getRight=function(){return this.right},p.prototype.getTop=function(){return this.top},p.prototype.getBottom=function(){return this.bottom},p.prototype.isConnected=function(){return this.isConnected},p.prototype.add=function(g,y,v){if(y==null&&v==null){var x=g;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(x)>-1)throw"Node already in graph!";return x.owner=this,this.getNodes().push(x),x}else{var b=g;if(!(this.getNodes().indexOf(y)>-1&&this.getNodes().indexOf(v)>-1))throw"Source or target not in graph!";if(!(y.owner==v.owner&&y.owner==this))throw"Both owners must be this graph!";return y.owner!=v.owner?null:(b.source=y,b.target=v,b.isInterGraph=!1,this.getEdges().push(b),y.edges.push(b),v!=y&&v.edges.push(b),b)}},p.prototype.remove=function(g){var y=g;if(g instanceof l){if(y==null)throw"Node is null!";if(!(y.owner!=null&&y.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var v=y.edges.slice(),x,b=v.length,w=0;w-1&&E>-1))throw"Source and/or target doesn't know this edge!";x.source.edges.splice(T,1),x.target!=x.source&&x.target.edges.splice(E,1);var S=x.source.owner.getEdges().indexOf(x);if(S==-1)throw"Not in owner's edge list!";x.source.owner.getEdges().splice(S,1)}},p.prototype.updateLeftTop=function(){for(var g=i.MAX_VALUE,y=i.MAX_VALUE,v,x,b,w=this.getNodes(),S=w.length,T=0;Tv&&(g=v),y>x&&(y=x)}return g==i.MAX_VALUE?null:(w[0].getParent().paddingLeft!=null?b=w[0].getParent().paddingLeft:b=this.margin,this.left=y-b,this.top=g-b,new f(this.left,this.top))},p.prototype.updateBounds=function(g){for(var y=i.MAX_VALUE,v=-i.MAX_VALUE,x=i.MAX_VALUE,b=-i.MAX_VALUE,w,S,T,E,_,A=this.nodes,L=A.length,M=0;Mw&&(y=w),vT&&(x=T),bw&&(y=w),vT&&(x=T),b=this.nodes.length){var L=0;v.forEach(function(M){M.owner==g&&L++}),L==this.nodes.length&&(this.isConnected=!0)}},t.exports=p},function(t,e,r){"use strict";var n,i=r(1);function a(s){n=r(6),this.layout=s,this.graphs=[],this.edges=[]}o(a,"LGraphManager"),a.prototype.addRoot=function(){var s=this.layout.newGraph(),l=this.layout.newNode(null),u=this.add(s,l);return this.setRootGraph(u),this.rootGraph},a.prototype.add=function(s,l,u,h,f){if(u==null&&h==null&&f==null){if(s==null)throw"Graph is null!";if(l==null)throw"Parent node is null!";if(this.graphs.indexOf(s)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(s),s.parent!=null)throw"Already has a parent!";if(l.child!=null)throw"Already has a child!";return s.parent=l,l.child=s,s}else{f=u,h=l,u=s;var d=h.getOwner(),p=f.getOwner();if(!(d!=null&&d.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(p!=null&&p.getGraphManager()==this))throw"Target not in this graph mgr!";if(d==p)return u.isInterGraph=!1,d.add(u,h,f);if(u.isInterGraph=!0,u.source=h,u.target=f,this.edges.indexOf(u)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(u),!(u.source!=null&&u.target!=null))throw"Edge source and/or target is null!";if(!(u.source.edges.indexOf(u)==-1&&u.target.edges.indexOf(u)==-1))throw"Edge already in source and/or target incidency list!";return u.source.edges.push(u),u.target.edges.push(u),u}},a.prototype.remove=function(s){if(s instanceof n){var l=s;if(l.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(l==this.rootGraph||l.parent!=null&&l.parent.graphManager==this))throw"Invalid parent node!";var u=[];u=u.concat(l.getEdges());for(var h,f=u.length,d=0;d=s.getRight()?l[0]+=Math.min(s.getX()-a.getX(),a.getRight()-s.getRight()):s.getX()<=a.getX()&&s.getRight()>=a.getRight()&&(l[0]+=Math.min(a.getX()-s.getX(),s.getRight()-a.getRight())),a.getY()<=s.getY()&&a.getBottom()>=s.getBottom()?l[1]+=Math.min(s.getY()-a.getY(),a.getBottom()-s.getBottom()):s.getY()<=a.getY()&&s.getBottom()>=a.getBottom()&&(l[1]+=Math.min(a.getY()-s.getY(),s.getBottom()-a.getBottom()));var f=Math.abs((s.getCenterY()-a.getCenterY())/(s.getCenterX()-a.getCenterX()));s.getCenterY()===a.getCenterY()&&s.getCenterX()===a.getCenterX()&&(f=1);var d=f*l[0],p=l[1]/f;l[0]d)return l[0]=u,l[1]=m,l[2]=f,l[3]=A,!1;if(hf)return l[0]=p,l[1]=h,l[2]=E,l[3]=d,!1;if(uf?(l[0]=y,l[1]=v,k=!0):(l[0]=g,l[1]=m,k=!0):C===D&&(u>f?(l[0]=p,l[1]=m,k=!0):(l[0]=x,l[1]=v,k=!0)),-O===D?f>u?(l[2]=_,l[3]=A,I=!0):(l[2]=E,l[3]=T,I=!0):O===D&&(f>u?(l[2]=S,l[3]=T,I=!0):(l[2]=L,l[3]=A,I=!0)),k&&I)return!1;if(u>f?h>d?(P=this.getCardinalDirection(C,D,4),F=this.getCardinalDirection(O,D,2)):(P=this.getCardinalDirection(-C,D,3),F=this.getCardinalDirection(-O,D,1)):h>d?(P=this.getCardinalDirection(-C,D,1),F=this.getCardinalDirection(-O,D,3)):(P=this.getCardinalDirection(C,D,2),F=this.getCardinalDirection(O,D,4)),!k)switch(P){case 1:$=m,B=u+-w/D,l[0]=B,l[1]=$;break;case 2:B=x,$=h+b*D,l[0]=B,l[1]=$;break;case 3:$=v,B=u+w/D,l[0]=B,l[1]=$;break;case 4:B=y,$=h+-b*D,l[0]=B,l[1]=$;break}if(!I)switch(F){case 1:Y=T,z=f+-N/D,l[2]=z,l[3]=Y;break;case 2:z=L,Y=d+M*D,l[2]=z,l[3]=Y;break;case 3:Y=A,z=f+N/D,l[2]=z,l[3]=Y;break;case 4:z=_,Y=d+-M*D,l[2]=z,l[3]=Y;break}}return!1},i.getCardinalDirection=function(a,s,l){return a>s?l:1+l%4},i.getIntersection=function(a,s,l,u){if(u==null)return this.getIntersection2(a,s,l);var h=a.x,f=a.y,d=s.x,p=s.y,m=l.x,g=l.y,y=u.x,v=u.y,x=void 0,b=void 0,w=void 0,S=void 0,T=void 0,E=void 0,_=void 0,A=void 0,L=void 0;return w=p-f,T=h-d,_=d*f-h*p,S=v-g,E=m-y,A=y*g-m*v,L=w*E-S*T,L===0?null:(x=(T*A-E*_)/L,b=(S*_-w*A)/L,new n(x,b))},i.angleOfVector=function(a,s,l,u){var h=void 0;return a!==l?(h=Math.atan((u-s)/(l-a)),l=0){var v=(-m+Math.sqrt(m*m-4*p*g))/(2*p),x=(-m-Math.sqrt(m*m-4*p*g))/(2*p),b=null;return v>=0&&v<=1?[v]:x>=0&&x<=1?[x]:b}else return null},i.HALF_PI=.5*Math.PI,i.ONE_AND_HALF_PI=1.5*Math.PI,i.TWO_PI=2*Math.PI,i.THREE_PI=3*Math.PI,t.exports=i},function(t,e,r){"use strict";function n(){}o(n,"IMath"),n.sign=function(i){return i>0?1:i<0?-1:0},n.floor=function(i){return i<0?Math.ceil(i):Math.floor(i)},n.ceil=function(i){return i<0?Math.floor(i):Math.ceil(i)},t.exports=n},function(t,e,r){"use strict";function n(){}o(n,"Integer"),n.MAX_VALUE=2147483647,n.MIN_VALUE=-2147483648,t.exports=n},function(t,e,r){"use strict";var n=function(){function h(f,d){for(var p=0;p"u"?"undefined":n(a);return a==null||s!="object"&&s!="function"},t.exports=i},function(t,e,r){"use strict";function n(m){if(Array.isArray(m)){for(var g=0,y=Array(m.length);g0&&g;){for(w.push(T[0]);w.length>0&&g;){var E=w[0];w.splice(0,1),b.add(E);for(var _=E.getEdges(),x=0;x<_.length;x++){var A=_[x].getOtherEnd(E);if(S.get(E)!=A)if(!b.has(A))w.push(A),S.set(A,E);else{g=!1;break}}}if(!g)m=[];else{var L=[].concat(n(b));m.push(L);for(var x=0;x-1&&T.splice(N,1)}b=new Set,S=new Map}}return m},p.prototype.createDummyNodesForBendpoints=function(m){for(var g=[],y=m.source,v=this.graphManager.calcLowestCommonAncestor(m.source,m.target),x=0;x0){for(var v=this.edgeToDummyNodes.get(y),x=0;x=0&&g.splice(A,1);var L=S.getNeighborsList();L.forEach(function(k){if(y.indexOf(k)<0){var I=v.get(k),C=I-1;C==1&&E.push(k),v.set(k,C)}})}y=y.concat(E),(g.length==1||g.length==2)&&(x=!0,b=g[0])}return b},p.prototype.setGraphManager=function(m){this.graphManager=m},t.exports=p},function(t,e,r){"use strict";function n(){}o(n,"RandomSeed"),n.seed=1,n.x=0,n.nextDouble=function(){return n.x=Math.sin(n.seed++)*1e4,n.x-Math.floor(n.x)},t.exports=n},function(t,e,r){"use strict";var n=r(5);function i(a,s){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}o(i,"Transform"),i.prototype.getWorldOrgX=function(){return this.lworldOrgX},i.prototype.setWorldOrgX=function(a){this.lworldOrgX=a},i.prototype.getWorldOrgY=function(){return this.lworldOrgY},i.prototype.setWorldOrgY=function(a){this.lworldOrgY=a},i.prototype.getWorldExtX=function(){return this.lworldExtX},i.prototype.setWorldExtX=function(a){this.lworldExtX=a},i.prototype.getWorldExtY=function(){return this.lworldExtY},i.prototype.setWorldExtY=function(a){this.lworldExtY=a},i.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},i.prototype.setDeviceOrgX=function(a){this.ldeviceOrgX=a},i.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},i.prototype.setDeviceOrgY=function(a){this.ldeviceOrgY=a},i.prototype.getDeviceExtX=function(){return this.ldeviceExtX},i.prototype.setDeviceExtX=function(a){this.ldeviceExtX=a},i.prototype.getDeviceExtY=function(){return this.ldeviceExtY},i.prototype.setDeviceExtY=function(a){this.ldeviceExtY=a},i.prototype.transformX=function(a){var s=0,l=this.lworldExtX;return l!=0&&(s=this.ldeviceOrgX+(a-this.lworldOrgX)*this.ldeviceExtX/l),s},i.prototype.transformY=function(a){var s=0,l=this.lworldExtY;return l!=0&&(s=this.ldeviceOrgY+(a-this.lworldOrgY)*this.ldeviceExtY/l),s},i.prototype.inverseTransformX=function(a){var s=0,l=this.ldeviceExtX;return l!=0&&(s=this.lworldOrgX+(a-this.ldeviceOrgX)*this.lworldExtX/l),s},i.prototype.inverseTransformY=function(a){var s=0,l=this.ldeviceExtY;return l!=0&&(s=this.lworldOrgY+(a-this.ldeviceOrgY)*this.lworldExtY/l),s},i.prototype.inverseTransformPoint=function(a){var s=new n(this.inverseTransformX(a.x),this.inverseTransformY(a.y));return s},t.exports=i},function(t,e,r){"use strict";function n(d){if(Array.isArray(d)){for(var p=0,m=Array(d.length);pa.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*a.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(d-a.ADAPTATION_LOWER_NODE_LIMIT)/(a.ADAPTATION_UPPER_NODE_LIMIT-a.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-a.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=a.MAX_NODE_DISPLACEMENT_INCREMENTAL):(d>a.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(a.COOLING_ADAPTATION_FACTOR,1-(d-a.ADAPTATION_LOWER_NODE_LIMIT)/(a.ADAPTATION_UPPER_NODE_LIMIT-a.ADAPTATION_LOWER_NODE_LIMIT)*(1-a.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=a.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.displacementThresholdPerNode=3*a.DEFAULT_EDGE_LENGTH/100,this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},h.prototype.calcSpringForces=function(){for(var d=this.getAllEdges(),p,m=0;m0&&arguments[0]!==void 0?arguments[0]:!0,p=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,m,g,y,v,x=this.getAllNodes(),b;if(this.useFRGridVariant)for(this.totalIterations%a.GRID_CALCULATION_CHECK_PERIOD==1&&d&&this.updateGrid(),b=new Set,m=0;mw||b>w)&&(d.gravitationForceX=-this.gravityConstant*y,d.gravitationForceY=-this.gravityConstant*v)):(w=p.getEstimatedSize()*this.compoundGravityRangeFactor,(x>w||b>w)&&(d.gravitationForceX=-this.gravityConstant*y*this.compoundGravityConstant,d.gravitationForceY=-this.gravityConstant*v*this.compoundGravityConstant))},h.prototype.isConverged=function(){var d,p=!1;return this.totalIterations>this.maxIterations/3&&(p=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),d=this.totalDisplacement=x.length||w>=x[0].length)){for(var S=0;Sh},"_defaultCompareFunction")}]),l}();t.exports=s},function(t,e,r){"use strict";function n(){}o(n,"SVD"),n.svd=function(i){this.U=null,this.V=null,this.s=null,this.m=0,this.n=0,this.m=i.length,this.n=i[0].length;var a=Math.min(this.m,this.n);this.s=function(it){for(var dt=[];it-- >0;)dt.push(0);return dt}(Math.min(this.m+1,this.n)),this.U=function(it){var dt=o(function lt(It){if(It.length==0)return 0;for(var mt=[],St=0;St0;)dt.push(0);return dt}(this.n),l=function(it){for(var dt=[];it-- >0;)dt.push(0);return dt}(this.m),u=!0,h=!0,f=Math.min(this.m-1,this.n),d=Math.max(0,Math.min(this.n-2,this.m)),p=0;p=0;D--)if(this.s[D]!==0){for(var P=D+1;P=0;X--){if(function(it,dt){return it&&dt}(X0;){var ue=void 0,te=void 0;for(ue=I-2;ue>=-1&&ue!==-1;ue--)if(Math.abs(s[ue])<=ce+se*(Math.abs(this.s[ue])+Math.abs(this.s[ue+1]))){s[ue]=0;break}if(ue===I-2)te=4;else{var De=void 0;for(De=I-1;De>=ue&&De!==ue;De--){var oe=(De!==I?Math.abs(s[De]):0)+(De!==ue+1?Math.abs(s[De-1]):0);if(Math.abs(this.s[De])<=ce+se*oe){this.s[De]=0;break}}De===ue?te=3:De===I-1?te=1:(te=2,ue=De)}switch(ue++,te){case 1:{var ke=s[I-2];s[I-2]=0;for(var Ie=I-2;Ie>=ue;Ie--){var Se=n.hypot(this.s[Ie],ke),Ue=this.s[Ie]/Se,Pe=ke/Se;if(this.s[Ie]=Se,Ie!==ue&&(ke=-Pe*s[Ie-1],s[Ie-1]=Ue*s[Ie-1]),h)for(var _e=0;_e=this.s[ue+1]);){var je=this.s[ue];if(this.s[ue]=this.s[ue+1],this.s[ue+1]=je,h&&ueMath.abs(a)?(s=a/i,s=Math.abs(i)*Math.sqrt(1+s*s)):a!=0?(s=i/a,s=Math.abs(a)*Math.sqrt(1+s*s)):s=0,s},t.exports=n},function(t,e,r){"use strict";var n=function(){function s(l,u){for(var h=0;h2&&arguments[2]!==void 0?arguments[2]:1,f=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,d=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;i(this,s),this.sequence1=l,this.sequence2=u,this.match_score=h,this.mismatch_penalty=f,this.gap_penalty=d,this.iMax=l.length+1,this.jMax=u.length+1,this.grid=new Array(this.iMax);for(var p=0;p=0;l--){var u=this.listeners[l];u.event===a&&u.callback===s&&this.listeners.splice(l,1)}},i.emit=function(a,s){for(var l=0;l{"use strict";o(function(e,r){typeof vb=="object"&&typeof QB=="object"?QB.exports=r(KB()):typeof define=="function"&&define.amd?define(["layout-base"],r):typeof vb=="object"?vb.coseBase=r(KB()):e.coseBase=r(e.layoutBase)},"webpackUniversalModuleDefinition")(vb,function(t){return(()=>{"use strict";var e={45:(a,s,l)=>{var u={};u.layoutBase=l(551),u.CoSEConstants=l(806),u.CoSEEdge=l(767),u.CoSEGraph=l(880),u.CoSEGraphManager=l(578),u.CoSELayout=l(765),u.CoSENode=l(991),u.ConstraintHandler=l(902),a.exports=u},806:(a,s,l)=>{var u=l(551).FDLayoutConstants;function h(){}o(h,"CoSEConstants");for(var f in u)h[f]=u[f];h.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,h.DEFAULT_RADIAL_SEPARATION=u.DEFAULT_EDGE_LENGTH,h.DEFAULT_COMPONENT_SEPERATION=60,h.TILE=!0,h.TILING_PADDING_VERTICAL=10,h.TILING_PADDING_HORIZONTAL=10,h.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,h.ENFORCE_CONSTRAINTS=!0,h.APPLY_LAYOUT=!0,h.RELAX_MOVEMENT_ON_CONSTRAINTS=!0,h.TREE_REDUCTION_ON_INCREMENTAL=!0,h.PURE_INCREMENTAL=h.DEFAULT_INCREMENTAL,a.exports=h},767:(a,s,l)=>{var u=l(551).FDLayoutEdge;function h(d,p,m){u.call(this,d,p,m)}o(h,"CoSEEdge"),h.prototype=Object.create(u.prototype);for(var f in u)h[f]=u[f];a.exports=h},880:(a,s,l)=>{var u=l(551).LGraph;function h(d,p,m){u.call(this,d,p,m)}o(h,"CoSEGraph"),h.prototype=Object.create(u.prototype);for(var f in u)h[f]=u[f];a.exports=h},578:(a,s,l)=>{var u=l(551).LGraphManager;function h(d){u.call(this,d)}o(h,"CoSEGraphManager"),h.prototype=Object.create(u.prototype);for(var f in u)h[f]=u[f];a.exports=h},765:(a,s,l)=>{var u=l(551).FDLayout,h=l(578),f=l(880),d=l(991),p=l(767),m=l(806),g=l(902),y=l(551).FDLayoutConstants,v=l(551).LayoutConstants,x=l(551).Point,b=l(551).PointD,w=l(551).DimensionD,S=l(551).Layout,T=l(551).Integer,E=l(551).IGeometry,_=l(551).LGraph,A=l(551).Transform,L=l(551).LinkedList;function M(){u.call(this),this.toBeTiled={},this.constraints={}}o(M,"CoSELayout"),M.prototype=Object.create(u.prototype);for(var N in u)M[N]=u[N];M.prototype.newGraphManager=function(){var k=new h(this);return this.graphManager=k,k},M.prototype.newGraph=function(k){return new f(null,this.graphManager,k)},M.prototype.newNode=function(k){return new d(this.graphManager,k)},M.prototype.newEdge=function(k){return new p(null,null,k)},M.prototype.initParameters=function(){u.prototype.initParameters.call(this,arguments),this.isSubLayout||(m.DEFAULT_EDGE_LENGTH<10?this.idealEdgeLength=10:this.idealEdgeLength=m.DEFAULT_EDGE_LENGTH,this.useSmartIdealEdgeLengthCalculation=m.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.gravityConstant=y.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=y.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=y.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=y.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.prunedNodesAll=[],this.growTreeIterations=0,this.afterGrowthIterations=0,this.isTreeGrowing=!1,this.isGrowthFinished=!1)},M.prototype.initSpringEmbedder=function(){u.prototype.initSpringEmbedder.call(this),this.coolingCycle=0,this.maxCoolingCycle=this.maxIterations/y.CONVERGENCE_CHECK_PERIOD,this.finalTemperature=.04,this.coolingAdjuster=1},M.prototype.layout=function(){var k=v.DEFAULT_CREATE_BENDS_AS_NEEDED;return k&&(this.createBendpoints(),this.graphManager.resetAllEdges()),this.level=0,this.classicLayout()},M.prototype.classicLayout=function(){if(this.nodesWithGravity=this.calculateNodesToApplyGravitationTo(),this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity),this.calcNoOfChildrenForAllNodes(),this.graphManager.calcLowestCommonAncestors(),this.graphManager.calcInclusionTreeDepths(),this.graphManager.getRoot().calcEstimatedSize(),this.calcIdealEdgeLengths(),this.incremental){if(m.TREE_REDUCTION_ON_INCREMENTAL){this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var I=new Set(this.getAllNodes()),C=this.nodesWithGravity.filter(function(P){return I.has(P)});this.graphManager.setAllNodesToApplyGravitation(C)}}else{var k=this.getFlatForest();if(k.length>0)this.positionNodesRadially(k);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var I=new Set(this.getAllNodes()),C=this.nodesWithGravity.filter(function(O){return I.has(O)});this.graphManager.setAllNodesToApplyGravitation(C),this.positionNodesRandomly()}}return Object.keys(this.constraints).length>0&&(g.handleConstraints(this),this.initConstraintVariables()),this.initSpringEmbedder(),m.APPLY_LAYOUT&&this.runSpringEmbedder(),!0},M.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%y.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var k=new Set(this.getAllNodes()),I=this.nodesWithGravity.filter(function(D){return k.has(D)});this.graphManager.setAllNodesToApplyGravitation(I),this.graphManager.updateBounds(),this.updateGrid(),m.PURE_INCREMENTAL?this.coolingFactor=y.DEFAULT_COOLING_FACTOR_INCREMENTAL/2:this.coolingFactor=y.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),m.PURE_INCREMENTAL?this.coolingFactor=y.DEFAULT_COOLING_FACTOR_INCREMENTAL/2*((100-this.afterGrowthIterations)/100):this.coolingFactor=y.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var C=!this.isTreeGrowing&&!this.isGrowthFinished,O=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(C,O),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},M.prototype.getPositionsData=function(){for(var k=this.graphManager.getAllNodes(),I={},C=0;C0&&this.updateDisplacements();for(var C=0;C0&&(O.fixedNodeWeight=P)}}if(this.constraints.relativePlacementConstraint){var F=new Map,B=new Map;if(this.dummyToNodeForVerticalAlignment=new Map,this.dummyToNodeForHorizontalAlignment=new Map,this.fixedNodesOnHorizontal=new Set,this.fixedNodesOnVertical=new Set,this.fixedNodeSet.forEach(function(J){k.fixedNodesOnHorizontal.add(J),k.fixedNodesOnVertical.add(J)}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var $=this.constraints.alignmentConstraint.vertical,C=0;C<$.length;C++)this.dummyToNodeForVerticalAlignment.set("dummy"+C,[]),$[C].forEach(function(Z){F.set(Z,"dummy"+C),k.dummyToNodeForVerticalAlignment.get("dummy"+C).push(Z),k.fixedNodeSet.has(Z)&&k.fixedNodesOnHorizontal.add("dummy"+C)});if(this.constraints.alignmentConstraint.horizontal)for(var z=this.constraints.alignmentConstraint.horizontal,C=0;C=2*J.length/3;q--)Z=Math.floor(Math.random()*(q+1)),H=J[q],J[q]=J[Z],J[Z]=H;return J},this.nodesInRelativeHorizontal=[],this.nodesInRelativeVertical=[],this.nodeToRelativeConstraintMapHorizontal=new Map,this.nodeToRelativeConstraintMapVertical=new Map,this.nodeToTempPositionMapHorizontal=new Map,this.nodeToTempPositionMapVertical=new Map,this.constraints.relativePlacementConstraint.forEach(function(J){if(J.left){var Z=F.has(J.left)?F.get(J.left):J.left,H=F.has(J.right)?F.get(J.right):J.right;k.nodesInRelativeHorizontal.includes(Z)||(k.nodesInRelativeHorizontal.push(Z),k.nodeToRelativeConstraintMapHorizontal.set(Z,[]),k.dummyToNodeForVerticalAlignment.has(Z)?k.nodeToTempPositionMapHorizontal.set(Z,k.idToNodeMap.get(k.dummyToNodeForVerticalAlignment.get(Z)[0]).getCenterX()):k.nodeToTempPositionMapHorizontal.set(Z,k.idToNodeMap.get(Z).getCenterX())),k.nodesInRelativeHorizontal.includes(H)||(k.nodesInRelativeHorizontal.push(H),k.nodeToRelativeConstraintMapHorizontal.set(H,[]),k.dummyToNodeForVerticalAlignment.has(H)?k.nodeToTempPositionMapHorizontal.set(H,k.idToNodeMap.get(k.dummyToNodeForVerticalAlignment.get(H)[0]).getCenterX()):k.nodeToTempPositionMapHorizontal.set(H,k.idToNodeMap.get(H).getCenterX())),k.nodeToRelativeConstraintMapHorizontal.get(Z).push({right:H,gap:J.gap}),k.nodeToRelativeConstraintMapHorizontal.get(H).push({left:Z,gap:J.gap})}else{var q=B.has(J.top)?B.get(J.top):J.top,K=B.has(J.bottom)?B.get(J.bottom):J.bottom;k.nodesInRelativeVertical.includes(q)||(k.nodesInRelativeVertical.push(q),k.nodeToRelativeConstraintMapVertical.set(q,[]),k.dummyToNodeForHorizontalAlignment.has(q)?k.nodeToTempPositionMapVertical.set(q,k.idToNodeMap.get(k.dummyToNodeForHorizontalAlignment.get(q)[0]).getCenterY()):k.nodeToTempPositionMapVertical.set(q,k.idToNodeMap.get(q).getCenterY())),k.nodesInRelativeVertical.includes(K)||(k.nodesInRelativeVertical.push(K),k.nodeToRelativeConstraintMapVertical.set(K,[]),k.dummyToNodeForHorizontalAlignment.has(K)?k.nodeToTempPositionMapVertical.set(K,k.idToNodeMap.get(k.dummyToNodeForHorizontalAlignment.get(K)[0]).getCenterY()):k.nodeToTempPositionMapVertical.set(K,k.idToNodeMap.get(K).getCenterY())),k.nodeToRelativeConstraintMapVertical.get(q).push({bottom:K,gap:J.gap}),k.nodeToRelativeConstraintMapVertical.get(K).push({top:q,gap:J.gap})}});else{var Y=new Map,Q=new Map;this.constraints.relativePlacementConstraint.forEach(function(J){if(J.left){var Z=F.has(J.left)?F.get(J.left):J.left,H=F.has(J.right)?F.get(J.right):J.right;Y.has(Z)?Y.get(Z).push(H):Y.set(Z,[H]),Y.has(H)?Y.get(H).push(Z):Y.set(H,[Z])}else{var q=B.has(J.top)?B.get(J.top):J.top,K=B.has(J.bottom)?B.get(J.bottom):J.bottom;Q.has(q)?Q.get(q).push(K):Q.set(q,[K]),Q.has(K)?Q.get(K).push(q):Q.set(K,[q])}});var X=o(function(Z,H){var q=[],K=[],se=new L,ce=new Set,ue=0;return Z.forEach(function(te,De){if(!ce.has(De)){q[ue]=[],K[ue]=!1;var oe=De;for(se.push(oe),ce.add(oe),q[ue].push(oe);se.length!=0;){oe=se.shift(),H.has(oe)&&(K[ue]=!0);var ke=Z.get(oe);ke.forEach(function(Ie){ce.has(Ie)||(se.push(Ie),ce.add(Ie),q[ue].push(Ie))})}ue++}}),{components:q,isFixed:K}},"constructComponents"),ie=X(Y,k.fixedNodesOnHorizontal);this.componentsOnHorizontal=ie.components,this.fixedComponentsOnHorizontal=ie.isFixed;var j=X(Q,k.fixedNodesOnVertical);this.componentsOnVertical=j.components,this.fixedComponentsOnVertical=j.isFixed}}},M.prototype.updateDisplacements=function(){var k=this;if(this.constraints.fixedNodeConstraint&&this.constraints.fixedNodeConstraint.forEach(function(j){var J=k.idToNodeMap.get(j.nodeId);J.displacementX=0,J.displacementY=0}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var I=this.constraints.alignmentConstraint.vertical,C=0;C1){var B;for(B=0;BO&&(O=Math.floor(F.y)),P=Math.floor(F.x+m.DEFAULT_COMPONENT_SEPERATION)}this.transform(new b(v.WORLD_CENTER_X-F.x/2,v.WORLD_CENTER_Y-F.y/2))},M.radialLayout=function(k,I,C){var O=Math.max(this.maxDiagonalInTree(k),m.DEFAULT_RADIAL_SEPARATION);M.branchRadialLayout(I,null,0,359,0,O);var D=_.calculateBounds(k),P=new A;P.setDeviceOrgX(D.getMinX()),P.setDeviceOrgY(D.getMinY()),P.setWorldOrgX(C.x),P.setWorldOrgY(C.y);for(var F=0;F1;){var q=H[0];H.splice(0,1);var K=X.indexOf(q);K>=0&&X.splice(K,1),J--,ie--}I!=null?Z=(X.indexOf(H[0])+1)%J:Z=0;for(var se=Math.abs(O-C)/ie,ce=Z;j!=ie;ce=++ce%J){var ue=X[ce].getOtherEnd(k);if(ue!=I){var te=(C+j*se)%360,De=(te+se)%360;M.branchRadialLayout(ue,k,te,De,D+P,P),j++}}},M.maxDiagonalInTree=function(k){for(var I=T.MIN_VALUE,C=0;CI&&(I=D)}return I},M.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},M.prototype.groupZeroDegreeMembers=function(){var k=this,I={};this.memberGroups={},this.idToDummyNode={};for(var C=[],O=this.graphManager.getAllNodes(),D=0;D"u"&&(I[B]=[]),I[B]=I[B].concat(P)}Object.keys(I).forEach(function($){if(I[$].length>1){var z="DummyCompound_"+$;k.memberGroups[z]=I[$];var Y=I[$][0].getParent(),Q=new d(k.graphManager);Q.id=z,Q.paddingLeft=Y.paddingLeft||0,Q.paddingRight=Y.paddingRight||0,Q.paddingBottom=Y.paddingBottom||0,Q.paddingTop=Y.paddingTop||0,k.idToDummyNode[z]=Q;var X=k.getGraphManager().add(k.newGraph(),Q),ie=Y.getChild();ie.add(Q);for(var j=0;jD?(O.rect.x-=(O.labelWidth-D)/2,O.setWidth(O.labelWidth),O.labelMarginLeft=(O.labelWidth-D)/2):O.labelPosHorizontal=="right"&&O.setWidth(D+O.labelWidth)),O.labelHeight&&(O.labelPosVertical=="top"?(O.rect.y-=O.labelHeight,O.setHeight(P+O.labelHeight),O.labelMarginTop=O.labelHeight):O.labelPosVertical=="center"&&O.labelHeight>P?(O.rect.y-=(O.labelHeight-P)/2,O.setHeight(O.labelHeight),O.labelMarginTop=(O.labelHeight-P)/2):O.labelPosVertical=="bottom"&&O.setHeight(P+O.labelHeight))}})},M.prototype.repopulateCompounds=function(){for(var k=this.compoundOrder.length-1;k>=0;k--){var I=this.compoundOrder[k],C=I.id,O=I.paddingLeft,D=I.paddingTop,P=I.labelMarginLeft,F=I.labelMarginTop;this.adjustLocations(this.tiledMemberPack[C],I.rect.x,I.rect.y,O,D,P,F)}},M.prototype.repopulateZeroDegreeMembers=function(){var k=this,I=this.tiledZeroDegreePack;Object.keys(I).forEach(function(C){var O=k.idToDummyNode[C],D=O.paddingLeft,P=O.paddingTop,F=O.labelMarginLeft,B=O.labelMarginTop;k.adjustLocations(I[C],O.rect.x,O.rect.y,D,P,F,B)})},M.prototype.getToBeTiled=function(k){var I=k.id;if(this.toBeTiled[I]!=null)return this.toBeTiled[I];var C=k.getChild();if(C==null)return this.toBeTiled[I]=!1,!1;for(var O=C.getNodes(),D=0;D0)return this.toBeTiled[I]=!1,!1;if(P.getChild()==null){this.toBeTiled[P.id]=!1;continue}if(!this.getToBeTiled(P))return this.toBeTiled[I]=!1,!1}return this.toBeTiled[I]=!0,!0},M.prototype.getNodeDegree=function(k){for(var I=k.id,C=k.getEdges(),O=0,D=0;DY&&(Y=X.rect.height)}C+=Y+k.verticalPadding}},M.prototype.tileCompoundMembers=function(k,I){var C=this;this.tiledMemberPack=[],Object.keys(k).forEach(function(O){var D=I[O];if(C.tiledMemberPack[O]=C.tileNodes(k[O],D.paddingLeft+D.paddingRight),D.rect.width=C.tiledMemberPack[O].width,D.rect.height=C.tiledMemberPack[O].height,D.setCenter(C.tiledMemberPack[O].centerX,C.tiledMemberPack[O].centerY),D.labelMarginLeft=0,D.labelMarginTop=0,m.NODE_DIMENSIONS_INCLUDE_LABELS){var P=D.rect.width,F=D.rect.height;D.labelWidth&&(D.labelPosHorizontal=="left"?(D.rect.x-=D.labelWidth,D.setWidth(P+D.labelWidth),D.labelMarginLeft=D.labelWidth):D.labelPosHorizontal=="center"&&D.labelWidth>P?(D.rect.x-=(D.labelWidth-P)/2,D.setWidth(D.labelWidth),D.labelMarginLeft=(D.labelWidth-P)/2):D.labelPosHorizontal=="right"&&D.setWidth(P+D.labelWidth)),D.labelHeight&&(D.labelPosVertical=="top"?(D.rect.y-=D.labelHeight,D.setHeight(F+D.labelHeight),D.labelMarginTop=D.labelHeight):D.labelPosVertical=="center"&&D.labelHeight>F?(D.rect.y-=(D.labelHeight-F)/2,D.setHeight(D.labelHeight),D.labelMarginTop=(D.labelHeight-F)/2):D.labelPosVertical=="bottom"&&D.setHeight(F+D.labelHeight))}})},M.prototype.tileNodes=function(k,I){var C=this.tileNodesByFavoringDim(k,I,!0),O=this.tileNodesByFavoringDim(k,I,!1),D=this.getOrgRatio(C),P=this.getOrgRatio(O),F;return PB&&(B=j.getWidth())});var $=P/D,z=F/D,Y=Math.pow(C-O,2)+4*($+O)*(z+C)*D,Q=(O-C+Math.sqrt(Y))/(2*($+O)),X;I?(X=Math.ceil(Q),X==Q&&X++):X=Math.floor(Q);var ie=X*($+O)-O;return B>ie&&(ie=B),ie+=O*2,ie},M.prototype.tileNodesByFavoringDim=function(k,I,C){var O=m.TILING_PADDING_VERTICAL,D=m.TILING_PADDING_HORIZONTAL,P=m.TILING_COMPARE_BY,F={rows:[],rowWidth:[],rowHeight:[],width:0,height:I,verticalPadding:O,horizontalPadding:D,centerX:0,centerY:0};P&&(F.idealRowWidth=this.calcIdealRowWidth(k,C));var B=o(function(J){return J.rect.width*J.rect.height},"getNodeArea"),$=o(function(J,Z){return B(Z)-B(J)},"areaCompareFcn");k.sort(function(j,J){var Z=$;return F.idealRowWidth?(Z=P,Z(j.id,J.id)):Z(j,J)});for(var z=0,Y=0,Q=0;Q0&&(F+=k.horizontalPadding),k.rowWidth[C]=F,k.width0&&(B+=k.verticalPadding);var $=0;B>k.rowHeight[C]&&($=k.rowHeight[C],k.rowHeight[C]=B,$=k.rowHeight[C]-$),k.height+=$,k.rows[C].push(I)},M.prototype.getShortestRowIndex=function(k){for(var I=-1,C=Number.MAX_VALUE,O=0;OC&&(I=O,C=k.rowWidth[O]);return I},M.prototype.canAddHorizontal=function(k,I,C){if(k.idealRowWidth){var O=k.rows.length-1,D=k.rowWidth[O];return D+I+k.horizontalPadding<=k.idealRowWidth}var P=this.getShortestRowIndex(k);if(P<0)return!0;var F=k.rowWidth[P];if(F+k.horizontalPadding+I<=k.width)return!0;var B=0;k.rowHeight[P]0&&(B=C+k.verticalPadding-k.rowHeight[P]);var $;k.width-F>=I+k.horizontalPadding?$=(k.height+B)/(F+I+k.horizontalPadding):$=(k.height+B)/k.width,B=C+k.verticalPadding;var z;return k.widthP&&I!=C){O.splice(-1,1),k.rows[C].push(D),k.rowWidth[I]=k.rowWidth[I]-P,k.rowWidth[C]=k.rowWidth[C]+P,k.width=k.rowWidth[instance.getLongestRowIndex(k)];for(var F=Number.MIN_VALUE,B=0;BF&&(F=O[B].height);I>0&&(F+=k.verticalPadding);var $=k.rowHeight[I]+k.rowHeight[C];k.rowHeight[I]=F,k.rowHeight[C]0)for(var ie=D;ie<=P;ie++)X[0]+=this.grid[ie][F-1].length+this.grid[ie][F].length-1;if(P0)for(var ie=F;ie<=B;ie++)X[3]+=this.grid[D-1][ie].length+this.grid[D][ie].length-1;for(var j=T.MAX_VALUE,J,Z,H=0;H{var u=l(551).FDLayoutNode,h=l(551).IMath;function f(p,m,g,y){u.call(this,p,m,g,y)}o(f,"CoSENode"),f.prototype=Object.create(u.prototype);for(var d in u)f[d]=u[d];f.prototype.calculateDisplacement=function(){var p=this.graphManager.getLayout();this.getChild()!=null&&this.fixedNodeWeight?(this.displacementX+=p.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.fixedNodeWeight,this.displacementY+=p.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.fixedNodeWeight):(this.displacementX+=p.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY+=p.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren),Math.abs(this.displacementX)>p.coolingFactor*p.maxNodeDisplacement&&(this.displacementX=p.coolingFactor*p.maxNodeDisplacement*h.sign(this.displacementX)),Math.abs(this.displacementY)>p.coolingFactor*p.maxNodeDisplacement&&(this.displacementY=p.coolingFactor*p.maxNodeDisplacement*h.sign(this.displacementY)),this.child&&this.child.getNodes().length>0&&this.propogateDisplacementToChildren(this.displacementX,this.displacementY)},f.prototype.propogateDisplacementToChildren=function(p,m){for(var g=this.getChild().getNodes(),y,v=0;v{function u(g){if(Array.isArray(g)){for(var y=0,v=Array(g.length);y0){var Je=0;Ye.forEach(function(je){we=="horizontal"?(ye.set(je,x.has(je)?b[x.get(je)]:Ce.get(je)),Je+=ye.get(je)):(ye.set(je,x.has(je)?w[x.get(je)]:Ce.get(je)),Je+=ye.get(je))}),Je=Je/Ye.length,tt.forEach(function(je){Te.has(je)||ye.set(je,Je)})}else{var Ve=0;tt.forEach(function(je){we=="horizontal"?Ve+=x.has(je)?b[x.get(je)]:Ce.get(je):Ve+=x.has(je)?w[x.get(je)]:Ce.get(je)}),Ve=Ve/tt.length,tt.forEach(function(je){ye.set(je,Ve)})}});for(var Ze=o(function(){var Ye=ze.shift(),Je=ae.get(Ye);Je.forEach(function(Ve){if(ye.get(Ve.id)je&&(je=mt),Stkt&&(kt=St)}}catch(Qn){xt=!0,it=Qn}finally{try{!at&&dt.return&&dt.return()}finally{if(xt)throw it}}var gr=(Je+je)/2-(Ve+kt)/2,xn=!0,jt=!1,rn=void 0;try{for(var Er=tt[Symbol.iterator](),Kn;!(xn=(Kn=Er.next()).done);xn=!0){var hn=Kn.value;ye.set(hn,ye.get(hn)+gr)}}catch(Qn){jt=!0,rn=Qn}finally{try{!xn&&Er.return&&Er.return()}finally{if(jt)throw rn}}})}return ye},"findAppropriatePositionForRelativePlacement"),N=o(function(ae){var we=0,Te=0,Ce=0,Ae=0;if(ae.forEach(function(He){He.left?b[x.get(He.left)]-b[x.get(He.right)]>=0?we++:Te++:w[x.get(He.top)]-w[x.get(He.bottom)]>=0?Ce++:Ae++}),we>Te&&Ce>Ae)for(var Ge=0;GeTe)for(var Me=0;MeAe)for(var ye=0;ye1)y.fixedNodeConstraint.forEach(function(ne,ae){O[ae]=[ne.position.x,ne.position.y],D[ae]=[b[x.get(ne.nodeId)],w[x.get(ne.nodeId)]]}),P=!0;else if(y.alignmentConstraint)(function(){var ne=0;if(y.alignmentConstraint.vertical){for(var ae=y.alignmentConstraint.vertical,we=o(function(ye){var He=new Set;ae[ye].forEach(function(gt){He.add(gt)});var ze=new Set([].concat(u(He)).filter(function(gt){return B.has(gt)})),Ze=void 0;ze.size>0?Ze=b[x.get(ze.values().next().value)]:Ze=L(He).x,ae[ye].forEach(function(gt){O[ne]=[Ze,w[x.get(gt)]],D[ne]=[b[x.get(gt)],w[x.get(gt)]],ne++})},"_loop2"),Te=0;Te0?Ze=b[x.get(ze.values().next().value)]:Ze=L(He).y,Ce[ye].forEach(function(gt){O[ne]=[b[x.get(gt)],Ze],D[ne]=[b[x.get(gt)],w[x.get(gt)]],ne++})},"_loop3"),Ge=0;GeQ&&(Q=Y[ie].length,X=ie);if(Q0){var Ue={x:0,y:0};y.fixedNodeConstraint.forEach(function(ne,ae){var we={x:b[x.get(ne.nodeId)],y:w[x.get(ne.nodeId)]},Te=ne.position,Ce=A(Te,we);Ue.x+=Ce.x,Ue.y+=Ce.y}),Ue.x/=y.fixedNodeConstraint.length,Ue.y/=y.fixedNodeConstraint.length,b.forEach(function(ne,ae){b[ae]+=Ue.x}),w.forEach(function(ne,ae){w[ae]+=Ue.y}),y.fixedNodeConstraint.forEach(function(ne){b[x.get(ne.nodeId)]=ne.position.x,w[x.get(ne.nodeId)]=ne.position.y})}if(y.alignmentConstraint){if(y.alignmentConstraint.vertical)for(var Pe=y.alignmentConstraint.vertical,_e=o(function(ae){var we=new Set;Pe[ae].forEach(function(Ae){we.add(Ae)});var Te=new Set([].concat(u(we)).filter(function(Ae){return B.has(Ae)})),Ce=void 0;Te.size>0?Ce=b[x.get(Te.values().next().value)]:Ce=L(we).x,we.forEach(function(Ae){B.has(Ae)||(b[x.get(Ae)]=Ce)})},"_loop4"),me=0;me0?Ce=w[x.get(Te.values().next().value)]:Ce=L(we).y,we.forEach(function(Ae){B.has(Ae)||(w[x.get(Ae)]=Ce)})},"_loop5"),ge=0;ge{a.exports=t}},r={};function n(a){var s=r[a];if(s!==void 0)return s.exports;var l=r[a]={exports:{}};return e[a](l,l.exports,n),l.exports}o(n,"__webpack_require__");var i=n(45);return i})()})});var X1e=gi((xb,JB)=>{"use strict";o(function(e,r){typeof xb=="object"&&typeof JB=="object"?JB.exports=r(ZB()):typeof define=="function"&&define.amd?define(["cose-base"],r):typeof xb=="object"?xb.cytoscapeFcose=r(ZB()):e.cytoscapeFcose=r(e.coseBase)},"webpackUniversalModuleDefinition")(xb,function(t){return(()=>{"use strict";var e={658:a=>{a.exports=Object.assign!=null?Object.assign.bind(Object):function(s){for(var l=arguments.length,u=Array(l>1?l-1:0),h=1;h{var u=function(){function d(p,m){var g=[],y=!0,v=!1,x=void 0;try{for(var b=p[Symbol.iterator](),w;!(y=(w=b.next()).done)&&(g.push(w.value),!(m&&g.length===m));y=!0);}catch(S){v=!0,x=S}finally{try{!y&&b.return&&b.return()}finally{if(v)throw x}}return g}return o(d,"sliceIterator"),function(p,m){if(Array.isArray(p))return p;if(Symbol.iterator in Object(p))return d(p,m);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),h=l(140).layoutBase.LinkedList,f={};f.getTopMostNodes=function(d){for(var p={},m=0;m0&&P.merge(z)});for(var F=0;F1){w=x[0],S=w.connectedEdges().length,x.forEach(function(D){D.connectedEdges().length0&&g.set("dummy"+(g.size+1),_),A},f.relocateComponent=function(d,p,m){if(!m.fixedNodeConstraint){var g=Number.POSITIVE_INFINITY,y=Number.NEGATIVE_INFINITY,v=Number.POSITIVE_INFINITY,x=Number.NEGATIVE_INFINITY;if(m.quality=="draft"){var b=!0,w=!1,S=void 0;try{for(var T=p.nodeIndexes[Symbol.iterator](),E;!(b=(E=T.next()).done);b=!0){var _=E.value,A=u(_,2),L=A[0],M=A[1],N=m.cy.getElementById(L);if(N){var k=N.boundingBox(),I=p.xCoords[M]-k.w/2,C=p.xCoords[M]+k.w/2,O=p.yCoords[M]-k.h/2,D=p.yCoords[M]+k.h/2;Iy&&(y=C),Ox&&(x=D)}}}catch(z){w=!0,S=z}finally{try{!b&&T.return&&T.return()}finally{if(w)throw S}}var P=d.x-(y+g)/2,F=d.y-(x+v)/2;p.xCoords=p.xCoords.map(function(z){return z+P}),p.yCoords=p.yCoords.map(function(z){return z+F})}else{Object.keys(p).forEach(function(z){var Y=p[z],Q=Y.getRect().x,X=Y.getRect().x+Y.getRect().width,ie=Y.getRect().y,j=Y.getRect().y+Y.getRect().height;Qy&&(y=X),iex&&(x=j)});var B=d.x-(y+g)/2,$=d.y-(x+v)/2;Object.keys(p).forEach(function(z){var Y=p[z];Y.setCenter(Y.getCenterX()+B,Y.getCenterY()+$)})}}},f.calcBoundingBox=function(d,p,m,g){for(var y=Number.MAX_SAFE_INTEGER,v=Number.MIN_SAFE_INTEGER,x=Number.MAX_SAFE_INTEGER,b=Number.MIN_SAFE_INTEGER,w=void 0,S=void 0,T=void 0,E=void 0,_=d.descendants().not(":parent"),A=_.length,L=0;Lw&&(y=w),vT&&(x=T),b{var u=l(548),h=l(140).CoSELayout,f=l(140).CoSENode,d=l(140).layoutBase.PointD,p=l(140).layoutBase.DimensionD,m=l(140).layoutBase.LayoutConstants,g=l(140).layoutBase.FDLayoutConstants,y=l(140).CoSEConstants,v=o(function(b,w){var S=b.cy,T=b.eles,E=T.nodes(),_=T.edges(),A=void 0,L=void 0,M=void 0,N={};b.randomize&&(A=w.nodeIndexes,L=w.xCoords,M=w.yCoords);var k=o(function(z){return typeof z=="function"},"isFn"),I=o(function(z,Y){return k(z)?z(Y):z},"optFn"),C=u.calcParentsWithoutChildren(S,T),O=o(function $(z,Y,Q,X){for(var ie=Y.length,j=0;j0){var se=void 0;se=Q.getGraphManager().add(Q.newGraph(),H),$(se,Z,Q,X)}}},"processChildrenList"),D=o(function(z,Y,Q){for(var X=0,ie=0,j=0;j0?y.DEFAULT_EDGE_LENGTH=g.DEFAULT_EDGE_LENGTH=X/ie:k(b.idealEdgeLength)?y.DEFAULT_EDGE_LENGTH=g.DEFAULT_EDGE_LENGTH=50:y.DEFAULT_EDGE_LENGTH=g.DEFAULT_EDGE_LENGTH=b.idealEdgeLength,y.MIN_REPULSION_DIST=g.MIN_REPULSION_DIST=g.DEFAULT_EDGE_LENGTH/10,y.DEFAULT_RADIAL_SEPARATION=g.DEFAULT_EDGE_LENGTH)},"processEdges"),P=o(function(z,Y){Y.fixedNodeConstraint&&(z.constraints.fixedNodeConstraint=Y.fixedNodeConstraint),Y.alignmentConstraint&&(z.constraints.alignmentConstraint=Y.alignmentConstraint),Y.relativePlacementConstraint&&(z.constraints.relativePlacementConstraint=Y.relativePlacementConstraint)},"processConstraints");b.nestingFactor!=null&&(y.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=g.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=b.nestingFactor),b.gravity!=null&&(y.DEFAULT_GRAVITY_STRENGTH=g.DEFAULT_GRAVITY_STRENGTH=b.gravity),b.numIter!=null&&(y.MAX_ITERATIONS=g.MAX_ITERATIONS=b.numIter),b.gravityRange!=null&&(y.DEFAULT_GRAVITY_RANGE_FACTOR=g.DEFAULT_GRAVITY_RANGE_FACTOR=b.gravityRange),b.gravityCompound!=null&&(y.DEFAULT_COMPOUND_GRAVITY_STRENGTH=g.DEFAULT_COMPOUND_GRAVITY_STRENGTH=b.gravityCompound),b.gravityRangeCompound!=null&&(y.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=g.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=b.gravityRangeCompound),b.initialEnergyOnIncremental!=null&&(y.DEFAULT_COOLING_FACTOR_INCREMENTAL=g.DEFAULT_COOLING_FACTOR_INCREMENTAL=b.initialEnergyOnIncremental),b.tilingCompareBy!=null&&(y.TILING_COMPARE_BY=b.tilingCompareBy),b.quality=="proof"?m.QUALITY=2:m.QUALITY=0,y.NODE_DIMENSIONS_INCLUDE_LABELS=g.NODE_DIMENSIONS_INCLUDE_LABELS=m.NODE_DIMENSIONS_INCLUDE_LABELS=b.nodeDimensionsIncludeLabels,y.DEFAULT_INCREMENTAL=g.DEFAULT_INCREMENTAL=m.DEFAULT_INCREMENTAL=!b.randomize,y.ANIMATE=g.ANIMATE=m.ANIMATE=b.animate,y.TILE=b.tile,y.TILING_PADDING_VERTICAL=typeof b.tilingPaddingVertical=="function"?b.tilingPaddingVertical.call():b.tilingPaddingVertical,y.TILING_PADDING_HORIZONTAL=typeof b.tilingPaddingHorizontal=="function"?b.tilingPaddingHorizontal.call():b.tilingPaddingHorizontal,y.DEFAULT_INCREMENTAL=g.DEFAULT_INCREMENTAL=m.DEFAULT_INCREMENTAL=!0,y.PURE_INCREMENTAL=!b.randomize,m.DEFAULT_UNIFORM_LEAF_NODE_SIZES=b.uniformNodeDimensions,b.step=="transformed"&&(y.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,y.ENFORCE_CONSTRAINTS=!1,y.APPLY_LAYOUT=!1),b.step=="enforced"&&(y.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,y.ENFORCE_CONSTRAINTS=!0,y.APPLY_LAYOUT=!1),b.step=="cose"&&(y.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,y.ENFORCE_CONSTRAINTS=!1,y.APPLY_LAYOUT=!0),b.step=="all"&&(b.randomize?y.TRANSFORM_ON_CONSTRAINT_HANDLING=!0:y.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,y.ENFORCE_CONSTRAINTS=!0,y.APPLY_LAYOUT=!0),b.fixedNodeConstraint||b.alignmentConstraint||b.relativePlacementConstraint?y.TREE_REDUCTION_ON_INCREMENTAL=!1:y.TREE_REDUCTION_ON_INCREMENTAL=!0;var F=new h,B=F.newGraphManager();return O(B.addRoot(),u.getTopMostNodes(E),F,b),D(F,B,_),P(F,b),F.runLayout(),N},"coseLayout");a.exports={coseLayout:v}},212:(a,s,l)=>{var u=function(){function b(w,S){for(var T=0;T0)if(D){var B=d.getTopMostNodes(T.eles.nodes());if(k=d.connectComponents(E,T.eles,B),k.forEach(function(oe){var ke=oe.boundingBox();I.push({x:ke.x1+ke.w/2,y:ke.y1+ke.h/2})}),T.randomize&&k.forEach(function(oe){T.eles=oe,A.push(m(T))}),T.quality=="default"||T.quality=="proof"){var $=E.collection();if(T.tile){var z=new Map,Y=[],Q=[],X=0,ie={nodeIndexes:z,xCoords:Y,yCoords:Q},j=[];if(k.forEach(function(oe,ke){oe.edges().length==0&&(oe.nodes().forEach(function(Ie,Se){$.merge(oe.nodes()[Se]),Ie.isParent()||(ie.nodeIndexes.set(oe.nodes()[Se].id(),X++),ie.xCoords.push(oe.nodes()[0].position().x),ie.yCoords.push(oe.nodes()[0].position().y))}),j.push(ke))}),$.length>1){var J=$.boundingBox();I.push({x:J.x1+J.w/2,y:J.y1+J.h/2}),k.push($),A.push(ie);for(var Z=j.length-1;Z>=0;Z--)k.splice(j[Z],1),A.splice(j[Z],1),I.splice(j[Z],1)}}k.forEach(function(oe,ke){T.eles=oe,N.push(y(T,A[ke])),d.relocateComponent(I[ke],N[ke],T)})}else k.forEach(function(oe,ke){d.relocateComponent(I[ke],A[ke],T)});var H=new Set;if(k.length>1){var q=[],K=_.filter(function(oe){return oe.css("display")=="none"});k.forEach(function(oe,ke){var Ie=void 0;if(T.quality=="draft"&&(Ie=A[ke].nodeIndexes),oe.nodes().not(K).length>0){var Se={};Se.edges=[],Se.nodes=[];var Ue=void 0;oe.nodes().not(K).forEach(function(Pe){if(T.quality=="draft")if(!Pe.isParent())Ue=Ie.get(Pe.id()),Se.nodes.push({x:A[ke].xCoords[Ue]-Pe.boundingbox().w/2,y:A[ke].yCoords[Ue]-Pe.boundingbox().h/2,width:Pe.boundingbox().w,height:Pe.boundingbox().h});else{var _e=d.calcBoundingBox(Pe,A[ke].xCoords,A[ke].yCoords,Ie);Se.nodes.push({x:_e.topLeftX,y:_e.topLeftY,width:_e.width,height:_e.height})}else N[ke][Pe.id()]&&Se.nodes.push({x:N[ke][Pe.id()].getLeft(),y:N[ke][Pe.id()].getTop(),width:N[ke][Pe.id()].getWidth(),height:N[ke][Pe.id()].getHeight()})}),oe.edges().forEach(function(Pe){var _e=Pe.source(),me=Pe.target();if(_e.css("display")!="none"&&me.css("display")!="none")if(T.quality=="draft"){var W=Ie.get(_e.id()),fe=Ie.get(me.id()),ge=[],re=[];if(_e.isParent()){var he=d.calcBoundingBox(_e,A[ke].xCoords,A[ke].yCoords,Ie);ge.push(he.topLeftX+he.width/2),ge.push(he.topLeftY+he.height/2)}else ge.push(A[ke].xCoords[W]),ge.push(A[ke].yCoords[W]);if(me.isParent()){var ne=d.calcBoundingBox(me,A[ke].xCoords,A[ke].yCoords,Ie);re.push(ne.topLeftX+ne.width/2),re.push(ne.topLeftY+ne.height/2)}else re.push(A[ke].xCoords[fe]),re.push(A[ke].yCoords[fe]);Se.edges.push({startX:ge[0],startY:ge[1],endX:re[0],endY:re[1]})}else N[ke][_e.id()]&&N[ke][me.id()]&&Se.edges.push({startX:N[ke][_e.id()].getCenterX(),startY:N[ke][_e.id()].getCenterY(),endX:N[ke][me.id()].getCenterX(),endY:N[ke][me.id()].getCenterY()})}),Se.nodes.length>0&&(q.push(Se),H.add(ke))}});var se=O.packComponents(q,T.randomize).shifts;if(T.quality=="draft")A.forEach(function(oe,ke){var Ie=oe.xCoords.map(function(Ue){return Ue+se[ke].dx}),Se=oe.yCoords.map(function(Ue){return Ue+se[ke].dy});oe.xCoords=Ie,oe.yCoords=Se});else{var ce=0;H.forEach(function(oe){Object.keys(N[oe]).forEach(function(ke){var Ie=N[oe][ke];Ie.setCenter(Ie.getCenterX()+se[ce].dx,Ie.getCenterY()+se[ce].dy)}),ce++})}}}else{var P=T.eles.boundingBox();if(I.push({x:P.x1+P.w/2,y:P.y1+P.h/2}),T.randomize){var F=m(T);A.push(F)}T.quality=="default"||T.quality=="proof"?(N.push(y(T,A[0])),d.relocateComponent(I[0],N[0],T)):d.relocateComponent(I[0],A[0],T)}var ue=o(function(ke,Ie){if(T.quality=="default"||T.quality=="proof"){typeof ke=="number"&&(ke=Ie);var Se=void 0,Ue=void 0,Pe=ke.data("id");return N.forEach(function(me){Pe in me&&(Se={x:me[Pe].getRect().getCenterX(),y:me[Pe].getRect().getCenterY()},Ue=me[Pe])}),T.nodeDimensionsIncludeLabels&&(Ue.labelWidth&&(Ue.labelPosHorizontal=="left"?Se.x+=Ue.labelWidth/2:Ue.labelPosHorizontal=="right"&&(Se.x-=Ue.labelWidth/2)),Ue.labelHeight&&(Ue.labelPosVertical=="top"?Se.y+=Ue.labelHeight/2:Ue.labelPosVertical=="bottom"&&(Se.y-=Ue.labelHeight/2))),Se==null&&(Se={x:ke.position("x"),y:ke.position("y")}),{x:Se.x,y:Se.y}}else{var _e=void 0;return A.forEach(function(me){var W=me.nodeIndexes.get(ke.id());W!=null&&(_e={x:me.xCoords[W],y:me.yCoords[W]})}),_e==null&&(_e={x:ke.position("x"),y:ke.position("y")}),{x:_e.x,y:_e.y}}},"getPositions");if(T.quality=="default"||T.quality=="proof"||T.randomize){var te=d.calcParentsWithoutChildren(E,_),De=_.filter(function(oe){return oe.css("display")=="none"});T.eles=_.not(De),_.nodes().not(":parent").not(De).layoutPositions(S,T,ue),te.length>0&&te.forEach(function(oe){oe.position(ue(oe))})}else console.log("If randomize option is set to false, then quality option must be 'default' or 'proof'.")},"run")}]),b}();a.exports=x},657:(a,s,l)=>{var u=l(548),h=l(140).layoutBase.Matrix,f=l(140).layoutBase.SVD,d=o(function(m){var g=m.cy,y=m.eles,v=y.nodes(),x=y.nodes(":parent"),b=new Map,w=new Map,S=new Map,T=[],E=[],_=[],A=[],L=[],M=[],N=[],k=[],I=void 0,C=void 0,O=1e8,D=1e-9,P=m.piTol,F=m.samplingType,B=m.nodeSeparation,$=void 0,z=o(function(){for(var we=0,Te=0,Ce=!1;Te<$;){we=Math.floor(Math.random()*C),Ce=!1;for(var Ae=0;Ae=Ge;){ye=Ae[Ge++];for(var tt=T[ye],Ye=0;YeZe&&(Ze=L[Ve],gt=Ve)}return gt},"BFS"),Q=o(function(we){var Te=void 0;if(we){Te=Math.floor(Math.random()*C),I=Te;for(var Ae=0;Ae=1)break;Ze=ze}for(var tt=0;tt=1)break;Ze=ze}for(var Je=0;Je0&&(Te.isParent()?T[we].push(S.get(Te.id())):T[we].push(Te.id()))})});var te=o(function(we){var Te=w.get(we),Ce=void 0;b.get(we).forEach(function(Ae){g.getElementById(Ae).isParent()?Ce=S.get(Ae):Ce=Ae,T[Te].push(Ce),T[w.get(Ce)].push(we)})},"_loop"),De=!0,oe=!1,ke=void 0;try{for(var Ie=b.keys()[Symbol.iterator](),Se;!(De=(Se=Ie.next()).done);De=!0){var Ue=Se.value;te(Ue)}}catch(ae){oe=!0,ke=ae}finally{try{!De&&Ie.return&&Ie.return()}finally{if(oe)throw ke}}C=w.size;var Pe=void 0;if(C>2){$=C{var u=l(212),h=o(function(d){d&&d("layout","fcose",u)},"register");typeof cytoscape<"u"&&h(cytoscape),a.exports=h},140:a=>{a.exports=t}},r={};function n(a){var s=r[a];if(s!==void 0)return s.exports;var l=r[a]={exports:{}};return e[a](l,l.exports,n),l.exports}o(n,"__webpack_require__");var i=n(579);return i})()})});var T1,J0,eF=R(()=>{"use strict";V1();T1=o(t=>`${t}`,"wrapIcon"),J0={prefix:"mermaid-architecture",height:80,width:80,icons:{database:{body:T1('')},server:{body:T1('')},disk:{body:T1('')},internet:{body:T1('')},cloud:{body:T1('')},unknown:FC,blank:{body:T1("")}}}});var j1e,K1e,Q1e,Z1e,J1e=R(()=>{"use strict";V1();_t();Al();gb();eF();cC();j1e=o(async function(t,e){let r=Ci("padding"),n=Ci("iconSize"),i=n/2,a=n/6,s=a/2;await Promise.all(e.edges().map(async l=>{let{source:u,sourceDir:h,sourceArrow:f,sourceGroup:d,target:p,targetDir:m,targetArrow:g,targetGroup:y,label:v}=lC(l),{x,y:b}=l[0].sourceEndpoint(),{x:w,y:S}=l[0].midpoint(),{x:T,y:E}=l[0].targetEndpoint(),_=r+4;if(d&&(cs(h)?x+=h==="L"?-_:_:b+=h==="T"?-_:_+18),y&&(cs(m)?T+=m==="L"?-_:_:E+=m==="T"?-_:_+18),!d&&Z0.getNode(u)?.type==="junction"&&(cs(h)?x+=h==="L"?i:-i:b+=h==="T"?i:-i),!y&&Z0.getNode(p)?.type==="junction"&&(cs(m)?T+=m==="L"?i:-i:E+=m==="T"?i:-i),l[0]._private.rscratch){let A=t.insert("g");if(A.insert("path").attr("d",`M ${x},${b} L ${w},${S} L${T},${E} `).attr("class","edge"),f){let L=cs(h)?pb[h](x,a):x-s,M=Wc(h)?pb[h](b,a):b-s;A.insert("polygon").attr("points",qB[h](a)).attr("transform",`translate(${L},${M})`).attr("class","arrow")}if(g){let L=cs(m)?pb[m](T,a):T-s,M=Wc(m)?pb[m](E,a):E-s;A.insert("polygon").attr("points",qB[m](a)).attr("transform",`translate(${L},${M})`).attr("class","arrow")}if(v){let L=oC(h,m)?"XY":cs(h)?"X":"Y",M=0;L==="X"?M=Math.abs(x-T):L==="Y"?M=Math.abs(b-E)/1.5:M=Math.abs(x-T)/2;let N=A.append("g");if(await ta(N,v,{useHtmlLabels:!1,width:M,classes:"architecture-service-label"},de()),N.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle"),L==="X")N.attr("transform","translate("+w+", "+S+")");else if(L==="Y")N.attr("transform","translate("+w+", "+S+") rotate(-90)");else if(L==="XY"){let k=mb(h,m);if(k&&F1e(k)){let I=N.node().getBoundingClientRect(),[C,O]=G1e(k);N.attr("dominant-baseline","auto").attr("transform",`rotate(${-1*C*O*45})`);let D=N.node().getBoundingClientRect();N.attr("transform",` + translate(${w}, ${S-I.height/2}) + translate(${C*D.width/2}, ${O*D.height/2}) + rotate(${-1*C*O*45}, 0, ${I.height/2}) + `)}}}}}))},"drawEdges"),K1e=o(async function(t,e){let n=Ci("padding")*.75,i=Ci("fontSize"),s=Ci("iconSize")/2;await Promise.all(e.nodes().map(async l=>{let u=If(l);if(u.type==="group"){let{h,w:f,x1:d,y1:p}=l.boundingBox();t.append("rect").attr("x",d+s).attr("y",p+s).attr("width",f).attr("height",h).attr("class","node-bkg");let m=t.append("g"),g=d,y=p;if(u.icon){let v=m.append("g");v.html(`${await zb(u.icon,{height:n,width:n,fallbackPrefix:J0.prefix})}`),v.attr("transform","translate("+(g+s+1)+", "+(y+s+1)+")"),g+=n,y+=i/2-1-2}if(u.label){let v=m.append("g");await ta(v,u.label,{useHtmlLabels:!1,width:f,classes:"architecture-service-label"},de()),v.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","start").attr("text-anchor","start"),v.attr("transform","translate("+(g+s+4)+", "+(y+s+2)+")")}}}))},"drawGroups"),Q1e=o(async function(t,e,r){for(let n of r){let i=e.append("g"),a=Ci("iconSize");if(n.title){let h=i.append("g");await ta(h,n.title,{useHtmlLabels:!1,width:a*1.5,classes:"architecture-service-label"},de()),h.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle"),h.attr("transform","translate("+a/2+", "+a+")")}let s=i.append("g");if(n.icon)s.html(`${await zb(n.icon,{height:a,width:a,fallbackPrefix:J0.prefix})}`);else if(n.iconText){s.html(`${await zb("blank",{height:a,width:a,fallbackPrefix:J0.prefix})}`);let d=s.append("g").append("foreignObject").attr("width",a).attr("height",a).append("div").attr("class","node-icon-text").attr("style",`height: ${a}px;`).append("div").html(n.iconText),p=parseInt(window.getComputedStyle(d.node(),null).getPropertyValue("font-size").replace(/\D/g,""))??16;d.attr("style",`-webkit-line-clamp: ${Math.floor((a-2)/p)};`)}else s.append("path").attr("class","node-bkg").attr("id","node-"+n.id).attr("d",`M0 ${a} v${-a} q0,-5 5,-5 h${a} q5,0 5,5 v${a} H0 Z`);i.attr("class","architecture-service");let{width:l,height:u}=i._groups[0][0].getBBox();n.width=l,n.height=u,t.setElementForId(n.id,i)}return 0},"drawServices"),Z1e=o(function(t,e,r){r.forEach(n=>{let i=e.append("g"),a=Ci("iconSize");i.append("g").append("rect").attr("id","node-"+n.id).attr("fill-opacity","0").attr("width",a).attr("height",a),i.attr("class","architecture-junction");let{width:l,height:u}=i._groups[0][0].getBBox();i.width=l,i.height=u,t.setElementForId(n.id,i)})},"drawJunctions")});function iet(t,e){t.forEach(r=>{e.add({group:"nodes",data:{type:"service",id:r.id,icon:r.icon,label:r.title,parent:r.in,width:Ci("iconSize"),height:Ci("iconSize")},classes:"node-service"})})}function aet(t,e){t.forEach(r=>{e.add({group:"nodes",data:{type:"junction",id:r.id,parent:r.in,width:Ci("iconSize"),height:Ci("iconSize")},classes:"node-junction"})})}function set(t,e){e.nodes().map(r=>{let n=If(r);if(n.type==="group")return;n.x=r.position().x,n.y=r.position().y,t.getElementById(n.id).attr("transform","translate("+(n.x||0)+","+(n.y||0)+")")})}function oet(t,e){t.forEach(r=>{e.add({group:"nodes",data:{type:"group",id:r.id,icon:r.icon,label:r.title,parent:r.in},classes:"node-group"})})}function cet(t,e){t.forEach(r=>{let{lhsId:n,rhsId:i,lhsInto:a,lhsGroup:s,rhsInto:l,lhsDir:u,rhsDir:h,rhsGroup:f,title:d}=r,p=oC(r.lhsDir,r.rhsDir)?"segments":"straight",m={id:`${n}-${i}`,label:d,source:n,sourceDir:u,sourceArrow:a,sourceGroup:s,sourceEndpoint:u==="L"?"0 50%":u==="R"?"100% 50%":u==="T"?"50% 0":"50% 100%",target:i,targetDir:h,targetArrow:l,targetGroup:f,targetEndpoint:h==="L"?"0 50%":h==="R"?"100% 50%":h==="T"?"50% 0":"50% 100%"};e.add({group:"edges",data:m,classes:p})})}function uet(t){let e=t.map(i=>{let a={},s={};return Object.entries(i).forEach(([l,[u,h]])=>{a[h]||(a[h]=[]),s[u]||(s[u]=[]),a[h].push(l),s[u].push(l)}),{horiz:Object.values(a).filter(l=>l.length>1),vert:Object.values(s).filter(l=>l.length>1)}}),[r,n]=e.reduce(([i,a],{horiz:s,vert:l})=>[[...i,...s],[...a,...l]],[[],[]]);return{horizontal:r,vertical:n}}function het(t){let e=[],r=o(i=>`${i[0]},${i[1]}`,"posToStr"),n=o(i=>i.split(",").map(a=>parseInt(a)),"strToPos");return t.forEach(i=>{let a=Object.fromEntries(Object.entries(i).map(([h,f])=>[r(f),h])),s=[r([0,0])],l={},u={L:[-1,0],R:[1,0],T:[0,1],B:[0,-1]};for(;s.length>0;){let h=s.shift();if(h){l[h]=1;let f=a[h];if(f){let d=n(h);Object.entries(u).forEach(([p,m])=>{let g=r([d[0]+m[0],d[1]+m[1]]),y=a[g];y&&!l[g]&&(s.push(g),e.push({[WB[p]]:y,[WB[B1e(p)]]:f,gap:1.5*Ci("iconSize")}))})}}}}),e}function fet(t,e,r,n,{spatialMaps:i}){return new Promise(a=>{let s=$e("body").append("div").attr("id","cy").attr("style","display:none"),l=rl({container:document.getElementById("cy"),style:[{selector:"edge",style:{"curve-style":"straight",label:"data(label)","source-endpoint":"data(sourceEndpoint)","target-endpoint":"data(targetEndpoint)"}},{selector:"edge.segments",style:{"curve-style":"segments","segment-weights":"0","segment-distances":[.5],"edge-distances":"endpoints","source-endpoint":"data(sourceEndpoint)","target-endpoint":"data(targetEndpoint)"}},{selector:"node",style:{"compound-sizing-wrt-labels":"include"}},{selector:"node[label]",style:{"text-valign":"bottom","text-halign":"center","font-size":`${Ci("fontSize")}px`}},{selector:".node-service",style:{label:"data(label)",width:"data(width)",height:"data(height)"}},{selector:".node-junction",style:{width:"data(width)",height:"data(height)"}},{selector:".node-group",style:{padding:`${Ci("padding")}px`}}]});s.remove(),oet(r,l),iet(t,l),aet(e,l),cet(n,l);let u=uet(i),h=het(i),f=l.layout({name:"fcose",quality:"proof",styleEnabled:!1,animate:!1,nodeDimensionsIncludeLabels:!1,idealEdgeLength(d){let[p,m]=d.connectedNodes(),{parent:g}=If(p),{parent:y}=If(m);return g===y?1.5*Ci("iconSize"):.5*Ci("iconSize")},edgeElasticity(d){let[p,m]=d.connectedNodes(),{parent:g}=If(p),{parent:y}=If(m);return g===y?.45:.001},alignmentConstraint:u,relativePlacementConstraint:h});f.one("layoutstop",()=>{function d(p,m,g,y){let v,x,{x:b,y:w}=p,{x:S,y:T}=m;x=(y-w+(b-g)*(w-T)/(b-S))/Math.sqrt(1+Math.pow((w-T)/(b-S),2)),v=Math.sqrt(Math.pow(y-w,2)+Math.pow(g-b,2)-Math.pow(x,2));let E=Math.sqrt(Math.pow(S-b,2)+Math.pow(T-w,2));v=v/E;let _=(S-b)*(y-w)-(T-w)*(g-b);switch(!0){case _>=0:_=1;break;case _<0:_=-1;break}let A=(S-b)*(g-b)+(T-w)*(y-w);switch(!0){case A>=0:A=1;break;case A<0:A=-1;break}return x=Math.abs(x)*_,v=v*A,{distances:x,weights:v}}o(d,"getSegmentWeights"),l.startBatch();for(let p of Object.values(l.edges()))if(p.data?.()){let{x:m,y:g}=p.source().position(),{x:y,y:v}=p.target().position();if(m!==y&&g!==v){let x=p.sourceEndpoint(),b=p.targetEndpoint(),{sourceDir:w}=lC(p),[S,T]=Wc(w)?[x.x,b.y]:[b.x,x.y],{weights:E,distances:_}=d(x,b,S,T);p.style("segment-distances",_),p.style("segment-weights",E)}}l.endBatch(),f.run()}),f.run(),l.ready(d=>{V.info("Ready",d),a(l)})})}var eye,det,tye,rye=R(()=>{"use strict";V1();vB();eye=Xi(X1e(),1);Zt();ut();pf();Yn();gb();eF();cC();J1e();Fb([{name:J0.prefix,icons:J0}]);rl.use(eye.default);o(iet,"addServices");o(aet,"addJunctions");o(set,"positionNodes");o(oet,"addGroups");o(cet,"addEdges");o(uet,"getAlignments");o(het,"getRelativeConstraints");o(fet,"layoutArchitecture");det=o(async(t,e,r,n)=>{let i=n.db,a=i.getServices(),s=i.getJunctions(),l=i.getGroups(),u=i.getEdges(),h=i.getDataStructures(),f=Ps(e),d=f.append("g");d.attr("class","architecture-edges");let p=f.append("g");p.attr("class","architecture-services");let m=f.append("g");m.attr("class","architecture-groups"),await Q1e(i,p,a),Z1e(i,p,s);let g=await fet(a,s,l,u,h);await j1e(d,g),await K1e(m,g),set(i,g),Lo(void 0,f,Ci("padding"),Ci("useMaxWidth"))},"draw"),tye={draw:det}});var nye={};hr(nye,{diagram:()=>pet});var pet,iye=R(()=>{"use strict";Y1e();gb();q1e();rye();pet={parser:H1e,db:Z0,renderer:tye,styles:W1e}});var knt={};hr(knt,{default:()=>Tnt});V1();zC();Hf();var BX="c4",mCe=o(t=>/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(t),"detector"),gCe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(PX(),OX));return{id:BX,diagram:t}},"loader"),yCe={id:BX,detector:mCe,loader:gCe},FX=yCe;var Zre="flowchart",SNe=o((t,e)=>e?.flowchart?.defaultRenderer==="dagre-wrapper"||e?.flowchart?.defaultRenderer==="elk"?!1:/^\s*graph/.test(t),"detector"),ANe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(uT(),cT));return{id:Zre,diagram:t}},"loader"),_Ne={id:Zre,detector:SNe,loader:ANe},Jre=_Ne;var ene="flowchart-v2",LNe=o((t,e)=>e?.flowchart?.defaultRenderer==="dagre-d3"?!1:(e?.flowchart?.defaultRenderer==="elk"&&(e.layout="elk"),/^\s*graph/.test(t)&&e?.flowchart?.defaultRenderer==="dagre-wrapper"?!0:/^\s*flowchart/.test(t)),"detector"),DNe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(uT(),cT));return{id:ene,diagram:t}},"loader"),RNe={id:ene,detector:LNe,loader:DNe},tne=RNe;var Dne="er",sMe=o(t=>/^\s*erDiagram/.test(t),"detector"),oMe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Lne(),_ne));return{id:Dne,diagram:t}},"loader"),lMe={id:Dne,detector:sMe,loader:oMe},Rne=lMe;var $le="gitGraph",NBe=o(t=>/^\s*gitGraph/.test(t),"detector"),MBe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Gle(),zle));return{id:$le,diagram:t}},"loader"),IBe={id:$le,detector:NBe,loader:MBe},Vle=IBe;var vce="gantt",wFe=o(t=>/^\s*gantt/.test(t),"detector"),TFe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(yce(),gce));return{id:vce,diagram:t}},"loader"),kFe={id:vce,detector:wFe,loader:TFe},xce=kFe;var _ce="info",LFe=o(t=>/^\s*info/.test(t),"detector"),DFe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Ace(),Sce));return{id:_ce,diagram:t}},"loader"),Lce={id:_ce,detector:LFe,loader:DFe};var zce="pie",UFe=o(t=>/^\s*pie/.test(t),"detector"),HFe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Fce(),Bce));return{id:zce,diagram:t}},"loader"),Gce={id:zce,detector:UFe,loader:HFe};var Jce="quadrantChart",lze=o(t=>/^\s*quadrantChart/.test(t),"detector"),cze=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Zce(),Qce));return{id:Jce,diagram:t}},"loader"),uze={id:Jce,detector:lze,loader:cze},eue=uze;var Aue="xychart",Sze=o(t=>/^\s*xychart-beta/.test(t),"detector"),Aze=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Sue(),Cue));return{id:Aue,diagram:t}},"loader"),_ze={id:Aue,detector:Sze,loader:Aze},_ue=_ze;var Hue="requirement",rGe=o(t=>/^\s*requirement(Diagram)?/.test(t),"detector"),nGe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Uue(),Vue));return{id:Hue,diagram:t}},"loader"),iGe={id:Hue,detector:rGe,loader:nGe},Yue=iGe;var vhe="sequence",o$e=o(t=>/^\s*sequenceDiagram/.test(t),"detector"),l$e=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(yhe(),ghe));return{id:vhe,diagram:t}},"loader"),c$e={id:vhe,detector:o$e,loader:l$e},xhe=c$e;var Ihe="class",U$e=o((t,e)=>e?.class?.defaultRenderer==="dagre-wrapper"?!1:/^\s*classDiagram/.test(t),"detector"),H$e=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Mhe(),Nhe));return{id:Ihe,diagram:t}},"loader"),Y$e={id:Ihe,detector:U$e,loader:H$e},Ohe=Y$e;var cfe="classDiagram",vVe=o((t,e)=>/^\s*classDiagram/.test(t)&&e?.class?.defaultRenderer==="dagre-wrapper"?!0:/^\s*classDiagram-v2/.test(t),"detector"),xVe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(lfe(),ofe));return{id:cfe,diagram:t}},"loader"),bVe={id:cfe,detector:vVe,loader:xVe},ufe=bVe;var tde="state",mUe=o((t,e)=>e?.state?.defaultRenderer==="dagre-wrapper"?!1:/^\s*stateDiagram/.test(t),"detector"),gUe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(ede(),Jfe));return{id:tde,diagram:t}},"loader"),yUe={id:tde,detector:mUe,loader:gUe},rde=yUe;var ade="stateDiagram",xUe=o((t,e)=>!!(/^\s*stateDiagram-v2/.test(t)||/^\s*stateDiagram/.test(t)&&e?.state?.defaultRenderer==="dagre-wrapper"),"detector"),bUe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(ide(),nde));return{id:ade,diagram:t}},"loader"),wUe={id:ade,detector:xUe,loader:bUe},sde=wUe;var Tde="journey",VUe=o(t=>/^\s*journey/.test(t),"detector"),UUe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(wde(),bde));return{id:Tde,diagram:t}},"loader"),HUe={id:Tde,detector:VUe,loader:UUe},kde=HUe;ut();pf();Yn();var YUe=o((t,e,r)=>{V.debug(`rendering svg for syntax error +`);let n=Ps(e),i=n.append("g");n.attr("viewBox","0 0 2412 512"),Sr(n,100,512,!0),i.append("path").attr("class","error-icon").attr("d","m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"),i.append("path").attr("class","error-icon").attr("d","m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"),i.append("path").attr("class","error-icon").attr("d","m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"),i.append("path").attr("class","error-icon").attr("d","m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"),i.append("path").attr("class","error-icon").attr("d","m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"),i.append("path").attr("class","error-icon").attr("d","m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"),i.append("text").attr("class","error-text").attr("x",1440).attr("y",250).attr("font-size","150px").style("text-anchor","middle").text("Syntax error in text"),i.append("text").attr("class","error-text").attr("x",1250).attr("y",400).attr("font-size","100px").style("text-anchor","middle").text(`mermaid version ${r}`)},"draw"),fP={draw:YUe},Ede=fP;var WUe={db:{},renderer:fP,parser:{parse:o(()=>{},"parse")}},Cde=WUe;var Sde="flowchart-elk",qUe=o((t,e={})=>/^\s*flowchart-elk/.test(t)||/^\s*flowchart|graph/.test(t)&&e?.flowchart?.defaultRenderer==="elk"?(e.layout="elk",!0):!1,"detector"),XUe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(uT(),cT));return{id:Sde,diagram:t}},"loader"),jUe={id:Sde,detector:qUe,loader:XUe},Ade=jUe;var Jde="timeline",pHe=o(t=>/^\s*timeline/.test(t),"detector"),mHe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Zde(),Qde));return{id:Jde,diagram:t}},"loader"),gHe={id:Jde,detector:pHe,loader:mHe},e0e=gHe;var vge="mindmap",TZe=o(t=>/^\s*mindmap/.test(t),"detector"),kZe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(yge(),gge));return{id:vge,diagram:t}},"loader"),EZe={id:vge,detector:TZe,loader:kZe},xge=EZe;var Zge="sankey",WZe=o(t=>/^\s*sankey-beta/.test(t),"detector"),qZe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(Qge(),Kge));return{id:Zge,diagram:t}},"loader"),XZe={id:Zge,detector:WZe,loader:qZe},Jge=XZe;var c1e="packet",oJe=o(t=>/^\s*packet-beta/.test(t),"detector"),lJe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(l1e(),o1e));return{id:c1e,diagram:t}},"loader"),u1e={id:c1e,detector:oJe,loader:lJe};var O1e="block",FJe=o(t=>/^\s*block-beta/.test(t),"detector"),zJe=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(I1e(),M1e));return{id:O1e,diagram:t}},"loader"),GJe={id:O1e,detector:FJe,loader:zJe},P1e=GJe;var aye="architecture",met=o(t=>/^\s*architecture/.test(t),"detector"),get=o(async()=>{let{diagram:t}=await Promise.resolve().then(()=>(iye(),nye));return{id:aye,diagram:t}},"loader"),yet={id:aye,detector:met,loader:get},sye=yet;Hf();_t();var oye=!1,k1=o(()=>{oye||(oye=!0,Jf("error",Cde,t=>t.toLowerCase().trim()==="error"),Jf("---",{db:{clear:o(()=>{},"clear")},styles:{},renderer:{draw:o(()=>{},"draw")},parser:{parse:o(()=>{throw new Error("Diagrams beginning with --- are not valid. If you were trying to use a YAML front-matter, please ensure that you've correctly opened and closed the YAML front-matter with un-indented `---` blocks")},"parse")},init:o(()=>null,"init")},t=>t.toLowerCase().trimStart().startsWith("---")),Ub(FX,ufe,Ohe,Rne,xce,Lce,Gce,Yue,xhe,Ade,tne,Jre,xge,e0e,Vle,sde,rde,kde,eue,Jge,u1e,_ue,P1e,sye))},"addDiagrams");ut();Hf();_t();var lye=o(async()=>{V.debug("Loading registered diagrams");let e=(await Promise.allSettled(Object.entries(Uf).map(async([r,{detector:n,loader:i}])=>{if(i)try{cy(r)}catch{try{let{diagram:a,id:s}=await i();Jf(s,a,n)}catch(a){throw V.error(`Failed to load external diagram with key ${r}. Removing from detectors.`),delete Uf[r],a}}}))).filter(r=>r.status==="rejected");if(e.length>0){V.error(`Failed to load ${e.length} external diagrams`);for(let r of e)V.error(r);throw new Error(`Failed to load ${e.length} external diagrams`)}},"loadRegisteredDiagrams");ut();Zt();var uC="comm",hC="rule",fC="decl";var cye="@import";var uye="@keyframes";var hye="@layer";var tF=Math.abs,bb=String.fromCharCode;function dC(t){return t.trim()}o(dC,"trim");function wb(t,e,r){return t.replace(e,r)}o(wb,"replace");function fye(t,e,r){return t.indexOf(e,r)}o(fye,"indexof");function ep(t,e){return t.charCodeAt(e)|0}o(ep,"charat");function Of(t,e,r){return t.slice(e,r)}o(Of,"substr");function wo(t){return t.length}o(wo,"strlen");function dye(t){return t.length}o(dye,"sizeof");function E1(t,e){return e.push(t),t}o(E1,"append");var pC=1,C1=1,pye=0,nl=0,Si=0,A1="";function mC(t,e,r,n,i,a,s,l){return{value:t,root:e,parent:r,type:n,props:i,children:a,line:pC,column:C1,length:s,return:"",siblings:l}}o(mC,"node");function mye(){return Si}o(mye,"char");function gye(){return Si=nl>0?ep(A1,--nl):0,C1--,Si===10&&(C1=1,pC--),Si}o(gye,"prev");function il(){return Si=nl2||S1(Si)>3?"":" "}o(xye,"whitespace");function bye(t,e){for(;--e&&il()&&!(Si<48||Si>102||Si>57&&Si<65||Si>70&&Si<97););return gC(t,Tb()+(e<6&&th()==32&&il()==32))}o(bye,"escaping");function rF(t){for(;il();)switch(Si){case t:return nl;case 34:case 39:t!==34&&t!==39&&rF(Si);break;case 40:t===41&&rF(t);break;case 92:il();break}return nl}o(rF,"delimiter");function wye(t,e){for(;il()&&t+Si!==57;)if(t+Si===84&&th()===47)break;return"/*"+gC(e,nl-1)+"*"+bb(t===47?t:il())}o(wye,"commenter");function Tye(t){for(;!S1(th());)il();return gC(t,nl)}o(Tye,"identifier");function Cye(t){return vye(vC("",null,null,null,[""],t=yye(t),0,[0],t))}o(Cye,"compile");function vC(t,e,r,n,i,a,s,l,u){for(var h=0,f=0,d=s,p=0,m=0,g=0,y=1,v=1,x=1,b=0,w="",S=i,T=a,E=n,_=w;v;)switch(g=b,b=il()){case 40:if(g!=108&&ep(_,d-1)==58){fye(_+=wb(yC(b),"&","&\f"),"&\f",tF(h?l[h-1]:0))!=-1&&(x=-1);break}case 34:case 39:case 91:_+=yC(b);break;case 9:case 10:case 13:case 32:_+=xye(g);break;case 92:_+=bye(Tb()-1,7);continue;case 47:switch(th()){case 42:case 47:E1(vet(wye(il(),Tb()),e,r,u),u),(S1(g||1)==5||S1(th()||1)==5)&&wo(_)&&Of(_,-1,void 0)!==" "&&(_+=" ");break;default:_+="/"}break;case 123*y:l[h++]=wo(_)*x;case 125*y:case 59:case 0:switch(b){case 0:case 125:v=0;case 59+f:x==-1&&(_=wb(_,/\f/g,"")),m>0&&(wo(_)-d||y===0&&g===47)&&E1(m>32?Eye(_+";",n,r,d-1,u):Eye(wb(_," ","")+";",n,r,d-2,u),u);break;case 59:_+=";";default:if(E1(E=kye(_,e,r,h,f,i,l,w,S=[],T=[],d,a),a),b===123)if(f===0)vC(_,e,E,E,S,a,d,l,T);else switch(p===99&&ep(_,3)===110?100:p){case 100:case 108:case 109:case 115:vC(t,E,E,n&&E1(kye(t,E,E,0,0,i,l,w,i,S=[],d,T),T),i,T,d,l,n?S:T);break;default:vC(_,E,E,E,[""],T,0,l,T)}}h=f=m=0,y=x=1,w=_="",d=s;break;case 58:d=1+wo(_),m=g;default:if(y<1){if(b==123)--y;else if(b==125&&y++==0&&gye()==125)continue}switch(_+=bb(b),b*y){case 38:x=f>0?1:(_+="\f",-1);break;case 44:l[h++]=(wo(_)-1)*x,x=1;break;case 64:th()===45&&(_+=yC(il())),p=th(),f=d=wo(w=_+=Tye(Tb())),b++;break;case 45:g===45&&wo(_)==2&&(y=0)}}return a}o(vC,"parse");function kye(t,e,r,n,i,a,s,l,u,h,f,d){for(var p=i-1,m=i===0?a:[""],g=dye(m),y=0,v=0,x=0;y0?m[b]+" "+w:wb(w,/&\f/g,m[b])))&&(u[x++]=S);return mC(t,e,r,i===0?hC:l,u,h,f,d)}o(kye,"ruleset");function vet(t,e,r,n){return mC(t,e,r,uC,bb(mye()),Of(t,2,-2),0,n)}o(vet,"comment");function Eye(t,e,r,n,i){return mC(t,e,r,fC,Of(t,0,n),Of(t,n+1,-1),n,i)}o(Eye,"declaration");function xC(t,e){for(var r="",n=0;n{Lye.forEach(t=>{t()}),Lye=[]},"attachFunctions");ut();var Rye=o(t=>t.replace(/^\s*%%(?!{)[^\n]+\n?/gm,"").trimStart(),"cleanupComments");Vb();function qye(t){return typeof t>"u"||t===null}o(qye,"isNothing");function bet(t){return typeof t=="object"&&t!==null}o(bet,"isObject");function wet(t){return Array.isArray(t)?t:qye(t)?[]:[t]}o(wet,"toArray");function Tet(t,e){var r,n,i,a;if(e)for(a=Object.keys(e),r=0,n=a.length;rl&&(a=" ... ",e=n-l+a.length),r-n>l&&(s=" ...",r=n+l-s.length),{str:a+t.slice(e,r).replace(/\t/g,"\u2192")+s,pos:n-e+a.length}}o(nF,"getLine");function iF(t,e){return Wi.repeat(" ",e-t.length)+t}o(iF,"padStart");function Net(t,e){if(e=Object.create(e||null),!t.buffer)return null;e.maxLength||(e.maxLength=79),typeof e.indent!="number"&&(e.indent=1),typeof e.linesBefore!="number"&&(e.linesBefore=3),typeof e.linesAfter!="number"&&(e.linesAfter=2);for(var r=/\r?\n|\r|\0/g,n=[0],i=[],a,s=-1;a=r.exec(t.buffer);)i.push(a.index),n.push(a.index+a[0].length),t.position<=a.index&&s<0&&(s=n.length-2);s<0&&(s=n.length-1);var l="",u,h,f=Math.min(t.line+e.linesAfter,i.length).toString().length,d=e.maxLength-(e.indent+f+3);for(u=1;u<=e.linesBefore&&!(s-u<0);u++)h=nF(t.buffer,n[s-u],i[s-u],t.position-(n[s]-n[s-u]),d),l=Wi.repeat(" ",e.indent)+iF((t.line-u+1).toString(),f)+" | "+h.str+` +`+l;for(h=nF(t.buffer,n[s],i[s],t.position,d),l+=Wi.repeat(" ",e.indent)+iF((t.line+1).toString(),f)+" | "+h.str+` +`,l+=Wi.repeat("-",e.indent+f+3+h.pos)+`^ +`,u=1;u<=e.linesAfter&&!(s+u>=i.length);u++)h=nF(t.buffer,n[s+u],i[s+u],t.position-(n[s]-n[s+u]),d),l+=Wi.repeat(" ",e.indent)+iF((t.line+u+1).toString(),f)+" | "+h.str+` +`;return l.replace(/\n$/,"")}o(Net,"makeSnippet");var Met=Net,Iet=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],Oet=["scalar","sequence","mapping"];function Pet(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(n){e[String(n)]=r})}),e}o(Pet,"compileStyleAliases");function Bet(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(Iet.indexOf(r)===-1)throw new $s('Unknown option "'+r+'" is met in definition of "'+t+'" YAML type.')}),this.options=e,this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.representName=e.representName||null,this.defaultStyle=e.defaultStyle||null,this.multi=e.multi||!1,this.styleAliases=Pet(e.styleAliases||null),Oet.indexOf(this.kind)===-1)throw new $s('Unknown kind "'+this.kind+'" is specified for "'+t+'" YAML type.')}o(Bet,"Type$1");var Va=Bet;function Nye(t,e){var r=[];return t[e].forEach(function(n){var i=r.length;r.forEach(function(a,s){a.tag===n.tag&&a.kind===n.kind&&a.multi===n.multi&&(i=s)}),r[i]=n}),r}o(Nye,"compileList");function Fet(){var t={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}},e,r;function n(i){i.multi?(t.multi[i.kind].push(i),t.multi.fallback.push(i)):t[i.kind][i.tag]=t.fallback[i.tag]=i}for(o(n,"collectType"),e=0,r=arguments.length;e=0?"0b"+t.toString(2):"-0b"+t.toString(2).slice(1)},"binary"),octal:o(function(t){return t>=0?"0o"+t.toString(8):"-0o"+t.toString(8).slice(1)},"octal"),decimal:o(function(t){return t.toString(10)},"decimal"),hexadecimal:o(function(t){return t>=0?"0x"+t.toString(16).toUpperCase():"-0x"+t.toString(16).toUpperCase().slice(1)},"hexadecimal")},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),att=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function stt(t){return!(t===null||!att.test(t)||t[t.length-1]==="_")}o(stt,"resolveYamlFloat");function ott(t){var e,r;return e=t.replace(/_/g,"").toLowerCase(),r=e[0]==="-"?-1:1,"+-".indexOf(e[0])>=0&&(e=e.slice(1)),e===".inf"?r===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===".nan"?NaN:r*parseFloat(e,10)}o(ott,"constructYamlFloat");var ltt=/^[-+]?[0-9]+e/;function ctt(t,e){var r;if(isNaN(t))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===t)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(Wi.isNegativeZero(t))return"-0.0";return r=t.toString(10),ltt.test(r)?r.replace("e",".e"):r}o(ctt,"representYamlFloat");function utt(t){return Object.prototype.toString.call(t)==="[object Number]"&&(t%1!==0||Wi.isNegativeZero(t))}o(utt,"isFloat");var htt=new Va("tag:yaml.org,2002:float",{kind:"scalar",resolve:stt,construct:ott,predicate:utt,represent:ctt,defaultStyle:"lowercase"}),jye=Uet.extend({implicit:[qet,Qet,itt,htt]}),ftt=jye,Kye=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),Qye=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function dtt(t){return t===null?!1:Kye.exec(t)!==null||Qye.exec(t)!==null}o(dtt,"resolveYamlTimestamp");function ptt(t){var e,r,n,i,a,s,l,u=0,h=null,f,d,p;if(e=Kye.exec(t),e===null&&(e=Qye.exec(t)),e===null)throw new Error("Date resolve error");if(r=+e[1],n=+e[2]-1,i=+e[3],!e[4])return new Date(Date.UTC(r,n,i));if(a=+e[4],s=+e[5],l=+e[6],e[7]){for(u=e[7].slice(0,3);u.length<3;)u+="0";u=+u}return e[9]&&(f=+e[10],d=+(e[11]||0),h=(f*60+d)*6e4,e[9]==="-"&&(h=-h)),p=new Date(Date.UTC(r,n,i,a,s,l,u)),h&&p.setTime(p.getTime()-h),p}o(ptt,"constructYamlTimestamp");function mtt(t){return t.toISOString()}o(mtt,"representYamlTimestamp");var gtt=new Va("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:dtt,construct:ptt,instanceOf:Date,represent:mtt});function ytt(t){return t==="<<"||t===null}o(ytt,"resolveYamlMerge");var vtt=new Va("tag:yaml.org,2002:merge",{kind:"scalar",resolve:ytt}),hF=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= +\r`;function xtt(t){if(t===null)return!1;var e,r,n=0,i=t.length,a=hF;for(r=0;r64)){if(e<0)return!1;n+=6}return n%8===0}o(xtt,"resolveYamlBinary");function btt(t){var e,r,n=t.replace(/[\r\n=]/g,""),i=n.length,a=hF,s=0,l=[];for(e=0;e>16&255),l.push(s>>8&255),l.push(s&255)),s=s<<6|a.indexOf(n.charAt(e));return r=i%4*6,r===0?(l.push(s>>16&255),l.push(s>>8&255),l.push(s&255)):r===18?(l.push(s>>10&255),l.push(s>>2&255)):r===12&&l.push(s>>4&255),new Uint8Array(l)}o(btt,"constructYamlBinary");function wtt(t){var e="",r=0,n,i,a=t.length,s=hF;for(n=0;n>18&63],e+=s[r>>12&63],e+=s[r>>6&63],e+=s[r&63]),r=(r<<8)+t[n];return i=a%3,i===0?(e+=s[r>>18&63],e+=s[r>>12&63],e+=s[r>>6&63],e+=s[r&63]):i===2?(e+=s[r>>10&63],e+=s[r>>4&63],e+=s[r<<2&63],e+=s[64]):i===1&&(e+=s[r>>2&63],e+=s[r<<4&63],e+=s[64],e+=s[64]),e}o(wtt,"representYamlBinary");function Ttt(t){return Object.prototype.toString.call(t)==="[object Uint8Array]"}o(Ttt,"isBinary");var ktt=new Va("tag:yaml.org,2002:binary",{kind:"scalar",resolve:xtt,construct:btt,predicate:Ttt,represent:wtt}),Ett=Object.prototype.hasOwnProperty,Ctt=Object.prototype.toString;function Stt(t){if(t===null)return!0;var e=[],r,n,i,a,s,l=t;for(r=0,n=l.length;r>10)+55296,(t-65536&1023)+56320)}o(Htt,"charFromCodepoint");var nve=new Array(256),ive=new Array(256);for(tp=0;tp<256;tp++)nve[tp]=Oye(tp)?1:0,ive[tp]=Oye(tp);var tp;function Ytt(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||Zye,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}o(Ytt,"State$1");function ave(t,e){var r={name:t.filename,buffer:t.input.slice(0,-1),position:t.position,line:t.line,column:t.position-t.lineStart};return r.snippet=Met(r),new $s(e,r)}o(ave,"generateError");function Gt(t,e){throw ave(t,e)}o(Gt,"throwError");function TC(t,e){t.onWarning&&t.onWarning.call(null,ave(t,e))}o(TC,"throwWarning");var Pye={YAML:o(function(e,r,n){var i,a,s;e.version!==null&&Gt(e,"duplication of %YAML directive"),n.length!==1&&Gt(e,"YAML directive accepts exactly one argument"),i=/^([0-9]+)\.([0-9]+)$/.exec(n[0]),i===null&&Gt(e,"ill-formed argument of the YAML directive"),a=parseInt(i[1],10),s=parseInt(i[2],10),a!==1&&Gt(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=s<2,s!==1&&s!==2&&TC(e,"unsupported YAML version of the document")},"handleYamlDirective"),TAG:o(function(e,r,n){var i,a;n.length!==2&&Gt(e,"TAG directive accepts exactly two arguments"),i=n[0],a=n[1],tve.test(i)||Gt(e,"ill-formed tag handle (first argument) of the TAG directive"),Bf.call(e.tagMap,i)&&Gt(e,'there is a previously declared suffix for "'+i+'" tag handle'),rve.test(a)||Gt(e,"ill-formed tag prefix (second argument) of the TAG directive");try{a=decodeURIComponent(a)}catch{Gt(e,"tag prefix is malformed: "+a)}e.tagMap[i]=a},"handleTagDirective")};function Pf(t,e,r,n){var i,a,s,l;if(e1&&(t.result+=Wi.repeat(` +`,e-1))}o(dF,"writeFoldedLines");function Wtt(t,e,r){var n,i,a,s,l,u,h,f,d=t.kind,p=t.result,m;if(m=t.input.charCodeAt(t.position),Vs(m)||D1(m)||m===35||m===38||m===42||m===33||m===124||m===62||m===39||m===34||m===37||m===64||m===96||(m===63||m===45)&&(i=t.input.charCodeAt(t.position+1),Vs(i)||r&&D1(i)))return!1;for(t.kind="scalar",t.result="",a=s=t.position,l=!1;m!==0;){if(m===58){if(i=t.input.charCodeAt(t.position+1),Vs(i)||r&&D1(i))break}else if(m===35){if(n=t.input.charCodeAt(t.position-1),Vs(n))break}else{if(t.position===t.lineStart&&CC(t)||r&&D1(m))break;if(qc(m))if(u=t.line,h=t.lineStart,f=t.lineIndent,Ai(t,!1,-1),t.lineIndent>=e){l=!0,m=t.input.charCodeAt(t.position);continue}else{t.position=s,t.line=u,t.lineStart=h,t.lineIndent=f;break}}l&&(Pf(t,a,s,!1),dF(t,t.line-u),a=s=t.position,l=!1),rp(m)||(s=t.position+1),m=t.input.charCodeAt(++t.position)}return Pf(t,a,s,!1),t.result?!0:(t.kind=d,t.result=p,!1)}o(Wtt,"readPlainScalar");function qtt(t,e){var r,n,i;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind="scalar",t.result="",t.position++,n=i=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(Pf(t,n,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)n=t.position,t.position++,i=t.position;else return!0;else qc(r)?(Pf(t,n,i,!0),dF(t,Ai(t,!1,e)),n=i=t.position):t.position===t.lineStart&&CC(t)?Gt(t,"unexpected end of the document within a single quoted scalar"):(t.position++,i=t.position);Gt(t,"unexpected end of the stream within a single quoted scalar")}o(qtt,"readSingleQuotedScalar");function Xtt(t,e){var r,n,i,a,s,l;if(l=t.input.charCodeAt(t.position),l!==34)return!1;for(t.kind="scalar",t.result="",t.position++,r=n=t.position;(l=t.input.charCodeAt(t.position))!==0;){if(l===34)return Pf(t,r,t.position,!0),t.position++,!0;if(l===92){if(Pf(t,r,t.position,!0),l=t.input.charCodeAt(++t.position),qc(l))Ai(t,!1,e);else if(l<256&&nve[l])t.result+=ive[l],t.position++;else if((s=Vtt(l))>0){for(i=s,a=0;i>0;i--)l=t.input.charCodeAt(++t.position),(s=$tt(l))>=0?a=(a<<4)+s:Gt(t,"expected hexadecimal character");t.result+=Htt(a),t.position++}else Gt(t,"unknown escape sequence");r=n=t.position}else qc(l)?(Pf(t,r,n,!0),dF(t,Ai(t,!1,e)),r=n=t.position):t.position===t.lineStart&&CC(t)?Gt(t,"unexpected end of the document within a double quoted scalar"):(t.position++,n=t.position)}Gt(t,"unexpected end of the stream within a double quoted scalar")}o(Xtt,"readDoubleQuotedScalar");function jtt(t,e){var r=!0,n,i,a,s=t.tag,l,u=t.anchor,h,f,d,p,m,g=Object.create(null),y,v,x,b;if(b=t.input.charCodeAt(t.position),b===91)f=93,m=!1,l=[];else if(b===123)f=125,m=!0,l={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=l),b=t.input.charCodeAt(++t.position);b!==0;){if(Ai(t,!0,e),b=t.input.charCodeAt(t.position),b===f)return t.position++,t.tag=s,t.anchor=u,t.kind=m?"mapping":"sequence",t.result=l,!0;r?b===44&&Gt(t,"expected the node content, but found ','"):Gt(t,"missed comma between flow collection entries"),v=y=x=null,d=p=!1,b===63&&(h=t.input.charCodeAt(t.position+1),Vs(h)&&(d=p=!0,t.position++,Ai(t,!0,e))),n=t.line,i=t.lineStart,a=t.position,N1(t,e,bC,!1,!0),v=t.tag,y=t.result,Ai(t,!0,e),b=t.input.charCodeAt(t.position),(p||t.line===n)&&b===58&&(d=!0,b=t.input.charCodeAt(++t.position),Ai(t,!0,e),N1(t,e,bC,!1,!0),x=t.result),m?R1(t,l,g,v,y,x,n,i,a):d?l.push(R1(t,null,g,v,y,x,n,i,a)):l.push(y),Ai(t,!0,e),b=t.input.charCodeAt(t.position),b===44?(r=!0,b=t.input.charCodeAt(++t.position)):r=!1}Gt(t,"unexpected end of the stream within a flow collection")}o(jtt,"readFlowCollection");function Ktt(t,e){var r,n,i=aF,a=!1,s=!1,l=e,u=0,h=!1,f,d;if(d=t.input.charCodeAt(t.position),d===124)n=!1;else if(d===62)n=!0;else return!1;for(t.kind="scalar",t.result="";d!==0;)if(d=t.input.charCodeAt(++t.position),d===43||d===45)aF===i?i=d===43?Mye:Btt:Gt(t,"repeat of a chomping mode identifier");else if((f=Utt(d))>=0)f===0?Gt(t,"bad explicit indentation width of a block scalar; it cannot be less than one"):s?Gt(t,"repeat of an indentation width identifier"):(l=e+f-1,s=!0);else break;if(rp(d)){do d=t.input.charCodeAt(++t.position);while(rp(d));if(d===35)do d=t.input.charCodeAt(++t.position);while(!qc(d)&&d!==0)}for(;d!==0;){for(fF(t),t.lineIndent=0,d=t.input.charCodeAt(t.position);(!s||t.lineIndentl&&(l=t.lineIndent),qc(d)){u++;continue}if(t.lineIndente)&&u!==0)Gt(t,"bad indentation of a sequence entry");else if(t.lineIndente)&&(v&&(s=t.line,l=t.lineStart,u=t.position),N1(t,e,wC,!0,i)&&(v?g=t.result:y=t.result),v||(R1(t,d,p,m,g,y,s,l,u),m=g=y=null),Ai(t,!0,-1),b=t.input.charCodeAt(t.position)),(t.line===a||t.lineIndent>e)&&b!==0)Gt(t,"bad indentation of a mapping entry");else if(t.lineIndente?u=1:t.lineIndent===e?u=0:t.lineIndente?u=1:t.lineIndent===e?u=0:t.lineIndent tag; it should be "scalar", not "'+t.kind+'"'),d=0,p=t.implicitTypes.length;d"),t.result!==null&&g.kind!==t.kind&&Gt(t,"unacceptable node kind for !<"+t.tag+'> tag; it should be "'+g.kind+'", not "'+t.kind+'"'),g.resolve(t.result,t.tag)?(t.result=g.construct(t.result,t.tag),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):Gt(t,"cannot resolve a node with !<"+t.tag+"> explicit tag")}return t.listener!==null&&t.listener("close",t),t.tag!==null||t.anchor!==null||f}o(N1,"composeNode");function trt(t){var e=t.position,r,n,i,a=!1,s;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap=Object.create(null),t.anchorMap=Object.create(null);(s=t.input.charCodeAt(t.position))!==0&&(Ai(t,!0,-1),s=t.input.charCodeAt(t.position),!(t.lineIndent>0||s!==37));){for(a=!0,s=t.input.charCodeAt(++t.position),r=t.position;s!==0&&!Vs(s);)s=t.input.charCodeAt(++t.position);for(n=t.input.slice(r,t.position),i=[],n.length<1&&Gt(t,"directive name must not be less than one character in length");s!==0;){for(;rp(s);)s=t.input.charCodeAt(++t.position);if(s===35){do s=t.input.charCodeAt(++t.position);while(s!==0&&!qc(s));break}if(qc(s))break;for(r=t.position;s!==0&&!Vs(s);)s=t.input.charCodeAt(++t.position);i.push(t.input.slice(r,t.position))}s!==0&&fF(t),Bf.call(Pye,n)?Pye[n](t,n,i):TC(t,'unknown document directive "'+n+'"')}if(Ai(t,!0,-1),t.lineIndent===0&&t.input.charCodeAt(t.position)===45&&t.input.charCodeAt(t.position+1)===45&&t.input.charCodeAt(t.position+2)===45?(t.position+=3,Ai(t,!0,-1)):a&&Gt(t,"directives end mark is expected"),N1(t,t.lineIndent-1,wC,!1,!0),Ai(t,!0,-1),t.checkLineBreaks&&ztt.test(t.input.slice(e,t.position))&&TC(t,"non-ASCII line breaks are interpreted as content"),t.documents.push(t.result),t.position===t.lineStart&&CC(t)){t.input.charCodeAt(t.position)===46&&(t.position+=3,Ai(t,!0,-1));return}if(t.position"u"&&(r=e,e=null);var n=sve(t,r);if(typeof e!="function")return n;for(var i=0,a=n.length;i=55296&&r<=56319&&e+1=56320&&n<=57343)?(r-55296)*1024+n-56320+65536:r}o(kb,"codePointAt");function mve(t){var e=/^\n* /;return e.test(t)}o(mve,"needIndentIndicator");var gve=1,cF=2,yve=3,vve=4,L1=5;function Rrt(t,e,r,n,i,a,s,l){var u,h=0,f=null,d=!1,p=!1,m=n!==-1,g=-1,y=Lrt(kb(t,0))&&Drt(kb(t,t.length-1));if(e||s)for(u=0;u=65536?u+=2:u++){if(h=kb(t,u),!Ab(h))return L1;y=y&&$ye(h,f,l),f=h}else{for(u=0;u=65536?u+=2:u++){if(h=kb(t,u),h===Cb)d=!0,m&&(p=p||u-g-1>n&&t[g+1]!==" ",g=u);else if(!Ab(h))return L1;y=y&&$ye(h,f,l),f=h}p=p||m&&u-g-1>n&&t[g+1]!==" "}return!d&&!p?y&&!s&&!i(t)?gve:a===Sb?L1:cF:r>9&&mve(t)?L1:s?a===Sb?L1:cF:p?vve:yve}o(Rrt,"chooseScalarStyle");function Nrt(t,e,r,n,i){t.dump=function(){if(e.length===0)return t.quotingType===Sb?'""':"''";if(!t.noCompatMode&&(Trt.indexOf(e)!==-1||krt.test(e)))return t.quotingType===Sb?'"'+e+'"':"'"+e+"'";var a=t.indent*Math.max(1,r),s=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),l=n||t.flowLevel>-1&&r>=t.flowLevel;function u(h){return _rt(t,h)}switch(o(u,"testAmbiguity"),Rrt(e,l,t.indent,s,u,t.quotingType,t.forceQuotes&&!n,i)){case gve:return e;case cF:return"'"+e.replace(/'/g,"''")+"'";case yve:return"|"+Vye(e,t.indent)+Uye(zye(e,a));case vve:return">"+Vye(e,t.indent)+Uye(zye(Mrt(e,s),a));case L1:return'"'+Irt(e)+'"';default:throw new $s("impossible error: invalid scalar style")}}()}o(Nrt,"writeScalar");function Vye(t,e){var r=mve(t)?String(e):"",n=t[t.length-1]===` +`,i=n&&(t[t.length-2]===` +`||t===` +`),a=i?"+":n?"":"-";return r+a+` +`}o(Vye,"blockHeader");function Uye(t){return t[t.length-1]===` +`?t.slice(0,-1):t}o(Uye,"dropEndingNewline");function Mrt(t,e){for(var r=/(\n+)([^\n]*)/g,n=function(){var h=t.indexOf(` +`);return h=h!==-1?h:t.length,r.lastIndex=h,Hye(t.slice(0,h),e)}(),i=t[0]===` +`||t[0]===" ",a,s;s=r.exec(t);){var l=s[1],u=s[2];a=u[0]===" ",n+=l+(!i&&!a&&u!==""?` +`:"")+Hye(u,e),i=a}return n}o(Mrt,"foldString");function Hye(t,e){if(t===""||t[0]===" ")return t;for(var r=/ [^ ]/g,n,i=0,a,s=0,l=0,u="";n=r.exec(t);)l=n.index,l-i>e&&(a=s>i?s:l,u+=` +`+t.slice(i,a),i=a+1),s=l;return u+=` +`,t.length-i>e&&s>i?u+=t.slice(i,s)+` +`+t.slice(s+1):u+=t.slice(i),u.slice(1)}o(Hye,"foldLine");function Irt(t){for(var e="",r=0,n,i=0;i=65536?i+=2:i++)r=kb(t,i),n=Ua[r],!n&&Ab(r)?(e+=t[i],r>=65536&&(e+=t[i+1])):e+=n||Crt(r);return e}o(Irt,"escapeString");function Ort(t,e,r){var n="",i=t.tag,a,s,l;for(a=0,s=r.length;a"u"&&rh(t,e,null,!1,!1))&&(n!==""&&(n+=","+(t.condenseFlow?"":" ")),n+=t.dump);t.tag=i,t.dump="["+n+"]"}o(Ort,"writeFlowSequence");function Yye(t,e,r,n){var i="",a=t.tag,s,l,u;for(s=0,l=r.length;s"u"&&rh(t,e+1,null,!0,!0,!1,!0))&&((!n||i!=="")&&(i+=lF(t,e)),t.dump&&Cb===t.dump.charCodeAt(0)?i+="-":i+="- ",i+=t.dump);t.tag=a,t.dump=i||"[]"}o(Yye,"writeBlockSequence");function Prt(t,e,r){var n="",i=t.tag,a=Object.keys(r),s,l,u,h,f;for(s=0,l=a.length;s1024&&(f+="? "),f+=t.dump+(t.condenseFlow?'"':"")+":"+(t.condenseFlow?"":" "),rh(t,e,h,!1,!1)&&(f+=t.dump,n+=f));t.tag=i,t.dump="{"+n+"}"}o(Prt,"writeFlowMapping");function Brt(t,e,r,n){var i="",a=t.tag,s=Object.keys(r),l,u,h,f,d,p;if(t.sortKeys===!0)s.sort();else if(typeof t.sortKeys=="function")s.sort(t.sortKeys);else if(t.sortKeys)throw new $s("sortKeys must be a boolean or a function");for(l=0,u=s.length;l1024,d&&(t.dump&&Cb===t.dump.charCodeAt(0)?p+="?":p+="? "),p+=t.dump,d&&(p+=lF(t,e)),rh(t,e+1,f,!0,d)&&(t.dump&&Cb===t.dump.charCodeAt(0)?p+=":":p+=": ",p+=t.dump,i+=p));t.tag=a,t.dump=i||"{}"}o(Brt,"writeBlockMapping");function Wye(t,e,r){var n,i,a,s,l,u;for(i=r?t.explicitTypes:t.implicitTypes,a=0,s=i.length;a tag resolver accepts not "'+u+'" style');t.dump=n}return!0}return!1}o(Wye,"detectType");function rh(t,e,r,n,i,a,s){t.tag=null,t.dump=r,Wye(t,r,!1)||Wye(t,r,!0);var l=lve.call(t.dump),u=n,h;n&&(n=t.flowLevel<0||t.flowLevel>e);var f=l==="[object Object]"||l==="[object Array]",d,p;if(f&&(d=t.duplicates.indexOf(r),p=d!==-1),(t.tag!==null&&t.tag!=="?"||p||t.indent!==2&&e>0)&&(i=!1),p&&t.usedDuplicates[d])t.dump="*ref_"+d;else{if(f&&p&&!t.usedDuplicates[d]&&(t.usedDuplicates[d]=!0),l==="[object Object]")n&&Object.keys(t.dump).length!==0?(Brt(t,e,t.dump,i),p&&(t.dump="&ref_"+d+t.dump)):(Prt(t,e,t.dump),p&&(t.dump="&ref_"+d+" "+t.dump));else if(l==="[object Array]")n&&t.dump.length!==0?(t.noArrayIndent&&!s&&e>0?Yye(t,e-1,t.dump,i):Yye(t,e,t.dump,i),p&&(t.dump="&ref_"+d+t.dump)):(Ort(t,e,t.dump),p&&(t.dump="&ref_"+d+" "+t.dump));else if(l==="[object String]")t.tag!=="?"&&Nrt(t,t.dump,e,a,u);else{if(l==="[object Undefined]")return!1;if(t.skipInvalid)return!1;throw new $s("unacceptable kind of an object to dump "+l)}t.tag!==null&&t.tag!=="?"&&(h=encodeURI(t.tag[0]==="!"?t.tag.slice(1):t.tag).replace(/!/g,"%21"),t.tag[0]==="!"?h="!"+h:h.slice(0,18)==="tag:yaml.org,2002:"?h="!!"+h.slice(18):h="!<"+h+">",t.dump=h+" "+t.dump)}return!0}o(rh,"writeNode");function Frt(t,e){var r=[],n=[],i,a;for(uF(t,r,n),i=0,a=n.length;it.replace(/\r\n?/g,` +`).replace(/<(\w+)([^>]*)>/g,(e,r,n)=>"<"+r+n.replace(/="([^"]*)"/g,"='$1'")+">"),"cleanupText"),Hrt=o(t=>{let{text:e,metadata:r}=wve(t),{displayMode:n,title:i,config:a={}}=r;return n&&(a.gantt||(a.gantt={}),a.gantt.displayMode=n),{title:i,config:a,text:e}},"processFrontmatter"),Yrt=o(t=>{let e=Lt.detectInit(t)??{},r=Lt.detectDirective(t,"wrap");return Array.isArray(r)?e.wrap=r.some(({type:n})=>n==="wrap"):r?.type==="wrap"&&(e.wrap=!0),{text:EX(t),directive:e}},"processDirectives");function gF(t){let e=Urt(t),r=Hrt(e),n=Yrt(r.text),i=Ts(r.config,n.directive);return t=Rye(n.text),{code:t,title:r.title,config:i}}o(gF,"preprocessDiagram");Z7();Kb();xr();function Tve(t){let e=new TextEncoder().encode(t),r=Array.from(e,n=>String.fromCodePoint(n)).join("");return btoa(r)}o(Tve,"toBase64");var Wrt=5e4,qrt="graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa",Xrt="sandbox",jrt="loose",Krt="http://www.w3.org/2000/svg",Qrt="http://www.w3.org/1999/xlink",Zrt="http://www.w3.org/1999/xhtml",Jrt="100%",ent="100%",tnt="border:0;margin:0;",rnt="margin:0",nnt="allow-top-navigation-by-user-activation allow-popups",int='The "iframe" tag is not supported by your browser.',ant=["foreignobject"],snt=["dominant-baseline"];function Ave(t){let e=gF(t);return Q1(),jz(e.config??{}),e}o(Ave,"processAndSetConfigs");async function ont(t,e){k1();try{let{code:r,config:n}=Ave(t);return{diagramType:(await _ve(r)).type,config:n}}catch(r){if(e?.suppressErrors)return!1;throw r}}o(ont,"parse");var kve=o((t,e,r=[])=>` +.${t} ${e} { ${r.join(" !important; ")} !important; }`,"cssImportantStyles"),lnt=o((t,e=new Map)=>{let r="";if(t.themeCSS!==void 0&&(r+=` +${t.themeCSS}`),t.fontFamily!==void 0&&(r+=` +:root { --mermaid-font-family: ${t.fontFamily}}`),t.altFontFamily!==void 0&&(r+=` +:root { --mermaid-alt-font-family: ${t.altFontFamily}}`),e instanceof Map){let s=t.htmlLabels??t.flowchart?.htmlLabels?["> *","span"]:["rect","polygon","ellipse","circle","path"];e.forEach(l=>{Qt(l.styles)||s.forEach(u=>{r+=kve(l.id,u,l.styles)}),Qt(l.textStyles)||(r+=kve(l.id,"tspan",(l?.textStyles||[]).map(u=>u.replace("color","fill"))))})}return r},"createCssStyles"),cnt=o((t,e,r,n)=>{let i=lnt(t,r),a=D$(e,i,t.themeVariables);return xC(Cye(`${n}{${a}}`),Sye)},"createUserStyles"),unt=o((t="",e,r)=>{let n=t;return!r&&!e&&(n=n.replace(/marker-end="url\([\d+./:=?A-Za-z-]*?#/g,'marker-end="url(#')),n=to(n),n=n.replace(/
    /g,"
    "),n},"cleanUpSvgCode"),hnt=o((t="",e)=>{let r=e?.viewBox?.baseVal?.height?e.viewBox.baseVal.height+"px":ent,n=Tve(`${t}`);return``},"putIntoIFrame"),Eve=o((t,e,r,n,i)=>{let a=t.append("div");a.attr("id",r),n&&a.attr("style",n);let s=a.append("svg").attr("id",e).attr("width","100%").attr("xmlns",Krt);return i&&s.attr("xmlns:xlink",i),s.append("g"),t},"appendDivSvgG");function Cve(t,e){return t.append("iframe").attr("id",e).attr("style","width: 100%; height: 100%;").attr("sandbox","")}o(Cve,"sandboxedIframe");var fnt=o((t,e,r,n)=>{t.getElementById(e)?.remove(),t.getElementById(r)?.remove(),t.getElementById(n)?.remove()},"removeExistingElements"),dnt=o(async function(t,e,r){k1();let n=Ave(e);e=n.code;let i=Or();V.debug(i),e.length>(i?.maxTextSize??Wrt)&&(e=qrt);let a="#"+t,s="i"+t,l="#"+s,u="d"+t,h="#"+u,f=o(()=>{let I=$e(p?l:h).node();I&&"remove"in I&&I.remove()},"removeTempElements"),d=$e("body"),p=i.securityLevel===Xrt,m=i.securityLevel===jrt,g=i.fontFamily;if(r!==void 0){if(r&&(r.innerHTML=""),p){let k=Cve($e(r),s);d=$e(k.nodes()[0].contentDocument.body),d.node().style.margin=0}else d=$e(r);Eve(d,t,u,`font-family: ${g}`,Qrt)}else{if(fnt(document,t,u,s),p){let k=Cve($e("body"),s);d=$e(k.nodes()[0].contentDocument.body),d.node().style.margin=0}else d=$e("body");Eve(d,t,u)}let y,v;try{y=await _1.fromText(e,{title:n.title})}catch(k){if(i.suppressErrorRendering)throw f(),k;y=await _1.fromText("error"),v=k}let x=d.select(h).node(),b=y.type,w=x.firstChild,S=w.firstChild,T=y.renderer.getClasses?.(e,y),E=cnt(i,b,T,a),_=document.createElement("style");_.innerHTML=E,w.insertBefore(_,S);try{await y.renderer.draw(e,t,fx,y)}catch(k){throw i.suppressErrorRendering?f():Ede.draw(e,t,fx),k}let A=d.select(`${h} svg`),L=y.db.getAccTitle?.(),M=y.db.getAccDescription?.();mnt(b,A,L,M),d.select(`[id="${t}"]`).selectAll("foreignobject > *").attr("xmlns",Zrt);let N=d.select(h).node().innerHTML;if(V.debug("config.arrowMarkerAbsolute",i.arrowMarkerAbsolute),N=unt(N,p,yr(i.arrowMarkerAbsolute)),p){let k=d.select(h+" svg").node();N=hnt(N,k)}else m||(N=Sve.default.sanitize(N,{ADD_TAGS:ant,ADD_ATTR:snt}));if(Dye(),v)throw v;return f(),{diagramType:b,svg:N,bindFunctions:y.db.bindFunctions}},"render");function pnt(t={}){let e=On({},t);e?.fontFamily&&!e.themeVariables?.fontFamily&&(e.themeVariables||(e.themeVariables={}),e.themeVariables.fontFamily=e.fontFamily),Wz(e),e?.theme&&e.theme in Co?e.themeVariables=Co[e.theme].getThemeVariables(e.themeVariables):e&&(e.themeVariables=Co.default.getThemeVariables(e.themeVariables));let r=typeof e=="object"?n7(e):i7();$1(r.logLevel),k1()}o(pnt,"initialize");var _ve=o((t,e={})=>{let{code:r}=gF(t);return _1.fromText(r,e)},"getDiagramFromText");function mnt(t,e,r,n){Aye(e,t),_ye(e,r,n,e.attr("id"))}o(mnt,"addA11yInfo");var Ff=Object.freeze({render:dnt,parse:ont,getDiagramFromText:_ve,initialize:pnt,getConfig:Or,setConfig:Zb,getSiteConfig:i7,updateSiteConfig:qz,reset:o(()=>{Q1()},"reset"),globalReset:o(()=>{Q1(uh)},"globalReset"),defaultConfig:uh});$1(Or().logLevel);Q1(Or());oT();xr();var gnt=o((t,e,r)=>{V.warn(t),r9(t)?(r&&r(t.str,t.hash),e.push({...t,message:t.str,error:t})):(r&&r(t),t instanceof Error&&e.push({str:t.message,message:t.message,hash:t.name,error:t}))},"handleError"),Lve=o(async function(t={querySelector:".mermaid"}){try{await ynt(t)}catch(e){if(r9(e)&&V.error(e.str),nh.parseError&&nh.parseError(e),!t.suppressErrors)throw V.error("Use the suppressErrors option to suppress these errors"),e}},"run"),ynt=o(async function({postRenderCallback:t,querySelector:e,nodes:r}={querySelector:".mermaid"}){let n=Ff.getConfig();V.debug(`${t?"":"No "}Callback function found`);let i;if(r)i=r;else if(e)i=document.querySelectorAll(e);else throw new Error("Nodes and querySelector are both undefined");V.debug(`Found ${i.length} diagrams`),n?.startOnLoad!==void 0&&(V.debug("Start On Load: "+n?.startOnLoad),Ff.updateSiteConfig({startOnLoad:n?.startOnLoad}));let a=new Lt.InitIDGenerator(n.deterministicIds,n.deterministicIDSeed),s,l=[];for(let u of Array.from(i)){V.info("Rendering diagram: "+u.id);if(u.getAttribute("data-processed"))continue;u.setAttribute("data-processed","true");let h=`mermaid-${a.next()}`;s=u.innerHTML,s=Gb(Lt.entityDecode(s)).trim().replace(//gi,"
    ");let f=Lt.detectInit(s);f&&V.debug("Detected early reinit: ",f);try{let{svg:d,bindFunctions:p}=await Mve(h,s,u);u.innerHTML=d,t&&await t(h),p&&p(u)}catch(d){gnt(d,l,nh.parseError)}}if(l.length>0)throw l[0]},"runThrowsErrors"),Dve=o(function(t){Ff.initialize(t)},"initialize"),vnt=o(async function(t,e,r){V.warn("mermaid.init is deprecated. Please use run instead."),t&&Dve(t);let n={postRenderCallback:r,querySelector:".mermaid"};typeof e=="string"?n.querySelector=e:e&&(e instanceof HTMLElement?n.nodes=[e]:n.nodes=e),await Lve(n)},"init"),xnt=o(async(t,{lazyLoad:e=!0}={})=>{k1(),Ub(...t),e===!1&&await lye()},"registerExternalDiagrams"),Rve=o(function(){if(nh.startOnLoad){let{startOnLoad:t}=Ff.getConfig();t&&nh.run().catch(e=>V.error("Mermaid failed to initialize",e))}},"contentLoaded");if(typeof document<"u"){window.addEventListener("load",Rve,!1)}var bnt=o(function(t){nh.parseError=t},"setParseErrorHandler"),SC=[],yF=!1,Nve=o(async()=>{if(!yF){for(yF=!0;SC.length>0;){let t=SC.shift();if(t)try{await t()}catch(e){V.error("Error executing queue",e)}}yF=!1}},"executeQueue"),wnt=o(async(t,e)=>new Promise((r,n)=>{let i=o(()=>new Promise((a,s)=>{Ff.parse(t,e).then(l=>{a(l),r(l)},l=>{V.error("Error parsing",l),nh.parseError?.(l),s(l),n(l)})}),"performCall");SC.push(i),Nve().catch(n)}),"parse"),Mve=o((t,e,r)=>new Promise((n,i)=>{let a=o(()=>new Promise((s,l)=>{Ff.render(t,e,r).then(u=>{s(u),n(u)},u=>{V.error("Error parsing",u),nh.parseError?.(u),l(u),i(u)})}),"performCall");SC.push(a),Nve().catch(i)}),"render"),nh={startOnLoad:!0,mermaidAPI:Ff,parse:wnt,render:Mve,init:vnt,run:Lve,registerExternalDiagrams:xnt,registerLayoutLoaders:gD,initialize:Dve,parseError:void 0,contentLoaded:Rve,setParseErrorHandler:bnt,detectType:lp,registerIconPacks:Fb},Tnt=nh;return $ve(knt);})(); +/*! Check if previously processed */ +/*! + * Wait for document loaded before starting the execution + */ +/*! Bundled license information: + +dompurify/dist/purify.js: + (*! @license DOMPurify 3.1.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.6/LICENSE *) + +lodash-es/lodash.js: + (** + * @license + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" -o ./` + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + *) + +cytoscape/dist/cytoscape.esm.mjs: + (*! + Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable + Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com) + Licensed under The MIT License (http://opensource.org/licenses/MIT) + *) + (*! + Event object based on jQuery events, MIT license + + https://jquery.org/license/ + https://tldrlegal.com/license/mit-license + https://github.com/jquery/jquery/blob/master/src/event.js + *) + (*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License *) + (*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License *) + +js-yaml/dist/js-yaml.mjs: + (*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT *) +*/ +globalThis.mermaid = globalThis.__esbuild_esm_mermaid.default; diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 000000000..d011bad7e Binary files /dev/null and b/assets/favicon.png differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 000000000..1cf13b9f9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.a59f24f2.min.js b/assets/javascripts/bundle.a59f24f2.min.js new file mode 100644 index 000000000..2635572d1 --- /dev/null +++ b/assets/javascripts/bundle.a59f24f2.min.js @@ -0,0 +1,3 @@ +"use strict";(()=>{var Ji=Object.create;var _r=Object.defineProperty;var Xi=Object.getOwnPropertyDescriptor;var Zi=Object.getOwnPropertyNames,Gt=Object.getOwnPropertySymbols,ea=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,ho=Object.prototype.propertyIsEnumerable;var uo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&uo(e,r,t[r]);if(Gt)for(var r of Gt(t))ho.call(t,r)&&uo(e,r,t[r]);return e};var bo=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Gt)for(var o of Gt(e))t.indexOf(o)<0&&ho.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ta=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Zi(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Xi(t,n))||o.enumerable});return e};var Pt=(e,t,r)=>(r=e!=null?Ji(ea(e)):{},ta(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var vo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var yo=Cr((kr,go)=>{(function(e,t){typeof kr=="object"&&typeof go!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(kr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function c(k){var ut=k.type,je=k.tagName;return!!(je==="INPUT"&&s[ut]&&!k.readOnly||je==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function p(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(k){o=!1}function d(k){a(k.target)&&(o||c(k.target))&&p(k.target)}function v(k){a(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function S(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",ee),document.addEventListener("mousedown",ee),document.addEventListener("mouseup",ee),document.addEventListener("pointermove",ee),document.addEventListener("pointerdown",ee),document.addEventListener("pointerup",ee),document.addEventListener("touchmove",ee),document.addEventListener("touchstart",ee),document.addEventListener("touchend",ee)}function re(){document.removeEventListener("mousemove",ee),document.removeEventListener("mousedown",ee),document.removeEventListener("mouseup",ee),document.removeEventListener("pointermove",ee),document.removeEventListener("pointerdown",ee),document.removeEventListener("pointerup",ee),document.removeEventListener("touchmove",ee),document.removeEventListener("touchstart",ee),document.removeEventListener("touchend",ee)}function ee(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,re())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",S,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",v,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var ro=Cr((Py,Pn)=>{"use strict";var Va=/["'&<>]/;Pn.exports=za;function za(e){var t=""+e,r=Va.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i{(function(t,r){typeof zt=="object"&&typeof io=="object"?io.exports=r():typeof define=="function"&&define.amd?define([],r):typeof zt=="object"?zt.ClipboardJS=r():t.ClipboardJS=r()})(zt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Gi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(q){try{return document.execCommand(q)}catch(C){return!1}}var d=function(C){var _=f()(C);return u("cut"),_},v=d;function S(q){var C=document.documentElement.getAttribute("dir")==="rtl",_=document.createElement("textarea");_.style.fontSize="12pt",_.style.border="0",_.style.padding="0",_.style.margin="0",_.style.position="absolute",_.style[C?"right":"left"]="-9999px";var W=window.pageYOffset||document.documentElement.scrollTop;return _.style.top="".concat(W,"px"),_.setAttribute("readonly",""),_.value=q,_}var X=function(C,_){var W=S(C);_.container.appendChild(W);var V=f()(W);return u("copy"),W.remove(),V},re=function(C){var _=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},W="";return typeof C=="string"?W=X(C,_):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?W=X(C.value,_):(W=f()(C),u("copy")),W},ee=re;function k(q){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(_){return typeof _}:k=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},k(q)}var ut=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},_=C.action,W=_===void 0?"copy":_,V=C.container,G=C.target,Ue=C.text;if(W!=="copy"&&W!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&k(G)==="object"&&G.nodeType===1){if(W==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(W==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return ee(Ue,{container:V});if(G)return W==="cut"?v(G):ee(G,{container:V})},je=ut;function R(q){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(_){return typeof _}:R=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},R(q)}function se(q,C){if(!(q instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(q,C){for(var _=0;_0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=R(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var G=this;this.listener=p()(V,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(V){var G=V.delegateTarget||V.currentTarget,Ue=this.action(G)||"copy",Bt=je({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Bt?"success":"error",{action:Ue,text:Bt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return Mr("action",V)}},{key:"defaultTarget",value:function(V){var G=Mr("target",V);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(V){return Mr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return ee(V,G)}},{key:"cut",value:function(V){return v(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof V=="string"?[V]:V,Ue=!!document.queryCommandSupported;return G.forEach(function(Bt){Ue=Ue&&!!document.queryCommandSupported(Bt)}),Ue}}]),_}(a()),Gi=Bi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,v){var S=p.apply(this,arguments);return l.addEventListener(u,S,v),{destroy:function(){l.removeEventListener(u,S,v)}}}function c(l,f,u,d,v){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(S){return a(S,f,u,d,v)}))}function p(l,f,u,d){return function(v){v.delegateTarget=s(v.target,f),v.delegateTarget&&d.call(l,v)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,v){if(!u&&!d&&!v)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(v))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,v);if(s.nodeList(u))return l(u,d,v);if(s.string(u))return f(u,d,v);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,v){return u.addEventListener(d,v),{destroy:function(){u.removeEventListener(d,v)}}}function l(u,d,v){return Array.prototype.forEach.call(u,function(S){S.addEventListener(d,v)}),{destroy:function(){Array.prototype.forEach.call(u,function(S){S.removeEventListener(d,v)})}}}function f(u,d,v){return a(document.body,u,d,v)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function K(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function B(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||c(d,S)})},v&&(n[d]=v(n[d])))}function c(d,v){try{p(o[d](v))}catch(S){u(i[0][3],S)}}function p(d){d.value instanceof dt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){c("next",d)}function f(d){c("throw",d)}function u(d,v){d(v),i.shift(),i.length&&c(i[0][0],i[0][1])}}function wo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Oe=="function"?Oe(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function I(e){return typeof e=="function"}function yt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=yt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ze(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var qe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Oe(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(S){t={error:S}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(I(l))try{l()}catch(S){i=S instanceof Xt?S.errors:[S]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Oe(f),d=u.next();!d.done;d=u.next()){var v=d.value;try{To(v)}catch(S){i=i!=null?i:[],S instanceof Xt?i=B(B([],K(i)),K(S.errors)):i.push(S)}}}catch(S){o={error:S}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)To(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ze(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ze(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var $r=qe.EMPTY;function Zt(e){return e instanceof qe||e&&"closed"in e&&I(e.remove)&&I(e.add)&&I(e.unsubscribe)}function To(e){I(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var xt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?$r:(this.currentObservers=null,a.push(r),new qe(function(){o.currentObservers=null,Ze(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,o){return new ko(r,o)},t}(F);var ko=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:$r},t}(T);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(T);var It={now:function(){return(It.delegate||Date).now()},delegate:void 0};var Ft=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=It);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(St);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(Ot);var Wr=new Po($o);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Tt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(Tt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(St);var Io=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(Ot);var ye=new Io(Ro);var y=new F(function(e){return e.complete()});function rr(e){return e&&I(e.schedule)}function Nr(e){return e[e.length-1]}function pt(e){return I(Nr(e))?e.pop():void 0}function Fe(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return I(e==null?void 0:e.then)}function ir(e){return I(e[wt])}function ar(e){return Symbol.asyncIterator&&I(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function la(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=la();function pr(e){return I(e==null?void 0:e[cr])}function lr(e){return Eo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,dt(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,dt(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,dt(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return I(e==null?void 0:e.getReader)}function D(e){if(e instanceof F)return e;if(e!=null){if(ir(e))return ma(e);if(Lt(e))return fa(e);if(nr(e))return ua(e);if(ar(e))return Fo(e);if(pr(e))return da(e);if(mr(e))return ha(e)}throw sr(e)}function ma(e){return new F(function(t){var r=e[wt]();if(I(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function fa(e){return new F(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?g(function(n,i){return e(n,i,o)}):be,Ee(1),r?Qe(t):en(function(){return new ur}))}}function Yr(e){return e<=0?function(){return y}:E(function(t,r){var o=[];t.subscribe(w(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new T}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,v=!1,S=!1,X=function(){f==null||f.unsubscribe(),f=void 0},re=function(){X(),l=u=void 0,v=S=!1},ee=function(){var k=l;re(),k==null||k.unsubscribe()};return E(function(k,ut){d++,!S&&!v&&X();var je=u=u!=null?u:r();ut.add(function(){d--,d===0&&!S&&!v&&(f=Br(ee,c))}),je.subscribe(ut),!l&&d>0&&(l=new bt({next:function(R){return je.next(R)},error:function(R){S=!0,X(),f=Br(re,n,R),je.error(R)},complete:function(){v=!0,X(),f=Br(re,s),je.complete()}}),D(k).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function M(e,t=document){return Array.from(t.querySelectorAll(e))}function j(e,t=document){let r=ue(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ue(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var $a=L(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),Q(void 0),m(()=>Ve()||document.body),Z(1));function Ye(e){return $a.pipe(m(t=>e.contains(t)),Y())}function it(e,t){return H(()=>L(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?Dt(r=>He(+!r*t)):be,Q(e.matches(":hover"))))}function an(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)an(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)an(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function At(e){let t=x("script",{src:e});return H(()=>(document.head.appendChild(t),L(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),Ee(1))))}var sn=new T,Pa=H(()=>typeof ResizeObserver=="undefined"?At("https://unpkg.com/resize-observer-polyfill"):$(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>sn.next(t)))),b(e=>L(tt,$(e)).pipe(A(()=>e.disconnect()))),Z(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Pa.pipe(O(r=>r.observe(t)),b(r=>sn.pipe(g(o=>o.target===t),A(()=>r.unobserve(t)))),m(()=>de(e)),Q(de(e)))}function Ct(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function cn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function pn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function ln(e){return L(h(window,"load"),h(window,"resize")).pipe($e(0,ye),m(()=>Be(e)),Q(Be(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ge(e){return L(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe($e(0,ye),m(()=>gr(e)),Q(gr(e)))}var mn=new T,Ra=H(()=>$(new IntersectionObserver(e=>{for(let t of e)mn.next(t)},{threshold:0}))).pipe(b(e=>L(tt,$(e)).pipe(A(()=>e.disconnect()))),Z(1));function mt(e){return Ra.pipe(O(t=>t.observe(e)),b(t=>mn.pipe(g(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function fn(e,t=16){return Ge(e).pipe(m(({y:r})=>{let o=de(e),n=Ct(e);return r>=n.height-o.height-t}),Y())}var yr={drawer:j("[data-md-toggle=drawer]"),search:j("[data-md-toggle=search]")};function un(e){return yr[e].checked}function at(e,t){yr[e].checked!==t&&yr[e].click()}function Je(e){let t=yr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Ia(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Fa(){return L(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function dn(){let e=h(window,"keydown").pipe(g(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:un("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),g(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Ia(o,r)}return!0}),le());return Fa().pipe(b(t=>t?y:e))}function we(){return new URL(location.href)}function st(e,t=!1){if(N("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function hn(){return new T}function bn(){return location.hash.slice(1)}function vn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return L(h(window,"hashchange"),e).pipe(m(bn),Q(bn()),g(t=>t.length>0),Z(1))}function gn(e){return Zr(e).pipe(m(t=>ue(`[id="${t}"]`)),g(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function yn(){let e=matchMedia("print");return L(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():y))}function to(e,t){return new F(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function ze(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),Z(1))}function xr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),Z(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),Z(1))}function En(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function wn(){return L(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(En),Q(En()))}function Tn(){return{width:innerWidth,height:innerHeight}}function Sn(){return h(window,"resize",{passive:!0}).pipe(m(Tn),Q(Tn()))}function On(){return z([wn(),Sn()]).pipe(m(([e,t])=>({offset:e,size:t})),Z(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(ne("size")),n=z([o,r]).pipe(m(()=>Be(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function ja(e){return h(e,"message",t=>t.data)}function Da(e){let t=new T;return t.subscribe(r=>e.postMessage(r)),t}function Ln(e,t=new Worker(e)){let r=ja(t),o=Da(t),n=new T;n.subscribe(o);let i=o.pipe(oe(),ae(!0));return n.pipe(oe(),Ne(r.pipe(U(i))),le())}var Ua=j("#__config"),kt=JSON.parse(Ua.textContent);kt.base=`${new URL(kt.base,we())}`;function Te(){return kt}function N(e){return kt.features.includes(e)}function Me(e,t){return typeof t!="undefined"?kt.translations[e].replace("#",t.toString()):kt.translations[e]}function Ce(e,t=document){return j(`[data-md-component=${e}]`,t)}function me(e,t=document){return M(`[data-md-component=${e}]`,t)}function Wa(e){let t=j(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>j(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Mn(e){if(!N("announce.dismiss")||!e.childElementCount)return y;if(!e.hidden){let t=j(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return H(()=>{let t=new T;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Wa(e).pipe(O(r=>t.next(r)),A(()=>t.complete()),m(r=>P({ref:e},r)))})}function Na(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function _n(e,t){let r=new T;return r.subscribe(({hidden:o})=>{e.hidden=o}),Na(e,t).pipe(O(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))}function Nt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return x("div",{class:"md-tooltip2",role:"dialog"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function Cn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Nt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Nt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function kn(e){return x("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return x("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function $n(){return x("nav",{class:"md-code__nav"})}var Rn=Pt(ro());function oo(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,x("del",null,(0,Rn.default)(p))," "],[]).slice(0,-1),i=Te(),s=new URL(e.location,i.base);N("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=Te();return x("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function In(e){let t=e[0].score,r=[...e],o=Te(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scoreoo(l,1)),...c.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>oo(l,1)))]:[]];return x("li",{class:"md-search-result__item"},p)}function Fn(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function no(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function jn(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function qa(e){var o;let t=Te(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Dn(e,t){var o;let r=Te();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Me("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(qa)))}var Ka=0;function Qa(e,t=250){let r=z([Ye(e),it(e,t)]).pipe(m(([n,i])=>n||i),Y()),o=H(()=>cn(e)).pipe(J(Ge),gt(1),Pe(r),m(()=>pn(e)));return r.pipe(Re(n=>n),b(()=>z([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Vt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Ka++}`;return H(()=>{let s=new T,a=new jr(!1);s.pipe(oe(),ae(!1)).subscribe(a);let c=a.pipe(Dt(l=>He(+!l*250,Wr)),Y(),b(l=>l?o:y),O(l=>l.id=i),le());z([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>it(l,250)),Q(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(g(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),v=d.width/2;if(f.role==="tooltip")return{x:v,y:8+d.height};if(d.y>=u.height/2){let{height:S}=de(f);return{x:v,y:-16-S}}else return{x:v,y:16+d.height}}));return z([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(g(l=>l),te(c,(l,f)=>f),g(l=>l.role==="tooltip")).subscribe(l=>{let f=de(j(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Y(),xe(ye),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),z([a.pipe(g(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(g(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Qa(e,r).pipe(O(l=>s.next(l)),A(()=>s.complete()),m(l=>P({ref:e},l)))})}function Xe(e,{viewport$:t},r=document.body){return Vt(e,{content$:new F(o=>{let n=e.title,i=An(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function Ya(e,t){let r=H(()=>z([ln(e),Ge(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=de(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ye(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),Ee(+!o||1/0))))}function Un(e,t,{target$:r}){let[o,n]=Array.from(e.children);return H(()=>{let i=new T,s=i.pipe(oe(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),mt(e).pipe(U(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),L(i.pipe(g(({active:a})=>a)),i.pipe(Ae(250),g(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe($e(16,ye)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(gt(125,ye),g(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(U(s),g(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(U(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(U(s),g(a=>a===o),nt(125)).subscribe(()=>e.focus()),Ya(e,t).pipe(O(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ba(e){let t=Te();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return M(r.join(", "),e)}function Ga(e){let t=[];for(let r of Ba(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function Wn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Ga(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ue(`:scope > li:nth-child(${c})`,e)&&(s.set(c,Cn(c,i)),a.replaceWith(s.get(c)))}return s.size===0?y:H(()=>{let a=new T,c=a.pipe(oe(),ae(!0)),p=[];for(let[l,f]of s)p.push([j(".md-typeset",f),j(`:scope > li:nth-child(${l})`,e)]);return o.pipe(U(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?Wn(f,u):Wn(u,f)}),L(...[...s].map(([,l])=>Un(l,t,{target$:r}))).pipe(A(()=>a.complete()),le())})}function Nn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Nn(t)}}function Vn(e,t){return H(()=>{let r=Nn(e);return typeof r!="undefined"?Tr(r,e,t):y})}var qn=Pt(ao());var Ja=0,zn=L(h(window,"keydown").pipe(m(()=>!0)),L(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(Q(!1),Z(1));function Kn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Kn(t)}}function Xa(e){return Le(e).pipe(m(({width:t})=>({scrollable:Ct(e).width>t})),ne("scrollable"))}function Qn(e,t){let{matches:r}=matchMedia("(hover)"),o=H(()=>{let n=new T,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Ja++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Kn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||N("content.code.annotate"))){let v=Tr(d,e,t);l.push(Le(f).pipe(U(i),m(({width:S,height:X})=>S&&X),Y(),b(S=>S?v:y)))}}let u=M(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||N("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),v=Hn();s.push(v),N("content.tooltips")&&l.push(Xe(v,{viewport$}));let S=h(v,"click").pipe(Ut(R=>!R,!1),O(()=>v.blur()),le());S.subscribe(R=>{v.classList.toggle("md-code__button--active",R)});let X=fe(u).pipe(J(R=>it(R).pipe(m(se=>[R,se]))));S.pipe(b(R=>R?X:y)).subscribe(([R,se])=>{let ce=ue(".hll.select",R);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(R.childNodes).slice(1)),R.append(he)}});let re=fe(u).pipe(J(R=>h(R,"mousedown").pipe(O(se=>se.preventDefault()),m(()=>R)))),ee=S.pipe(b(R=>R?re:y),te(zn),m(([R,se])=>{var he;let ce=u.indexOf(R)+d;if(se===!1)return[ce,ce];{let Se=M(".hll",e).map(De=>u.indexOf(De.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Se),Math.max(ce,...Se)]}})),k=Zr(y).pipe(g(R=>R.startsWith(`__codelineno-${p}-`)));k.subscribe(R=>{let[,,se]=R.split("-"),ce=se.split(":").map(Se=>+Se-d+1);ce.length===1&&ce.push(ce[0]);for(let Se of M(".hll:not(.select)",e))Se.replaceWith(...Array.from(Se.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Se of he){let De=document.createElement("span");De.className="hll",De.append(...Array.from(Se.childNodes).slice(1)),Se.append(De)}}),k.pipe(Ee(1),xe(pe)).subscribe(R=>{if(R.includes(":")){let se=document.getElementById(R.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let je=fe(M('a[href^="#__codelineno"]',f)).pipe(J(R=>h(R,"click").pipe(O(se=>se.preventDefault()),m(()=>R)))).pipe(U(i),te(zn),m(([R,se])=>{let he=+j(`[id="${R.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Se=M(".hll",e).map(De=>+De.parentElement.id.split("-").pop());return[Math.min(he,...Se),Math.max(he,...Se)]}}));L(ee,je).subscribe(R=>{let se=`#__codelineno-${p}-`;R[0]===R[1]?se+=R[0]:se+=`${R[0]}:${R[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(qn.default.isSupported()&&(e.closest(".copy")||N("content.code.copy")&&!e.closest(".no-copy"))){let d=kn(a.id);s.push(d),N("content.tooltips")&&l.push(Xe(d,{viewport$}))}if(s.length){let d=$n();d.append(...s),a.insertBefore(d,e)}return Xa(e).pipe(O(d=>n.next(d)),A(()=>n.complete()),m(d=>P({ref:e},d)),Ne(L(...l).pipe(U(i))))});return N("content.lazy")?mt(e).pipe(g(n=>n),Ee(1),b(()=>o)):o}function Za(e,{target$:t,print$:r}){let o=!0;return L(t.pipe(m(n=>n.closest("details:not([open])")),g(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(g(n=>n||!o),O(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Yn(e,t){return H(()=>{let r=new T;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Za(e,t).pipe(O(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}var Bn=0;function es(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function ts(e,t){for(let r of M("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}for(let r of M("[name^=__], [for]",e))for(let o of["id","for","name"]){let n=r.getAttribute(o);n&&r.setAttribute(o,`${n}$preview_${Bn}`)}return Bn++,$(e)}function Gn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return y;if(!(N("navigation.instant.preview")||e.hasAttribute("data-preview")))return y;let o=z([Ye(e),it(e)]).pipe(m(([i,s])=>i||s),Y(),g(i=>i));return rt([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?$(s):y}),b(i=>xr(i).pipe(b(s=>ts(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=ue(s,i);return typeof a=="undefined"?y:$(es(a))})).pipe(b(i=>{let s=new F(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Vt(e,P({content$:s},t))}))}var Jn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var so,os=0;function ns(){return typeof mermaid=="undefined"||mermaid instanceof Element?At("https://wpbrowser.wptestkit.dev/assets/external/unpkg.com/mermaid@11/dist/mermaid.min.js"):$(void 0)}function Xn(e){return e.classList.remove("mermaid"),so||(so=ns().pipe(O(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Jn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),Z(1))),so.subscribe(()=>vo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${os++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),so.pipe(m(()=>({ref:e})))}var Zn=x("table");function ei(e){return e.replaceWith(Zn),Zn.replaceWith(jn(e)),$({ref:e})}function is(e){let t=e.find(r=>r.checked)||e[0];return L(...e.map(r=>h(r,"change").pipe(m(()=>j(`label[for="${r.id}"]`))))).pipe(Q(j(`label[for="${t.id}"]`)),m(r=>({active:r})))}function ti(e,{viewport$:t,target$:r}){let o=j(".tabbed-labels",e),n=M(":scope > input",e),i=no("prev");e.append(i);let s=no("next");return e.append(s),H(()=>{let a=new T,c=a.pipe(oe(),ae(!0));z([a,Le(e),mt(e)]).pipe(U(c),$e(1,ye)).subscribe({next([{active:p},l]){let f=Be(p),{width:u}=de(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ge(o),Le(o)]).pipe(U(c)).subscribe(([p,l])=>{let f=Ct(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),L(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(U(c)).subscribe(p=>{let{width:l}=de(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(U(c),g(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=j(`label[for="${p.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(U(c),g(f=>!(f.metaKey||f.ctrlKey)),O(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return N("content.tabs.link")&&a.pipe(Ie(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let v of M("[data-tabs]"))for(let S of M(":scope > input",v)){let X=j(`label[for="${S.id}"]`);if(X!==p&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),S.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(U(c)).subscribe(()=>{for(let p of M("audio, video",e))p.pause()}),is(n).pipe(O(p=>a.next(p)),A(()=>a.complete()),m(p=>P({ref:e},p)))}).pipe(et(pe))}function ri(e,t){let{viewport$:r,target$:o,print$:n}=t;return L(...M(".annotate:not(.highlight)",e).map(i=>Vn(i,{target$:o,print$:n})),...M("pre:not(.mermaid) > code",e).map(i=>Qn(i,{target$:o,print$:n})),...M("a:not([title])",e).map(i=>Gn(i,t)),...M("pre.mermaid",e).map(i=>Xn(i)),...M("table:not([class])",e).map(i=>ei(i)),...M("details",e).map(i=>Yn(i,{target$:o,print$:n})),...M("[data-tabs]",e).map(i=>ti(i,{viewport$:r,target$:o})),...M("[title]",e).filter(()=>N("content.tooltips")).map(i=>Xe(i,{viewport$:r})),...M(".footnote-ref",e).filter(()=>N("content.footnote.tooltips")).map(i=>Vt(i,{content$:new F(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function as(e,{alert$:t}){return t.pipe(b(r=>L($(!0),$(!1).pipe(nt(2e3))).pipe(m(o=>({message:r,active:o})))))}function oi(e,t){let r=j(".md-typeset",e);return H(()=>{let o=new T;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),as(e,t).pipe(O(n=>o.next(n)),A(()=>o.complete()),m(n=>P({ref:e},n)))})}var ss=0;function cs(e,t){document.body.append(e);let{width:r}=de(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ge(o):$({x:0,y:0}),i=L(Ye(t),it(t)).pipe(Y());return z([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Be(t),l=de(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ni(e){let t=e.title;if(!t.length)return y;let r=`__tooltip_${ss++}`,o=Nt(r,"inline"),n=j(".md-typeset",o);return n.innerHTML=t,H(()=>{let i=new T;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),L(i.pipe(g(({active:s})=>s)),i.pipe(Ae(250),g(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe($e(16,ye)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(gt(125,ye),g(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),cs(o,e).pipe(O(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))}).pipe(et(pe))}function ps({viewport$:e}){if(!N("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:n}})=>n),ot(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Y()),o=Je("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Y(),b(n=>n?r:$(!1)),Q(!1))}function ii(e,t){return H(()=>z([Le(e),ps(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Y((r,o)=>r.height===o.height&&r.hidden===o.hidden),Z(1))}function ai(e,{header$:t,main$:r}){return H(()=>{let o=new T,n=o.pipe(oe(),ae(!0));o.pipe(ne("active"),Pe(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(M("[title]",e)).pipe(g(()=>N("content.tooltips")),J(s=>ni(s)));return r.subscribe(o),t.pipe(U(n),m(s=>P({ref:e},s)),Ne(i.pipe(U(n))))})}function ls(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=de(e);return{active:o>=n}}),ne("active"))}function si(e,t){return H(()=>{let r=new T;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ue(".md-content h1");return typeof o=="undefined"?y:ls(o,t).pipe(O(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))})}function ci(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Y()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),ne("bottom"))));return z([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Y((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function ms(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return $(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),Z(1))}function pi(e){let t=M("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return H(()=>{let i=new T;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(xe(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),ms(t).pipe(U(n.pipe(Ie(1))),vt(),O(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))})}function li(e,{progress$:t}){return H(()=>{let r=new T;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(O(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}function mi(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function fs(e,t){let r=new Map;for(let o of M("url",e)){let n=j("loc",o),i=[mi(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of M("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(mi(new URL(a),t))}}return r}function Ht(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>fs(t,new URL(e))),ve(()=>$(new Map)),le())}function fi({document$:e}){let t=new Map;e.pipe(b(()=>M("link[rel=alternate]")),m(r=>new URL(r.href)),g(r=>!t.has(r.toString())),J(r=>Ht(r).pipe(m(o=>[r,o]),ve(()=>y)))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(g(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(`${f}/`));if(typeof n=="undefined")return y;let[i,s]=n,a=we();if(a.href.startsWith(i))return y;let c=Te(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),$(l)}}return y})).subscribe(r=>st(r,!0))}var co=Pt(ao());function us(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function ui({alert$:e}){co.default.isSupported()&&new F(t=>{new co.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||us(j(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(O(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function di(e,t){if(!(e.target instanceof Element))return y;let r=e.target.closest("a");if(r===null)return y;if(r.target||e.metaKey||e.ctrlKey)return y;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),$(r)):y}function hi(e){let t=new Map;for(let r of M(":scope > *",e.head))t.set(r.outerHTML,r);return t}function bi(e){for(let t of M("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return $(e)}function ds(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...N("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=ue(o),i=ue(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=hi(document);for(let[o,n]of hi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return Ke(M("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new F(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),y}),oe(),ae(document))}function vi({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return y;$(document).subscribe(bi);let n=h(document.body,"click").pipe(Pe(e),b(([a,c])=>di(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(we),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),L(n,i).subscribe(t);let s=t.pipe(ne("pathname"),b(a=>xr(a,{progress$:o}).pipe(ve(()=>(st(a,!0),y)))),b(bi),b(ds),le());return L(s.pipe(te(t,(a,c)=>c)),s.pipe(b(()=>t),ne("pathname"),b(()=>t),ne("hash")),t.pipe(Y((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),O(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",vn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(ne("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),N("navigation.instant.prefetch")&&L(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(Pe(e),b(([a,c])=>di(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),Ee(1))})).subscribe(a=>a.remove()),s}var gi=Pt(ro());function yi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,gi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function qt(e){return e.type===1}function Sr(e){return e.type===3}function xi(e,t){let r=Ln(e);return L($(location.protocol!=="file:"),Je("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:N("search.suggest")}}})),r}function Ei({document$:e}){let t=Te(),r=ze(new URL("../versions.json",t.base)).pipe(ve(()=>y)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(g(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?y:(i.preventDefault(),$(c))}}return y}),b(i=>Ht(new URL(i)).pipe(m(s=>{let c=we().href.replace(t.base,i);return s.has(c.split("#")[0])?new URL(c):new URL(i)})))))).subscribe(n=>st(n,!0)),z([r,o]).subscribe(([n,i])=>{j(".md-header__topic").appendChild(Dn(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function vs(e,{worker$:t}){let{searchParams:r}=we();r.has("q")&&(at("search",!0),e.value=r.get("q"),e.focus(),Je("search").pipe(Re(i=>!i)).subscribe(()=>{let i=we();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ye(e),n=L(t.pipe(Re(qt)),h(e,"keyup"),o).pipe(m(()=>e.value),Y());return z([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),Z(1))}function wi(e,{worker$:t}){let r=new T,o=r.pipe(oe(),ae(!0));z([t.pipe(Re(qt)),r],(i,s)=>s).pipe(ne("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(ne("focus")).subscribe(({focus:i})=>{i&&at("search",i)}),h(e.form,"reset").pipe(U(o)).subscribe(()=>e.focus());let n=j("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),vs(e,{worker$:t}).pipe(O(i=>r.next(i)),A(()=>r.complete()),m(i=>P({ref:e},i)),Z(1))}function Ti(e,{worker$:t,query$:r}){let o=new T,n=fn(e.parentElement).pipe(g(Boolean)),i=e.parentElement,s=j(":scope > :first-child",e),a=j(":scope > :last-child",e);Je("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(qt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(O(()=>a.innerHTML=""),b(({items:l})=>L($(...l.slice(0,10)),$(...l.slice(10)).pipe(ot(4),Xr(n),b(([f])=>f)))),m(In),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=ue("details",l);return typeof f=="undefined"?y:h(f,"toggle").pipe(U(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(g(Sr),m(({data:l})=>l)).pipe(O(l=>o.next(l)),A(()=>o.complete()),m(l=>P({ref:e},l)))}function gs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=we();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Si(e,t){let r=new T,o=r.pipe(oe(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(U(o)).subscribe(n=>n.preventDefault()),gs(e,t).pipe(O(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))}function Oi(e,{worker$:t,keyboard$:r}){let o=new T,n=Ce("search-query"),i=L(h(n,"keydown"),h(n,"focus")).pipe(xe(pe),m(()=>n.value),Y());return o.pipe(Pe(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(g(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(g(Sr),m(({data:a})=>a)).pipe(O(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Li(e,{index$:t,keyboard$:r}){let o=Te();try{let n=xi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(g(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>at("search",!1)),r.pipe(g(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of M(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":at("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...M(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(g(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=wi(i,{worker$:n});return L(a,Ti(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>Si(c,{query$:a})),...me("search-suggest",e).map(c=>Oi(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,tt}}function Mi(e,{index$:t,location$:r}){return z([t,r.pipe(Q(we()),g(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>yi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=x("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function ys(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Y((i,s)=>i.height===s.height&&i.locked===s.locked))}function po(e,o){var n=o,{header$:t}=n,r=bo(n,["header$"]);let i=j(".md-sidebar__scrollwrap",e),{y:s}=Be(i);return H(()=>{let a=new T,c=a.pipe(oe(),ae(!0)),p=a.pipe($e(0,ye));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of M(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2})}}}),fe(M("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(xe(pe),m(()=>l),U(c)))).subscribe(l=>{let f=j(`[id="${l.htmlFor}"]`);j(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),N("content.tooltips")&&fe(M("abbr[title]",e)).pipe(J(l=>Xe(l,{viewport$})),U(c)).subscribe(),ys(e,r).pipe(O(l=>a.next(l)),A(()=>a.complete()),m(l=>P({ref:e},l)))})}function _i(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return rt(ze(`${r}/releases/latest`).pipe(ve(()=>y),m(o=>({version:o.tag_name})),Qe({})),ze(r).pipe(ve(()=>y),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Qe({}))).pipe(m(([o,n])=>P(P({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return ze(r).pipe(m(o=>({repositories:o.public_repos})),Qe({}))}}function Ai(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return rt(ze(`${r}/releases/permalink/latest`).pipe(ve(()=>y),m(({tag_name:o})=>({version:o})),Qe({})),ze(r).pipe(ve(()=>y),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Qe({}))).pipe(m(([o,n])=>P(P({},o),n)))}function Ci(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return _i(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return Ai(r,o)}return y}var xs;function Es(e){return xs||(xs=H(()=>{let t=__md_get("__source",sessionStorage);if(t)return $(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return y}return Ci(e.href).pipe(O(o=>__md_set("__source",o,sessionStorage)))}).pipe(ve(()=>y),g(t=>Object.keys(t).length>0),m(t=>({facts:t})),Z(1)))}function ki(e){let t=j(":scope > :last-child",e);return H(()=>{let r=new T;return r.subscribe(({facts:o})=>{t.appendChild(Fn(o)),t.classList.add("md-source__repository--active")}),Es(e).pipe(O(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function ws(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),ne("hidden"))}function Hi(e,t){return H(()=>{let r=new T;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(N("navigation.tabs.sticky")?$({hidden:!1}):ws(e,t)).pipe(O(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Ts(e,{viewport$:t,header$:r}){let o=new Map,n=M(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ue(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(ne("height"),m(({height:a})=>{let c=Ce("main"),p=j(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(ne("height"),b(a=>H(()=>{let c=[];return $([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),Pe(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let v=u+d.height>=Math.floor(a.height);for(;f.length;){let[,S]=f[0];if(S-p=u&&!v)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Y((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),Q({prev:[],next:[]}),ot(2,1),m(([a,c])=>a.prev.length{let i=new T,s=i.pipe(oe(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),N("toc.follow")){let a=L(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(g(({prev:c})=>c.length>0),Pe(o.pipe(xe(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return N("navigation.tracking")&&t.pipe(U(s),ne("offset"),Ae(250),Ie(1),U(n.pipe(Ie(1))),vt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=we(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Ts(e,{viewport$:t,header$:r}).pipe(O(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ss(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),ot(2,1),m(([s,a])=>s>a&&a>0),Y()),i=r.pipe(m(({active:s})=>s));return z([i,n]).pipe(m(([s,a])=>!(s&&a)),Y(),U(o.pipe(Ie(1))),ae(!0),vt({delay:250}),m(s=>({hidden:s})))}function Pi(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new T,s=i.pipe(oe(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(U(s),ne("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Ss(e,{viewport$:t,main$:o,target$:n}).pipe(O(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))}function Ri({document$:e,viewport$:t}){e.pipe(b(()=>M(".md-ellipsis")),J(r=>mt(r).pipe(U(e.pipe(Ie(1))),g(o=>o),m(()=>r),Ee(1))),g(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,N("content.tooltips")?Xe(n,{viewport$:t}).pipe(U(e.pipe(Ie(1))),A(()=>n.removeAttribute("title"))):y})).subscribe(),N("content.tooltips")&&e.pipe(b(()=>M(".md-status")),J(r=>Xe(r,{viewport$:t}))).subscribe()}function Ii({document$:e,tablet$:t}){e.pipe(b(()=>M(".md-toggle--indeterminate")),O(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Os(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Fi({document$:e}){e.pipe(b(()=>M("[data-md-scrollfix]")),O(t=>t.removeAttribute("data-md-scrollfix")),g(Os),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function ji({viewport$:e,tablet$:t}){z([Je("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>$(r).pipe(nt(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ls(){return location.protocol==="file:"?At(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),Z(1)):ze(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ct=nn(),Qt=hn(),$t=gn(Qt),lo=dn(),ke=On(),Lr=Wt("(min-width: 960px)"),Ui=Wt("(min-width: 1220px)"),Wi=yn(),Or=Te(),Ni=document.forms.namedItem("search")?Ls():tt,mo=new T;ui({alert$:mo});fi({document$:ct});var fo=new T,Vi=Ht(Or.base);N("navigation.instant")&&vi({sitemap$:Vi,location$:Qt,viewport$:ke,progress$:fo}).subscribe(ct);var Di;((Di=Or.version)==null?void 0:Di.provider)==="mike"&&Ei({document$:ct});L(Qt,$t).pipe(nt(125)).subscribe(()=>{at("drawer",!1),at("search",!1)});lo.pipe(g(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ue("link[rel=prev]");typeof t!="undefined"&&st(t);break;case"n":case".":let r=ue("link[rel=next]");typeof r!="undefined"&&st(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});Ri({viewport$:ke,document$:ct});Ii({document$:ct,tablet$:Lr});Fi({document$:ct});ji({viewport$:ke,tablet$:Lr});var ft=ii(Ce("header"),{viewport$:ke}),Kt=ct.pipe(m(()=>Ce("main")),b(e=>ci(e,{viewport$:ke,header$:ft})),Z(1)),Ms=L(...me("consent").map(e=>_n(e,{target$:$t})),...me("dialog").map(e=>oi(e,{alert$:mo})),...me("header").map(e=>ai(e,{viewport$:ke,header$:ft,main$:Kt})),...me("palette").map(e=>pi(e)),...me("progress").map(e=>li(e,{progress$:fo})),...me("search").map(e=>Li(e,{index$:Ni,keyboard$:lo})),...me("source").map(e=>ki(e))),_s=H(()=>L(...me("announce").map(e=>Mn(e)),...me("content").map(e=>ri(e,{sitemap$:Vi,viewport$:ke,target$:$t,print$:Wi})),...me("content").map(e=>N("search.highlight")?Mi(e,{index$:Ni,location$:Qt}):y),...me("header-title").map(e=>si(e,{viewport$:ke,header$:ft})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(Ui,()=>po(e,{viewport$:ke,header$:ft,main$:Kt})):eo(Lr,()=>po(e,{viewport$:ke,header$:ft,main$:Kt}))),...me("tabs").map(e=>Hi(e,{viewport$:ke,header$:ft})),...me("toc").map(e=>$i(e,{viewport$:ke,header$:ft,main$:Kt,target$:$t})),...me("top").map(e=>Pi(e,{viewport$:ke,header$:ft,main$:Kt,target$:$t})))),zi=ct.pipe(b(()=>_s),Ne(Ms),Z(1));zi.subscribe();window.document$=ct;window.location$=Qt;window.target$=$t;window.keyboard$=lo;window.viewport$=ke;window.tablet$=Lr;window.screen$=Ui;window.print$=Wi;window.alert$=mo;window.progress$=fo;window.component$=zi;})(); diff --git a/assets/javascripts/lunr/min/lunr.ar.min.js b/assets/javascripts/lunr/min/lunr.ar.min.js new file mode 100644 index 000000000..9b06c26c1 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ar.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ar=function(){this.pipeline.reset(),this.pipeline.add(e.ar.trimmer,e.ar.stopWordFilter,e.ar.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ar.stemmer))},e.ar.wordCharacters="ء-ٛٱـ",e.ar.trimmer=e.trimmerSupport.generateTrimmer(e.ar.wordCharacters),e.Pipeline.registerFunction(e.ar.trimmer,"trimmer-ar"),e.ar.stemmer=function(){var e=this;return e.result=!1,e.preRemoved=!1,e.sufRemoved=!1,e.pre={pre1:"ف ك ب و س ل ن ا ي ت",pre2:"ال لل",pre3:"بال وال فال تال كال ولل",pre4:"فبال كبال وبال وكال"},e.suf={suf1:"ه ك ت ن ا ي",suf2:"نك نه ها وك يا اه ون ين تن تم نا وا ان كم كن ني نن ما هم هن تك ته ات يه",suf3:"تين كهم نيه نهم ونه وها يهم ونا ونك وني وهم تكم تنا تها تني تهم كما كها ناه نكم هنا تان يها",suf4:"كموه ناها ونني ونهم تكما تموه تكاه كماه ناكم ناهم نيها وننا"},e.patterns=JSON.parse('{"pt43":[{"pt":[{"c":"ا","l":1}]},{"pt":[{"c":"ا,ت,ن,ي","l":0}],"mPt":[{"c":"ف","l":0,"m":1},{"c":"ع","l":1,"m":2},{"c":"ل","l":2,"m":3}]},{"pt":[{"c":"و","l":2}],"mPt":[{"c":"ف","l":0,"m":0},{"c":"ع","l":1,"m":1},{"c":"ل","l":2,"m":3}]},{"pt":[{"c":"ا","l":2}]},{"pt":[{"c":"ي","l":2}],"mPt":[{"c":"ف","l":0,"m":0},{"c":"ع","l":1,"m":1},{"c":"ا","l":2},{"c":"ل","l":3,"m":3}]},{"pt":[{"c":"م","l":0}]}],"pt53":[{"pt":[{"c":"ت","l":0},{"c":"ا","l":2}]},{"pt":[{"c":"ا,ن,ت,ي","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":0},{"c":"ا","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":3},{"c":"ل","l":3,"m":4},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":0},{"c":"ا","l":3}],"mPt":[{"c":"ف","l":0,"m":1},{"c":"ع","l":1,"m":2},{"c":"ل","l":2,"m":4}]},{"pt":[{"c":"ا","l":3},{"c":"ن","l":4}]},{"pt":[{"c":"ت","l":0},{"c":"ي","l":3}]},{"pt":[{"c":"م","l":0},{"c":"و","l":3}]},{"pt":[{"c":"ا","l":1},{"c":"و","l":3}]},{"pt":[{"c":"و","l":1},{"c":"ا","l":2}]},{"pt":[{"c":"م","l":0},{"c":"ا","l":3}]},{"pt":[{"c":"م","l":0},{"c":"ي","l":3}]},{"pt":[{"c":"ا","l":2},{"c":"ن","l":3}]},{"pt":[{"c":"م","l":0},{"c":"ن","l":1}],"mPt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ف","l":2,"m":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"م","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"م","l":0},{"c":"ا","l":2}]},{"pt":[{"c":"م","l":1},{"c":"ا","l":3}]},{"pt":[{"c":"ي,ت,ا,ن","l":0},{"c":"ت","l":1}],"mPt":[{"c":"ف","l":0,"m":2},{"c":"ع","l":1,"m":3},{"c":"ا","l":2},{"c":"ل","l":3,"m":4}]},{"pt":[{"c":"ت,ي,ا,ن","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":2},{"c":"ي","l":3}]},{"pt":[{"c":"ا,ي,ت,ن","l":0},{"c":"ن","l":1}],"mPt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ف","l":2,"m":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":3},{"c":"ء","l":4}]}],"pt63":[{"pt":[{"c":"ا","l":0},{"c":"ت","l":2},{"c":"ا","l":4}]},{"pt":[{"c":"ا,ت,ن,ي","l":0},{"c":"س","l":1},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ف","l":3,"m":3},{"c":"ع","l":4,"m":4},{"c":"ا","l":5},{"c":"ل","l":6,"m":5}]},{"pt":[{"c":"ا,ن,ت,ي","l":0},{"c":"و","l":3}]},{"pt":[{"c":"م","l":0},{"c":"س","l":1},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ف","l":3,"m":3},{"c":"ع","l":4,"m":4},{"c":"ا","l":5},{"c":"ل","l":6,"m":5}]},{"pt":[{"c":"ي","l":1},{"c":"ي","l":3},{"c":"ا","l":4},{"c":"ء","l":5}]},{"pt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ا","l":4}]}],"pt54":[{"pt":[{"c":"ت","l":0}]},{"pt":[{"c":"ا,ي,ت,ن","l":0}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":2},{"c":"ل","l":3,"m":3},{"c":"ر","l":4,"m":4},{"c":"ا","l":5},{"c":"ر","l":6,"m":4}]},{"pt":[{"c":"م","l":0}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":2},{"c":"ل","l":3,"m":3},{"c":"ر","l":4,"m":4},{"c":"ا","l":5},{"c":"ر","l":6,"m":4}]},{"pt":[{"c":"ا","l":2}]},{"pt":[{"c":"ا","l":0},{"c":"ن","l":2}]}],"pt64":[{"pt":[{"c":"ا","l":0},{"c":"ا","l":4}]},{"pt":[{"c":"م","l":0},{"c":"ت","l":1}]}],"pt73":[{"pt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ا","l":5}]}],"pt75":[{"pt":[{"c":"ا","l":0},{"c":"ا","l":5}]}]}'),e.execArray=["cleanWord","removeDiacritics","cleanAlef","removeStopWords","normalizeHamzaAndAlef","removeStartWaw","removePre432","removeEndTaa","wordCheck"],e.stem=function(){var r=0;for(e.result=!1,e.preRemoved=!1,e.sufRemoved=!1;r=0)return!0},e.normalizeHamzaAndAlef=function(){return e.word=e.word.replace("ؤ","ء"),e.word=e.word.replace("ئ","ء"),e.word=e.word.replace(/([\u0627])\1+/gi,"ا"),!1},e.removeEndTaa=function(){return!(e.word.length>2)||(e.word=e.word.replace(/[\u0627]$/,""),e.word=e.word.replace("ة",""),!1)},e.removeStartWaw=function(){return e.word.length>3&&"و"==e.word[0]&&"و"==e.word[1]&&(e.word=e.word.slice(1)),!1},e.removePre432=function(){var r=e.word;if(e.word.length>=7){var t=new RegExp("^("+e.pre.pre4.split(" ").join("|")+")");e.word=e.word.replace(t,"")}if(e.word==r&&e.word.length>=6){var c=new RegExp("^("+e.pre.pre3.split(" ").join("|")+")");e.word=e.word.replace(c,"")}if(e.word==r&&e.word.length>=5){var l=new RegExp("^("+e.pre.pre2.split(" ").join("|")+")");e.word=e.word.replace(l,"")}return r!=e.word&&(e.preRemoved=!0),!1},e.patternCheck=function(r){for(var t=0;t3){var t=new RegExp("^("+e.pre.pre1.split(" ").join("|")+")");e.word=e.word.replace(t,"")}return r!=e.word&&(e.preRemoved=!0),!1},e.removeSuf1=function(){var r=e.word;if(0==e.sufRemoved&&e.word.length>3){var t=new RegExp("("+e.suf.suf1.split(" ").join("|")+")$");e.word=e.word.replace(t,"")}return r!=e.word&&(e.sufRemoved=!0),!1},e.removeSuf432=function(){var r=e.word;if(e.word.length>=6){var t=new RegExp("("+e.suf.suf4.split(" ").join("|")+")$");e.word=e.word.replace(t,"")}if(e.word==r&&e.word.length>=5){var c=new RegExp("("+e.suf.suf3.split(" ").join("|")+")$");e.word=e.word.replace(c,"")}if(e.word==r&&e.word.length>=4){var l=new RegExp("("+e.suf.suf2.split(" ").join("|")+")$");e.word=e.word.replace(l,"")}return r!=e.word&&(e.sufRemoved=!0),!1},e.wordCheck=function(){for(var r=(e.word,[e.removeSuf432,e.removeSuf1,e.removePre1]),t=0,c=!1;e.word.length>=7&&!e.result&&t=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.de.min.js b/assets/javascripts/lunr/min/lunr.de.min.js new file mode 100644 index 000000000..f3b5c108c --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.de.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `German` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.du.min.js b/assets/javascripts/lunr/min/lunr.du.min.js new file mode 100644 index 000000000..49a0f3f0a --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.du.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Dutch` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.el.min.js b/assets/javascripts/lunr/min/lunr.el.min.js new file mode 100644 index 000000000..ace017bd6 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.el.min.js @@ -0,0 +1 @@ +!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.el=function(){this.pipeline.reset(),void 0===this.searchPipeline&&this.pipeline.add(e.el.trimmer,e.el.normilizer),this.pipeline.add(e.el.stopWordFilter,e.el.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.el.stemmer))},e.el.wordCharacters="A-Za-zΑαΒβΓγΔδΕεΖζΗηΘθΙιΚκΛλΜμΝνΞξΟοΠπΡρΣσςΤτΥυΦφΧχΨψΩωΆάΈέΉήΊίΌόΎύΏώΪΐΫΰΐΰ",e.el.trimmer=e.trimmerSupport.generateTrimmer(e.el.wordCharacters),e.Pipeline.registerFunction(e.el.trimmer,"trimmer-el"),e.el.stemmer=function(){function e(e){return s.test(e)}function t(e){return/[ΑΕΗΙΟΥΩ]$/.test(e)}function r(e){return/[ΑΕΗΙΟΩ]$/.test(e)}function n(n){var s=n;if(n.length<3)return s;if(!e(n))return s;if(i.indexOf(n)>=0)return s;var u=new RegExp("(.*)("+Object.keys(l).join("|")+")$"),o=u.exec(s);return null!==o&&(s=o[1]+l[o[2]]),null!==(o=/^(.+?)(ΑΔΕΣ|ΑΔΩΝ)$/.exec(s))&&(s=o[1],/(ΟΚ|ΜΑΜ|ΜΑΝ|ΜΠΑΜΠ|ΠΑΤΕΡ|ΓΙΑΓΙ|ΝΤΑΝΤ|ΚΥΡ|ΘΕΙ|ΠΕΘΕΡ|ΜΟΥΣΑΜ|ΚΑΠΛΑΜ|ΠΑΡ|ΨΑΡ|ΤΖΟΥΡ|ΤΑΜΠΟΥΡ|ΓΑΛΑΤ|ΦΑΦΛΑΤ)$/.test(o[1])||(s+="ΑΔ")),null!==(o=/^(.+?)(ΕΔΕΣ|ΕΔΩΝ)$/.exec(s))&&(s=o[1],/(ΟΠ|ΙΠ|ΕΜΠ|ΥΠ|ΓΗΠ|ΔΑΠ|ΚΡΑΣΠ|ΜΙΛ)$/.test(o[1])&&(s+="ΕΔ")),null!==(o=/^(.+?)(ΟΥΔΕΣ|ΟΥΔΩΝ)$/.exec(s))&&(s=o[1],/(ΑΡΚ|ΚΑΛΙΑΚ|ΠΕΤΑΛ|ΛΙΧ|ΠΛΕΞ|ΣΚ|Σ|ΦΛ|ΦΡ|ΒΕΛ|ΛΟΥΛ|ΧΝ|ΣΠ|ΤΡΑΓ|ΦΕ)$/.test(o[1])&&(s+="ΟΥΔ")),null!==(o=/^(.+?)(ΕΩΣ|ΕΩΝ|ΕΑΣ|ΕΑ)$/.exec(s))&&(s=o[1],/^(Θ|Δ|ΕΛ|ΓΑΛ|Ν|Π|ΙΔ|ΠΑΡ|ΣΤΕΡ|ΟΡΦ|ΑΝΔΡ|ΑΝΤΡ)$/.test(o[1])&&(s+="Ε")),null!==(o=/^(.+?)(ΕΙΟ|ΕΙΟΣ|ΕΙΟΙ|ΕΙΑ|ΕΙΑΣ|ΕΙΕΣ|ΕΙΟΥ|ΕΙΟΥΣ|ΕΙΩΝ)$/.exec(s))&&o[1].length>4&&(s=o[1]),null!==(o=/^(.+?)(ΙΟΥΣ|ΙΑΣ|ΙΕΣ|ΙΟΣ|ΙΟΥ|ΙΟΙ|ΙΩΝ|ΙΟΝ|ΙΑ|ΙΟ)$/.exec(s))&&(s=o[1],(t(s)||s.length<2||/^(ΑΓ|ΑΓΓΕΛ|ΑΓΡ|ΑΕΡ|ΑΘΛ|ΑΚΟΥΣ|ΑΞ|ΑΣ|Β|ΒΙΒΛ|ΒΥΤ|Γ|ΓΙΑΓ|ΓΩΝ|Δ|ΔΑΝ|ΔΗΛ|ΔΗΜ|ΔΟΚΙΜ|ΕΛ|ΖΑΧΑΡ|ΗΛ|ΗΠ|ΙΔ|ΙΣΚ|ΙΣΤ|ΙΟΝ|ΙΩΝ|ΚΙΜΩΛ|ΚΟΛΟΝ|ΚΟΡ|ΚΤΗΡ|ΚΥΡ|ΛΑΓ|ΛΟΓ|ΜΑΓ|ΜΠΑΝ|ΜΠΡ|ΝΑΥΤ|ΝΟΤ|ΟΠΑΛ|ΟΞ|ΟΡ|ΟΣ|ΠΑΝΑΓ|ΠΑΤΡ|ΠΗΛ|ΠΗΝ|ΠΛΑΙΣ|ΠΟΝΤ|ΡΑΔ|ΡΟΔ|ΣΚ|ΣΚΟΡΠ|ΣΟΥΝ|ΣΠΑΝ|ΣΤΑΔ|ΣΥΡ|ΤΗΛ|ΤΙΜ|ΤΟΚ|ΤΟΠ|ΤΡΟΧ|ΦΙΛ|ΦΩΤ|Χ|ΧΙΛ|ΧΡΩΜ|ΧΩΡ)$/.test(o[1]))&&(s+="Ι"),/^(ΠΑΛ)$/.test(o[1])&&(s+="ΑΙ")),null!==(o=/^(.+?)(ΙΚΟΣ|ΙΚΟΝ|ΙΚΕΙΣ|ΙΚΟΙ|ΙΚΕΣ|ΙΚΟΥΣ|ΙΚΗ|ΙΚΗΣ|ΙΚΟ|ΙΚΑ|ΙΚΟΥ|ΙΚΩΝ|ΙΚΩΣ)$/.exec(s))&&(s=o[1],(t(s)||/^(ΑΔ|ΑΛ|ΑΜΑΝ|ΑΜΕΡ|ΑΜΜΟΧΑΛ|ΑΝΗΘ|ΑΝΤΙΔ|ΑΠΛ|ΑΤΤ|ΑΦΡ|ΒΑΣ|ΒΡΩΜ|ΓΕΝ|ΓΕΡ|Δ|ΔΙΚΑΝ|ΔΥΤ|ΕΙΔ|ΕΝΔ|ΕΞΩΔ|ΗΘ|ΘΕΤ|ΚΑΛΛΙΝ|ΚΑΛΠ|ΚΑΤΑΔ|ΚΟΥΖΙΝ|ΚΡ|ΚΩΔ|ΛΟΓ|Μ|ΜΕΡ|ΜΟΝΑΔ|ΜΟΥΛ|ΜΟΥΣ|ΜΠΑΓΙΑΤ|ΜΠΑΝ|ΜΠΟΛ|ΜΠΟΣ|ΜΥΣΤ|Ν|ΝΙΤ|ΞΙΚ|ΟΠΤ|ΠΑΝ|ΠΕΤΣ|ΠΙΚΑΝΤ|ΠΙΤΣ|ΠΛΑΣΤ|ΠΛΙΑΤΣ|ΠΟΝΤ|ΠΟΣΤΕΛΝ|ΠΡΩΤΟΔ|ΣΕΡΤ|ΣΗΜΑΝΤ|ΣΤΑΤ|ΣΥΝΑΔ|ΣΥΝΟΜΗΛ|ΤΕΛ|ΤΕΧΝ|ΤΡΟΠ|ΤΣΑΜ|ΥΠΟΔ|Φ|ΦΙΛΟΝ|ΦΥΛΟΔ|ΦΥΣ|ΧΑΣ)$/.test(o[1])||/(ΦΟΙΝ)$/.test(o[1]))&&(s+="ΙΚ")),"ΑΓΑΜΕ"===s&&(s="ΑΓΑΜ"),null!==(o=/^(.+?)(ΑΓΑΜΕ|ΗΣΑΜΕ|ΟΥΣΑΜΕ|ΗΚΑΜΕ|ΗΘΗΚΑΜΕ)$/.exec(s))&&(s=o[1]),null!==(o=/^(.+?)(ΑΜΕ)$/.exec(s))&&(s=o[1],/^(ΑΝΑΠ|ΑΠΟΘ|ΑΠΟΚ|ΑΠΟΣΤ|ΒΟΥΒ|ΞΕΘ|ΟΥΛ|ΠΕΘ|ΠΙΚΡ|ΠΟΤ|ΣΙΧ|Χ)$/.test(o[1])&&(s+="ΑΜ")),null!==(o=/^(.+?)(ΑΓΑΝΕ|ΗΣΑΝΕ|ΟΥΣΑΝΕ|ΙΟΝΤΑΝΕ|ΙΟΤΑΝΕ|ΙΟΥΝΤΑΝΕ|ΟΝΤΑΝΕ|ΟΤΑΝΕ|ΟΥΝΤΑΝΕ|ΗΚΑΝΕ|ΗΘΗΚΑΝΕ)$/.exec(s))&&(s=o[1],/^(ΤΡ|ΤΣ)$/.test(o[1])&&(s+="ΑΓΑΝ")),null!==(o=/^(.+?)(ΑΝΕ)$/.exec(s))&&(s=o[1],(r(s)||/^(ΒΕΤΕΡ|ΒΟΥΛΚ|ΒΡΑΧΜ|Γ|ΔΡΑΔΟΥΜ|Θ|ΚΑΛΠΟΥΖ|ΚΑΣΤΕΛ|ΚΟΡΜΟΡ|ΛΑΟΠΛ|ΜΩΑΜΕΘ|Μ|ΜΟΥΣΟΥΛΜΑΝ|ΟΥΛ|Π|ΠΕΛΕΚ|ΠΛ|ΠΟΛΙΣ|ΠΟΡΤΟΛ|ΣΑΡΑΚΑΤΣ|ΣΟΥΛΤ|ΤΣΑΡΛΑΤ|ΟΡΦ|ΤΣΙΓΓ|ΤΣΟΠ|ΦΩΤΟΣΤΕΦ|Χ|ΨΥΧΟΠΛ|ΑΓ|ΟΡΦ|ΓΑΛ|ΓΕΡ|ΔΕΚ|ΔΙΠΛ|ΑΜΕΡΙΚΑΝ|ΟΥΡ|ΠΙΘ|ΠΟΥΡΙΤ|Σ|ΖΩΝΤ|ΙΚ|ΚΑΣΤ|ΚΟΠ|ΛΙΧ|ΛΟΥΘΗΡ|ΜΑΙΝΤ|ΜΕΛ|ΣΙΓ|ΣΠ|ΣΤΕΓ|ΤΡΑΓ|ΤΣΑΓ|Φ|ΕΡ|ΑΔΑΠ|ΑΘΙΓΓ|ΑΜΗΧ|ΑΝΙΚ|ΑΝΟΡΓ|ΑΠΗΓ|ΑΠΙΘ|ΑΤΣΙΓΓ|ΒΑΣ|ΒΑΣΚ|ΒΑΘΥΓΑΛ|ΒΙΟΜΗΧ|ΒΡΑΧΥΚ|ΔΙΑΤ|ΔΙΑΦ|ΕΝΟΡΓ|ΘΥΣ|ΚΑΠΝΟΒΙΟΜΗΧ|ΚΑΤΑΓΑΛ|ΚΛΙΒ|ΚΟΙΛΑΡΦ|ΛΙΒ|ΜΕΓΛΟΒΙΟΜΗΧ|ΜΙΚΡΟΒΙΟΜΗΧ|ΝΤΑΒ|ΞΗΡΟΚΛΙΒ|ΟΛΙΓΟΔΑΜ|ΟΛΟΓΑΛ|ΠΕΝΤΑΡΦ|ΠΕΡΗΦ|ΠΕΡΙΤΡ|ΠΛΑΤ|ΠΟΛΥΔΑΠ|ΠΟΛΥΜΗΧ|ΣΤΕΦ|ΤΑΒ|ΤΕΤ|ΥΠΕΡΗΦ|ΥΠΟΚΟΠ|ΧΑΜΗΛΟΔΑΠ|ΨΗΛΟΤΑΒ)$/.test(o[1]))&&(s+="ΑΝ")),null!==(o=/^(.+?)(ΗΣΕΤΕ)$/.exec(s))&&(s=o[1]),null!==(o=/^(.+?)(ΕΤΕ)$/.exec(s))&&(s=o[1],(r(s)||/(ΟΔ|ΑΙΡ|ΦΟΡ|ΤΑΘ|ΔΙΑΘ|ΣΧ|ΕΝΔ|ΕΥΡ|ΤΙΘ|ΥΠΕΡΘ|ΡΑΘ|ΕΝΘ|ΡΟΘ|ΣΘ|ΠΥΡ|ΑΙΝ|ΣΥΝΔ|ΣΥΝ|ΣΥΝΘ|ΧΩΡ|ΠΟΝ|ΒΡ|ΚΑΘ|ΕΥΘ|ΕΚΘ|ΝΕΤ|ΡΟΝ|ΑΡΚ|ΒΑΡ|ΒΟΛ|ΩΦΕΛ)$/.test(o[1])||/^(ΑΒΑΡ|ΒΕΝ|ΕΝΑΡ|ΑΒΡ|ΑΔ|ΑΘ|ΑΝ|ΑΠΛ|ΒΑΡΟΝ|ΝΤΡ|ΣΚ|ΚΟΠ|ΜΠΟΡ|ΝΙΦ|ΠΑΓ|ΠΑΡΑΚΑΛ|ΣΕΡΠ|ΣΚΕΛ|ΣΥΡΦ|ΤΟΚ|Υ|Δ|ΕΜ|ΘΑΡΡ|Θ)$/.test(o[1]))&&(s+="ΕΤ")),null!==(o=/^(.+?)(ΟΝΤΑΣ|ΩΝΤΑΣ)$/.exec(s))&&(s=o[1],/^ΑΡΧ$/.test(o[1])&&(s+="ΟΝΤ"),/ΚΡΕ$/.test(o[1])&&(s+="ΩΝΤ")),null!==(o=/^(.+?)(ΟΜΑΣΤΕ|ΙΟΜΑΣΤΕ)$/.exec(s))&&(s=o[1],/^ΟΝ$/.test(o[1])&&(s+="ΟΜΑΣΤ")),null!==(o=/^(.+?)(ΙΕΣΤΕ)$/.exec(s))&&(s=o[1],/^(Π|ΑΠ|ΣΥΜΠ|ΑΣΥΜΠ|ΑΚΑΤΑΠ|ΑΜΕΤΑΜΦ)$/.test(o[1])&&(s+="ΙΕΣΤ")),null!==(o=/^(.+?)(ΕΣΤΕ)$/.exec(s))&&(s=o[1],/^(ΑΛ|ΑΡ|ΕΚΤΕΛ|Ζ|Μ|Ξ|ΠΑΡΑΚΑΛ|ΠΡΟ|ΝΙΣ)$/.test(o[1])&&(s+="ΕΣΤ")),null!==(o=/^(.+?)(ΗΘΗΚΑ|ΗΘΗΚΕΣ|ΗΘΗΚΕ)$/.exec(s))&&(s=o[1]),null!==(o=/^(.+?)(ΗΚΑ|ΗΚΕΣ|ΗΚΕ)$/.exec(s))&&(s=o[1],(/(ΣΚΩΛ|ΣΚΟΥΛ|ΝΑΡΘ|ΣΦ|ΟΘ|ΠΙΘ)$/.test(o[1])||/^(ΔΙΑΘ|Θ|ΠΑΡΑΚΑΤΑΘ|ΠΡΟΣΘ|ΣΥΝΘ)$/.test(o[1]))&&(s+="ΗΚ")),null!==(o=/^(.+?)(ΟΥΣΑ|ΟΥΣΕΣ|ΟΥΣΕ)$/.exec(s))&&(s=o[1],(t(s)||/^(ΦΑΡΜΑΚ|ΧΑΔ|ΑΓΚ|ΑΝΑΡΡ|ΒΡΟΜ|ΕΚΛΙΠ|ΛΑΜΠΙΔ|ΛΕΧ|Μ|ΠΑΤ|Ρ|Λ|ΜΕΔ|ΜΕΣΑΖ|ΥΠΟΤΕΙΝ|ΑΜ|ΑΙΘ|ΑΝΗΚ|ΔΕΣΠΟΖ|ΕΝΔΙΑΦΕΡ)$/.test(o[1])||/(ΠΟΔΑΡ|ΒΛΕΠ|ΠΑΝΤΑΧ|ΦΡΥΔ|ΜΑΝΤΙΛ|ΜΑΛΛ|ΚΥΜΑΤ|ΛΑΧ|ΛΗΓ|ΦΑΓ|ΟΜ|ΠΡΩΤ)$/.test(o[1]))&&(s+="ΟΥΣ")),null!==(o=/^(.+?)(ΑΓΑ|ΑΓΕΣ|ΑΓΕ)$/.exec(s))&&(s=o[1],(/^(ΑΒΑΣΤ|ΠΟΛΥΦ|ΑΔΗΦ|ΠΑΜΦ|Ρ|ΑΣΠ|ΑΦ|ΑΜΑΛ|ΑΜΑΛΛΙ|ΑΝΥΣΤ|ΑΠΕΡ|ΑΣΠΑΡ|ΑΧΑΡ|ΔΕΡΒΕΝ|ΔΡΟΣΟΠ|ΞΕΦ|ΝΕΟΠ|ΝΟΜΟΤ|ΟΛΟΠ|ΟΜΟΤ|ΠΡΟΣΤ|ΠΡΟΣΩΠΟΠ|ΣΥΜΠ|ΣΥΝΤ|Τ|ΥΠΟΤ|ΧΑΡ|ΑΕΙΠ|ΑΙΜΟΣΤ|ΑΝΥΠ|ΑΠΟΤ|ΑΡΤΙΠ|ΔΙΑΤ|ΕΝ|ΕΠΙΤ|ΚΡΟΚΑΛΟΠ|ΣΙΔΗΡΟΠ|Λ|ΝΑΥ|ΟΥΛΑΜ|ΟΥΡ|Π|ΤΡ|Μ)$/.test(o[1])||/(ΟΦ|ΠΕΛ|ΧΟΡΤ|ΛΛ|ΣΦ|ΡΠ|ΦΡ|ΠΡ|ΛΟΧ|ΣΜΗΝ)$/.test(o[1])&&!/^(ΨΟΦ|ΝΑΥΛΟΧ)$/.test(o[1])||/(ΚΟΛΛ)$/.test(o[1]))&&(s+="ΑΓ")),null!==(o=/^(.+?)(ΗΣΕ|ΗΣΟΥ|ΗΣΑ)$/.exec(s))&&(s=o[1],/^(Ν|ΧΕΡΣΟΝ|ΔΩΔΕΚΑΝ|ΕΡΗΜΟΝ|ΜΕΓΑΛΟΝ|ΕΠΤΑΝ|Ι)$/.test(o[1])&&(s+="ΗΣ")),null!==(o=/^(.+?)(ΗΣΤΕ)$/.exec(s))&&(s=o[1],/^(ΑΣΒ|ΣΒ|ΑΧΡ|ΧΡ|ΑΠΛ|ΑΕΙΜΝ|ΔΥΣΧΡ|ΕΥΧΡ|ΚΟΙΝΟΧΡ|ΠΑΛΙΜΨ)$/.test(o[1])&&(s+="ΗΣΤ")),null!==(o=/^(.+?)(ΟΥΝΕ|ΗΣΟΥΝΕ|ΗΘΟΥΝΕ)$/.exec(s))&&(s=o[1],/^(Ν|Ρ|ΣΠΙ|ΣΤΡΑΒΟΜΟΥΤΣ|ΚΑΚΟΜΟΥΤΣ|ΕΞΩΝ)$/.test(o[1])&&(s+="ΟΥΝ")),null!==(o=/^(.+?)(ΟΥΜΕ|ΗΣΟΥΜΕ|ΗΘΟΥΜΕ)$/.exec(s))&&(s=o[1],/^(ΠΑΡΑΣΟΥΣ|Φ|Χ|ΩΡΙΟΠΛ|ΑΖ|ΑΛΛΟΣΟΥΣ|ΑΣΟΥΣ)$/.test(o[1])&&(s+="ΟΥΜ")),null!=(o=/^(.+?)(ΜΑΤΟΙ|ΜΑΤΟΥΣ|ΜΑΤΟ|ΜΑΤΑ|ΜΑΤΩΣ|ΜΑΤΩΝ|ΜΑΤΟΣ|ΜΑΤΕΣ|ΜΑΤΗ|ΜΑΤΗΣ|ΜΑΤΟΥ)$/.exec(s))&&(s=o[1]+"Μ",/^(ΓΡΑΜ)$/.test(o[1])?s+="Α":/^(ΓΕ|ΣΤΑ)$/.test(o[1])&&(s+="ΑΤ")),null!==(o=/^(.+?)(ΟΥΑ)$/.exec(s))&&(s=o[1]+"ΟΥ"),n.length===s.length&&null!==(o=/^(.+?)(Α|ΑΓΑΤΕ|ΑΓΑΝ|ΑΕΙ|ΑΜΑΙ|ΑΝ|ΑΣ|ΑΣΑΙ|ΑΤΑΙ|ΑΩ|Ε|ΕΙ|ΕΙΣ|ΕΙΤΕ|ΕΣΑΙ|ΕΣ|ΕΤΑΙ|Ι|ΙΕΜΑΙ|ΙΕΜΑΣΤΕ|ΙΕΤΑΙ|ΙΕΣΑΙ|ΙΕΣΑΣΤΕ|ΙΟΜΑΣΤΑΝ|ΙΟΜΟΥΝ|ΙΟΜΟΥΝΑ|ΙΟΝΤΑΝ|ΙΟΝΤΟΥΣΑΝ|ΙΟΣΑΣΤΑΝ|ΙΟΣΑΣΤΕ|ΙΟΣΟΥΝ|ΙΟΣΟΥΝΑ|ΙΟΤΑΝ|ΙΟΥΜΑ|ΙΟΥΜΑΣΤΕ|ΙΟΥΝΤΑΙ|ΙΟΥΝΤΑΝ|Η|ΗΔΕΣ|ΗΔΩΝ|ΗΘΕΙ|ΗΘΕΙΣ|ΗΘΕΙΤΕ|ΗΘΗΚΑΤΕ|ΗΘΗΚΑΝ|ΗΘΟΥΝ|ΗΘΩ|ΗΚΑΤΕ|ΗΚΑΝ|ΗΣ|ΗΣΑΝ|ΗΣΑΤΕ|ΗΣΕΙ|ΗΣΕΣ|ΗΣΟΥΝ|ΗΣΩ|Ο|ΟΙ|ΟΜΑΙ|ΟΜΑΣΤΑΝ|ΟΜΟΥΝ|ΟΜΟΥΝΑ|ΟΝΤΑΙ|ΟΝΤΑΝ|ΟΝΤΟΥΣΑΝ|ΟΣ|ΟΣΑΣΤΑΝ|ΟΣΑΣΤΕ|ΟΣΟΥΝ|ΟΣΟΥΝΑ|ΟΤΑΝ|ΟΥ|ΟΥΜΑΙ|ΟΥΜΑΣΤΕ|ΟΥΝ|ΟΥΝΤΑΙ|ΟΥΝΤΑΝ|ΟΥΣ|ΟΥΣΑΝ|ΟΥΣΑΤΕ|Υ||ΥΑ|ΥΣ|Ω|ΩΝ|ΟΙΣ)$/.exec(s))&&(s=o[1]),null!=(o=/^(.+?)(ΕΣΤΕΡ|ΕΣΤΑΤ|ΟΤΕΡ|ΟΤΑΤ|ΥΤΕΡ|ΥΤΑΤ|ΩΤΕΡ|ΩΤΑΤ)$/.exec(s))&&(/^(ΕΞ|ΕΣ|ΑΝ|ΚΑΤ|Κ|ΠΡ)$/.test(o[1])||(s=o[1]),/^(ΚΑ|Μ|ΕΛΕ|ΛΕ|ΔΕ)$/.test(o[1])&&(s+="ΥΤ")),s}var l={"ΦΑΓΙΑ":"ΦΑ","ΦΑΓΙΟΥ":"ΦΑ","ΦΑΓΙΩΝ":"ΦΑ","ΣΚΑΓΙΑ":"ΣΚΑ","ΣΚΑΓΙΟΥ":"ΣΚΑ","ΣΚΑΓΙΩΝ":"ΣΚΑ","ΣΟΓΙΟΥ":"ΣΟ","ΣΟΓΙΑ":"ΣΟ","ΣΟΓΙΩΝ":"ΣΟ","ΤΑΤΟΓΙΑ":"ΤΑΤΟ","ΤΑΤΟΓΙΟΥ":"ΤΑΤΟ","ΤΑΤΟΓΙΩΝ":"ΤΑΤΟ","ΚΡΕΑΣ":"ΚΡΕ","ΚΡΕΑΤΟΣ":"ΚΡΕ","ΚΡΕΑΤΑ":"ΚΡΕ","ΚΡΕΑΤΩΝ":"ΚΡΕ","ΠΕΡΑΣ":"ΠΕΡ","ΠΕΡΑΤΟΣ":"ΠΕΡ","ΠΕΡΑΤΑ":"ΠΕΡ","ΠΕΡΑΤΩΝ":"ΠΕΡ","ΤΕΡΑΣ":"ΤΕΡ","ΤΕΡΑΤΟΣ":"ΤΕΡ","ΤΕΡΑΤΑ":"ΤΕΡ","ΤΕΡΑΤΩΝ":"ΤΕΡ","ΦΩΣ":"ΦΩ","ΦΩΤΟΣ":"ΦΩ","ΦΩΤΑ":"ΦΩ","ΦΩΤΩΝ":"ΦΩ","ΚΑΘΕΣΤΩΣ":"ΚΑΘΕΣΤ","ΚΑΘΕΣΤΩΤΟΣ":"ΚΑΘΕΣΤ","ΚΑΘΕΣΤΩΤΑ":"ΚΑΘΕΣΤ","ΚΑΘΕΣΤΩΤΩΝ":"ΚΑΘΕΣΤ","ΓΕΓΟΝΟΣ":"ΓΕΓΟΝ","ΓΕΓΟΝΟΤΟΣ":"ΓΕΓΟΝ","ΓΕΓΟΝΟΤΑ":"ΓΕΓΟΝ","ΓΕΓΟΝΟΤΩΝ":"ΓΕΓΟΝ","ΕΥΑ":"ΕΥ"},i=["ΑΚΡΙΒΩΣ","ΑΛΑ","ΑΛΛΑ","ΑΛΛΙΩΣ","ΑΛΛΟΤΕ","ΑΜΑ","ΑΝΩ","ΑΝΑ","ΑΝΑΜΕΣΑ","ΑΝΑΜΕΤΑΞΥ","ΑΝΕΥ","ΑΝΤΙ","ΑΝΤΙΠΕΡΑ","ΑΝΤΙΟ","ΑΞΑΦΝΑ","ΑΠΟ","ΑΠΟΨΕ","ΑΡΑ","ΑΡΑΓΕ","ΑΥΡΙΟ","ΑΦΟΙ","ΑΦΟΥ","ΑΦΟΤΟΥ","ΒΡΕ","ΓΕΙΑ","ΓΙΑ","ΓΙΑΤΙ","ΓΡΑΜΜΑ","ΔΕΗ","ΔΕΝ","ΔΗΛΑΔΗ","ΔΙΧΩΣ","ΔΥΟ","ΕΑΝ","ΕΓΩ","ΕΔΩ","ΕΔΑ","ΕΙΘΕ","ΕΙΜΑΙ","ΕΙΜΑΣΤΕ","ΕΙΣΑΙ","ΕΙΣΑΣΤΕ","ΕΙΝΑΙ","ΕΙΣΤΕ","ΕΙΤΕ","ΕΚΕΙ","ΕΚΟ","ΕΛΑ","ΕΜΑΣ","ΕΜΕΙΣ","ΕΝΤΕΛΩΣ","ΕΝΤΟΣ","ΕΝΤΩΜΕΤΑΞΥ","ΕΝΩ","ΕΞΙ","ΕΞΙΣΟΥ","ΕΞΗΣ","ΕΞΩ","ΕΟΚ","ΕΠΑΝΩ","ΕΠΕΙΔΗ","ΕΠΕΙΤΑ","ΕΠΙ","ΕΠΙΣΗΣ","ΕΠΟΜΕΝΩΣ","ΕΠΤΑ","ΕΣΑΣ","ΕΣΕΙΣ","ΕΣΤΩ","ΕΣΥ","ΕΣΩ","ΕΤΣΙ","ΕΥΓΕ","ΕΦΕ","ΕΦΕΞΗΣ","ΕΧΤΕΣ","ΕΩΣ","ΗΔΗ","ΗΜΙ","ΗΠΑ","ΗΤΟΙ","ΘΕΣ","ΙΔΙΩΣ","ΙΔΗ","ΙΚΑ","ΙΣΩΣ","ΚΑΘΕ","ΚΑΘΕΤΙ","ΚΑΘΟΛΟΥ","ΚΑΘΩΣ","ΚΑΙ","ΚΑΝ","ΚΑΠΟΤΕ","ΚΑΠΟΥ","ΚΑΤΑ","ΚΑΤΙ","ΚΑΤΟΠΙΝ","ΚΑΤΩ","ΚΕΙ","ΚΙΧ","ΚΚΕ","ΚΟΛΑΝ","ΚΥΡΙΩΣ","ΚΩΣ","ΜΑΚΑΡΙ","ΜΑΛΙΣΤΑ","ΜΑΛΛΟΝ","ΜΑΙ","ΜΑΟ","ΜΑΟΥΣ","ΜΑΣ","ΜΕΘΑΥΡΙΟ","ΜΕΣ","ΜΕΣΑ","ΜΕΤΑ","ΜΕΤΑΞΥ","ΜΕΧΡΙ","ΜΗΔΕ","ΜΗΝ","ΜΗΠΩΣ","ΜΗΤΕ","ΜΙΑ","ΜΙΑΣ","ΜΙΣ","ΜΜΕ","ΜΟΛΟΝΟΤΙ","ΜΟΥ","ΜΠΑ","ΜΠΑΣ","ΜΠΟΥΦΑΝ","ΜΠΡΟΣ","ΝΑΙ","ΝΕΣ","ΝΤΑ","ΝΤΕ","ΞΑΝΑ","ΟΗΕ","ΟΚΤΩ","ΟΜΩΣ","ΟΝΕ","ΟΠΑ","ΟΠΟΥ","ΟΠΩΣ","ΟΣΟ","ΟΤΑΝ","ΟΤΕ","ΟΤΙ","ΟΥΤΕ","ΟΧΙ","ΠΑΛΙ","ΠΑΝ","ΠΑΝΟ","ΠΑΝΤΟΤΕ","ΠΑΝΤΟΥ","ΠΑΝΤΩΣ","ΠΑΝΩ","ΠΑΡΑ","ΠΕΡΑ","ΠΕΡΙ","ΠΕΡΙΠΟΥ","ΠΙΑ","ΠΙΟ","ΠΙΣΩ","ΠΛΑΙ","ΠΛΕΟΝ","ΠΛΗΝ","ΠΟΤΕ","ΠΟΥ","ΠΡΟ","ΠΡΟΣ","ΠΡΟΧΤΕΣ","ΠΡΟΧΘΕΣ","ΡΟΔΙ","ΠΩΣ","ΣΑΙ","ΣΑΣ","ΣΑΝ","ΣΕΙΣ","ΣΙΑ","ΣΚΙ","ΣΟΙ","ΣΟΥ","ΣΡΙ","ΣΥΝ","ΣΥΝΑΜΑ","ΣΧΕΔΟΝ","ΤΑΔΕ","ΤΑΞΙ","ΤΑΧΑ","ΤΕΙ","ΤΗΝ","ΤΗΣ","ΤΙΠΟΤΑ","ΤΙΠΟΤΕ","ΤΙΣ","ΤΟΝ","ΤΟΤΕ","ΤΟΥ","ΤΟΥΣ","ΤΣΑ","ΤΣΕ","ΤΣΙ","ΤΣΟΥ","ΤΩΝ","ΥΠΟ","ΥΠΟΨΗ","ΥΠΟΨΙΝ","ΥΣΤΕΡΑ","ΦΕΤΟΣ","ΦΙΣ","ΦΠΑ","ΧΑΦ","ΧΘΕΣ","ΧΤΕΣ","ΧΩΡΙΣ","ΩΣ","ΩΣΑΝ","ΩΣΟΤΟΥ","ΩΣΠΟΥ","ΩΣΤΕ","ΩΣΤΟΣΟ"],s=new RegExp("^[ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ]+$");return function(e){return"function"==typeof e.update?e.update(function(e){return n(e.toUpperCase()).toLowerCase()}):n(e.toUpperCase()).toLowerCase()}}(),e.Pipeline.registerFunction(e.el.stemmer,"stemmer-el"),e.el.stopWordFilter=e.generateStopWordFilter("αλλα αν αντι απο αυτα αυτεσ αυτη αυτο αυτοι αυτοσ αυτουσ αυτων για δε δεν εαν ειμαι ειμαστε ειναι εισαι ειστε εκεινα εκεινεσ εκεινη εκεινο εκεινοι εκεινοσ εκεινουσ εκεινων ενω επι η θα ισωσ κ και κατα κι μα με μετα μη μην να ο οι ομωσ οπωσ οσο οτι παρα ποια ποιεσ ποιο ποιοι ποιοσ ποιουσ ποιων που προσ πωσ σε στη στην στο στον τα την τησ το τον τοτε του των ωσ".split(" ")),e.Pipeline.registerFunction(e.el.stopWordFilter,"stopWordFilter-el"),e.el.normilizer=function(){var e={"Ά":"Α","ά":"α","Έ":"Ε","έ":"ε","Ή":"Η","ή":"η","Ί":"Ι","ί":"ι","Ό":"Ο","ο":"ο","Ύ":"Υ","ύ":"υ","Ώ":"Ω","ώ":"ω","Ϊ":"Ι","ϊ":"ι","Ϋ":"Υ","ϋ":"υ","ΐ":"ι","ΰ":"υ"};return function(t){if("function"==typeof t.update)return t.update(function(t){for(var r="",n=0;n=A.limit)return!0;A.cursor++}return!1}return!0}function n(){if(A.in_grouping(x,97,252)){var s=A.cursor;if(e()){if(A.cursor=s,!A.in_grouping(x,97,252))return!0;for(;!A.out_grouping(x,97,252);){if(A.cursor>=A.limit)return!0;A.cursor++}}return!1}return!0}function i(){var s,r=A.cursor;if(n()){if(A.cursor=r,!A.out_grouping(x,97,252))return;if(s=A.cursor,e()){if(A.cursor=s,!A.in_grouping(x,97,252)||A.cursor>=A.limit)return;A.cursor++}}g=A.cursor}function a(){for(;!A.in_grouping(x,97,252);){if(A.cursor>=A.limit)return!1;A.cursor++}for(;!A.out_grouping(x,97,252);){if(A.cursor>=A.limit)return!1;A.cursor++}return!0}function t(){var e=A.cursor;g=A.limit,p=g,v=g,i(),A.cursor=e,a()&&(p=A.cursor,a()&&(v=A.cursor))}function o(){for(var e;;){if(A.bra=A.cursor,e=A.find_among(k,6))switch(A.ket=A.cursor,e){case 1:A.slice_from("a");continue;case 2:A.slice_from("e");continue;case 3:A.slice_from("i");continue;case 4:A.slice_from("o");continue;case 5:A.slice_from("u");continue;case 6:if(A.cursor>=A.limit)break;A.cursor++;continue}break}}function u(){return g<=A.cursor}function w(){return p<=A.cursor}function c(){return v<=A.cursor}function m(){var e;if(A.ket=A.cursor,A.find_among_b(y,13)&&(A.bra=A.cursor,(e=A.find_among_b(q,11))&&u()))switch(e){case 1:A.bra=A.cursor,A.slice_from("iendo");break;case 2:A.bra=A.cursor,A.slice_from("ando");break;case 3:A.bra=A.cursor,A.slice_from("ar");break;case 4:A.bra=A.cursor,A.slice_from("er");break;case 5:A.bra=A.cursor,A.slice_from("ir");break;case 6:A.slice_del();break;case 7:A.eq_s_b(1,"u")&&A.slice_del()}}function l(e,s){if(!c())return!0;A.slice_del(),A.ket=A.cursor;var r=A.find_among_b(e,s);return r&&(A.bra=A.cursor,1==r&&c()&&A.slice_del()),!1}function d(e){return!c()||(A.slice_del(),A.ket=A.cursor,A.eq_s_b(2,e)&&(A.bra=A.cursor,c()&&A.slice_del()),!1)}function b(){var e;if(A.ket=A.cursor,e=A.find_among_b(S,46)){switch(A.bra=A.cursor,e){case 1:if(!c())return!1;A.slice_del();break;case 2:if(d("ic"))return!1;break;case 3:if(!c())return!1;A.slice_from("log");break;case 4:if(!c())return!1;A.slice_from("u");break;case 5:if(!c())return!1;A.slice_from("ente");break;case 6:if(!w())return!1;A.slice_del(),A.ket=A.cursor,e=A.find_among_b(C,4),e&&(A.bra=A.cursor,c()&&(A.slice_del(),1==e&&(A.ket=A.cursor,A.eq_s_b(2,"at")&&(A.bra=A.cursor,c()&&A.slice_del()))));break;case 7:if(l(P,3))return!1;break;case 8:if(l(F,3))return!1;break;case 9:if(d("at"))return!1}return!0}return!1}function f(){var e,s;if(A.cursor>=g&&(s=A.limit_backward,A.limit_backward=g,A.ket=A.cursor,e=A.find_among_b(W,12),A.limit_backward=s,e)){if(A.bra=A.cursor,1==e){if(!A.eq_s_b(1,"u"))return!1;A.slice_del()}return!0}return!1}function _(){var e,s,r,n;if(A.cursor>=g&&(s=A.limit_backward,A.limit_backward=g,A.ket=A.cursor,e=A.find_among_b(L,96),A.limit_backward=s,e))switch(A.bra=A.cursor,e){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"u")?(n=A.limit-A.cursor,A.eq_s_b(1,"g")?A.cursor=A.limit-n:A.cursor=A.limit-r):A.cursor=A.limit-r,A.bra=A.cursor;case 2:A.slice_del()}}function h(){var e,s;if(A.ket=A.cursor,e=A.find_among_b(z,8))switch(A.bra=A.cursor,e){case 1:u()&&A.slice_del();break;case 2:u()&&(A.slice_del(),A.ket=A.cursor,A.eq_s_b(1,"u")&&(A.bra=A.cursor,s=A.limit-A.cursor,A.eq_s_b(1,"g")&&(A.cursor=A.limit-s,u()&&A.slice_del())))}}var v,p,g,k=[new s("",-1,6),new s("á",0,1),new s("é",0,2),new s("í",0,3),new s("ó",0,4),new s("ú",0,5)],y=[new s("la",-1,-1),new s("sela",0,-1),new s("le",-1,-1),new s("me",-1,-1),new s("se",-1,-1),new s("lo",-1,-1),new s("selo",5,-1),new s("las",-1,-1),new s("selas",7,-1),new s("les",-1,-1),new s("los",-1,-1),new s("selos",10,-1),new s("nos",-1,-1)],q=[new s("ando",-1,6),new s("iendo",-1,6),new s("yendo",-1,7),new s("ándo",-1,2),new s("iéndo",-1,1),new s("ar",-1,6),new s("er",-1,6),new s("ir",-1,6),new s("ár",-1,3),new s("ér",-1,4),new s("ír",-1,5)],C=[new s("ic",-1,-1),new s("ad",-1,-1),new s("os",-1,-1),new s("iv",-1,1)],P=[new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,1)],F=[new s("ic",-1,1),new s("abil",-1,1),new s("iv",-1,1)],S=[new s("ica",-1,1),new s("ancia",-1,2),new s("encia",-1,5),new s("adora",-1,2),new s("osa",-1,1),new s("ista",-1,1),new s("iva",-1,9),new s("anza",-1,1),new s("logía",-1,3),new s("idad",-1,8),new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,2),new s("mente",-1,7),new s("amente",13,6),new s("ación",-1,2),new s("ución",-1,4),new s("ico",-1,1),new s("ismo",-1,1),new s("oso",-1,1),new s("amiento",-1,1),new s("imiento",-1,1),new s("ivo",-1,9),new s("ador",-1,2),new s("icas",-1,1),new s("ancias",-1,2),new s("encias",-1,5),new s("adoras",-1,2),new s("osas",-1,1),new s("istas",-1,1),new s("ivas",-1,9),new s("anzas",-1,1),new s("logías",-1,3),new s("idades",-1,8),new s("ables",-1,1),new s("ibles",-1,1),new s("aciones",-1,2),new s("uciones",-1,4),new s("adores",-1,2),new s("antes",-1,2),new s("icos",-1,1),new s("ismos",-1,1),new s("osos",-1,1),new s("amientos",-1,1),new s("imientos",-1,1),new s("ivos",-1,9)],W=[new s("ya",-1,1),new s("ye",-1,1),new s("yan",-1,1),new s("yen",-1,1),new s("yeron",-1,1),new s("yendo",-1,1),new s("yo",-1,1),new s("yas",-1,1),new s("yes",-1,1),new s("yais",-1,1),new s("yamos",-1,1),new s("yó",-1,1)],L=[new s("aba",-1,2),new s("ada",-1,2),new s("ida",-1,2),new s("ara",-1,2),new s("iera",-1,2),new s("ía",-1,2),new s("aría",5,2),new s("ería",5,2),new s("iría",5,2),new s("ad",-1,2),new s("ed",-1,2),new s("id",-1,2),new s("ase",-1,2),new s("iese",-1,2),new s("aste",-1,2),new s("iste",-1,2),new s("an",-1,2),new s("aban",16,2),new s("aran",16,2),new s("ieran",16,2),new s("ían",16,2),new s("arían",20,2),new s("erían",20,2),new s("irían",20,2),new s("en",-1,1),new s("asen",24,2),new s("iesen",24,2),new s("aron",-1,2),new s("ieron",-1,2),new s("arán",-1,2),new s("erán",-1,2),new s("irán",-1,2),new s("ado",-1,2),new s("ido",-1,2),new s("ando",-1,2),new s("iendo",-1,2),new s("ar",-1,2),new s("er",-1,2),new s("ir",-1,2),new s("as",-1,2),new s("abas",39,2),new s("adas",39,2),new s("idas",39,2),new s("aras",39,2),new s("ieras",39,2),new s("ías",39,2),new s("arías",45,2),new s("erías",45,2),new s("irías",45,2),new s("es",-1,1),new s("ases",49,2),new s("ieses",49,2),new s("abais",-1,2),new s("arais",-1,2),new s("ierais",-1,2),new s("íais",-1,2),new s("aríais",55,2),new s("eríais",55,2),new s("iríais",55,2),new s("aseis",-1,2),new s("ieseis",-1,2),new s("asteis",-1,2),new s("isteis",-1,2),new s("áis",-1,2),new s("éis",-1,1),new s("aréis",64,2),new s("eréis",64,2),new s("iréis",64,2),new s("ados",-1,2),new s("idos",-1,2),new s("amos",-1,2),new s("ábamos",70,2),new s("áramos",70,2),new s("iéramos",70,2),new s("íamos",70,2),new s("aríamos",74,2),new s("eríamos",74,2),new s("iríamos",74,2),new s("emos",-1,1),new s("aremos",78,2),new s("eremos",78,2),new s("iremos",78,2),new s("ásemos",78,2),new s("iésemos",78,2),new s("imos",-1,2),new s("arás",-1,2),new s("erás",-1,2),new s("irás",-1,2),new s("ís",-1,2),new s("ará",-1,2),new s("erá",-1,2),new s("irá",-1,2),new s("aré",-1,2),new s("eré",-1,2),new s("iré",-1,2),new s("ió",-1,2)],z=[new s("a",-1,1),new s("e",-1,2),new s("o",-1,1),new s("os",-1,1),new s("á",-1,1),new s("é",-1,2),new s("í",-1,1),new s("ó",-1,1)],x=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,4,10],A=new r;this.setCurrent=function(e){A.setCurrent(e)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return t(),A.limit_backward=e,A.cursor=A.limit,m(),A.cursor=A.limit,b()||(A.cursor=A.limit,f()||(A.cursor=A.limit,_())),A.cursor=A.limit,h(),A.cursor=A.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.es.stemmer,"stemmer-es"),e.es.stopWordFilter=e.generateStopWordFilter("a al algo algunas algunos ante antes como con contra cual cuando de del desde donde durante e el ella ellas ellos en entre era erais eran eras eres es esa esas ese eso esos esta estaba estabais estaban estabas estad estada estadas estado estados estamos estando estar estaremos estará estarán estarás estaré estaréis estaría estaríais estaríamos estarían estarías estas este estemos esto estos estoy estuve estuviera estuvierais estuvieran estuvieras estuvieron estuviese estuvieseis estuviesen estuvieses estuvimos estuviste estuvisteis estuviéramos estuviésemos estuvo está estábamos estáis están estás esté estéis estén estés fue fuera fuerais fueran fueras fueron fuese fueseis fuesen fueses fui fuimos fuiste fuisteis fuéramos fuésemos ha habida habidas habido habidos habiendo habremos habrá habrán habrás habré habréis habría habríais habríamos habrían habrías habéis había habíais habíamos habían habías han has hasta hay haya hayamos hayan hayas hayáis he hemos hube hubiera hubierais hubieran hubieras hubieron hubiese hubieseis hubiesen hubieses hubimos hubiste hubisteis hubiéramos hubiésemos hubo la las le les lo los me mi mis mucho muchos muy más mí mía mías mío míos nada ni no nos nosotras nosotros nuestra nuestras nuestro nuestros o os otra otras otro otros para pero poco por porque que quien quienes qué se sea seamos sean seas seremos será serán serás seré seréis sería seríais seríamos serían serías seáis sido siendo sin sobre sois somos son soy su sus suya suyas suyo suyos sí también tanto te tendremos tendrá tendrán tendrás tendré tendréis tendría tendríais tendríamos tendrían tendrías tened tenemos tenga tengamos tengan tengas tengo tengáis tenida tenidas tenido tenidos teniendo tenéis tenía teníais teníamos tenían tenías ti tiene tienen tienes todo todos tu tus tuve tuviera tuvierais tuvieran tuvieras tuvieron tuviese tuvieseis tuviesen tuvieses tuvimos tuviste tuvisteis tuviéramos tuviésemos tuvo tuya tuyas tuyo tuyos tú un una uno unos vosotras vosotros vuestra vuestras vuestro vuestros y ya yo él éramos".split(" ")),e.Pipeline.registerFunction(e.es.stopWordFilter,"stopWordFilter-es")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.fi.min.js b/assets/javascripts/lunr/min/lunr.fi.min.js new file mode 100644 index 000000000..29f5dfcea --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.fi.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Finnish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=function(){var e=i.stemmerSupport.Among,r=i.stemmerSupport.SnowballProgram,n=new function(){function i(){f=A.limit,d=f,n()||(f=A.cursor,n()||(d=A.cursor))}function n(){for(var i;;){if(i=A.cursor,A.in_grouping(W,97,246))break;if(A.cursor=i,i>=A.limit)return!0;A.cursor++}for(A.cursor=i;!A.out_grouping(W,97,246);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}function t(){return d<=A.cursor}function s(){var i,e;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(h,10)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.in_grouping_b(x,97,246))return;break;case 2:if(!t())return}A.slice_del()}else A.limit_backward=e}function o(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(v,9))switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"k")||(A.cursor=A.limit-r,A.slice_del());break;case 2:A.slice_del(),A.ket=A.cursor,A.eq_s_b(3,"kse")&&(A.bra=A.cursor,A.slice_from("ksi"));break;case 3:A.slice_del();break;case 4:A.find_among_b(p,6)&&A.slice_del();break;case 5:A.find_among_b(g,6)&&A.slice_del();break;case 6:A.find_among_b(j,2)&&A.slice_del()}else A.limit_backward=e}function l(){return A.find_among_b(q,7)}function a(){return A.eq_s_b(1,"i")&&A.in_grouping_b(L,97,246)}function u(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(C,30)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.eq_s_b(1,"a"))return;break;case 2:case 9:if(!A.eq_s_b(1,"e"))return;break;case 3:if(!A.eq_s_b(1,"i"))return;break;case 4:if(!A.eq_s_b(1,"o"))return;break;case 5:if(!A.eq_s_b(1,"ä"))return;break;case 6:if(!A.eq_s_b(1,"ö"))return;break;case 7:if(r=A.limit-A.cursor,!l()&&(A.cursor=A.limit-r,!A.eq_s_b(2,"ie"))){A.cursor=A.limit-r;break}if(A.cursor=A.limit-r,A.cursor<=A.limit_backward){A.cursor=A.limit-r;break}A.cursor--,A.bra=A.cursor;break;case 8:if(!A.in_grouping_b(W,97,246)||!A.out_grouping_b(W,97,246))return}A.slice_del(),k=!0}else A.limit_backward=e}function c(){var i,e,r;if(A.cursor>=d)if(e=A.limit_backward,A.limit_backward=d,A.ket=A.cursor,i=A.find_among_b(P,14)){if(A.bra=A.cursor,A.limit_backward=e,1==i){if(r=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-r}A.slice_del()}else A.limit_backward=e}function m(){var i;A.cursor>=f&&(i=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.find_among_b(F,2)?(A.bra=A.cursor,A.limit_backward=i,A.slice_del()):A.limit_backward=i)}function w(){var i,e,r,n,t,s;if(A.cursor>=f){if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.eq_s_b(1,"t")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.in_grouping_b(W,97,246)&&(A.cursor=A.limit-r,A.slice_del(),A.limit_backward=e,n=A.limit-A.cursor,A.cursor>=d&&(A.cursor=d,t=A.limit_backward,A.limit_backward=A.cursor,A.cursor=A.limit-n,A.ket=A.cursor,i=A.find_among_b(S,2))))){if(A.bra=A.cursor,A.limit_backward=t,1==i){if(s=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-s}return void A.slice_del()}A.limit_backward=e}}function _(){var i,e,r,n;if(A.cursor>=f){for(i=A.limit_backward,A.limit_backward=f,e=A.limit-A.cursor,l()&&(A.cursor=A.limit-e,A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.in_grouping_b(y,97,228)&&(A.bra=A.cursor,A.out_grouping_b(W,97,246)&&A.slice_del()),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"j")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.eq_s_b(1,"o")?A.slice_del():(A.cursor=A.limit-r,A.eq_s_b(1,"u")&&A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"o")&&(A.bra=A.cursor,A.eq_s_b(1,"j")&&A.slice_del()),A.cursor=A.limit-e,A.limit_backward=i;;){if(n=A.limit-A.cursor,A.out_grouping_b(W,97,246)){A.cursor=A.limit-n;break}if(A.cursor=A.limit-n,A.cursor<=A.limit_backward)return;A.cursor--}A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,b=A.slice_to(),A.eq_v_b(b)&&A.slice_del())}}var k,b,d,f,h=[new e("pa",-1,1),new e("sti",-1,2),new e("kaan",-1,1),new e("han",-1,1),new e("kin",-1,1),new e("hän",-1,1),new e("kään",-1,1),new e("ko",-1,1),new e("pä",-1,1),new e("kö",-1,1)],p=[new e("lla",-1,-1),new e("na",-1,-1),new e("ssa",-1,-1),new e("ta",-1,-1),new e("lta",3,-1),new e("sta",3,-1)],g=[new e("llä",-1,-1),new e("nä",-1,-1),new e("ssä",-1,-1),new e("tä",-1,-1),new e("ltä",3,-1),new e("stä",3,-1)],j=[new e("lle",-1,-1),new e("ine",-1,-1)],v=[new e("nsa",-1,3),new e("mme",-1,3),new e("nne",-1,3),new e("ni",-1,2),new e("si",-1,1),new e("an",-1,4),new e("en",-1,6),new e("än",-1,5),new e("nsä",-1,3)],q=[new e("aa",-1,-1),new e("ee",-1,-1),new e("ii",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1),new e("ää",-1,-1),new e("öö",-1,-1)],C=[new e("a",-1,8),new e("lla",0,-1),new e("na",0,-1),new e("ssa",0,-1),new e("ta",0,-1),new e("lta",4,-1),new e("sta",4,-1),new e("tta",4,9),new e("lle",-1,-1),new e("ine",-1,-1),new e("ksi",-1,-1),new e("n",-1,7),new e("han",11,1),new e("den",11,-1,a),new e("seen",11,-1,l),new e("hen",11,2),new e("tten",11,-1,a),new e("hin",11,3),new e("siin",11,-1,a),new e("hon",11,4),new e("hän",11,5),new e("hön",11,6),new e("ä",-1,8),new e("llä",22,-1),new e("nä",22,-1),new e("ssä",22,-1),new e("tä",22,-1),new e("ltä",26,-1),new e("stä",26,-1),new e("ttä",26,9)],P=[new e("eja",-1,-1),new e("mma",-1,1),new e("imma",1,-1),new e("mpa",-1,1),new e("impa",3,-1),new e("mmi",-1,1),new e("immi",5,-1),new e("mpi",-1,1),new e("impi",7,-1),new e("ejä",-1,-1),new e("mmä",-1,1),new e("immä",10,-1),new e("mpä",-1,1),new e("impä",12,-1)],F=[new e("i",-1,-1),new e("j",-1,-1)],S=[new e("mma",-1,1),new e("imma",0,-1)],y=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],W=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],x=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],A=new r;this.setCurrent=function(i){A.setCurrent(i)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return i(),k=!1,A.limit_backward=e,A.cursor=A.limit,s(),A.cursor=A.limit,o(),A.cursor=A.limit,u(),A.cursor=A.limit,c(),A.cursor=A.limit,k?(m(),A.cursor=A.limit):(A.cursor=A.limit,w(),A.cursor=A.limit),_(),!0}};return function(i){return"function"==typeof i.update?i.update(function(i){return n.setCurrent(i),n.stem(),n.getCurrent()}):(n.setCurrent(i),n.stem(),n.getCurrent())}}(),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.fr.min.js b/assets/javascripts/lunr/min/lunr.fr.min.js new file mode 100644 index 000000000..68cd0094a --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.fr.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `French` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,s){return!(!W.eq_s(1,e)||(W.ket=W.cursor,!W.in_grouping(F,97,251)))&&(W.slice_from(r),W.cursor=s,!0)}function i(e,r,s){return!!W.eq_s(1,e)&&(W.ket=W.cursor,W.slice_from(r),W.cursor=s,!0)}function n(){for(var r,s;;){if(r=W.cursor,W.in_grouping(F,97,251)){if(W.bra=W.cursor,s=W.cursor,e("u","U",r))continue;if(W.cursor=s,e("i","I",r))continue;if(W.cursor=s,i("y","Y",r))continue}if(W.cursor=r,W.bra=r,!e("y","Y",r)){if(W.cursor=r,W.eq_s(1,"q")&&(W.bra=W.cursor,i("u","U",r)))continue;if(W.cursor=r,r>=W.limit)return;W.cursor++}}}function t(){for(;!W.in_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}for(;!W.out_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}return!1}function u(){var e=W.cursor;if(q=W.limit,g=q,p=q,W.in_grouping(F,97,251)&&W.in_grouping(F,97,251)&&W.cursor=W.limit){W.cursor=q;break}W.cursor++}while(!W.in_grouping(F,97,251))}q=W.cursor,W.cursor=e,t()||(g=W.cursor,t()||(p=W.cursor))}function o(){for(var e,r;;){if(r=W.cursor,W.bra=r,!(e=W.find_among(h,4)))break;switch(W.ket=W.cursor,e){case 1:W.slice_from("i");break;case 2:W.slice_from("u");break;case 3:W.slice_from("y");break;case 4:if(W.cursor>=W.limit)return;W.cursor++}}}function c(){return q<=W.cursor}function a(){return g<=W.cursor}function l(){return p<=W.cursor}function w(){var e,r;if(W.ket=W.cursor,e=W.find_among_b(C,43)){switch(W.bra=W.cursor,e){case 1:if(!l())return!1;W.slice_del();break;case 2:if(!l())return!1;W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")&&(W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU"));break;case 3:if(!l())return!1;W.slice_from("log");break;case 4:if(!l())return!1;W.slice_from("u");break;case 5:if(!l())return!1;W.slice_from("ent");break;case 6:if(!c())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(z,6))switch(W.bra=W.cursor,e){case 1:l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&W.slice_del()));break;case 2:l()?W.slice_del():a()&&W.slice_from("eux");break;case 3:l()&&W.slice_del();break;case 4:c()&&W.slice_from("i")}break;case 7:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(y,3))switch(W.bra=W.cursor,e){case 1:l()?W.slice_del():W.slice_from("abl");break;case 2:l()?W.slice_del():W.slice_from("iqU");break;case 3:l()&&W.slice_del()}break;case 8:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")))){W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU");break}break;case 9:W.slice_from("eau");break;case 10:if(!a())return!1;W.slice_from("al");break;case 11:if(l())W.slice_del();else{if(!a())return!1;W.slice_from("eux")}break;case 12:if(!a()||!W.out_grouping_b(F,97,251))return!1;W.slice_del();break;case 13:return c()&&W.slice_from("ant"),!1;case 14:return c()&&W.slice_from("ent"),!1;case 15:return r=W.limit-W.cursor,W.in_grouping_b(F,97,251)&&c()&&(W.cursor=W.limit-r,W.slice_del()),!1}return!0}return!1}function f(){var e,r;if(W.cursor=q){if(s=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,e=W.find_among_b(P,7))switch(W.bra=W.cursor,e){case 1:if(l()){if(i=W.limit-W.cursor,!W.eq_s_b(1,"s")&&(W.cursor=W.limit-i,!W.eq_s_b(1,"t")))break;W.slice_del()}break;case 2:W.slice_from("i");break;case 3:W.slice_del();break;case 4:W.eq_s_b(2,"gu")&&W.slice_del()}W.limit_backward=s}}function b(){var e=W.limit-W.cursor;W.find_among_b(U,5)&&(W.cursor=W.limit-e,W.ket=W.cursor,W.cursor>W.limit_backward&&(W.cursor--,W.bra=W.cursor,W.slice_del()))}function d(){for(var e,r=1;W.out_grouping_b(F,97,251);)r--;if(r<=0){if(W.ket=W.cursor,e=W.limit-W.cursor,!W.eq_s_b(1,"é")&&(W.cursor=W.limit-e,!W.eq_s_b(1,"è")))return;W.bra=W.cursor,W.slice_from("e")}}function k(){if(!w()&&(W.cursor=W.limit,!f()&&(W.cursor=W.limit,!m())))return W.cursor=W.limit,void _();W.cursor=W.limit,W.ket=W.cursor,W.eq_s_b(1,"Y")?(W.bra=W.cursor,W.slice_from("i")):(W.cursor=W.limit,W.eq_s_b(1,"ç")&&(W.bra=W.cursor,W.slice_from("c")))}var p,g,q,v=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],h=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],z=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],y=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],C=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],x=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],I=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],P=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],U=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],F=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],S=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],W=new s;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){var e=W.cursor;return n(),W.cursor=e,u(),W.limit_backward=e,W.cursor=W.limit,k(),W.cursor=W.limit,b(),W.cursor=W.limit,d(),W.cursor=W.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.he.min.js b/assets/javascripts/lunr/min/lunr.he.min.js new file mode 100644 index 000000000..b863d3eae --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.he.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.he=function(){this.pipeline.reset(),this.pipeline.add(e.he.trimmer,e.he.stopWordFilter,e.he.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.he.stemmer))},e.he.wordCharacters="֑-״א-תa-zA-Za-zA-Z0-90-9",e.he.trimmer=e.trimmerSupport.generateTrimmer(e.he.wordCharacters),e.Pipeline.registerFunction(e.he.trimmer,"trimmer-he"),e.he.stemmer=function(){var e=this;return e.result=!1,e.preRemoved=!1,e.sufRemoved=!1,e.pre={pre1:"ה ו י ת",pre2:"ב כ ל מ ש כש",pre3:"הב הכ הל המ הש בש לכ",pre4:"וב וכ ול ומ וש",pre5:"מה שה כל",pre6:"מב מכ מל ממ מש",pre7:"בה בו בי בת כה כו כי כת לה לו לי לת",pre8:"ובה ובו ובי ובת וכה וכו וכי וכת ולה ולו ולי ולת"},e.suf={suf1:"ך כ ם ן נ",suf2:"ים ות וך וכ ום ון ונ הם הן יכ יך ינ ים",suf3:"תי תך תכ תם תן תנ",suf4:"ותי ותך ותכ ותם ותן ותנ",suf5:"נו כם כן הם הן",suf6:"ונו וכם וכן והם והן",suf7:"תכם תכן תנו תהם תהן",suf8:"הוא היא הם הן אני אתה את אנו אתם אתן",suf9:"ני נו כי כו כם כן תי תך תכ תם תן",suf10:"י ך כ ם ן נ ת"},e.patterns=JSON.parse('{"hebrewPatterns": [{"pt1": [{"c": "ה", "l": 0}]}, {"pt2": [{"c": "ו", "l": 0}]}, {"pt3": [{"c": "י", "l": 0}]}, {"pt4": [{"c": "ת", "l": 0}]}, {"pt5": [{"c": "מ", "l": 0}]}, {"pt6": [{"c": "ל", "l": 0}]}, {"pt7": [{"c": "ב", "l": 0}]}, {"pt8": [{"c": "כ", "l": 0}]}, {"pt9": [{"c": "ש", "l": 0}]}, {"pt10": [{"c": "כש", "l": 0}]}, {"pt11": [{"c": "בה", "l": 0}]}, {"pt12": [{"c": "וב", "l": 0}]}, {"pt13": [{"c": "וכ", "l": 0}]}, {"pt14": [{"c": "ול", "l": 0}]}, {"pt15": [{"c": "ומ", "l": 0}]}, {"pt16": [{"c": "וש", "l": 0}]}, {"pt17": [{"c": "הב", "l": 0}]}, {"pt18": [{"c": "הכ", "l": 0}]}, {"pt19": [{"c": "הל", "l": 0}]}, {"pt20": [{"c": "המ", "l": 0}]}, {"pt21": [{"c": "הש", "l": 0}]}, {"pt22": [{"c": "מה", "l": 0}]}, {"pt23": [{"c": "שה", "l": 0}]}, {"pt24": [{"c": "כל", "l": 0}]}]}'),e.execArray=["cleanWord","removeDiacritics","removeStopWords","normalizeHebrewCharacters"],e.stem=function(){var r=0;for(e.result=!1,e.preRemoved=!1,e.sufRemoved=!1;r=0)return!0},e.normalizeHebrewCharacters=function(){return e.word=e.word.replace("ך","כ"),e.word=e.word.replace("ם","מ"),e.word=e.word.replace("ן","נ"),e.word=e.word.replace("ף","פ"),e.word=e.word.replace("ץ","צ"),!1},function(r){return"function"==typeof r.update?r.update(function(r){return e.setCurrent(r),e.stem(),e.getCurrent()}):(e.setCurrent(r),e.stem(),e.getCurrent())}}(),e.Pipeline.registerFunction(e.he.stemmer,"stemmer-he"),e.he.stopWordFilter=e.generateStopWordFilter("אבל או אולי אותו אותי אותך אותם אותן אותנו אז אחר אחרות אחרי אחריכן אחרים אחרת אי איזה איך אין איפה אל אלה אלו אם אנחנו אני אף אפשר את אתה אתכם אתכן אתם אתן באיזה באיזו בגלל בין בלבד בעבור בעזרת בכל בכן בלי במידה במקום שבו ברוב בשביל בשעה ש בתוך גם דרך הוא היא היה היי היכן היתה היתי הם הן הנה הסיבה שבגללה הרי ואילו ואת זאת זה זות יהיה יוכל יוכלו יותר מדי יכול יכולה יכולות יכולים יכל יכלה יכלו יש כאן כאשר כולם כולן כזה כי כיצד כך כל כלל כמו כן כפי כש לא לאו לאיזותך לאן לבין לה להיות להם להן לו לזה לזות לי לך לכם לכן למה למעלה למעלה מ למטה למטה מ למעט למקום שבו למרות לנו לעבר לעיכן לפיכך לפני מאד מאחורי מאיזו סיבה מאין מאיפה מבלי מבעד מדוע מה מהיכן מול מחוץ מי מידע מכאן מכל מכן מלבד מן מנין מסוגל מעט מעטים מעל מצד מקום בו מתחת מתי נגד נגר נו עד עז על עלי עליו עליה עליהם עליך עלינו עם עצמה עצמהם עצמהן עצמו עצמי עצמם עצמן עצמנו פה רק שוב של שלה שלהם שלהן שלו שלי שלך שלכה שלכם שלכן שלנו שם תהיה תחת".split(" ")),e.Pipeline.registerFunction(e.he.stopWordFilter,"stopWordFilter-he")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.hi.min.js b/assets/javascripts/lunr/min/lunr.hi.min.js new file mode 100644 index 000000000..7dbc41402 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.hi.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.hu.min.js b/assets/javascripts/lunr/min/lunr.hu.min.js new file mode 100644 index 000000000..ed9d909f7 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.hu.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Hungarian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,n=L.cursor;if(d=L.limit,L.in_grouping(W,97,252))for(;;){if(e=L.cursor,L.out_grouping(W,97,252))return L.cursor=e,L.find_among(g,8)||(L.cursor=e,e=L.limit)return void(d=e);L.cursor++}if(L.cursor=n,L.out_grouping(W,97,252)){for(;!L.in_grouping(W,97,252);){if(L.cursor>=L.limit)return;L.cursor++}d=L.cursor}}function i(){return d<=L.cursor}function a(){var e;if(L.ket=L.cursor,(e=L.find_among_b(h,2))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e")}}function t(){var e=L.limit-L.cursor;return!!L.find_among_b(p,23)&&(L.cursor=L.limit-e,!0)}function s(){if(L.cursor>L.limit_backward){L.cursor--,L.ket=L.cursor;var e=L.cursor-1;L.limit_backward<=e&&e<=L.limit&&(L.cursor=e,L.bra=e,L.slice_del())}}function c(){var e;if(L.ket=L.cursor,(e=L.find_among_b(_,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function o(){L.ket=L.cursor,L.find_among_b(v,44)&&(L.bra=L.cursor,i()&&(L.slice_del(),a()))}function w(){var e;if(L.ket=L.cursor,(e=L.find_among_b(z,3))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("e");break;case 2:case 3:L.slice_from("a")}}function l(){var e;if(L.ket=L.cursor,(e=L.find_among_b(y,6))&&(L.bra=L.cursor,i()))switch(e){case 1:case 2:L.slice_del();break;case 3:L.slice_from("a");break;case 4:L.slice_from("e")}}function u(){var e;if(L.ket=L.cursor,(e=L.find_among_b(j,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function m(){var e;if(L.ket=L.cursor,(e=L.find_among_b(C,7))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:L.slice_del()}}function k(){var e;if(L.ket=L.cursor,(e=L.find_among_b(P,12))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 9:L.slice_del();break;case 2:case 5:case 8:L.slice_from("e");break;case 3:case 6:L.slice_from("a")}}function f(){var e;if(L.ket=L.cursor,(e=L.find_among_b(F,31))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:L.slice_del();break;case 2:case 5:case 10:case 14:case 19:L.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:L.slice_from("e")}}function b(){var e;if(L.ket=L.cursor,(e=L.find_among_b(S,42))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:L.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:L.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:L.slice_from("e")}}var d,g=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],h=[new n("á",-1,1),new n("é",-1,2)],p=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],_=[new n("al",-1,1),new n("el",-1,2)],v=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],z=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],y=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],j=[new n("á",-1,1),new n("é",-1,2)],C=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],P=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],F=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],S=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var n=L.cursor;return e(),L.limit_backward=n,L.cursor=L.limit,c(),L.cursor=L.limit,o(),L.cursor=L.limit,w(),L.cursor=L.limit,l(),L.cursor=L.limit,u(),L.cursor=L.limit,k(),L.cursor=L.limit,f(),L.cursor=L.limit,b(),L.cursor=L.limit,m(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.hy.min.js b/assets/javascripts/lunr/min/lunr.hy.min.js new file mode 100644 index 000000000..b37f79298 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.hy.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hy=function(){this.pipeline.reset(),this.pipeline.add(e.hy.trimmer,e.hy.stopWordFilter)},e.hy.wordCharacters="[A-Za-z԰-֏ff-ﭏ]",e.hy.trimmer=e.trimmerSupport.generateTrimmer(e.hy.wordCharacters),e.Pipeline.registerFunction(e.hy.trimmer,"trimmer-hy"),e.hy.stopWordFilter=e.generateStopWordFilter("դու և եք էիր էիք հետո նաև նրանք որը վրա է որ պիտի են այս մեջ ն իր ու ի այդ որոնք այն կամ էր մի ես համար այլ իսկ էին ենք հետ ին թ էինք մենք նրա նա դուք եմ էի ըստ որպես ում".split(" ")),e.Pipeline.registerFunction(e.hy.stopWordFilter,"stopWordFilter-hy"),e.hy.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}(),e.Pipeline.registerFunction(e.hy.stemmer,"stemmer-hy")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.it.min.js b/assets/javascripts/lunr/min/lunr.it.min.js new file mode 100644 index 000000000..344b6a3c0 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.it.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Italian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.it=function(){this.pipeline.reset(),this.pipeline.add(e.it.trimmer,e.it.stopWordFilter,e.it.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.it.stemmer))},e.it.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.it.trimmer=e.trimmerSupport.generateTrimmer(e.it.wordCharacters),e.Pipeline.registerFunction(e.it.trimmer,"trimmer-it"),e.it.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!x.eq_s(1,e)||(x.ket=x.cursor,!x.in_grouping(L,97,249)))&&(x.slice_from(r),x.cursor=n,!0)}function i(){for(var r,n,i,o,t=x.cursor;;){if(x.bra=x.cursor,r=x.find_among(h,7))switch(x.ket=x.cursor,r){case 1:x.slice_from("à");continue;case 2:x.slice_from("è");continue;case 3:x.slice_from("ì");continue;case 4:x.slice_from("ò");continue;case 5:x.slice_from("ù");continue;case 6:x.slice_from("qU");continue;case 7:if(x.cursor>=x.limit)break;x.cursor++;continue}break}for(x.cursor=t;;)for(n=x.cursor;;){if(i=x.cursor,x.in_grouping(L,97,249)){if(x.bra=x.cursor,o=x.cursor,e("u","U",i))break;if(x.cursor=o,e("i","I",i))break}if(x.cursor=i,x.cursor>=x.limit)return void(x.cursor=n);x.cursor++}}function o(e){if(x.cursor=e,!x.in_grouping(L,97,249))return!1;for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function t(){if(x.in_grouping(L,97,249)){var e=x.cursor;if(x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return o(e);x.cursor++}return!0}return o(e)}return!1}function s(){var e,r=x.cursor;if(!t()){if(x.cursor=r,!x.out_grouping(L,97,249))return;if(e=x.cursor,x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return x.cursor=e,void(x.in_grouping(L,97,249)&&x.cursor=x.limit)return;x.cursor++}k=x.cursor}function a(){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function u(){var e=x.cursor;k=x.limit,p=k,g=k,s(),x.cursor=e,a()&&(p=x.cursor,a()&&(g=x.cursor))}function c(){for(var e;;){if(x.bra=x.cursor,!(e=x.find_among(q,3)))break;switch(x.ket=x.cursor,e){case 1:x.slice_from("i");break;case 2:x.slice_from("u");break;case 3:if(x.cursor>=x.limit)return;x.cursor++}}}function w(){return k<=x.cursor}function l(){return p<=x.cursor}function m(){return g<=x.cursor}function f(){var e;if(x.ket=x.cursor,x.find_among_b(C,37)&&(x.bra=x.cursor,(e=x.find_among_b(z,5))&&w()))switch(e){case 1:x.slice_del();break;case 2:x.slice_from("e")}}function v(){var e;if(x.ket=x.cursor,!(e=x.find_among_b(S,51)))return!1;switch(x.bra=x.cursor,e){case 1:if(!m())return!1;x.slice_del();break;case 2:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del());break;case 3:if(!m())return!1;x.slice_from("log");break;case 4:if(!m())return!1;x.slice_from("u");break;case 5:if(!m())return!1;x.slice_from("ente");break;case 6:if(!w())return!1;x.slice_del();break;case 7:if(!l())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(P,4),e&&(x.bra=x.cursor,m()&&(x.slice_del(),1==e&&(x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&x.slice_del()))));break;case 8:if(!m())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(F,3),e&&(x.bra=x.cursor,1==e&&m()&&x.slice_del());break;case 9:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del())))}return!0}function b(){var e,r;x.cursor>=k&&(r=x.limit_backward,x.limit_backward=k,x.ket=x.cursor,e=x.find_among_b(W,87),e&&(x.bra=x.cursor,1==e&&x.slice_del()),x.limit_backward=r)}function d(){var e=x.limit-x.cursor;if(x.ket=x.cursor,x.in_grouping_b(y,97,242)&&(x.bra=x.cursor,w()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(1,"i")&&(x.bra=x.cursor,w()))))return void x.slice_del();x.cursor=x.limit-e}function _(){d(),x.ket=x.cursor,x.eq_s_b(1,"h")&&(x.bra=x.cursor,x.in_grouping_b(U,99,103)&&w()&&x.slice_del())}var g,p,k,h=[new r("",-1,7),new r("qu",0,6),new r("á",0,1),new r("é",0,2),new r("í",0,3),new r("ó",0,4),new r("ú",0,5)],q=[new r("",-1,3),new r("I",0,1),new r("U",0,2)],C=[new r("la",-1,-1),new r("cela",0,-1),new r("gliela",0,-1),new r("mela",0,-1),new r("tela",0,-1),new r("vela",0,-1),new r("le",-1,-1),new r("cele",6,-1),new r("gliele",6,-1),new r("mele",6,-1),new r("tele",6,-1),new r("vele",6,-1),new r("ne",-1,-1),new r("cene",12,-1),new r("gliene",12,-1),new r("mene",12,-1),new r("sene",12,-1),new r("tene",12,-1),new r("vene",12,-1),new r("ci",-1,-1),new r("li",-1,-1),new r("celi",20,-1),new r("glieli",20,-1),new r("meli",20,-1),new r("teli",20,-1),new r("veli",20,-1),new r("gli",20,-1),new r("mi",-1,-1),new r("si",-1,-1),new r("ti",-1,-1),new r("vi",-1,-1),new r("lo",-1,-1),new r("celo",31,-1),new r("glielo",31,-1),new r("melo",31,-1),new r("telo",31,-1),new r("velo",31,-1)],z=[new r("ando",-1,1),new r("endo",-1,1),new r("ar",-1,2),new r("er",-1,2),new r("ir",-1,2)],P=[new r("ic",-1,-1),new r("abil",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],F=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],S=[new r("ica",-1,1),new r("logia",-1,3),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,9),new r("anza",-1,1),new r("enza",-1,5),new r("ice",-1,1),new r("atrice",7,1),new r("iche",-1,1),new r("logie",-1,3),new r("abile",-1,1),new r("ibile",-1,1),new r("usione",-1,4),new r("azione",-1,2),new r("uzione",-1,4),new r("atore",-1,2),new r("ose",-1,1),new r("ante",-1,1),new r("mente",-1,1),new r("amente",19,7),new r("iste",-1,1),new r("ive",-1,9),new r("anze",-1,1),new r("enze",-1,5),new r("ici",-1,1),new r("atrici",25,1),new r("ichi",-1,1),new r("abili",-1,1),new r("ibili",-1,1),new r("ismi",-1,1),new r("usioni",-1,4),new r("azioni",-1,2),new r("uzioni",-1,4),new r("atori",-1,2),new r("osi",-1,1),new r("anti",-1,1),new r("amenti",-1,6),new r("imenti",-1,6),new r("isti",-1,1),new r("ivi",-1,9),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,6),new r("imento",-1,6),new r("ivo",-1,9),new r("ità",-1,8),new r("istà",-1,1),new r("istè",-1,1),new r("istì",-1,1)],W=[new r("isca",-1,1),new r("enda",-1,1),new r("ata",-1,1),new r("ita",-1,1),new r("uta",-1,1),new r("ava",-1,1),new r("eva",-1,1),new r("iva",-1,1),new r("erebbe",-1,1),new r("irebbe",-1,1),new r("isce",-1,1),new r("ende",-1,1),new r("are",-1,1),new r("ere",-1,1),new r("ire",-1,1),new r("asse",-1,1),new r("ate",-1,1),new r("avate",16,1),new r("evate",16,1),new r("ivate",16,1),new r("ete",-1,1),new r("erete",20,1),new r("irete",20,1),new r("ite",-1,1),new r("ereste",-1,1),new r("ireste",-1,1),new r("ute",-1,1),new r("erai",-1,1),new r("irai",-1,1),new r("isci",-1,1),new r("endi",-1,1),new r("erei",-1,1),new r("irei",-1,1),new r("assi",-1,1),new r("ati",-1,1),new r("iti",-1,1),new r("eresti",-1,1),new r("iresti",-1,1),new r("uti",-1,1),new r("avi",-1,1),new r("evi",-1,1),new r("ivi",-1,1),new r("isco",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("Yamo",-1,1),new r("iamo",-1,1),new r("avamo",-1,1),new r("evamo",-1,1),new r("ivamo",-1,1),new r("eremo",-1,1),new r("iremo",-1,1),new r("assimo",-1,1),new r("ammo",-1,1),new r("emmo",-1,1),new r("eremmo",54,1),new r("iremmo",54,1),new r("immo",-1,1),new r("ano",-1,1),new r("iscano",58,1),new r("avano",58,1),new r("evano",58,1),new r("ivano",58,1),new r("eranno",-1,1),new r("iranno",-1,1),new r("ono",-1,1),new r("iscono",65,1),new r("arono",65,1),new r("erono",65,1),new r("irono",65,1),new r("erebbero",-1,1),new r("irebbero",-1,1),new r("assero",-1,1),new r("essero",-1,1),new r("issero",-1,1),new r("ato",-1,1),new r("ito",-1,1),new r("uto",-1,1),new r("avo",-1,1),new r("evo",-1,1),new r("ivo",-1,1),new r("ar",-1,1),new r("ir",-1,1),new r("erà",-1,1),new r("irà",-1,1),new r("erò",-1,1),new r("irò",-1,1)],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2,1],y=[17,65,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2],U=[17],x=new n;this.setCurrent=function(e){x.setCurrent(e)},this.getCurrent=function(){return x.getCurrent()},this.stem=function(){var e=x.cursor;return i(),x.cursor=e,u(),x.limit_backward=e,x.cursor=x.limit,f(),x.cursor=x.limit,v()||(x.cursor=x.limit,b()),x.cursor=x.limit,_(),x.cursor=x.limit_backward,c(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.it.stemmer,"stemmer-it"),e.it.stopWordFilter=e.generateStopWordFilter("a abbia abbiamo abbiano abbiate ad agl agli ai al all alla alle allo anche avemmo avendo avesse avessero avessi avessimo aveste avesti avete aveva avevamo avevano avevate avevi avevo avrai avranno avrebbe avrebbero avrei avremmo avremo avreste avresti avrete avrà avrò avuta avute avuti avuto c che chi ci coi col come con contro cui da dagl dagli dai dal dall dalla dalle dallo degl degli dei del dell della delle dello di dov dove e ebbe ebbero ebbi ed era erano eravamo eravate eri ero essendo faccia facciamo facciano facciate faccio facemmo facendo facesse facessero facessi facessimo faceste facesti faceva facevamo facevano facevate facevi facevo fai fanno farai faranno farebbe farebbero farei faremmo faremo fareste faresti farete farà farò fece fecero feci fosse fossero fossi fossimo foste fosti fu fui fummo furono gli ha hai hanno ho i il in io l la le lei li lo loro lui ma mi mia mie miei mio ne negl negli nei nel nell nella nelle nello noi non nostra nostre nostri nostro o per perché più quale quanta quante quanti quanto quella quelle quelli quello questa queste questi questo sarai saranno sarebbe sarebbero sarei saremmo saremo sareste saresti sarete sarà sarò se sei si sia siamo siano siate siete sono sta stai stando stanno starai staranno starebbe starebbero starei staremmo staremo stareste staresti starete starà starò stava stavamo stavano stavate stavi stavo stemmo stesse stessero stessi stessimo steste stesti stette stettero stetti stia stiamo stiano stiate sto su sua sue sugl sugli sui sul sull sulla sulle sullo suo suoi ti tra tu tua tue tuo tuoi tutti tutto un una uno vi voi vostra vostre vostri vostro è".split(" ")),e.Pipeline.registerFunction(e.it.stopWordFilter,"stopWordFilter-it")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ja.min.js b/assets/javascripts/lunr/min/lunr.ja.min.js new file mode 100644 index 000000000..5f254ebe9 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ja.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.no.min.js b/assets/javascripts/lunr/min/lunr.no.min.js new file mode 100644 index 000000000..92bc7e4e8 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.no.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Norwegian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.pt.min.js b/assets/javascripts/lunr/min/lunr.pt.min.js new file mode 100644 index 000000000..6c16996d6 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.pt.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Portuguese` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(k,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("a~");continue;case 2:z.slice_from("o~");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function n(){if(z.out_grouping(y,97,250)){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!0;z.cursor++}return!1}return!0}function i(){if(z.in_grouping(y,97,250))for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return g=z.cursor,!0}function o(){var e,r,s=z.cursor;if(z.in_grouping(y,97,250))if(e=z.cursor,n()){if(z.cursor=e,i())return}else g=z.cursor;if(z.cursor=s,z.out_grouping(y,97,250)){if(r=z.cursor,n()){if(z.cursor=r,!z.in_grouping(y,97,250)||z.cursor>=z.limit)return;z.cursor++}g=z.cursor}}function t(){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return!0}function a(){var e=z.cursor;g=z.limit,b=g,h=g,o(),z.cursor=e,t()&&(b=z.cursor,t()&&(h=z.cursor))}function u(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(q,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("ã");continue;case 2:z.slice_from("õ");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function w(){return g<=z.cursor}function m(){return b<=z.cursor}function c(){return h<=z.cursor}function l(){var e;if(z.ket=z.cursor,!(e=z.find_among_b(F,45)))return!1;switch(z.bra=z.cursor,e){case 1:if(!c())return!1;z.slice_del();break;case 2:if(!c())return!1;z.slice_from("log");break;case 3:if(!c())return!1;z.slice_from("u");break;case 4:if(!c())return!1;z.slice_from("ente");break;case 5:if(!m())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(j,4),e&&(z.bra=z.cursor,c()&&(z.slice_del(),1==e&&(z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del()))));break;case 6:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(C,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 7:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(P,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 8:if(!c())return!1;z.slice_del(),z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del());break;case 9:if(!w()||!z.eq_s_b(1,"e"))return!1;z.slice_from("ir")}return!0}function f(){var e,r;if(z.cursor>=g){if(r=z.limit_backward,z.limit_backward=g,z.ket=z.cursor,e=z.find_among_b(S,120))return z.bra=z.cursor,1==e&&z.slice_del(),z.limit_backward=r,!0;z.limit_backward=r}return!1}function d(){var e;z.ket=z.cursor,(e=z.find_among_b(W,7))&&(z.bra=z.cursor,1==e&&w()&&z.slice_del())}function v(e,r){if(z.eq_s_b(1,e)){z.bra=z.cursor;var s=z.limit-z.cursor;if(z.eq_s_b(1,r))return z.cursor=z.limit-s,w()&&z.slice_del(),!1}return!0}function p(){var e;if(z.ket=z.cursor,e=z.find_among_b(L,4))switch(z.bra=z.cursor,e){case 1:w()&&(z.slice_del(),z.ket=z.cursor,z.limit-z.cursor,v("u","g")&&v("i","c"));break;case 2:z.slice_from("c")}}function _(){if(!l()&&(z.cursor=z.limit,!f()))return z.cursor=z.limit,void d();z.cursor=z.limit,z.ket=z.cursor,z.eq_s_b(1,"i")&&(z.bra=z.cursor,z.eq_s_b(1,"c")&&(z.cursor=z.limit,w()&&z.slice_del()))}var h,b,g,k=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],q=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],j=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],C=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],P=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],F=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],S=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],W=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],L=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],y=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],z=new s;this.setCurrent=function(e){z.setCurrent(e)},this.getCurrent=function(){return z.getCurrent()},this.stem=function(){var r=z.cursor;return e(),z.cursor=r,a(),z.limit_backward=r,z.cursor=z.limit,_(),z.cursor=z.limit,p(),z.cursor=z.limit_backward,u(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ro.min.js b/assets/javascripts/lunr/min/lunr.ro.min.js new file mode 100644 index 000000000..727714018 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ro.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Romanian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ro=function(){this.pipeline.reset(),this.pipeline.add(e.ro.trimmer,e.ro.stopWordFilter,e.ro.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ro.stemmer))},e.ro.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.ro.trimmer=e.trimmerSupport.generateTrimmer(e.ro.wordCharacters),e.Pipeline.registerFunction(e.ro.trimmer,"trimmer-ro"),e.ro.stemmer=function(){var i=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){function e(e,i){L.eq_s(1,e)&&(L.ket=L.cursor,L.in_grouping(W,97,259)&&L.slice_from(i))}function n(){for(var i,r;;){if(i=L.cursor,L.in_grouping(W,97,259)&&(r=L.cursor,L.bra=r,e("u","U"),L.cursor=r,e("i","I")),L.cursor=i,L.cursor>=L.limit)break;L.cursor++}}function t(){if(L.out_grouping(W,97,259)){for(;!L.in_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}return!0}function a(){if(L.in_grouping(W,97,259))for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}function o(){var e,i,r=L.cursor;if(L.in_grouping(W,97,259)){if(e=L.cursor,!t())return void(h=L.cursor);if(L.cursor=e,!a())return void(h=L.cursor)}L.cursor=r,L.out_grouping(W,97,259)&&(i=L.cursor,t()&&(L.cursor=i,L.in_grouping(W,97,259)&&L.cursor=L.limit)return!1;L.cursor++}for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!1;L.cursor++}return!0}function c(){var e=L.cursor;h=L.limit,k=h,g=h,o(),L.cursor=e,u()&&(k=L.cursor,u()&&(g=L.cursor))}function s(){for(var e;;){if(L.bra=L.cursor,e=L.find_among(z,3))switch(L.ket=L.cursor,e){case 1:L.slice_from("i");continue;case 2:L.slice_from("u");continue;case 3:if(L.cursor>=L.limit)break;L.cursor++;continue}break}}function w(){return h<=L.cursor}function m(){return k<=L.cursor}function l(){return g<=L.cursor}function f(){var e,i;if(L.ket=L.cursor,(e=L.find_among_b(C,16))&&(L.bra=L.cursor,m()))switch(e){case 1:L.slice_del();break;case 2:L.slice_from("a");break;case 3:L.slice_from("e");break;case 4:L.slice_from("i");break;case 5:i=L.limit-L.cursor,L.eq_s_b(2,"ab")||(L.cursor=L.limit-i,L.slice_from("i"));break;case 6:L.slice_from("at");break;case 7:L.slice_from("aţi")}}function p(){var e,i=L.limit-L.cursor;if(L.ket=L.cursor,(e=L.find_among_b(P,46))&&(L.bra=L.cursor,m())){switch(e){case 1:L.slice_from("abil");break;case 2:L.slice_from("ibil");break;case 3:L.slice_from("iv");break;case 4:L.slice_from("ic");break;case 5:L.slice_from("at");break;case 6:L.slice_from("it")}return _=!0,L.cursor=L.limit-i,!0}return!1}function d(){var e,i;for(_=!1;;)if(i=L.limit-L.cursor,!p()){L.cursor=L.limit-i;break}if(L.ket=L.cursor,(e=L.find_among_b(F,62))&&(L.bra=L.cursor,l())){switch(e){case 1:L.slice_del();break;case 2:L.eq_s_b(1,"ţ")&&(L.bra=L.cursor,L.slice_from("t"));break;case 3:L.slice_from("ist")}_=!0}}function b(){var e,i,r;if(L.cursor>=h){if(i=L.limit_backward,L.limit_backward=h,L.ket=L.cursor,e=L.find_among_b(q,94))switch(L.bra=L.cursor,e){case 1:if(r=L.limit-L.cursor,!L.out_grouping_b(W,97,259)&&(L.cursor=L.limit-r,!L.eq_s_b(1,"u")))break;case 2:L.slice_del()}L.limit_backward=i}}function v(){var e;L.ket=L.cursor,(e=L.find_among_b(S,5))&&(L.bra=L.cursor,w()&&1==e&&L.slice_del())}var _,g,k,h,z=[new i("",-1,3),new i("I",0,1),new i("U",0,2)],C=[new i("ea",-1,3),new i("aţia",-1,7),new i("aua",-1,2),new i("iua",-1,4),new i("aţie",-1,7),new i("ele",-1,3),new i("ile",-1,5),new i("iile",6,4),new i("iei",-1,4),new i("atei",-1,6),new i("ii",-1,4),new i("ului",-1,1),new i("ul",-1,1),new i("elor",-1,3),new i("ilor",-1,4),new i("iilor",14,4)],P=[new i("icala",-1,4),new i("iciva",-1,4),new i("ativa",-1,5),new i("itiva",-1,6),new i("icale",-1,4),new i("aţiune",-1,5),new i("iţiune",-1,6),new i("atoare",-1,5),new i("itoare",-1,6),new i("ătoare",-1,5),new i("icitate",-1,4),new i("abilitate",-1,1),new i("ibilitate",-1,2),new i("ivitate",-1,3),new i("icive",-1,4),new i("ative",-1,5),new i("itive",-1,6),new i("icali",-1,4),new i("atori",-1,5),new i("icatori",18,4),new i("itori",-1,6),new i("ători",-1,5),new i("icitati",-1,4),new i("abilitati",-1,1),new i("ivitati",-1,3),new i("icivi",-1,4),new i("ativi",-1,5),new i("itivi",-1,6),new i("icităi",-1,4),new i("abilităi",-1,1),new i("ivităi",-1,3),new i("icităţi",-1,4),new i("abilităţi",-1,1),new i("ivităţi",-1,3),new i("ical",-1,4),new i("ator",-1,5),new i("icator",35,4),new i("itor",-1,6),new i("ător",-1,5),new i("iciv",-1,4),new i("ativ",-1,5),new i("itiv",-1,6),new i("icală",-1,4),new i("icivă",-1,4),new i("ativă",-1,5),new i("itivă",-1,6)],F=[new i("ica",-1,1),new i("abila",-1,1),new i("ibila",-1,1),new i("oasa",-1,1),new i("ata",-1,1),new i("ita",-1,1),new i("anta",-1,1),new i("ista",-1,3),new i("uta",-1,1),new i("iva",-1,1),new i("ic",-1,1),new i("ice",-1,1),new i("abile",-1,1),new i("ibile",-1,1),new i("isme",-1,3),new i("iune",-1,2),new i("oase",-1,1),new i("ate",-1,1),new i("itate",17,1),new i("ite",-1,1),new i("ante",-1,1),new i("iste",-1,3),new i("ute",-1,1),new i("ive",-1,1),new i("ici",-1,1),new i("abili",-1,1),new i("ibili",-1,1),new i("iuni",-1,2),new i("atori",-1,1),new i("osi",-1,1),new i("ati",-1,1),new i("itati",30,1),new i("iti",-1,1),new i("anti",-1,1),new i("isti",-1,3),new i("uti",-1,1),new i("işti",-1,3),new i("ivi",-1,1),new i("ităi",-1,1),new i("oşi",-1,1),new i("ităţi",-1,1),new i("abil",-1,1),new i("ibil",-1,1),new i("ism",-1,3),new i("ator",-1,1),new i("os",-1,1),new i("at",-1,1),new i("it",-1,1),new i("ant",-1,1),new i("ist",-1,3),new i("ut",-1,1),new i("iv",-1,1),new i("ică",-1,1),new i("abilă",-1,1),new i("ibilă",-1,1),new i("oasă",-1,1),new i("ată",-1,1),new i("ită",-1,1),new i("antă",-1,1),new i("istă",-1,3),new i("ută",-1,1),new i("ivă",-1,1)],q=[new i("ea",-1,1),new i("ia",-1,1),new i("esc",-1,1),new i("ăsc",-1,1),new i("ind",-1,1),new i("ând",-1,1),new i("are",-1,1),new i("ere",-1,1),new i("ire",-1,1),new i("âre",-1,1),new i("se",-1,2),new i("ase",10,1),new i("sese",10,2),new i("ise",10,1),new i("use",10,1),new i("âse",10,1),new i("eşte",-1,1),new i("ăşte",-1,1),new i("eze",-1,1),new i("ai",-1,1),new i("eai",19,1),new i("iai",19,1),new i("sei",-1,2),new i("eşti",-1,1),new i("ăşti",-1,1),new i("ui",-1,1),new i("ezi",-1,1),new i("âi",-1,1),new i("aşi",-1,1),new i("seşi",-1,2),new i("aseşi",29,1),new i("seseşi",29,2),new i("iseşi",29,1),new i("useşi",29,1),new i("âseşi",29,1),new i("işi",-1,1),new i("uşi",-1,1),new i("âşi",-1,1),new i("aţi",-1,2),new i("eaţi",38,1),new i("iaţi",38,1),new i("eţi",-1,2),new i("iţi",-1,2),new i("âţi",-1,2),new i("arăţi",-1,1),new i("serăţi",-1,2),new i("aserăţi",45,1),new i("seserăţi",45,2),new i("iserăţi",45,1),new i("userăţi",45,1),new i("âserăţi",45,1),new i("irăţi",-1,1),new i("urăţi",-1,1),new i("ârăţi",-1,1),new i("am",-1,1),new i("eam",54,1),new i("iam",54,1),new i("em",-1,2),new i("asem",57,1),new i("sesem",57,2),new i("isem",57,1),new i("usem",57,1),new i("âsem",57,1),new i("im",-1,2),new i("âm",-1,2),new i("ăm",-1,2),new i("arăm",65,1),new i("serăm",65,2),new i("aserăm",67,1),new i("seserăm",67,2),new i("iserăm",67,1),new i("userăm",67,1),new i("âserăm",67,1),new i("irăm",65,1),new i("urăm",65,1),new i("ârăm",65,1),new i("au",-1,1),new i("eau",76,1),new i("iau",76,1),new i("indu",-1,1),new i("ându",-1,1),new i("ez",-1,1),new i("ească",-1,1),new i("ară",-1,1),new i("seră",-1,2),new i("aseră",84,1),new i("seseră",84,2),new i("iseră",84,1),new i("useră",84,1),new i("âseră",84,1),new i("iră",-1,1),new i("ură",-1,1),new i("âră",-1,1),new i("ează",-1,1)],S=[new i("a",-1,1),new i("e",-1,1),new i("ie",1,1),new i("i",-1,1),new i("ă",-1,1)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var e=L.cursor;return n(),L.cursor=e,c(),L.limit_backward=e,L.cursor=L.limit,f(),L.cursor=L.limit,d(),L.cursor=L.limit,_||(L.cursor=L.limit,b(),L.cursor=L.limit),v(),L.cursor=L.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.ro.stemmer,"stemmer-ro"),e.ro.stopWordFilter=e.generateStopWordFilter("acea aceasta această aceea acei aceia acel acela acele acelea acest acesta aceste acestea aceşti aceştia acolo acord acum ai aia aibă aici al ale alea altceva altcineva am ar are asemenea asta astea astăzi asupra au avea avem aveţi azi aş aşadar aţi bine bucur bună ca care caut ce cel ceva chiar cinci cine cineva contra cu cum cumva curând curînd când cât câte câtva câţi cînd cît cîte cîtva cîţi că căci cărei căror cărui către da dacă dar datorită dată dau de deci deja deoarece departe deşi din dinaintea dintr- dintre doi doilea două drept după dă ea ei el ele eram este eu eşti face fata fi fie fiecare fii fim fiu fiţi frumos fără graţie halbă iar ieri la le li lor lui lângă lîngă mai mea mei mele mereu meu mi mie mine mult multă mulţi mulţumesc mâine mîine mă ne nevoie nici nicăieri nimeni nimeri nimic nişte noastre noastră noi noroc nostru nouă noştri nu opt ori oricare orice oricine oricum oricând oricât oricînd oricît oriunde patra patru patrulea pe pentru peste pic poate pot prea prima primul prin puţin puţina puţină până pînă rog sa sale sau se spate spre sub sunt suntem sunteţi sută sînt sîntem sînteţi să săi său ta tale te timp tine toate toată tot totuşi toţi trei treia treilea tu tăi tău un una unde undeva unei uneia unele uneori unii unor unora unu unui unuia unul vi voastre voastră voi vostru vouă voştri vreme vreo vreun vă zece zero zi zice îi îl îmi împotriva în înainte înaintea încotro încât încît între întrucât întrucît îţi ăla ălea ăsta ăstea ăştia şapte şase şi ştiu ţi ţie".split(" ")),e.Pipeline.registerFunction(e.ro.stopWordFilter,"stopWordFilter-ro")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ru.min.js b/assets/javascripts/lunr/min/lunr.ru.min.js new file mode 100644 index 000000000..186cc485c --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ru.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Russian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,t=new function(){function e(){for(;!W.in_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function t(){for(;!W.out_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function w(){b=W.limit,_=b,e()&&(b=W.cursor,t()&&e()&&t()&&(_=W.cursor))}function i(){return _<=W.cursor}function u(e,n){var r,t;if(W.ket=W.cursor,r=W.find_among_b(e,n)){switch(W.bra=W.cursor,r){case 1:if(t=W.limit-W.cursor,!W.eq_s_b(1,"а")&&(W.cursor=W.limit-t,!W.eq_s_b(1,"я")))return!1;case 2:W.slice_del()}return!0}return!1}function o(){return u(h,9)}function s(e,n){var r;return W.ket=W.cursor,!!(r=W.find_among_b(e,n))&&(W.bra=W.cursor,1==r&&W.slice_del(),!0)}function c(){return s(g,26)}function m(){return!!c()&&(u(C,8),!0)}function f(){return s(k,2)}function l(){return u(P,46)}function a(){s(v,36)}function p(){var e;W.ket=W.cursor,(e=W.find_among_b(F,2))&&(W.bra=W.cursor,i()&&1==e&&W.slice_del())}function d(){var e;if(W.ket=W.cursor,e=W.find_among_b(q,4))switch(W.bra=W.cursor,e){case 1:if(W.slice_del(),W.ket=W.cursor,!W.eq_s_b(1,"н"))break;W.bra=W.cursor;case 2:if(!W.eq_s_b(1,"н"))break;case 3:W.slice_del()}}var _,b,h=[new n("в",-1,1),new n("ив",0,2),new n("ыв",0,2),new n("вши",-1,1),new n("ивши",3,2),new n("ывши",3,2),new n("вшись",-1,1),new n("ившись",6,2),new n("ывшись",6,2)],g=[new n("ее",-1,1),new n("ие",-1,1),new n("ое",-1,1),new n("ые",-1,1),new n("ими",-1,1),new n("ыми",-1,1),new n("ей",-1,1),new n("ий",-1,1),new n("ой",-1,1),new n("ый",-1,1),new n("ем",-1,1),new n("им",-1,1),new n("ом",-1,1),new n("ым",-1,1),new n("его",-1,1),new n("ого",-1,1),new n("ему",-1,1),new n("ому",-1,1),new n("их",-1,1),new n("ых",-1,1),new n("ею",-1,1),new n("ою",-1,1),new n("ую",-1,1),new n("юю",-1,1),new n("ая",-1,1),new n("яя",-1,1)],C=[new n("ем",-1,1),new n("нн",-1,1),new n("вш",-1,1),new n("ивш",2,2),new n("ывш",2,2),new n("щ",-1,1),new n("ющ",5,1),new n("ующ",6,2)],k=[new n("сь",-1,1),new n("ся",-1,1)],P=[new n("ла",-1,1),new n("ила",0,2),new n("ыла",0,2),new n("на",-1,1),new n("ена",3,2),new n("ете",-1,1),new n("ите",-1,2),new n("йте",-1,1),new n("ейте",7,2),new n("уйте",7,2),new n("ли",-1,1),new n("или",10,2),new n("ыли",10,2),new n("й",-1,1),new n("ей",13,2),new n("уй",13,2),new n("л",-1,1),new n("ил",16,2),new n("ыл",16,2),new n("ем",-1,1),new n("им",-1,2),new n("ым",-1,2),new n("н",-1,1),new n("ен",22,2),new n("ло",-1,1),new n("ило",24,2),new n("ыло",24,2),new n("но",-1,1),new n("ено",27,2),new n("нно",27,1),new n("ет",-1,1),new n("ует",30,2),new n("ит",-1,2),new n("ыт",-1,2),new n("ют",-1,1),new n("уют",34,2),new n("ят",-1,2),new n("ны",-1,1),new n("ены",37,2),new n("ть",-1,1),new n("ить",39,2),new n("ыть",39,2),new n("ешь",-1,1),new n("ишь",-1,2),new n("ю",-1,2),new n("ую",44,2)],v=[new n("а",-1,1),new n("ев",-1,1),new n("ов",-1,1),new n("е",-1,1),new n("ие",3,1),new n("ье",3,1),new n("и",-1,1),new n("еи",6,1),new n("ии",6,1),new n("ами",6,1),new n("ями",6,1),new n("иями",10,1),new n("й",-1,1),new n("ей",12,1),new n("ией",13,1),new n("ий",12,1),new n("ой",12,1),new n("ам",-1,1),new n("ем",-1,1),new n("ием",18,1),new n("ом",-1,1),new n("ям",-1,1),new n("иям",21,1),new n("о",-1,1),new n("у",-1,1),new n("ах",-1,1),new n("ях",-1,1),new n("иях",26,1),new n("ы",-1,1),new n("ь",-1,1),new n("ю",-1,1),new n("ию",30,1),new n("ью",30,1),new n("я",-1,1),new n("ия",33,1),new n("ья",33,1)],F=[new n("ост",-1,1),new n("ость",-1,1)],q=[new n("ейше",-1,1),new n("н",-1,2),new n("ейш",-1,1),new n("ь",-1,3)],S=[33,65,8,232],W=new r;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){return w(),W.cursor=W.limit,!(W.cursor=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.sv.min.js b/assets/javascripts/lunr/min/lunr.sv.min.js new file mode 100644 index 000000000..3e5eb6400 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.sv.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Swedish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ta.min.js b/assets/javascripts/lunr/min/lunr.ta.min.js new file mode 100644 index 000000000..a644bed22 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ta.min.js @@ -0,0 +1 @@ +!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ta=function(){this.pipeline.reset(),this.pipeline.add(e.ta.trimmer,e.ta.stopWordFilter,e.ta.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ta.stemmer))},e.ta.wordCharacters="஀-உஊ-ஏஐ-ஙச-ட஠-னப-யர-ஹ஺-ிீ-௉ொ-௏ௐ-௙௚-௟௠-௩௪-௯௰-௹௺-௿a-zA-Za-zA-Z0-90-9",e.ta.trimmer=e.trimmerSupport.generateTrimmer(e.ta.wordCharacters),e.Pipeline.registerFunction(e.ta.trimmer,"trimmer-ta"),e.ta.stopWordFilter=e.generateStopWordFilter("அங்கு அங்கே அது அதை அந்த அவர் அவர்கள் அவள் அவன் அவை ஆக ஆகவே ஆகையால் ஆதலால் ஆதலினால் ஆனாலும் ஆனால் இங்கு இங்கே இது இதை இந்த இப்படி இவர் இவர்கள் இவள் இவன் இவை இவ்வளவு உனக்கு உனது உன் உன்னால் எங்கு எங்கே எது எதை எந்த எப்படி எவர் எவர்கள் எவள் எவன் எவை எவ்வளவு எனக்கு எனது எனவே என் என்ன என்னால் ஏது ஏன் தனது தன்னால் தானே தான் நாங்கள் நாம் நான் நீ நீங்கள்".split(" ")),e.ta.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.ta.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.ta.stemmer,"stemmer-ta"),e.Pipeline.registerFunction(e.ta.stopWordFilter,"stopWordFilter-ta")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.te.min.js b/assets/javascripts/lunr/min/lunr.te.min.js new file mode 100644 index 000000000..9fa7a93b9 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.te.min.js @@ -0,0 +1 @@ +!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.te=function(){this.pipeline.reset(),this.pipeline.add(e.te.trimmer,e.te.stopWordFilter,e.te.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.te.stemmer))},e.te.wordCharacters="ఀ-ఄఅ-ఔక-హా-ౌౕ-ౖౘ-ౚౠ-ౡౢ-ౣ౦-౯౸-౿఼ఽ్ౝ౷౤౥",e.te.trimmer=e.trimmerSupport.generateTrimmer(e.te.wordCharacters),e.Pipeline.registerFunction(e.te.trimmer,"trimmer-te"),e.te.stopWordFilter=e.generateStopWordFilter("అందరూ అందుబాటులో అడగండి అడగడం అడ్డంగా అనుగుణంగా అనుమతించు అనుమతిస్తుంది అయితే ఇప్పటికే ఉన్నారు ఎక్కడైనా ఎప్పుడు ఎవరైనా ఎవరో ఏ ఏదైనా ఏమైనప్పటికి ఒక ఒకరు కనిపిస్తాయి కాదు కూడా గా గురించి చుట్టూ చేయగలిగింది తగిన తర్వాత దాదాపు దూరంగా నిజంగా పై ప్రకారం ప్రక్కన మధ్య మరియు మరొక మళ్ళీ మాత్రమే మెచ్చుకో వద్ద వెంట వేరుగా వ్యతిరేకంగా సంబంధం".split(" ")),e.te.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.te.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.te.stemmer,"stemmer-te"),e.Pipeline.registerFunction(e.te.stopWordFilter,"stopWordFilter-te")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.th.min.js b/assets/javascripts/lunr/min/lunr.th.min.js new file mode 100644 index 000000000..dee3aac6e --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.th.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[฀-๿]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.tr.min.js b/assets/javascripts/lunr/min/lunr.tr.min.js new file mode 100644 index 000000000..563f6ec1f --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.tr.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Turkish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(r,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");r.tr=function(){this.pipeline.reset(),this.pipeline.add(r.tr.trimmer,r.tr.stopWordFilter,r.tr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.tr.stemmer))},r.tr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.tr.trimmer=r.trimmerSupport.generateTrimmer(r.tr.wordCharacters),r.Pipeline.registerFunction(r.tr.trimmer,"trimmer-tr"),r.tr.stemmer=function(){var i=r.stemmerSupport.Among,e=r.stemmerSupport.SnowballProgram,n=new function(){function r(r,i,e){for(;;){var n=Dr.limit-Dr.cursor;if(Dr.in_grouping_b(r,i,e)){Dr.cursor=Dr.limit-n;break}if(Dr.cursor=Dr.limit-n,Dr.cursor<=Dr.limit_backward)return!1;Dr.cursor--}return!0}function n(){var i,e;i=Dr.limit-Dr.cursor,r(Wr,97,305);for(var n=0;nDr.limit_backward&&(Dr.cursor--,e=Dr.limit-Dr.cursor,i()))?(Dr.cursor=Dr.limit-e,!0):(Dr.cursor=Dr.limit-n,r()?(Dr.cursor=Dr.limit-n,!1):(Dr.cursor=Dr.limit-n,!(Dr.cursor<=Dr.limit_backward)&&(Dr.cursor--,!!i()&&(Dr.cursor=Dr.limit-n,!0))))}function u(r){return t(r,function(){return Dr.in_grouping_b(Wr,97,305)})}function o(){return u(function(){return Dr.eq_s_b(1,"n")})}function s(){return u(function(){return Dr.eq_s_b(1,"s")})}function c(){return u(function(){return Dr.eq_s_b(1,"y")})}function l(){return t(function(){return Dr.in_grouping_b(Lr,105,305)},function(){return Dr.out_grouping_b(Wr,97,305)})}function a(){return Dr.find_among_b(ur,10)&&l()}function m(){return n()&&Dr.in_grouping_b(Lr,105,305)&&s()}function d(){return Dr.find_among_b(or,2)}function f(){return n()&&Dr.in_grouping_b(Lr,105,305)&&c()}function b(){return n()&&Dr.find_among_b(sr,4)}function w(){return n()&&Dr.find_among_b(cr,4)&&o()}function _(){return n()&&Dr.find_among_b(lr,2)&&c()}function k(){return n()&&Dr.find_among_b(ar,2)}function p(){return n()&&Dr.find_among_b(mr,4)}function g(){return n()&&Dr.find_among_b(dr,2)}function y(){return n()&&Dr.find_among_b(fr,4)}function z(){return n()&&Dr.find_among_b(br,2)}function v(){return n()&&Dr.find_among_b(wr,2)&&c()}function h(){return Dr.eq_s_b(2,"ki")}function q(){return n()&&Dr.find_among_b(_r,2)&&o()}function C(){return n()&&Dr.find_among_b(kr,4)&&c()}function P(){return n()&&Dr.find_among_b(pr,4)}function F(){return n()&&Dr.find_among_b(gr,4)&&c()}function S(){return Dr.find_among_b(yr,4)}function W(){return n()&&Dr.find_among_b(zr,2)}function L(){return n()&&Dr.find_among_b(vr,4)}function x(){return n()&&Dr.find_among_b(hr,8)}function A(){return Dr.find_among_b(qr,2)}function E(){return n()&&Dr.find_among_b(Cr,32)&&c()}function j(){return Dr.find_among_b(Pr,8)&&c()}function T(){return n()&&Dr.find_among_b(Fr,4)&&c()}function Z(){return Dr.eq_s_b(3,"ken")&&c()}function B(){var r=Dr.limit-Dr.cursor;return!(T()||(Dr.cursor=Dr.limit-r,E()||(Dr.cursor=Dr.limit-r,j()||(Dr.cursor=Dr.limit-r,Z()))))}function D(){if(A()){var r=Dr.limit-Dr.cursor;if(S()||(Dr.cursor=Dr.limit-r,W()||(Dr.cursor=Dr.limit-r,C()||(Dr.cursor=Dr.limit-r,P()||(Dr.cursor=Dr.limit-r,F()||(Dr.cursor=Dr.limit-r))))),T())return!1}return!0}function G(){if(W()){Dr.bra=Dr.cursor,Dr.slice_del();var r=Dr.limit-Dr.cursor;return Dr.ket=Dr.cursor,x()||(Dr.cursor=Dr.limit-r,E()||(Dr.cursor=Dr.limit-r,j()||(Dr.cursor=Dr.limit-r,T()||(Dr.cursor=Dr.limit-r)))),nr=!1,!1}return!0}function H(){if(!L())return!0;var r=Dr.limit-Dr.cursor;return!E()&&(Dr.cursor=Dr.limit-r,!j())}function I(){var r,i=Dr.limit-Dr.cursor;return!(S()||(Dr.cursor=Dr.limit-i,F()||(Dr.cursor=Dr.limit-i,P()||(Dr.cursor=Dr.limit-i,C()))))||(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,T()||(Dr.cursor=Dr.limit-r),!1)}function J(){var r,i=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,nr=!0,B()&&(Dr.cursor=Dr.limit-i,D()&&(Dr.cursor=Dr.limit-i,G()&&(Dr.cursor=Dr.limit-i,H()&&(Dr.cursor=Dr.limit-i,I()))))){if(Dr.cursor=Dr.limit-i,!x())return;Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,r=Dr.limit-Dr.cursor,S()||(Dr.cursor=Dr.limit-r,W()||(Dr.cursor=Dr.limit-r,C()||(Dr.cursor=Dr.limit-r,P()||(Dr.cursor=Dr.limit-r,F()||(Dr.cursor=Dr.limit-r))))),T()||(Dr.cursor=Dr.limit-r)}Dr.bra=Dr.cursor,Dr.slice_del()}function K(){var r,i,e,n;if(Dr.ket=Dr.cursor,h()){if(r=Dr.limit-Dr.cursor,p())return Dr.bra=Dr.cursor,Dr.slice_del(),i=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,W()?(Dr.bra=Dr.cursor,Dr.slice_del(),K()):(Dr.cursor=Dr.limit-i,a()&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()))),!0;if(Dr.cursor=Dr.limit-r,w()){if(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,e=Dr.limit-Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else{if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,!a()&&(Dr.cursor=Dr.limit-e,!m()&&(Dr.cursor=Dr.limit-e,!K())))return!0;Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())}return!0}if(Dr.cursor=Dr.limit-r,g()){if(n=Dr.limit-Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else if(Dr.cursor=Dr.limit-n,m())Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K());else if(Dr.cursor=Dr.limit-n,!K())return!1;return!0}}return!1}function M(r){if(Dr.ket=Dr.cursor,!g()&&(Dr.cursor=Dr.limit-r,!k()))return!1;var i=Dr.limit-Dr.cursor;if(d())Dr.bra=Dr.cursor,Dr.slice_del();else if(Dr.cursor=Dr.limit-i,m())Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K());else if(Dr.cursor=Dr.limit-i,!K())return!1;return!0}function N(r){if(Dr.ket=Dr.cursor,!z()&&(Dr.cursor=Dr.limit-r,!b()))return!1;var i=Dr.limit-Dr.cursor;return!(!m()&&(Dr.cursor=Dr.limit-i,!d()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()),!0)}function O(){var r,i=Dr.limit-Dr.cursor;return Dr.ket=Dr.cursor,!(!w()&&(Dr.cursor=Dr.limit-i,!v()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,!(!W()||(Dr.bra=Dr.cursor,Dr.slice_del(),!K()))||(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!(a()||(Dr.cursor=Dr.limit-r,m()||(Dr.cursor=Dr.limit-r,K())))||(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()),!0)))}function Q(){var r,i,e=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,!p()&&(Dr.cursor=Dr.limit-e,!f()&&(Dr.cursor=Dr.limit-e,!_())))return!1;if(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,r=Dr.limit-Dr.cursor,a())Dr.bra=Dr.cursor,Dr.slice_del(),i=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,W()||(Dr.cursor=Dr.limit-i);else if(Dr.cursor=Dr.limit-r,!W())return!0;return Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,K(),!0}function R(){var r,i,e=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,W())return Dr.bra=Dr.cursor,Dr.slice_del(),void K();if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,q())if(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else{if(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!a()&&(Dr.cursor=Dr.limit-r,!m())){if(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!W())return;if(Dr.bra=Dr.cursor,Dr.slice_del(),!K())return}Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())}else if(Dr.cursor=Dr.limit-e,!M(e)&&(Dr.cursor=Dr.limit-e,!N(e))){if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,y())return Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,i=Dr.limit-Dr.cursor,void(a()?(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())):(Dr.cursor=Dr.limit-i,W()?(Dr.bra=Dr.cursor,Dr.slice_del(),K()):(Dr.cursor=Dr.limit-i,K())));if(Dr.cursor=Dr.limit-e,!O()){if(Dr.cursor=Dr.limit-e,d())return Dr.bra=Dr.cursor,void Dr.slice_del();Dr.cursor=Dr.limit-e,K()||(Dr.cursor=Dr.limit-e,Q()||(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,(a()||(Dr.cursor=Dr.limit-e,m()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()))))}}}function U(){var r;if(Dr.ket=Dr.cursor,r=Dr.find_among_b(Sr,4))switch(Dr.bra=Dr.cursor,r){case 1:Dr.slice_from("p");break;case 2:Dr.slice_from("ç");break;case 3:Dr.slice_from("t");break;case 4:Dr.slice_from("k")}}function V(){for(;;){var r=Dr.limit-Dr.cursor;if(Dr.in_grouping_b(Wr,97,305)){Dr.cursor=Dr.limit-r;break}if(Dr.cursor=Dr.limit-r,Dr.cursor<=Dr.limit_backward)return!1;Dr.cursor--}return!0}function X(r,i,e){if(Dr.cursor=Dr.limit-r,V()){var n=Dr.limit-Dr.cursor;if(!Dr.eq_s_b(1,i)&&(Dr.cursor=Dr.limit-n,!Dr.eq_s_b(1,e)))return!0;Dr.cursor=Dr.limit-r;var t=Dr.cursor;return Dr.insert(Dr.cursor,Dr.cursor,e),Dr.cursor=t,!1}return!0}function Y(){var r=Dr.limit-Dr.cursor;(Dr.eq_s_b(1,"d")||(Dr.cursor=Dr.limit-r,Dr.eq_s_b(1,"g")))&&X(r,"a","ı")&&X(r,"e","i")&&X(r,"o","u")&&X(r,"ö","ü")}function $(){for(var r,i=Dr.cursor,e=2;;){for(r=Dr.cursor;!Dr.in_grouping(Wr,97,305);){if(Dr.cursor>=Dr.limit)return Dr.cursor=r,!(e>0)&&(Dr.cursor=i,!0);Dr.cursor++}e--}}function rr(r,i,e){for(;!Dr.eq_s(i,e);){if(Dr.cursor>=Dr.limit)return!0;Dr.cursor++}return(tr=i)!=Dr.limit||(Dr.cursor=r,!1)}function ir(){var r=Dr.cursor;return!rr(r,2,"ad")||(Dr.cursor=r,!rr(r,5,"soyad"))}function er(){var r=Dr.cursor;return!ir()&&(Dr.limit_backward=r,Dr.cursor=Dr.limit,Y(),Dr.cursor=Dr.limit,U(),!0)}var nr,tr,ur=[new i("m",-1,-1),new i("n",-1,-1),new i("miz",-1,-1),new i("niz",-1,-1),new i("muz",-1,-1),new i("nuz",-1,-1),new i("müz",-1,-1),new i("nüz",-1,-1),new i("mız",-1,-1),new i("nız",-1,-1)],or=[new i("leri",-1,-1),new i("ları",-1,-1)],sr=[new i("ni",-1,-1),new i("nu",-1,-1),new i("nü",-1,-1),new i("nı",-1,-1)],cr=[new i("in",-1,-1),new i("un",-1,-1),new i("ün",-1,-1),new i("ın",-1,-1)],lr=[new i("a",-1,-1),new i("e",-1,-1)],ar=[new i("na",-1,-1),new i("ne",-1,-1)],mr=[new i("da",-1,-1),new i("ta",-1,-1),new i("de",-1,-1),new i("te",-1,-1)],dr=[new i("nda",-1,-1),new i("nde",-1,-1)],fr=[new i("dan",-1,-1),new i("tan",-1,-1),new i("den",-1,-1),new i("ten",-1,-1)],br=[new i("ndan",-1,-1),new i("nden",-1,-1)],wr=[new i("la",-1,-1),new i("le",-1,-1)],_r=[new i("ca",-1,-1),new i("ce",-1,-1)],kr=[new i("im",-1,-1),new i("um",-1,-1),new i("üm",-1,-1),new i("ım",-1,-1)],pr=[new i("sin",-1,-1),new i("sun",-1,-1),new i("sün",-1,-1),new i("sın",-1,-1)],gr=[new i("iz",-1,-1),new i("uz",-1,-1),new i("üz",-1,-1),new i("ız",-1,-1)],yr=[new i("siniz",-1,-1),new i("sunuz",-1,-1),new i("sünüz",-1,-1),new i("sınız",-1,-1)],zr=[new i("lar",-1,-1),new i("ler",-1,-1)],vr=[new i("niz",-1,-1),new i("nuz",-1,-1),new i("nüz",-1,-1),new i("nız",-1,-1)],hr=[new i("dir",-1,-1),new i("tir",-1,-1),new i("dur",-1,-1),new i("tur",-1,-1),new i("dür",-1,-1),new i("tür",-1,-1),new i("dır",-1,-1),new i("tır",-1,-1)],qr=[new i("casına",-1,-1),new i("cesine",-1,-1)],Cr=[new i("di",-1,-1),new i("ti",-1,-1),new i("dik",-1,-1),new i("tik",-1,-1),new i("duk",-1,-1),new i("tuk",-1,-1),new i("dük",-1,-1),new i("tük",-1,-1),new i("dık",-1,-1),new i("tık",-1,-1),new i("dim",-1,-1),new i("tim",-1,-1),new i("dum",-1,-1),new i("tum",-1,-1),new i("düm",-1,-1),new i("tüm",-1,-1),new i("dım",-1,-1),new i("tım",-1,-1),new i("din",-1,-1),new i("tin",-1,-1),new i("dun",-1,-1),new i("tun",-1,-1),new i("dün",-1,-1),new i("tün",-1,-1),new i("dın",-1,-1),new i("tın",-1,-1),new i("du",-1,-1),new i("tu",-1,-1),new i("dü",-1,-1),new i("tü",-1,-1),new i("dı",-1,-1),new i("tı",-1,-1)],Pr=[new i("sa",-1,-1),new i("se",-1,-1),new i("sak",-1,-1),new i("sek",-1,-1),new i("sam",-1,-1),new i("sem",-1,-1),new i("san",-1,-1),new i("sen",-1,-1)],Fr=[new i("miş",-1,-1),new i("muş",-1,-1),new i("müş",-1,-1),new i("mış",-1,-1)],Sr=[new i("b",-1,1),new i("c",-1,2),new i("d",-1,3),new i("ğ",-1,4)],Wr=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,8,0,0,0,0,0,0,1],Lr=[1,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1],xr=[1,64,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],Ar=[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130],Er=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],jr=[17],Tr=[65],Zr=[65],Br=[["a",xr,97,305],["e",Ar,101,252],["ı",Er,97,305],["i",jr,101,105],["o",Tr,111,117],["ö",Zr,246,252],["u",Tr,111,117]],Dr=new e;this.setCurrent=function(r){Dr.setCurrent(r)},this.getCurrent=function(){return Dr.getCurrent()},this.stem=function(){return!!($()&&(Dr.limit_backward=Dr.cursor,Dr.cursor=Dr.limit,J(),Dr.cursor=Dr.limit,nr&&(R(),Dr.cursor=Dr.limit_backward,er())))}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.tr.stemmer,"stemmer-tr"),r.tr.stopWordFilter=r.generateStopWordFilter("acaba altmış altı ama ancak arada aslında ayrıca bana bazı belki ben benden beni benim beri beş bile bin bir biri birkaç birkez birçok birşey birşeyi biz bizden bize bizi bizim bu buna bunda bundan bunlar bunları bunların bunu bunun burada böyle böylece da daha dahi de defa değil diye diğer doksan dokuz dolayı dolayısıyla dört edecek eden ederek edilecek ediliyor edilmesi ediyor elli en etmesi etti ettiği ettiğini eğer gibi göre halen hangi hatta hem henüz hep hepsi her herhangi herkesin hiç hiçbir iki ile ilgili ise itibaren itibariyle için işte kadar karşın katrilyon kendi kendilerine kendini kendisi kendisine kendisini kez ki kim kimden kime kimi kimse kırk milyar milyon mu mü mı nasıl ne neden nedenle nerde nerede nereye niye niçin o olan olarak oldu olduklarını olduğu olduğunu olmadı olmadığı olmak olması olmayan olmaz olsa olsun olup olur olursa oluyor on ona ondan onlar onlardan onları onların onu onun otuz oysa pek rağmen sadece sanki sekiz seksen sen senden seni senin siz sizden sizi sizin tarafından trilyon tüm var vardı ve veya ya yani yapacak yapmak yaptı yaptıkları yaptığı yaptığını yapılan yapılması yapıyor yedi yerine yetmiş yine yirmi yoksa yüz zaten çok çünkü öyle üzere üç şey şeyden şeyi şeyler şu şuna şunda şundan şunları şunu şöyle".split(" ")),r.Pipeline.registerFunction(r.tr.stopWordFilter,"stopWordFilter-tr")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.vi.min.js b/assets/javascripts/lunr/min/lunr.vi.min.js new file mode 100644 index 000000000..22aed28c4 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.vi.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.zh.min.js b/assets/javascripts/lunr/min/lunr.zh.min.js new file mode 100644 index 000000000..fda66e9c5 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.zh.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("@node-rs/jieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 為 以 于 於 上 他 而 后 後 之 来 來 及 了 因 下 可 到 由 这 這 与 與 也 此 但 并 並 个 個 其 已 无 無 小 我 们 們 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 當 从 從 得 打 凡 儿 兒 尔 爾 该 該 各 给 給 跟 和 何 还 還 即 几 幾 既 看 据 據 距 靠 啦 另 么 麽 每 嘛 拿 哪 您 凭 憑 且 却 卻 让 讓 仍 啥 如 若 使 谁 誰 虽 雖 随 隨 同 所 她 哇 嗡 往 些 向 沿 哟 喲 用 咱 则 則 怎 曾 至 致 着 著 诸 諸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/tinyseg.js b/assets/javascripts/lunr/tinyseg.js new file mode 100644 index 000000000..167fa6dd6 --- /dev/null +++ b/assets/javascripts/lunr/tinyseg.js @@ -0,0 +1,206 @@ +/** + * export the module via AMD, CommonJS or as a browser global + * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js + */ +;(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(factory) + } else if (typeof exports === 'object') { + /** + * Node. Does not work with strict CommonJS, but + * only CommonJS-like environments that support module.exports, + * like Node. + */ + module.exports = factory() + } else { + // Browser globals (root is window) + factory()(root.lunr); + } +}(this, function () { + /** + * Just return a value to define the module export. + * This example returns an object, but the module + * can return a function as the exported value. + */ + + return function(lunr) { + // TinySegmenter 0.1 -- Super compact Japanese tokenizer in Javascript + // (c) 2008 Taku Kudo + // TinySegmenter is freely distributable under the terms of a new BSD licence. + // For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt + + function TinySegmenter() { + var patterns = { + "[一二三四五六七八九十百千万億兆]":"M", + "[一-龠々〆ヵヶ]":"H", + "[ぁ-ん]":"I", + "[ァ-ヴーア-ン゙ー]":"K", + "[a-zA-Za-zA-Z]":"A", + "[0-90-9]":"N" + } + this.chartype_ = []; + for (var i in patterns) { + var regexp = new RegExp(i); + this.chartype_.push([regexp, patterns[i]]); + } + + this.BIAS__ = -332 + this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378}; + this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920}; + this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266}; + this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352}; + this.BP2__ = {"BO":60,"OO":-1762}; + this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965}; + this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146}; + this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699}; + this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973}; + this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682}; + this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669}; + this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990}; + this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832}; + this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649}; + this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393}; + this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841}; + this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68}; + this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591}; + this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685}; + this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156}; + this.TW1__ = {"につい":-4681,"東京都":2026}; + this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216}; + this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287}; + this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865}; + this.UC1__ = {"A":484,"K":93,"M":645,"O":-505}; + this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646}; + this.UC3__ = {"A":-1370,"I":2311}; + this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646}; + this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831}; + this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387}; + this.UP1__ = {"O":-214}; + this.UP2__ = {"B":69,"O":935}; + this.UP3__ = {"B":189}; + this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422}; + this.UQ2__ = {"BH":216,"BI":113,"OK":1759}; + this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212}; + this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135}; + this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568}; + this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278}; + this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637}; + this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343}; + this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496}; + + return this; + } + TinySegmenter.prototype.ctype_ = function(str) { + for (var i in this.chartype_) { + if (str.match(this.chartype_[i][0])) { + return this.chartype_[i][1]; + } + } + return "O"; + } + + TinySegmenter.prototype.ts_ = function(v) { + if (v) { return v; } + return 0; + } + + TinySegmenter.prototype.segment = function(input) { + if (input == null || input == undefined || input == "") { + return []; + } + var result = []; + var seg = ["B3","B2","B1"]; + var ctype = ["O","O","O"]; + var o = input.split(""); + for (i = 0; i < o.length; ++i) { + seg.push(o[i]); + ctype.push(this.ctype_(o[i])) + } + seg.push("E1"); + seg.push("E2"); + seg.push("E3"); + ctype.push("O"); + ctype.push("O"); + ctype.push("O"); + var word = seg[3]; + var p1 = "U"; + var p2 = "U"; + var p3 = "U"; + for (var i = 4; i < seg.length - 3; ++i) { + var score = this.BIAS__; + var w1 = seg[i-3]; + var w2 = seg[i-2]; + var w3 = seg[i-1]; + var w4 = seg[i]; + var w5 = seg[i+1]; + var w6 = seg[i+2]; + var c1 = ctype[i-3]; + var c2 = ctype[i-2]; + var c3 = ctype[i-1]; + var c4 = ctype[i]; + var c5 = ctype[i+1]; + var c6 = ctype[i+2]; + score += this.ts_(this.UP1__[p1]); + score += this.ts_(this.UP2__[p2]); + score += this.ts_(this.UP3__[p3]); + score += this.ts_(this.BP1__[p1 + p2]); + score += this.ts_(this.BP2__[p2 + p3]); + score += this.ts_(this.UW1__[w1]); + score += this.ts_(this.UW2__[w2]); + score += this.ts_(this.UW3__[w3]); + score += this.ts_(this.UW4__[w4]); + score += this.ts_(this.UW5__[w5]); + score += this.ts_(this.UW6__[w6]); + score += this.ts_(this.BW1__[w2 + w3]); + score += this.ts_(this.BW2__[w3 + w4]); + score += this.ts_(this.BW3__[w4 + w5]); + score += this.ts_(this.TW1__[w1 + w2 + w3]); + score += this.ts_(this.TW2__[w2 + w3 + w4]); + score += this.ts_(this.TW3__[w3 + w4 + w5]); + score += this.ts_(this.TW4__[w4 + w5 + w6]); + score += this.ts_(this.UC1__[c1]); + score += this.ts_(this.UC2__[c2]); + score += this.ts_(this.UC3__[c3]); + score += this.ts_(this.UC4__[c4]); + score += this.ts_(this.UC5__[c5]); + score += this.ts_(this.UC6__[c6]); + score += this.ts_(this.BC1__[c2 + c3]); + score += this.ts_(this.BC2__[c3 + c4]); + score += this.ts_(this.BC3__[c4 + c5]); + score += this.ts_(this.TC1__[c1 + c2 + c3]); + score += this.ts_(this.TC2__[c2 + c3 + c4]); + score += this.ts_(this.TC3__[c3 + c4 + c5]); + score += this.ts_(this.TC4__[c4 + c5 + c6]); + // score += this.ts_(this.TC5__[c4 + c5 + c6]); + score += this.ts_(this.UQ1__[p1 + c1]); + score += this.ts_(this.UQ2__[p2 + c2]); + score += this.ts_(this.UQ3__[p3 + c3]); + score += this.ts_(this.BQ1__[p2 + c2 + c3]); + score += this.ts_(this.BQ2__[p2 + c3 + c4]); + score += this.ts_(this.BQ3__[p3 + c2 + c3]); + score += this.ts_(this.BQ4__[p3 + c3 + c4]); + score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]); + score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]); + score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]); + score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]); + var p = "O"; + if (score > 0) { + result.push(word); + word = ""; + p = "B"; + } + p1 = p2; + p2 = p3; + p3 = p; + word += seg[i]; + } + result.push(word); + + return result; + } + + lunr.TinySegmenter = TinySegmenter; + }; + +})); \ No newline at end of file diff --git a/assets/javascripts/lunr/wordcut.js b/assets/javascripts/lunr/wordcut.js new file mode 100644 index 000000000..0d898c9ed --- /dev/null +++ b/assets/javascripts/lunr/wordcut.js @@ -0,0 +1,6708 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.lunr || (g.lunr = {})).wordcut = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1; + }) + this.addWords(words, false) + } + if(finalize){ + this.finalizeDict(); + } + }, + + dictSeek: function (l, r, ch, strOffset, pos) { + var ans = null; + while (l <= r) { + var m = Math.floor((l + r) / 2), + dict_item = this.dict[m], + len = dict_item.length; + if (len <= strOffset) { + l = m + 1; + } else { + var ch_ = dict_item[strOffset]; + if (ch_ < ch) { + l = m + 1; + } else if (ch_ > ch) { + r = m - 1; + } else { + ans = m; + if (pos == LEFT) { + r = m - 1; + } else { + l = m + 1; + } + } + } + } + return ans; + }, + + isFinal: function (acceptor) { + return this.dict[acceptor.l].length == acceptor.strOffset; + }, + + createAcceptor: function () { + return { + l: 0, + r: this.dict.length - 1, + strOffset: 0, + isFinal: false, + dict: this, + transit: function (ch) { + return this.dict.transit(this, ch); + }, + isError: false, + tag: "DICT", + w: 1, + type: "DICT" + }; + }, + + transit: function (acceptor, ch) { + var l = this.dictSeek(acceptor.l, + acceptor.r, + ch, + acceptor.strOffset, + LEFT); + if (l !== null) { + var r = this.dictSeek(l, + acceptor.r, + ch, + acceptor.strOffset, + RIGHT); + acceptor.l = l; + acceptor.r = r; + acceptor.strOffset++; + acceptor.isFinal = this.isFinal(acceptor); + } else { + acceptor.isError = true; + } + return acceptor; + }, + + sortuniq: function(a){ + return a.sort().filter(function(item, pos, arr){ + return !pos || item != arr[pos - 1]; + }) + }, + + flatten: function(a){ + //[[1,2],[3]] -> [1,2,3] + return [].concat.apply([], a); + } +}; +module.exports = WordcutDict; + +}).call(this,"/dist/tmp") +},{"glob":16,"path":22}],3:[function(require,module,exports){ +var WordRule = { + createAcceptor: function(tag) { + if (tag["WORD_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + var lch = ch.toLowerCase(); + if (lch >= "a" && lch <= "z") { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "WORD_RULE", + type: "WORD_RULE", + w: 1}; + } +}; + +var NumberRule = { + createAcceptor: function(tag) { + if (tag["NUMBER_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (ch >= "0" && ch <= "9") { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "NUMBER_RULE", + type: "NUMBER_RULE", + w: 1}; + } +}; + +var SpaceRule = { + tag: "SPACE_RULE", + createAcceptor: function(tag) { + + if (tag["SPACE_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (ch == " " || ch == "\t" || ch == "\r" || ch == "\n" || + ch == "\u00A0" || ch=="\u2003"//nbsp and emsp + ) { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: SpaceRule.tag, + w: 1, + type: "SPACE_RULE"}; + } +} + +var SingleSymbolRule = { + tag: "SINSYM", + createAcceptor: function(tag) { + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (this.strOffset == 0 && ch.match(/^[\@\(\)\/\,\-\."`]$/)) { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "SINSYM", + w: 1, + type: "SINSYM"}; + } +} + + +var LatinRules = [WordRule, SpaceRule, SingleSymbolRule, NumberRule]; + +module.exports = LatinRules; + +},{}],4:[function(require,module,exports){ +var _ = require("underscore") + , WordcutCore = require("./wordcut_core"); +var PathInfoBuilder = { + + /* + buildByPartAcceptors: function(path, acceptors, i) { + var + var genInfos = partAcceptors.reduce(function(genInfos, acceptor) { + + }, []); + + return genInfos; + } + */ + + buildByAcceptors: function(path, finalAcceptors, i) { + var self = this; + var infos = finalAcceptors.map(function(acceptor) { + var p = i - acceptor.strOffset + 1 + , _info = path[p]; + + var info = {p: p, + mw: _info.mw + (acceptor.mw === undefined ? 0 : acceptor.mw), + w: acceptor.w + _info.w, + unk: (acceptor.unk ? acceptor.unk : 0) + _info.unk, + type: acceptor.type}; + + if (acceptor.type == "PART") { + for(var j = p + 1; j <= i; j++) { + path[j].merge = p; + } + info.merge = p; + } + + return info; + }); + return infos.filter(function(info) { return info; }); + }, + + fallback: function(path, leftBoundary, text, i) { + var _info = path[leftBoundary]; + if (text[i].match(/[\u0E48-\u0E4E]/)) { + if (leftBoundary != 0) + leftBoundary = path[leftBoundary].p; + return {p: leftBoundary, + mw: 0, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; +/* } else if(leftBoundary > 0 && path[leftBoundary].type !== "UNK") { + leftBoundary = path[leftBoundary].p; + return {p: leftBoundary, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; */ + } else { + return {p: leftBoundary, + mw: _info.mw, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; + } + }, + + build: function(path, finalAcceptors, i, leftBoundary, text) { + var basicPathInfos = this.buildByAcceptors(path, finalAcceptors, i); + if (basicPathInfos.length > 0) { + return basicPathInfos; + } else { + return [this.fallback(path, leftBoundary, text, i)]; + } + } +}; + +module.exports = function() { + return _.clone(PathInfoBuilder); +} + +},{"./wordcut_core":8,"underscore":25}],5:[function(require,module,exports){ +var _ = require("underscore"); + + +var PathSelector = { + selectPath: function(paths) { + var path = paths.reduce(function(selectedPath, path) { + if (selectedPath == null) { + return path; + } else { + if (path.unk < selectedPath.unk) + return path; + if (path.unk == selectedPath.unk) { + if (path.mw < selectedPath.mw) + return path + if (path.mw == selectedPath.mw) { + if (path.w < selectedPath.w) + return path; + } + } + return selectedPath; + } + }, null); + return path; + }, + + createPath: function() { + return [{p:null, w:0, unk:0, type: "INIT", mw:0}]; + } +}; + +module.exports = function() { + return _.clone(PathSelector); +}; + +},{"underscore":25}],6:[function(require,module,exports){ +function isMatch(pat, offset, ch) { + if (pat.length <= offset) + return false; + var _ch = pat[offset]; + return _ch == ch || + (_ch.match(/[กข]/) && ch.match(/[ก-ฮ]/)) || + (_ch.match(/[มบ]/) && ch.match(/[ก-ฮ]/)) || + (_ch.match(/\u0E49/) && ch.match(/[\u0E48-\u0E4B]/)); +} + +var Rule0 = { + pat: "เหก็ม", + createAcceptor: function(tag) { + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (isMatch(Rule0.pat, this.strOffset,ch)) { + this.isFinal = (this.strOffset + 1 == Rule0.pat.length); + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "THAI_RULE", + type: "THAI_RULE", + w: 1}; + } +}; + +var PartRule = { + createAcceptor: function(tag) { + return {strOffset: 0, + patterns: [ + "แก", "เก", "ก้", "กก์", "กา", "กี", "กิ", "กืก" + ], + isFinal: false, + transit: function(ch) { + var offset = this.strOffset; + this.patterns = this.patterns.filter(function(pat) { + return isMatch(pat, offset, ch); + }); + + if (this.patterns.length > 0) { + var len = 1 + offset; + this.isFinal = this.patterns.some(function(pat) { + return pat.length == len; + }); + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "PART", + type: "PART", + unk: 1, + w: 1}; + } +}; + +var ThaiRules = [Rule0, PartRule]; + +module.exports = ThaiRules; + +},{}],7:[function(require,module,exports){ +var sys = require("sys") + , WordcutDict = require("./dict") + , WordcutCore = require("./wordcut_core") + , PathInfoBuilder = require("./path_info_builder") + , PathSelector = require("./path_selector") + , Acceptors = require("./acceptors") + , latinRules = require("./latin_rules") + , thaiRules = require("./thai_rules") + , _ = require("underscore"); + + +var Wordcut = Object.create(WordcutCore); +Wordcut.defaultPathInfoBuilder = PathInfoBuilder; +Wordcut.defaultPathSelector = PathSelector; +Wordcut.defaultAcceptors = Acceptors; +Wordcut.defaultLatinRules = latinRules; +Wordcut.defaultThaiRules = thaiRules; +Wordcut.defaultDict = WordcutDict; + + +Wordcut.initNoDict = function(dict_path) { + var self = this; + self.pathInfoBuilder = new self.defaultPathInfoBuilder; + self.pathSelector = new self.defaultPathSelector; + self.acceptors = new self.defaultAcceptors; + self.defaultLatinRules.forEach(function(rule) { + self.acceptors.creators.push(rule); + }); + self.defaultThaiRules.forEach(function(rule) { + self.acceptors.creators.push(rule); + }); +}; + +Wordcut.init = function(dict_path, withDefault, additionalWords) { + withDefault = withDefault || false; + this.initNoDict(); + var dict = _.clone(this.defaultDict); + dict.init(dict_path, withDefault, additionalWords); + this.acceptors.creators.push(dict); +}; + +module.exports = Wordcut; + +},{"./acceptors":1,"./dict":2,"./latin_rules":3,"./path_info_builder":4,"./path_selector":5,"./thai_rules":6,"./wordcut_core":8,"sys":28,"underscore":25}],8:[function(require,module,exports){ +var WordcutCore = { + + buildPath: function(text) { + var self = this + , path = self.pathSelector.createPath() + , leftBoundary = 0; + self.acceptors.reset(); + for (var i = 0; i < text.length; i++) { + var ch = text[i]; + self.acceptors.transit(ch); + + var possiblePathInfos = self + .pathInfoBuilder + .build(path, + self.acceptors.getFinalAcceptors(), + i, + leftBoundary, + text); + var selectedPath = self.pathSelector.selectPath(possiblePathInfos) + + path.push(selectedPath); + if (selectedPath.type !== "UNK") { + leftBoundary = i; + } + } + return path; + }, + + pathToRanges: function(path) { + var e = path.length - 1 + , ranges = []; + + while (e > 0) { + var info = path[e] + , s = info.p; + + if (info.merge !== undefined && ranges.length > 0) { + var r = ranges[ranges.length - 1]; + r.s = info.merge; + s = r.s; + } else { + ranges.push({s:s, e:e}); + } + e = s; + } + return ranges.reverse(); + }, + + rangesToText: function(text, ranges, delimiter) { + return ranges.map(function(r) { + return text.substring(r.s, r.e); + }).join(delimiter); + }, + + cut: function(text, delimiter) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + return this + .rangesToText(text, ranges, + (delimiter === undefined ? "|" : delimiter)); + }, + + cutIntoRanges: function(text, noText) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + + if (!noText) { + ranges.forEach(function(r) { + r.text = text.substring(r.s, r.e); + }); + } + return ranges; + }, + + cutIntoArray: function(text) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + + return ranges.map(function(r) { + return text.substring(r.s, r.e) + }); + } +}; + +module.exports = WordcutCore; + +},{}],9:[function(require,module,exports){ +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// when used in node, this will actually load the util module we depend on +// versus loading the builtin util module as happens otherwise +// this is a bug in node module loading as far as I am concerned +var util = require('util/'); + +var pSlice = Array.prototype.slice; +var hasOwn = Object.prototype.hasOwnProperty; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } + else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = stackStartFunction.name; + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && !isFinite(value)) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) { + return a === b; + } + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + var ka = objectKeys(a), + kb = objectKeys(b), + key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (util.isString(expected)) { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +},{"util/":28}],10:[function(require,module,exports){ +'use strict'; +module.exports = balanced; +function balanced(a, b, str) { + if (a instanceof RegExp) a = maybeMatch(a, str); + if (b instanceof RegExp) b = maybeMatch(b, str); + + var r = range(a, b, str); + + return r && { + start: r[0], + end: r[1], + pre: str.slice(0, r[0]), + body: str.slice(r[0] + a.length, r[1]), + post: str.slice(r[1] + b.length) + }; +} + +function maybeMatch(reg, str) { + var m = str.match(reg); + return m ? m[0] : null; +} + +balanced.range = range; +function range(a, b, str) { + var begs, beg, left, right, result; + var ai = str.indexOf(a); + var bi = str.indexOf(b, ai + 1); + var i = ai; + + if (ai >= 0 && bi > 0) { + begs = []; + left = str.length; + + while (i >= 0 && !result) { + if (i == ai) { + begs.push(i); + ai = str.indexOf(a, i + 1); + } else if (begs.length == 1) { + result = [ begs.pop(), bi ]; + } else { + beg = begs.pop(); + if (beg < left) { + left = beg; + right = bi; + } + + bi = str.indexOf(b, i + 1); + } + + i = ai < bi && ai >= 0 ? ai : bi; + } + + if (begs.length) { + result = [ left, right ]; + } + } + + return result; +} + +},{}],11:[function(require,module,exports){ +var concatMap = require('concat-map'); +var balanced = require('balanced-match'); + +module.exports = expandTop; + +var escSlash = '\0SLASH'+Math.random()+'\0'; +var escOpen = '\0OPEN'+Math.random()+'\0'; +var escClose = '\0CLOSE'+Math.random()+'\0'; +var escComma = '\0COMMA'+Math.random()+'\0'; +var escPeriod = '\0PERIOD'+Math.random()+'\0'; + +function numeric(str) { + return parseInt(str, 10) == str + ? parseInt(str, 10) + : str.charCodeAt(0); +} + +function escapeBraces(str) { + return str.split('\\\\').join(escSlash) + .split('\\{').join(escOpen) + .split('\\}').join(escClose) + .split('\\,').join(escComma) + .split('\\.').join(escPeriod); +} + +function unescapeBraces(str) { + return str.split(escSlash).join('\\') + .split(escOpen).join('{') + .split(escClose).join('}') + .split(escComma).join(',') + .split(escPeriod).join('.'); +} + + +// Basically just str.split(","), but handling cases +// where we have nested braced sections, which should be +// treated as individual members, like {a,{b,c},d} +function parseCommaParts(str) { + if (!str) + return ['']; + + var parts = []; + var m = balanced('{', '}', str); + + if (!m) + return str.split(','); + + var pre = m.pre; + var body = m.body; + var post = m.post; + var p = pre.split(','); + + p[p.length-1] += '{' + body + '}'; + var postParts = parseCommaParts(post); + if (post.length) { + p[p.length-1] += postParts.shift(); + p.push.apply(p, postParts); + } + + parts.push.apply(parts, p); + + return parts; +} + +function expandTop(str) { + if (!str) + return []; + + // I don't know why Bash 4.3 does this, but it does. + // Anything starting with {} will have the first two bytes preserved + // but *only* at the top level, so {},a}b will not expand to anything, + // but a{},b}c will be expanded to [a}c,abc]. + // One could argue that this is a bug in Bash, but since the goal of + // this module is to match Bash's rules, we escape a leading {} + if (str.substr(0, 2) === '{}') { + str = '\\{\\}' + str.substr(2); + } + + return expand(escapeBraces(str), true).map(unescapeBraces); +} + +function identity(e) { + return e; +} + +function embrace(str) { + return '{' + str + '}'; +} +function isPadded(el) { + return /^-?0\d/.test(el); +} + +function lte(i, y) { + return i <= y; +} +function gte(i, y) { + return i >= y; +} + +function expand(str, isTop) { + var expansions = []; + + var m = balanced('{', '}', str); + if (!m || /\$$/.test(m.pre)) return [str]; + + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); + var isSequence = isNumericSequence || isAlphaSequence; + var isOptions = m.body.indexOf(',') >= 0; + if (!isSequence && !isOptions) { + // {a},b} + if (m.post.match(/,.*\}/)) { + str = m.pre + '{' + m.body + escClose + m.post; + return expand(str); + } + return [str]; + } + + var n; + if (isSequence) { + n = m.body.split(/\.\./); + } else { + n = parseCommaParts(m.body); + if (n.length === 1) { + // x{{a,b}}y ==> x{a}y x{b}y + n = expand(n[0], false).map(embrace); + if (n.length === 1) { + var post = m.post.length + ? expand(m.post, false) + : ['']; + return post.map(function(p) { + return m.pre + n[0] + p; + }); + } + } + } + + // at this point, n is the parts, and we know it's not a comma set + // with a single entry. + + // no need to expand pre, since it is guaranteed to be free of brace-sets + var pre = m.pre; + var post = m.post.length + ? expand(m.post, false) + : ['']; + + var N; + + if (isSequence) { + var x = numeric(n[0]); + var y = numeric(n[1]); + var width = Math.max(n[0].length, n[1].length) + var incr = n.length == 3 + ? Math.abs(numeric(n[2])) + : 1; + var test = lte; + var reverse = y < x; + if (reverse) { + incr *= -1; + test = gte; + } + var pad = n.some(isPadded); + + N = []; + + for (var i = x; test(i, y); i += incr) { + var c; + if (isAlphaSequence) { + c = String.fromCharCode(i); + if (c === '\\') + c = ''; + } else { + c = String(i); + if (pad) { + var need = width - c.length; + if (need > 0) { + var z = new Array(need + 1).join('0'); + if (i < 0) + c = '-' + z + c.slice(1); + else + c = z + c; + } + } + } + N.push(c); + } + } else { + N = concatMap(n, function(el) { return expand(el, false) }); + } + + for (var j = 0; j < N.length; j++) { + for (var k = 0; k < post.length; k++) { + var expansion = pre + N[j] + post[k]; + if (!isTop || isSequence || expansion) + expansions.push(expansion); + } + } + + return expansions; +} + + +},{"balanced-match":10,"concat-map":13}],12:[function(require,module,exports){ + +},{}],13:[function(require,module,exports){ +module.exports = function (xs, fn) { + var res = []; + for (var i = 0; i < xs.length; i++) { + var x = fn(xs[i], i); + if (isArray(x)) res.push.apply(res, x); + else res.push(x); + } + return res; +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +},{}],14:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],15:[function(require,module,exports){ +(function (process){ +exports.alphasort = alphasort +exports.alphasorti = alphasorti +exports.setopts = setopts +exports.ownProp = ownProp +exports.makeAbs = makeAbs +exports.finish = finish +exports.mark = mark +exports.isIgnored = isIgnored +exports.childrenIgnored = childrenIgnored + +function ownProp (obj, field) { + return Object.prototype.hasOwnProperty.call(obj, field) +} + +var path = require("path") +var minimatch = require("minimatch") +var isAbsolute = require("path-is-absolute") +var Minimatch = minimatch.Minimatch + +function alphasorti (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()) +} + +function alphasort (a, b) { + return a.localeCompare(b) +} + +function setupIgnores (self, options) { + self.ignore = options.ignore || [] + + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] + + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) + } +} + +function ignoreMap (pattern) { + var gmatcher = null + if (pattern.slice(-3) === '/**') { + var gpattern = pattern.replace(/(\/\*\*)+$/, '') + gmatcher = new Minimatch(gpattern) + } + + return { + matcher: new Minimatch(pattern), + gmatcher: gmatcher + } +} + +function setopts (self, pattern, options) { + if (!options) + options = {} + + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") + } + pattern = "**/" + pattern + } + + self.silent = !!options.silent + self.pattern = pattern + self.strict = options.strict !== false + self.realpath = !!options.realpath + self.realpathCache = options.realpathCache || Object.create(null) + self.follow = !!options.follow + self.dot = !!options.dot + self.mark = !!options.mark + self.nodir = !!options.nodir + if (self.nodir) + self.mark = true + self.sync = !!options.sync + self.nounique = !!options.nounique + self.nonull = !!options.nonull + self.nosort = !!options.nosort + self.nocase = !!options.nocase + self.stat = !!options.stat + self.noprocess = !!options.noprocess + + self.maxLength = options.maxLength || Infinity + self.cache = options.cache || Object.create(null) + self.statCache = options.statCache || Object.create(null) + self.symlinks = options.symlinks || Object.create(null) + + setupIgnores(self, options) + + self.changedCwd = false + var cwd = process.cwd() + if (!ownProp(options, "cwd")) + self.cwd = cwd + else { + self.cwd = options.cwd + self.changedCwd = path.resolve(options.cwd) !== cwd + } + + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") + + self.nomount = !!options.nomount + + // disable comments and negation unless the user explicitly + // passes in false as the option. + options.nonegate = options.nonegate === false ? false : true + options.nocomment = options.nocomment === false ? false : true + deprecationWarning(options) + + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options +} + +// TODO(isaacs): remove entirely in v6 +// exported to reset in tests +exports.deprecationWarned +function deprecationWarning(options) { + if (!options.nonegate || !options.nocomment) { + if (process.noDeprecation !== true && !exports.deprecationWarned) { + var msg = 'glob WARNING: comments and negation will be disabled in v6' + if (process.throwDeprecation) + throw new Error(msg) + else if (process.traceDeprecation) + console.trace(msg) + else + console.error(msg) + + exports.deprecationWarned = true + } + } +} + +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) + + for (var i = 0, l = self.matches.length; i < l; i ++) { + var matches = self.matches[i] + if (!matches || Object.keys(matches).length === 0) { + if (self.nonull) { + // do like the shell, and spit out the literal glob + var literal = self.minimatch.globSet[i] + if (nou) + all.push(literal) + else + all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) + all.push.apply(all, m) + else + m.forEach(function (m) { + all[m] = true + }) + } + } + + if (!nou) + all = Object.keys(all) + + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) + + // at *some* point we statted all of these + if (self.mark) { + for (var i = 0; i < all.length; i++) { + all[i] = self._mark(all[i]) + } + if (self.nodir) { + all = all.filter(function (e) { + return !(/\/$/.test(e)) + }) + } + } + + if (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) + + self.found = all +} + +function mark (self, p) { + var abs = makeAbs(self, p) + var c = self.cache[abs] + var m = p + if (c) { + var isDir = c === 'DIR' || Array.isArray(c) + var slash = p.slice(-1) === '/' + + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) + + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] + } + } + + return m +} + +// lotta situps... +function makeAbs (self, f) { + var abs = f + if (f.charAt(0) === '/') { + abs = path.join(self.root, f) + } else if (isAbsolute(f) || f === '') { + abs = f + } else if (self.changedCwd) { + abs = path.resolve(self.cwd, f) + } else { + abs = path.resolve(f) + } + return abs +} + + +// Return true, if pattern ends with globstar '**', for the accompanying parent directory. +// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents +function isIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) +} + +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) +} + +}).call(this,require('_process')) +},{"_process":24,"minimatch":20,"path":22,"path-is-absolute":23}],16:[function(require,module,exports){ +(function (process){ +// Approach: +// +// 1. Get the minimatch set +// 2. For each pattern in the set, PROCESS(pattern, false) +// 3. Store matches per-set, then uniq them +// +// PROCESS(pattern, inGlobStar) +// Get the first [n] items from pattern that are all strings +// Join these together. This is PREFIX. +// If there is no more remaining, then stat(PREFIX) and +// add to matches if it succeeds. END. +// +// If inGlobStar and PREFIX is symlink and points to dir +// set ENTRIES = [] +// else readdir(PREFIX) as ENTRIES +// If fail, END +// +// with ENTRIES +// If pattern[n] is GLOBSTAR +// // handle the case where the globstar match is empty +// // by pruning it out, and testing the resulting pattern +// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) +// // handle other cases. +// for ENTRY in ENTRIES (not dotfiles) +// // attach globstar + tail onto the entry +// // Mark that this entry is a globstar match +// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) +// +// else // not globstar +// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) +// Test ENTRY against pattern[n] +// If fails, continue +// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) +// +// Caveat: +// Cache all stats and readdirs results to minimize syscall. Since all +// we ever care about is existence and directory-ness, we can just keep +// `true` for files, and [children,...] for directories, or `false` for +// things that don't exist. + +module.exports = glob + +var fs = require('fs') +var minimatch = require('minimatch') +var Minimatch = minimatch.Minimatch +var inherits = require('inherits') +var EE = require('events').EventEmitter +var path = require('path') +var assert = require('assert') +var isAbsolute = require('path-is-absolute') +var globSync = require('./sync.js') +var common = require('./common.js') +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var inflight = require('inflight') +var util = require('util') +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored + +var once = require('once') + +function glob (pattern, options, cb) { + if (typeof options === 'function') cb = options, options = {} + if (!options) options = {} + + if (options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return globSync(pattern, options) + } + + return new Glob(pattern, options, cb) +} + +glob.sync = globSync +var GlobSync = glob.GlobSync = globSync.GlobSync + +// old api surface +glob.glob = glob + +glob.hasMagic = function (pattern, options_) { + var options = util._extend({}, options_) + options.noprocess = true + + var g = new Glob(pattern, options) + var set = g.minimatch.set + if (set.length > 1) + return true + + for (var j = 0; j < set[0].length; j++) { + if (typeof set[0][j] !== 'string') + return true + } + + return false +} + +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (typeof options === 'function') { + cb = options + options = null + } + + if (options && options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return new GlobSync(pattern, options) + } + + if (!(this instanceof Glob)) + return new Glob(pattern, options, cb) + + setopts(this, pattern, options) + this._didRealPath = false + + // process each pattern in the minimatch set + var n = this.minimatch.set.length + + // The matches are stored as {: true,...} so that + // duplicates are automagically pruned. + // Later, we do an Object.keys() on these. + // Keep them as a list so we can fill in when nonull is set. + this.matches = new Array(n) + + if (typeof cb === 'function') { + cb = once(cb) + this.on('error', cb) + this.on('end', function (matches) { + cb(null, matches) + }) + } + + var self = this + var n = this.minimatch.set.length + this._processing = 0 + this.matches = new Array(n) + + this._emitQueue = [] + this._processQueue = [] + this.paused = false + + if (this.noprocess) + return this + + if (n === 0) + return done() + + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false, done) + } + + function done () { + --self._processing + if (self._processing <= 0) + self._finish() + } +} + +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return + + if (this.realpath && !this._didRealpath) + return this._realpath() + + common.finish(this) + this.emit('end', this.found) +} + +Glob.prototype._realpath = function () { + if (this._didRealpath) + return + + this._didRealpath = true + + var n = this.matches.length + if (n === 0) + return this._finish() + + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) + + function next () { + if (--n === 0) + self._finish() + } +} + +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() + + var found = Object.keys(matchset) + var self = this + var n = found.length + + if (n === 0) + return cb() + + var set = this.matches[index] = Object.create(null) + found.forEach(function (p, i) { + // If there's a problem with the stat, then it means that + // one or more of the links in the realpath couldn't be + // resolved. just return the abs value in that case. + p = self._makeAbs(p) + fs.realpath(p, self.realpathCache, function (er, real) { + if (!er) + set[real] = true + else if (er.syscall === 'stat') + set[p] = true + else + self.emit('error', er) // srsly wtf right here + + if (--n === 0) { + self.matches[index] = set + cb() + } + }) + }) +} + +Glob.prototype._mark = function (p) { + return common.mark(this, p) +} + +Glob.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} + +Glob.prototype.abort = function () { + this.aborted = true + this.emit('abort') +} + +Glob.prototype.pause = function () { + if (!this.paused) { + this.paused = true + this.emit('pause') + } +} + +Glob.prototype.resume = function () { + if (this.paused) { + this.emit('resume') + this.paused = false + if (this._emitQueue.length) { + var eq = this._emitQueue.slice(0) + this._emitQueue.length = 0 + for (var i = 0; i < eq.length; i ++) { + var e = eq[i] + this._emitMatch(e[0], e[1]) + } + } + if (this._processQueue.length) { + var pq = this._processQueue.slice(0) + this._processQueue.length = 0 + for (var i = 0; i < pq.length; i ++) { + var p = pq[i] + this._processing-- + this._process(p[0], p[1], p[2], p[3]) + } + } + } +} + +Glob.prototype._process = function (pattern, index, inGlobStar, cb) { + assert(this instanceof Glob) + assert(typeof cb === 'function') + + if (this.aborted) + return + + this._processing++ + if (this.paused) { + this._processQueue.push([pattern, index, inGlobStar, cb]) + return + } + + //console.error('PROCESS %d', this._processing, pattern) + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // see if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index, cb) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } + + var remain = pattern.slice(n) + + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + + var abs = this._makeAbs(read) + + //if ignored, skip _processing + if (childrenIgnored(this, read)) + return cb() + + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) +} + +Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} + +Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + + // if the abs isn't a dir, then nothing can match! + if (!entries) + return cb() + + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + + //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) + + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return cb() + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) + } + // This was the last one, and no stats were needed + return cb() + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + this._process([e].concat(remain), index, inGlobStar, cb) + } + cb() +} + +Glob.prototype._emitMatch = function (index, e) { + if (this.aborted) + return + + if (this.matches[index][e]) + return + + if (isIgnored(this, e)) + return + + if (this.paused) { + this._emitQueue.push([index, e]) + return + } + + var abs = this._makeAbs(e) + + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } + + if (this.mark) + e = this._mark(e) + + this.matches[index][e] = true + + var st = this.statCache[abs] + if (st) + this.emit('stat', e, st) + + this.emit('match', e) +} + +Glob.prototype._readdirInGlobStar = function (abs, cb) { + if (this.aborted) + return + + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false, cb) + + var lstatkey = 'lstat\0' + abs + var self = this + var lstatcb = inflight(lstatkey, lstatcb_) + + if (lstatcb) + fs.lstat(abs, lstatcb) + + function lstatcb_ (er, lstat) { + if (er) + return cb() + + var isSym = lstat.isSymbolicLink() + self.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && !lstat.isDirectory()) { + self.cache[abs] = 'FILE' + cb() + } else + self._readdir(abs, false, cb) + } +} + +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return + + cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) + if (!cb) + return + + //console.error('RD %j %j', +inGlobStar, abs) + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs, cb) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return cb() + + if (Array.isArray(c)) + return cb(null, c) + } + + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} + +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) + } +} + +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return + + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } + + this.cache[abs] = entries + return cb(null, entries) +} + +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return + + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + this.cache[this._makeAbs(f)] = 'FILE' + break + + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) { + this.emit('error', er) + // If the error is handled, then we abort + // if not, we threw out of here + this.abort() + } + if (!this.silent) + console.error('glob error', er) + break + } + + return cb() +} + +Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} + + +Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) + + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() + + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) + + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) + + var isSym = this.symlinks[abs] + var len = entries.length + + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return cb() + + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true, cb) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true, cb) + } + + cb() +} + +Glob.prototype._processSimple = function (prefix, index, cb) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var self = this + this._stat(prefix, function (er, exists) { + self._processSimple2(prefix, index, er, exists, cb) + }) +} +Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { + + //console.error('ps2', prefix, exists) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return cb() + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } + + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + + // Mark this as a match + this._emitMatch(index, prefix) + cb() +} + +// Returns either 'DIR', 'FILE', or false +Glob.prototype._stat = function (f, cb) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + + if (f.length > this.maxLength) + return cb() + + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + + if (Array.isArray(c)) + c = 'DIR' + + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return cb(null, c) + + if (needDir && c === 'FILE') + return cb() + + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } + + var exists + var stat = this.statCache[abs] + if (stat !== undefined) { + if (stat === false) + return cb(null, stat) + else { + var type = stat.isDirectory() ? 'DIR' : 'FILE' + if (needDir && type === 'FILE') + return cb() + else + return cb(null, type, stat) + } + } + + var self = this + var statcb = inflight('stat\0' + abs, lstatcb_) + if (statcb) + fs.lstat(abs, statcb) + + function lstatcb_ (er, lstat) { + if (lstat && lstat.isSymbolicLink()) { + // If it's a symlink, then treat it as the target, unless + // the target does not exist, then treat it as a file. + return fs.stat(abs, function (er, stat) { + if (er) + self._stat2(f, abs, null, lstat, cb) + else + self._stat2(f, abs, er, stat, cb) + }) + } else { + self._stat2(f, abs, er, lstat, cb) + } + } +} + +Glob.prototype._stat2 = function (f, abs, er, stat, cb) { + if (er) { + this.statCache[abs] = false + return cb() + } + + var needDir = f.slice(-1) === '/' + this.statCache[abs] = stat + + if (abs.slice(-1) === '/' && !stat.isDirectory()) + return cb(null, false, stat) + + var c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + + if (needDir && c !== 'DIR') + return cb() + + return cb(null, c, stat) +} + +}).call(this,require('_process')) +},{"./common.js":15,"./sync.js":17,"_process":24,"assert":9,"events":14,"fs":12,"inflight":18,"inherits":19,"minimatch":20,"once":21,"path":22,"path-is-absolute":23,"util":28}],17:[function(require,module,exports){ +(function (process){ +module.exports = globSync +globSync.GlobSync = GlobSync + +var fs = require('fs') +var minimatch = require('minimatch') +var Minimatch = minimatch.Minimatch +var Glob = require('./glob.js').Glob +var util = require('util') +var path = require('path') +var assert = require('assert') +var isAbsolute = require('path-is-absolute') +var common = require('./common.js') +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var childrenIgnored = common.childrenIgnored + +function globSync (pattern, options) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') + + return new GlobSync(pattern, options).found +} + +function GlobSync (pattern, options) { + if (!pattern) + throw new Error('must provide pattern') + + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') + + if (!(this instanceof GlobSync)) + return new GlobSync(pattern, options) + + setopts(this, pattern, options) + + if (this.noprocess) + return this + + var n = this.minimatch.set.length + this.matches = new Array(n) + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false) + } + this._finish() +} + +GlobSync.prototype._finish = function () { + assert(this instanceof GlobSync) + if (this.realpath) { + var self = this + this.matches.forEach(function (matchset, index) { + var set = self.matches[index] = Object.create(null) + for (var p in matchset) { + try { + p = self._makeAbs(p) + var real = fs.realpathSync(p, self.realpathCache) + set[real] = true + } catch (er) { + if (er.syscall === 'stat') + set[self._makeAbs(p)] = true + else + throw er + } + } + }) + } + common.finish(this) +} + + +GlobSync.prototype._process = function (pattern, index, inGlobStar) { + assert(this instanceof GlobSync) + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // See if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } + + var remain = pattern.slice(n) + + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + + var abs = this._makeAbs(read) + + //if ignored, skip processing + if (childrenIgnored(this, read)) + return + + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar) +} + + +GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { + var entries = this._readdir(abs, inGlobStar) + + // if the abs isn't a dir, then nothing can match! + if (!entries) + return + + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this.matches[index][e] = true + } + // This was the last one, and no stats were needed + return + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) + newPattern = [prefix, e] + else + newPattern = [e] + this._process(newPattern.concat(remain), index, inGlobStar) + } +} + + +GlobSync.prototype._emitMatch = function (index, e) { + var abs = this._makeAbs(e) + if (this.mark) + e = this._mark(e) + + if (this.matches[index][e]) + return + + if (this.nodir) { + var c = this.cache[this._makeAbs(e)] + if (c === 'DIR' || Array.isArray(c)) + return + } + + this.matches[index][e] = true + if (this.stat) + this._stat(e) +} + + +GlobSync.prototype._readdirInGlobStar = function (abs) { + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false) + + var entries + var lstat + var stat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + // lstat failed, doesn't exist + return null + } + + var isSym = lstat.isSymbolicLink() + this.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && !lstat.isDirectory()) + this.cache[abs] = 'FILE' + else + entries = this._readdir(abs, false) + + return entries +} + +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries + + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null + + if (Array.isArray(c)) + return c + } + + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} + +GlobSync.prototype._readdirEntries = function (abs, entries) { + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } + + this.cache[abs] = entries + + // mark and cache dir-ness + return entries +} + +GlobSync.prototype._readdirError = function (f, er) { + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + this.cache[this._makeAbs(f)] = 'FILE' + break + + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) + throw er + if (!this.silent) + console.error('glob error', er) + break + } +} + +GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { + + var entries = this._readdir(abs, inGlobStar) + + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return + + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) + + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false) + + var len = entries.length + var isSym = this.symlinks[abs] + + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return + + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true) + } +} + +GlobSync.prototype._processSimple = function (prefix, index) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var exists = this._stat(prefix) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } + + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + + // Mark this as a match + this.matches[index][prefix] = true +} + +// Returns either 'DIR', 'FILE', or false +GlobSync.prototype._stat = function (f) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + + if (f.length > this.maxLength) + return false + + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + + if (Array.isArray(c)) + c = 'DIR' + + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return c + + if (needDir && c === 'FILE') + return false + + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } + + var exists + var stat = this.statCache[abs] + if (!stat) { + var lstat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + return false + } + + if (lstat.isSymbolicLink()) { + try { + stat = fs.statSync(abs) + } catch (er) { + stat = lstat + } + } else { + stat = lstat + } + } + + this.statCache[abs] = stat + + var c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + + if (needDir && c !== 'DIR') + return false + + return c +} + +GlobSync.prototype._mark = function (p) { + return common.mark(this, p) +} + +GlobSync.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} + +}).call(this,require('_process')) +},{"./common.js":15,"./glob.js":16,"_process":24,"assert":9,"fs":12,"minimatch":20,"path":22,"path-is-absolute":23,"util":28}],18:[function(require,module,exports){ +(function (process){ +var wrappy = require('wrappy') +var reqs = Object.create(null) +var once = require('once') + +module.exports = wrappy(inflight) + +function inflight (key, cb) { + if (reqs[key]) { + reqs[key].push(cb) + return null + } else { + reqs[key] = [cb] + return makeres(key) + } +} + +function makeres (key) { + return once(function RES () { + var cbs = reqs[key] + var len = cbs.length + var args = slice(arguments) + + // XXX It's somewhat ambiguous whether a new callback added in this + // pass should be queued for later execution if something in the + // list of callbacks throws, or if it should just be discarded. + // However, it's such an edge case that it hardly matters, and either + // choice is likely as surprising as the other. + // As it happens, we do go ahead and schedule it for later execution. + try { + for (var i = 0; i < len; i++) { + cbs[i].apply(null, args) + } + } finally { + if (cbs.length > len) { + // added more in the interim. + // de-zalgo, just in case, but don't call again. + cbs.splice(0, len) + process.nextTick(function () { + RES.apply(null, args) + }) + } else { + delete reqs[key] + } + } + }) +} + +function slice (args) { + var length = args.length + var array = [] + + for (var i = 0; i < length; i++) array[i] = args[i] + return array +} + +}).call(this,require('_process')) +},{"_process":24,"once":21,"wrappy":29}],19:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],20:[function(require,module,exports){ +module.exports = minimatch +minimatch.Minimatch = Minimatch + +var path = { sep: '/' } +try { + path = require('path') +} catch (er) {} + +var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} +var expand = require('brace-expansion') + +var plTypes = { + '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, + '?': { open: '(?:', close: ')?' }, + '+': { open: '(?:', close: ')+' }, + '*': { open: '(?:', close: ')*' }, + '@': { open: '(?:', close: ')' } +} + +// any single thing other than / +// don't need to escape / when using new RegExp() +var qmark = '[^/]' + +// * => any number of characters +var star = qmark + '*?' + +// ** when dots are allowed. Anything goes, except .. and . +// not (^ or / followed by one or two dots followed by $ or /), +// followed by anything, any number of times. +var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' + +// not a ^ or / followed by a dot, +// followed by anything, any number of times. +var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' + +// characters that need to be escaped in RegExp. +var reSpecials = charSet('().*{}+?[]^$\\!') + +// "abc" -> { a:true, b:true, c:true } +function charSet (s) { + return s.split('').reduce(function (set, c) { + set[c] = true + return set + }, {}) +} + +// normalizes slashes. +var slashSplit = /\/+/ + +minimatch.filter = filter +function filter (pattern, options) { + options = options || {} + return function (p, i, list) { + return minimatch(p, pattern, options) + } +} + +function ext (a, b) { + a = a || {} + b = b || {} + var t = {} + Object.keys(b).forEach(function (k) { + t[k] = b[k] + }) + Object.keys(a).forEach(function (k) { + t[k] = a[k] + }) + return t +} + +minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return minimatch + + var orig = minimatch + + var m = function minimatch (p, pattern, options) { + return orig.minimatch(p, pattern, ext(def, options)) + } + + m.Minimatch = function Minimatch (pattern, options) { + return new orig.Minimatch(pattern, ext(def, options)) + } + + return m +} + +Minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return Minimatch + return minimatch.defaults(def).Minimatch +} + +function minimatch (p, pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('glob pattern string required') + } + + if (!options) options = {} + + // shortcut: comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + return false + } + + // "" only matches "" + if (pattern.trim() === '') return p === '' + + return new Minimatch(pattern, options).match(p) +} + +function Minimatch (pattern, options) { + if (!(this instanceof Minimatch)) { + return new Minimatch(pattern, options) + } + + if (typeof pattern !== 'string') { + throw new TypeError('glob pattern string required') + } + + if (!options) options = {} + pattern = pattern.trim() + + // windows support: need to use /, not \ + if (path.sep !== '/') { + pattern = pattern.split(path.sep).join('/') + } + + this.options = options + this.set = [] + this.pattern = pattern + this.regexp = null + this.negate = false + this.comment = false + this.empty = false + + // make the set of regexps etc. + this.make() +} + +Minimatch.prototype.debug = function () {} + +Minimatch.prototype.make = make +function make () { + // don't do it more than once. + if (this._made) return + + var pattern = this.pattern + var options = this.options + + // empty patterns and comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + this.comment = true + return + } + if (!pattern) { + this.empty = true + return + } + + // step 1: figure out negation, etc. + this.parseNegate() + + // step 2: expand braces + var set = this.globSet = this.braceExpand() + + if (options.debug) this.debug = console.error + + this.debug(this.pattern, set) + + // step 3: now we have a set, so turn each one into a series of path-portion + // matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + set = this.globParts = set.map(function (s) { + return s.split(slashSplit) + }) + + this.debug(this.pattern, set) + + // glob --> regexps + set = set.map(function (s, si, set) { + return s.map(this.parse, this) + }, this) + + this.debug(this.pattern, set) + + // filter out everything that didn't compile properly. + set = set.filter(function (s) { + return s.indexOf(false) === -1 + }) + + this.debug(this.pattern, set) + + this.set = set +} + +Minimatch.prototype.parseNegate = parseNegate +function parseNegate () { + var pattern = this.pattern + var negate = false + var options = this.options + var negateOffset = 0 + + if (options.nonegate) return + + for (var i = 0, l = pattern.length + ; i < l && pattern.charAt(i) === '!' + ; i++) { + negate = !negate + negateOffset++ + } + + if (negateOffset) this.pattern = pattern.substr(negateOffset) + this.negate = negate +} + +// Brace expansion: +// a{b,c}d -> abd acd +// a{b,}c -> abc ac +// a{0..3}d -> a0d a1d a2d a3d +// a{b,c{d,e}f}g -> abg acdfg acefg +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg +// +// Invalid sets are not expanded. +// a{2..}b -> a{2..}b +// a{b}c -> a{b}c +minimatch.braceExpand = function (pattern, options) { + return braceExpand(pattern, options) +} + +Minimatch.prototype.braceExpand = braceExpand + +function braceExpand (pattern, options) { + if (!options) { + if (this instanceof Minimatch) { + options = this.options + } else { + options = {} + } + } + + pattern = typeof pattern === 'undefined' + ? this.pattern : pattern + + if (typeof pattern === 'undefined') { + throw new TypeError('undefined pattern') + } + + if (options.nobrace || + !pattern.match(/\{.*\}/)) { + // shortcut. no need to expand. + return [pattern] + } + + return expand(pattern) +} + +// parse a component of the expanded set. +// At this point, no pattern may contain "/" in it +// so we're going to return a 2d array, where each entry is the full +// pattern, split on '/', and then turned into a regular expression. +// A regexp is made at the end which joins each array with an +// escaped /, and another full one which joins each regexp with |. +// +// Following the lead of Bash 4.1, note that "**" only has special meaning +// when it is the *only* thing in a path portion. Otherwise, any series +// of * is equivalent to a single *. Globstar behavior is enabled by +// default, and can be disabled by setting options.noglobstar. +Minimatch.prototype.parse = parse +var SUBPARSE = {} +function parse (pattern, isSub) { + if (pattern.length > 1024 * 64) { + throw new TypeError('pattern is too long') + } + + var options = this.options + + // shortcuts + if (!options.noglobstar && pattern === '**') return GLOBSTAR + if (pattern === '') return '' + + var re = '' + var hasMagic = !!options.nocase + var escaping = false + // ? => one single character + var patternListStack = [] + var negativeLists = [] + var stateChar + var inClass = false + var reClassStart = -1 + var classStart = -1 + // . and .. never match anything that doesn't start with ., + // even when options.dot is set. + var patternStart = pattern.charAt(0) === '.' ? '' // anything + // not (start or / followed by . or .. followed by / or end) + : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' + : '(?!\\.)' + var self = this + + function clearStateChar () { + if (stateChar) { + // we had some state-tracking character + // that wasn't consumed by this pass. + switch (stateChar) { + case '*': + re += star + hasMagic = true + break + case '?': + re += qmark + hasMagic = true + break + default: + re += '\\' + stateChar + break + } + self.debug('clearStateChar %j %j', stateChar, re) + stateChar = false + } + } + + for (var i = 0, len = pattern.length, c + ; (i < len) && (c = pattern.charAt(i)) + ; i++) { + this.debug('%s\t%s %s %j', pattern, i, re, c) + + // skip over any that are escaped. + if (escaping && reSpecials[c]) { + re += '\\' + c + escaping = false + continue + } + + switch (c) { + case '/': + // completely not allowed, even escaped. + // Should already be path-split by now. + return false + + case '\\': + clearStateChar() + escaping = true + continue + + // the various stateChar values + // for the "extglob" stuff. + case '?': + case '*': + case '+': + case '@': + case '!': + this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) + + // all of those are literals inside a class, except that + // the glob [!a] means [^a] in regexp + if (inClass) { + this.debug(' in class') + if (c === '!' && i === classStart + 1) c = '^' + re += c + continue + } + + // if we already have a stateChar, then it means + // that there was something like ** or +? in there. + // Handle the stateChar, then proceed with this one. + self.debug('call clearStateChar %j', stateChar) + clearStateChar() + stateChar = c + // if extglob is disabled, then +(asdf|foo) isn't a thing. + // just clear the statechar *now*, rather than even diving into + // the patternList stuff. + if (options.noext) clearStateChar() + continue + + case '(': + if (inClass) { + re += '(' + continue + } + + if (!stateChar) { + re += '\\(' + continue + } + + patternListStack.push({ + type: stateChar, + start: i - 1, + reStart: re.length, + open: plTypes[stateChar].open, + close: plTypes[stateChar].close + }) + // negation is (?:(?!js)[^/]*) + re += stateChar === '!' ? '(?:(?!(?:' : '(?:' + this.debug('plType %j %j', stateChar, re) + stateChar = false + continue + + case ')': + if (inClass || !patternListStack.length) { + re += '\\)' + continue + } + + clearStateChar() + hasMagic = true + var pl = patternListStack.pop() + // negation is (?:(?!js)[^/]*) + // The others are (?:) + re += pl.close + if (pl.type === '!') { + negativeLists.push(pl) + } + pl.reEnd = re.length + continue + + case '|': + if (inClass || !patternListStack.length || escaping) { + re += '\\|' + escaping = false + continue + } + + clearStateChar() + re += '|' + continue + + // these are mostly the same in regexp and glob + case '[': + // swallow any state-tracking char before the [ + clearStateChar() + + if (inClass) { + re += '\\' + c + continue + } + + inClass = true + classStart = i + reClassStart = re.length + re += c + continue + + case ']': + // a right bracket shall lose its special + // meaning and represent itself in + // a bracket expression if it occurs + // first in the list. -- POSIX.2 2.8.3.2 + if (i === classStart + 1 || !inClass) { + re += '\\' + c + escaping = false + continue + } + + // handle the case where we left a class open. + // "[z-a]" is valid, equivalent to "\[z-a\]" + if (inClass) { + // split where the last [ was, make sure we don't have + // an invalid re. if so, re-walk the contents of the + // would-be class to re-translate any characters that + // were passed through as-is + // TODO: It would probably be faster to determine this + // without a try/catch and a new RegExp, but it's tricky + // to do safely. For now, this is safe and works. + var cs = pattern.substring(classStart + 1, i) + try { + RegExp('[' + cs + ']') + } catch (er) { + // not a valid class! + var sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' + hasMagic = hasMagic || sp[1] + inClass = false + continue + } + } + + // finish up the class. + hasMagic = true + inClass = false + re += c + continue + + default: + // swallow any state char that wasn't consumed + clearStateChar() + + if (escaping) { + // no need + escaping = false + } else if (reSpecials[c] + && !(c === '^' && inClass)) { + re += '\\' + } + + re += c + + } // switch + } // for + + // handle the case where we left a class open. + // "[abc" is valid, equivalent to "\[abc" + if (inClass) { + // split where the last [ was, and escape it + // this is a huge pita. We now have to re-walk + // the contents of the would-be class to re-translate + // any characters that were passed through as-is + cs = pattern.substr(classStart + 1) + sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + hasMagic = hasMagic || sp[1] + } + + // handle the case where we had a +( thing at the *end* + // of the pattern. + // each pattern list stack adds 3 chars, and we need to go through + // and escape any | chars that were passed through as-is for the regexp. + // Go through and escape them, taking care not to double-escape any + // | chars that were already escaped. + for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { + var tail = re.slice(pl.reStart + pl.open.length) + this.debug('setting tail', re, pl) + // maybe some even number of \, then maybe 1 \, followed by a | + tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { + if (!$2) { + // the | isn't already escaped, so escape it. + $2 = '\\' + } + + // need to escape all those slashes *again*, without escaping the + // one that we need for escaping the | character. As it works out, + // escaping an even number of slashes can be done by simply repeating + // it exactly after itself. That's why this trick works. + // + // I am sorry that you have to see this. + return $1 + $1 + $2 + '|' + }) + + this.debug('tail=%j\n %s', tail, tail, pl, re) + var t = pl.type === '*' ? star + : pl.type === '?' ? qmark + : '\\' + pl.type + + hasMagic = true + re = re.slice(0, pl.reStart) + t + '\\(' + tail + } + + // handle trailing things that only matter at the very end. + clearStateChar() + if (escaping) { + // trailing \\ + re += '\\\\' + } + + // only need to apply the nodot start if the re starts with + // something that could conceivably capture a dot + var addPatternStart = false + switch (re.charAt(0)) { + case '.': + case '[': + case '(': addPatternStart = true + } + + // Hack to work around lack of negative lookbehind in JS + // A pattern like: *.!(x).!(y|z) needs to ensure that a name + // like 'a.xyz.yz' doesn't match. So, the first negative + // lookahead, has to look ALL the way ahead, to the end of + // the pattern. + for (var n = negativeLists.length - 1; n > -1; n--) { + var nl = negativeLists[n] + + var nlBefore = re.slice(0, nl.reStart) + var nlFirst = re.slice(nl.reStart, nl.reEnd - 8) + var nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + var nlAfter = re.slice(nl.reEnd) + + nlLast += nlAfter + + // Handle nested stuff like *(*.js|!(*.json)), where open parens + // mean that we should *not* include the ) in the bit that is considered + // "after" the negated section. + var openParensBefore = nlBefore.split('(').length - 1 + var cleanAfter = nlAfter + for (i = 0; i < openParensBefore; i++) { + cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') + } + nlAfter = cleanAfter + + var dollar = '' + if (nlAfter === '' && isSub !== SUBPARSE) { + dollar = '$' + } + var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast + re = newRe + } + + // if the re is not "" at this point, then we need to make sure + // it doesn't match against an empty path part. + // Otherwise a/* will match a/, which it should not. + if (re !== '' && hasMagic) { + re = '(?=.)' + re + } + + if (addPatternStart) { + re = patternStart + re + } + + // parsing just a piece of a larger pattern. + if (isSub === SUBPARSE) { + return [re, hasMagic] + } + + // skip the regexp for non-magical patterns + // unescape anything in it, though, so that it'll be + // an exact match against a file etc. + if (!hasMagic) { + return globUnescape(pattern) + } + + var flags = options.nocase ? 'i' : '' + try { + var regExp = new RegExp('^' + re + '$', flags) + } catch (er) { + // If it was an invalid regular expression, then it can't match + // anything. This trick looks for a character after the end of + // the string, which is of course impossible, except in multi-line + // mode, but it's not a /m regex. + return new RegExp('$.') + } + + regExp._glob = pattern + regExp._src = re + + return regExp +} + +minimatch.makeRe = function (pattern, options) { + return new Minimatch(pattern, options || {}).makeRe() +} + +Minimatch.prototype.makeRe = makeRe +function makeRe () { + if (this.regexp || this.regexp === false) return this.regexp + + // at this point, this.set is a 2d array of partial + // pattern strings, or "**". + // + // It's better to use .match(). This function shouldn't + // be used, really, but it's pretty convenient sometimes, + // when you just want to work with a regex. + var set = this.set + + if (!set.length) { + this.regexp = false + return this.regexp + } + var options = this.options + + var twoStar = options.noglobstar ? star + : options.dot ? twoStarDot + : twoStarNoDot + var flags = options.nocase ? 'i' : '' + + var re = set.map(function (pattern) { + return pattern.map(function (p) { + return (p === GLOBSTAR) ? twoStar + : (typeof p === 'string') ? regExpEscape(p) + : p._src + }).join('\\\/') + }).join('|') + + // must match entire pattern + // ending in a * or ** will make it less strict. + re = '^(?:' + re + ')$' + + // can match anything, as long as it's not this. + if (this.negate) re = '^(?!' + re + ').*$' + + try { + this.regexp = new RegExp(re, flags) + } catch (ex) { + this.regexp = false + } + return this.regexp +} + +minimatch.match = function (list, pattern, options) { + options = options || {} + var mm = new Minimatch(pattern, options) + list = list.filter(function (f) { + return mm.match(f) + }) + if (mm.options.nonull && !list.length) { + list.push(pattern) + } + return list +} + +Minimatch.prototype.match = match +function match (f, partial) { + this.debug('match', f, this.pattern) + // short-circuit in the case of busted things. + // comments, etc. + if (this.comment) return false + if (this.empty) return f === '' + + if (f === '/' && partial) return true + + var options = this.options + + // windows: need to use /, not \ + if (path.sep !== '/') { + f = f.split(path.sep).join('/') + } + + // treat the test path as a set of pathparts. + f = f.split(slashSplit) + this.debug(this.pattern, 'split', f) + + // just ONE of the pattern sets in this.set needs to match + // in order for it to be valid. If negating, then just one + // match means that we have failed. + // Either way, return on the first hit. + + var set = this.set + this.debug(this.pattern, 'set', set) + + // Find the basename of the path by looking for the last non-empty segment + var filename + var i + for (i = f.length - 1; i >= 0; i--) { + filename = f[i] + if (filename) break + } + + for (i = 0; i < set.length; i++) { + var pattern = set[i] + var file = f + if (options.matchBase && pattern.length === 1) { + file = [filename] + } + var hit = this.matchOne(file, pattern, partial) + if (hit) { + if (options.flipNegate) return true + return !this.negate + } + } + + // didn't get any hits. this is success if it's a negative + // pattern, failure otherwise. + if (options.flipNegate) return false + return this.negate +} + +// set partial to true to test if, for example, +// "/a/b" matches the start of "/*/b/*/d" +// Partial means, if you run out of file before you run +// out of pattern, then that's fine, as long as all +// the parts match. +Minimatch.prototype.matchOne = function (file, pattern, partial) { + var options = this.options + + this.debug('matchOne', + { 'this': this, file: file, pattern: pattern }) + + this.debug('matchOne', file.length, pattern.length) + + for (var fi = 0, + pi = 0, + fl = file.length, + pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi++, pi++) { + this.debug('matchOne loop') + var p = pattern[pi] + var f = file[fi] + + this.debug(pattern, p, f) + + // should be impossible. + // some invalid regexp stuff in the set. + if (p === false) return false + + if (p === GLOBSTAR) { + this.debug('GLOBSTAR', [pattern, p, f]) + + // "**" + // a/**/b/**/c would match the following: + // a/b/x/y/z/c + // a/x/y/z/b/c + // a/b/x/b/x/c + // a/b/c + // To do this, take the rest of the pattern after + // the **, and see if it would match the file remainder. + // If so, return success. + // If not, the ** "swallows" a segment, and try again. + // This is recursively awful. + // + // a/**/b/**/c matching a/b/x/y/z/c + // - a matches a + // - doublestar + // - matchOne(b/x/y/z/c, b/**/c) + // - b matches b + // - doublestar + // - matchOne(x/y/z/c, c) -> no + // - matchOne(y/z/c, c) -> no + // - matchOne(z/c, c) -> no + // - matchOne(c, c) yes, hit + var fr = fi + var pr = pi + 1 + if (pr === pl) { + this.debug('** at the end') + // a ** at the end will just swallow the rest. + // We have found a match. + // however, it will not swallow /.x, unless + // options.dot is set. + // . and .. are *never* matched by **, for explosively + // exponential reasons. + for (; fi < fl; fi++) { + if (file[fi] === '.' || file[fi] === '..' || + (!options.dot && file[fi].charAt(0) === '.')) return false + } + return true + } + + // ok, let's see if we can swallow whatever we can. + while (fr < fl) { + var swallowee = file[fr] + + this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) + + // XXX remove this slice. Just pass the start index. + if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { + this.debug('globstar found match!', fr, fl, swallowee) + // found a match. + return true + } else { + // can't swallow "." or ".." ever. + // can only swallow ".foo" when explicitly asked. + if (swallowee === '.' || swallowee === '..' || + (!options.dot && swallowee.charAt(0) === '.')) { + this.debug('dot detected!', file, fr, pattern, pr) + break + } + + // ** swallows a segment, and continue. + this.debug('globstar swallow a segment, and continue') + fr++ + } + } + + // no match was found. + // However, in partial mode, we can't say this is necessarily over. + // If there's more *pattern* left, then + if (partial) { + // ran out of file + this.debug('\n>>> no match, partial?', file, fr, pattern, pr) + if (fr === fl) return true + } + return false + } + + // something other than ** + // non-magic patterns just have to match exactly + // patterns with magic have been turned into regexps. + var hit + if (typeof p === 'string') { + if (options.nocase) { + hit = f.toLowerCase() === p.toLowerCase() + } else { + hit = f === p + } + this.debug('string match', p, f, hit) + } else { + hit = f.match(p) + this.debug('pattern match', p, f, hit) + } + + if (!hit) return false + } + + // Note: ending in / means that we'll get a final "" + // at the end of the pattern. This can only match a + // corresponding "" at the end of the file. + // If the file ends in /, then it can only match a + // a pattern that ends in /, unless the pattern just + // doesn't have any more for it. But, a/b/ should *not* + // match "a/b/*", even though "" matches against the + // [^/]*? pattern, except in partial mode, where it might + // simply not be reached yet. + // However, a/b/ should still satisfy a/* + + // now either we fell off the end of the pattern, or we're done. + if (fi === fl && pi === pl) { + // ran out of pattern and filename at the same time. + // an exact hit! + return true + } else if (fi === fl) { + // ran out of file, but still had pattern left. + // this is ok if we're doing the match as part of + // a glob fs traversal. + return partial + } else if (pi === pl) { + // ran out of pattern, still have file left. + // this is only acceptable if we're on the very last + // empty segment of a file with a trailing slash. + // a/* should match a/b/ + var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') + return emptyFileEnd + } + + // should be unreachable. + throw new Error('wtf?') +} + +// replace stuff like \* with * +function globUnescape (s) { + return s.replace(/\\(.)/g, '$1') +} + +function regExpEscape (s) { + return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') +} + +},{"brace-expansion":11,"path":22}],21:[function(require,module,exports){ +var wrappy = require('wrappy') +module.exports = wrappy(once) +module.exports.strict = wrappy(onceStrict) + +once.proto = once(function () { + Object.defineProperty(Function.prototype, 'once', { + value: function () { + return once(this) + }, + configurable: true + }) + + Object.defineProperty(Function.prototype, 'onceStrict', { + value: function () { + return onceStrict(this) + }, + configurable: true + }) +}) + +function once (fn) { + var f = function () { + if (f.called) return f.value + f.called = true + return f.value = fn.apply(this, arguments) + } + f.called = false + return f +} + +function onceStrict (fn) { + var f = function () { + if (f.called) + throw new Error(f.onceError) + f.called = true + return f.value = fn.apply(this, arguments) + } + var name = fn.name || 'Function wrapped with `once`' + f.onceError = name + " shouldn't be called more than once" + f.called = false + return f +} + +},{"wrappy":29}],22:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":24}],23:[function(require,module,exports){ +(function (process){ +'use strict'; + +function posix(path) { + return path.charAt(0) === '/'; +} + +function win32(path) { + // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56 + var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; + var result = splitDeviceRe.exec(path); + var device = result[1] || ''; + var isUnc = Boolean(device && device.charAt(1) !== ':'); + + // UNC paths are always absolute + return Boolean(result[2] || isUnc); +} + +module.exports = process.platform === 'win32' ? win32 : posix; +module.exports.posix = posix; +module.exports.win32 = win32; + +}).call(this,require('_process')) +},{"_process":24}],24:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],25:[function(require,module,exports){ +// Underscore.js 1.8.3 +// http://underscorejs.org +// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.8.3'; + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + var optimizeCb = function(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + case 2: return function(value, other) { + return func.call(context, value, other); + }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + }; + + // A mostly-internal function to generate callbacks that can be applied + // to each element in a collection, returning the desired result — either + // identity, an arbitrary callback, a property matcher, or a property accessor. + var cb = function(value, context, argCount) { + if (value == null) return _.identity; + if (_.isFunction(value)) return optimizeCb(value, context, argCount); + if (_.isObject(value)) return _.matcher(value); + return _.property(value); + }; + _.iteratee = function(value, context) { + return cb(value, context, Infinity); + }; + + // An internal function for creating assigner functions. + var createAssigner = function(keysFunc, undefinedOnly) { + return function(obj) { + var length = arguments.length; + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + }; + + // An internal function for creating a new object that inherits from another. + var baseCreate = function(prototype) { + if (!_.isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + }; + + var property = function(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + }; + + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object + // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = property('length'); + var isArrayLike = function(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; + }; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + _.each = _.forEach = function(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var keys = _.keys(obj); + for (i = 0, length = keys.length; i < length; i++) { + iteratee(obj[keys[i]], keys[i], obj); + } + } + return obj; + }; + + // Return the results of applying the iteratee to each element. + _.map = _.collect = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Optimized iterator function as using arguments.length + // in the main function will deoptimize the, see #1991. + function iterator(obj, iteratee, memo, keys, index, length) { + for (; index >= 0 && index < length; index += dir) { + var currentKey = keys ? keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + } + + return function(obj, iteratee, memo, context) { + iteratee = optimizeCb(iteratee, context, 4); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + // Determine the initial value if none is provided. + if (arguments.length < 3) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } + return iterator(obj, iteratee, memo, keys, index, length); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + _.reduce = _.foldl = _.inject = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + _.reduceRight = _.foldr = createReduce(-1); + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var key; + if (isArrayLike(obj)) { + key = _.findIndex(obj, predicate, context); + } else { + key = _.findKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) return obj[key]; + }; + + // Return all the elements that pass a truth test. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + _.each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, _.negate(cb(predicate)), context); + }; + + // Determine whether all of the elements match a truth test. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + }; + + // Determine if at least one element in the object matches a truth test. + // Aliased as `any`. + _.some = _.any = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + }; + + // Determine if the array or object contains a given item (using `===`). + // Aliased as `includes` and `include`. + _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return _.indexOf(obj, item, fromIndex) >= 0; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + var func = isFunc ? method : value[method]; + return func == null ? func : func.apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matcher(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matcher(attrs)); + }; + + // Return the maximum element (or element-based computation). + _.max = function(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Shuffle a collection, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var set = isArrayLike(obj) ? obj : _.values(obj); + var length = set.length; + var shuffled = Array(length); + for (var index = 0, rand; index < length; index++) { + rand = _.random(0, index); + if (rand !== index) shuffled[index] = shuffled[rand]; + shuffled[rand] = set[index]; + } + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // Sort the object's values by a criterion produced by an iteratee. + _.sortBy = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iteratee(value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iteratee, context) { + var result = {}; + iteratee = cb(iteratee, context); + _.each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, value, key) { + if (_.has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, value, key) { + if (_.has(result, key)) result[key]++; else result[key] = 1; + }); + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (isArrayLike(obj)) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : _.keys(obj).length; + }; + + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(obj, predicate, context) { + predicate = cb(predicate, context); + var pass = [], fail = []; + _.each(obj, function(value, key, obj) { + (predicate(value, key, obj) ? pass : fail).push(value); + }); + return [pass, fail]; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[0]; + return _.initial(array, array.length - n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + _.initial = function(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[array.length - 1]; + return _.rest(array, Math.max(0, array.length - n)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, strict, startIndex) { + var output = [], idx = 0; + for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { + //flatten current level of array or arguments object + if (!shallow) value = flatten(value, shallow, strict); + var j = 0, len = value.length; + output.length += len; + while (j < len) { + output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, false); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iteratee, context) { + if (!_.isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!_.contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!_.contains(result, value)) { + result.push(value); + } + } + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(flatten(arguments, true, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (_.contains(result, item)) continue; + for (var j = 1; j < argsLength; j++) { + if (!_.contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = flatten(arguments, true, true, 1); + return _.filter(array, function(value){ + return !_.contains(rest, value); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + return _.unzip(arguments); + }; + + // Complement of _.zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices + _.unzip = function(array) { + var length = array && _.max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = _.pluck(array, index); + } + return result; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // Generator function to create the findIndex and findLastIndex functions + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a predicate test + _.findIndex = createPredicateIndexFinder(1); + _.findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + }; + + // Generator function to create the indexOf and lastIndexOf functions + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _.isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); + _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + step = step || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (_.isObject(result)) return result; + return self; + }; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); + var args = slice.call(arguments, 2); + var bound = function() { + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); + }; + return bound; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var i, length = arguments.length, key; + if (length <= 1) throw new Error('bindAll must be passed function names'); + for (i = 1; i < length; i++) { + key = arguments[i]; + obj[key] = _.bind(obj[key], obj); + } + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ + return func.apply(null, args); + }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = _.partial(_.delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + if (!timeout) context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a negated version of the passed-in predicate. + _.negate = function(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + }; + + // Returns a function that will only be executed on and after the Nth call. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Returns a function that will only be executed up to (but not including) the Nth call. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + + // Object Functions + // ---------------- + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + function collectNonEnumProps(obj, keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve all the property names of an object. + _.allKeys = function(obj) { + if (!_.isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Returns the results of applying the iteratee to each element of the object + // In contrast to _.map it returns an object + _.mapObject = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = _.keys(obj), + length = keys.length, + results = {}, + currentKey; + for (var index = 0; index < length; index++) { + currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = createAssigner(_.allKeys); + + // Assigns a given object with all the own properties in the passed-in object(s) + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + _.extendOwn = _.assign = createAssigner(_.keys); + + // Returns the first key on an object that passes a predicate test + _.findKey = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = _.keys(obj), key; + for (var i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(object, oiteratee, context) { + var result = {}, obj = object, iteratee, keys; + if (obj == null) return result; + if (_.isFunction(oiteratee)) { + keys = _.allKeys(obj); + iteratee = optimizeCb(oiteratee, context); + } else { + keys = flatten(arguments, false, false, 1); + iteratee = function(value, key, obj) { return key in obj; }; + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj, iteratee, context) { + if (_.isFunction(iteratee)) { + iteratee = _.negate(iteratee); + } else { + var keys = _.map(flatten(arguments, false, false, 1), String); + iteratee = function(value, key) { + return !_.contains(keys, key); + }; + } + return _.pick(obj, iteratee, context); + }; + + // Fill in a given object with default properties. + _.defaults = createAssigner(_.allKeys, true); + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + _.create = function(prototype, props) { + var result = baseCreate(prototype); + if (props) _.extendOwn(result, props); + return result; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Returns whether an object has a given set of `key:value` pairs. + _.isMatch = function(object, attrs) { + var keys = _.keys(attrs), length = keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + }; + + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && + _.isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = _.keys(a), key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (_.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; + return _.keys(obj).length === 0; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return _.has(obj, 'callee'); + }; + } + + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), and in Safari 8 (#1929). + if (typeof /./ != 'function' && typeof Int8Array != 'object') { + _.isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj !== +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iteratees. + _.identity = function(value) { + return value; + }; + + // Predicate-generating functions. Often useful outside of Underscore. + _.constant = function(value) { + return function() { + return value; + }; + }; + + _.noop = function(){}; + + _.property = property; + + // Generates a function for a given object that returns a given property. + _.propertyOf = function(obj) { + return obj == null ? function(){} : function(key) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + _.matcher = _.matches = function(attrs) { + attrs = _.extendOwn({}, attrs); + return function(obj) { + return _.isMatch(obj, attrs); + }; + }; + + // Run a function **n** times. + _.times = function(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { + return new Date().getTime(); + }; + + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = _.invert(escapeMap); + + // Functions for escaping and unescaping strings to/from HTML interpolation. + var createEscaper = function(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped + var source = '(?:' + _.keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property, fallback) { + var value = object == null ? void 0 : object[property]; + if (value === void 0) { + value = fallback; + } + return _.isFunction(value) ? value.call(object) : value; + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + _.template = function(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escaper, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offest. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function. Start chaining a wrapped Underscore object. + _.chain = function(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + _.each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result(this, func.apply(_, args)); + }; + }); + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return result(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result(this, method.apply(this._wrapped, arguments)); + }; + }); + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return '' + this._wrapped; + }; + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } +}.call(this)); + +},{}],26:[function(require,module,exports){ +arguments[4][19][0].apply(exports,arguments) +},{"dup":19}],27:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],28:[function(require,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":27,"_process":24,"inherits":26}],29:[function(require,module,exports){ +// Returns a wrapper function that returns a wrapped callback +// The wrapper function should do some stuff, and return a +// presumably different callback function. +// This makes sure that own properties are retained, so that +// decorations and such are not lost along the way. +module.exports = wrappy +function wrappy (fn, cb) { + if (fn && cb) return wrappy(fn)(cb) + + if (typeof fn !== 'function') + throw new TypeError('need wrapper function') + + Object.keys(fn).forEach(function (k) { + wrapper[k] = fn[k] + }) + + return wrapper + + function wrapper() { + var args = new Array(arguments.length) + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i] + } + var ret = fn.apply(this, args) + var cb = args[args.length-1] + if (typeof ret === 'function' && ret !== cb) { + Object.keys(cb).forEach(function (k) { + ret[k] = cb[k] + }) + } + return ret + } +} + +},{}]},{},[7])(7) +}); \ No newline at end of file diff --git a/assets/javascripts/workers/search.1e90e0fb.min.js b/assets/javascripts/workers/search.1e90e0fb.min.js new file mode 100644 index 000000000..ff43aeddd --- /dev/null +++ b/assets/javascripts/workers/search.1e90e0fb.min.js @@ -0,0 +1,2 @@ +"use strict";(()=>{var xe=Object.create;var G=Object.defineProperty,ve=Object.defineProperties,Se=Object.getOwnPropertyDescriptor,Te=Object.getOwnPropertyDescriptors,Qe=Object.getOwnPropertyNames,Y=Object.getOwnPropertySymbols,Ee=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty,be=Object.prototype.propertyIsEnumerable;var Z=Math.pow,J=(t,e,r)=>e in t?G(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,_=(t,e)=>{for(var r in e||(e={}))X.call(e,r)&&J(t,r,e[r]);if(Y)for(var r of Y(e))be.call(e,r)&&J(t,r,e[r]);return t},B=(t,e)=>ve(t,Te(e));var Le=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var we=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Qe(e))!X.call(t,i)&&i!==r&&G(t,i,{get:()=>e[i],enumerable:!(n=Se(e,i))||n.enumerable});return t};var Pe=(t,e,r)=>(r=t!=null?xe(Ee(t)):{},we(e||!t||!t.__esModule?G(r,"default",{value:t,enumerable:!0}):r,t));var W=(t,e,r)=>new Promise((n,i)=>{var s=u=>{try{a(r.next(u))}catch(c){i(c)}},o=u=>{try{a(r.throw(u))}catch(c){i(c)}},a=u=>u.done?n(u.value):Promise.resolve(u.value).then(s,o);a((r=r.apply(t,e)).next())});var te=Le((K,ee)=>{(function(){var t=function(e){var r=new t.Builder;return r.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),r.searchPipeline.add(t.stemmer),e.call(r,r),r.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(r){e.console&&console.warn&&console.warn(r)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var r=Object.create(null),n=Object.keys(e),i=0;i0){var f=t.utils.clone(r)||{};f.position=[a,c],f.index=s.length,s.push(new t.Token(n.slice(a,o),f))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,r){r in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+r),e.label=r,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var r=e.label&&e.label in this.registeredFunctions;r||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var r=new t.Pipeline;return e.forEach(function(n){var i=t.Pipeline.registeredFunctions[n];if(i)r.add(i);else throw new Error("Cannot load unregistered function: "+n)}),r},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(r){t.Pipeline.warnIfFunctionNotRegistered(r),this._stack.push(r)},this)},t.Pipeline.prototype.after=function(e,r){t.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(e);if(n==-1)throw new Error("Cannot find existingFn");n=n+1,this._stack.splice(n,0,r)},t.Pipeline.prototype.before=function(e,r){t.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(e);if(n==-1)throw new Error("Cannot find existingFn");this._stack.splice(n,0,r)},t.Pipeline.prototype.remove=function(e){var r=this._stack.indexOf(e);r!=-1&&this._stack.splice(r,1)},t.Pipeline.prototype.run=function(e){for(var r=this._stack.length,n=0;n1&&(oe&&(n=s),o!=e);)i=n-r,s=r+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?f+=2:a==u&&(r+=n[c+1]*i[f+1],c+=2,f+=2);return r},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),r=1,n=0;r0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}s.str.length==1&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var f=s.str.charAt(0),g=s.str.charAt(1),l;g in s.node.edges?l=s.node.edges[g]:(l=new t.TokenSet,s.node.edges[g]=l),s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:f+s.str.slice(2)})}}}return n},t.TokenSet.fromString=function(e){for(var r=new t.TokenSet,n=r,i=0,s=e.length;i=e;r--){var n=this.uncheckedNodes[r],i=n.child.toString();i in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[i]:(n.child._str=i,this.minimizedNodes[i]=n.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(r){var n=new t.QueryParser(e,r);n.parse()})},t.Index.prototype.query=function(e){for(var r=new t.Query(this.fields),n=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,r){var n=e[this._ref],i=Object.keys(this._fields);this._documents[n]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,r;do e=this.next(),r=e.charCodeAt(0);while(r>47&&r<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var r=e.next();if(r==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(r.charCodeAt(0)==92){e.escapeCharacter();continue}if(r==":")return t.QueryLexer.lexField;if(r=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(r=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(r=="+"&&e.width()===1||r=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(r.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,r){this.lexer=new t.QueryLexer(e),this.query=r,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var r=e.peekLexeme();if(r!=null)switch(r.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(n+=" with value '"+r.str+"'"),new t.QueryParseError(n,r.start,r.end)}},t.QueryParser.parsePresence=function(e){var r=e.consumeLexeme();if(r!=null){switch(r.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+r.str+"'";throw new t.QueryParseError(n,r.start,r.end)}var i=e.peekLexeme();if(i==null){var n="expecting term or field, found nothing";throw new t.QueryParseError(n,r.start,r.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(n,i.start,i.end)}}},t.QueryParser.parseField=function(e){var r=e.consumeLexeme();if(r!=null){if(e.query.allFields.indexOf(r.str)==-1){var n=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+r.str+"', possible fields: "+n;throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.fields=[r.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,r.start,r.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var r=e.consumeLexeme();if(r!=null){e.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(n==null){e.nextClause();return}switch(n.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+n.type+"'";throw new t.QueryParseError(i,n.start,n.end)}}},t.QueryParser.parseEditDistance=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="edit distance must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.editDistance=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="boost must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.boost=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,r){typeof define=="function"&&define.amd?define(r):typeof K=="object"?ee.exports=r():e.lunr=r()}(this,function(){return t})})()});var de=Pe(te());function re(t,e=document){let r=ke(t,e);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${t}" to be present`);return r}function ke(t,e=document){return e.querySelector(t)||void 0}Object.entries||(Object.entries=function(t){let e=[];for(let r of Object.keys(t))e.push([r,t[r]]);return e});Object.values||(Object.values=function(t){let e=[];for(let r of Object.keys(t))e.push(t[r]);return e});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(t,e){typeof t=="object"?(this.scrollLeft=t.left,this.scrollTop=t.top):(this.scrollLeft=t,this.scrollTop=e)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...t){let e=this.parentNode;if(e){t.length===0&&e.removeChild(this);for(let r=t.length-1;r>=0;r--){let n=t[r];typeof n=="string"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?e.insertBefore(this.previousSibling,n):e.replaceChild(n,this)}}}));function ne(t){let e=new Map;for(let r of t){let[n]=r.location.split("#"),i=e.get(n);typeof i=="undefined"?e.set(n,r):(e.set(r.location,r),r.parent=i)}return e}function H(t,e,r){var s;e=new RegExp(e,"g");let n,i=0;do{n=e.exec(t);let o=(s=n==null?void 0:n.index)!=null?s:t.length;if(in?e(r,1,n,n=i):t.charAt(i)===">"&&(t.charAt(n+1)==="/"?--s===0&&e(r++,2,n,i+1):t.charAt(i-1)!=="/"&&s++===0&&e(r,0,n,i+1),n=i+1);i>n&&e(r,1,n,i)}function se(t,e,r,n=!1){return q([t],e,r,n).pop()}function q(t,e,r,n=!1){let i=[0];for(let s=1;s>>2&1023,c=a[0]>>>12;i.push(+(u>c)+i[i.length-1])}return t.map((s,o)=>{let a=0,u=new Map;for(let f of r.sort((g,l)=>g-l)){let g=f&1048575,l=f>>>20;if(i[l]!==o)continue;let m=u.get(l);typeof m=="undefined"&&u.set(l,m=[]),m.push(g)}if(u.size===0)return s;let c=[];for(let[f,g]of u){let l=e[f],m=l[0]>>>12,x=l[l.length-1]>>>12,v=l[l.length-1]>>>2&1023;n&&m>a&&c.push(s.slice(a,m));let d=s.slice(m,x+v);for(let y of g.sort((b,E)=>E-b)){let b=(l[y]>>>12)-m,E=(l[y]>>>2&1023)+b;d=[d.slice(0,b),"",d.slice(b,E),"",d.slice(E)].join("")}if(a=x+v,c.push(d)===2)break}return n&&a{var f;switch(i[f=o+=s]||(i[f]=[]),a){case 0:case 2:i[o].push(u<<12|c-u<<2|a);break;case 1:let g=r[n].slice(u,c);H(g,lunr.tokenizer.separator,(l,m)=>{if(typeof lunr.segmenter!="undefined"){let x=g.slice(l,m);if(/^[MHIK]$/.test(lunr.segmenter.ctype_(x))){let v=lunr.segmenter.segment(x);for(let d=0,y=0;dr){return t.trim().split(/"([^"]+)"/g).map((r,n)=>n&1?r.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):r).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").split(/\s+/g).reduce((r,n)=>{let i=e(n);return[...r,...Array.isArray(i)?i:[i]]},[]).map(r=>/([~^]$)/.test(r)?`${r}1`:r).map(r=>/(^[+-]|[~^]\d+$)/.test(r)?r:`${r}*`).join(" ")}function ue(t){return ae(t,e=>{let r=[],n=new lunr.QueryLexer(e);n.run();for(let{type:i,str:s,start:o,end:a}of n.lexemes)switch(i){case"FIELD":["title","text","tags"].includes(s)||(e=[e.slice(0,a)," ",e.slice(a+1)].join(""));break;case"TERM":H(s,lunr.tokenizer.separator,(...u)=>{r.push([e.slice(0,o),s.slice(...u),e.slice(a)].join(""))})}return r})}function ce(t){let e=new lunr.Query(["title","text","tags"]);new lunr.QueryParser(t,e).parse();for(let n of e.clauses)n.usePipeline=!0,n.term.startsWith("*")&&(n.wildcard=lunr.Query.wildcard.LEADING,n.term=n.term.slice(1)),n.term.endsWith("*")&&(n.wildcard=lunr.Query.wildcard.TRAILING,n.term=n.term.slice(0,-1));return e.clauses}function le(t,e){var i;let r=new Set(t),n={};for(let s=0;s0;){let o=i[--s];for(let u=1;un[o]-u&&(r.add(t.slice(o,o+u)),i[s++]=o+u);let a=o+n[o];n[a]&&ar=>{if(typeof r[e]=="undefined")return;let n=[r.location,e].join(":");return t.set(n,lunr.tokenizer.table=[]),r[e]}}function Re(t,e){let[r,n]=[new Set(t),new Set(e)];return[...new Set([...r].filter(i=>!n.has(i)))]}var U=class{constructor({config:e,docs:r,options:n}){let i=Oe(this.table=new Map);this.map=ne(r),this.options=n,this.index=lunr(function(){this.metadataWhitelist=["position"],this.b(0),e.lang.length===1&&e.lang[0]!=="en"?this.use(lunr[e.lang[0]]):e.lang.length>1&&this.use(lunr.multiLanguage(...e.lang)),this.tokenizer=oe,lunr.tokenizer.separator=new RegExp(e.separator),lunr.segmenter="TinySegmenter"in lunr?new lunr.TinySegmenter:void 0;let s=Re(["trimmer","stopWordFilter","stemmer"],e.pipeline);for(let o of e.lang.map(a=>a==="en"?lunr:lunr[a]))for(let a of s)this.pipeline.remove(o[a]),this.searchPipeline.remove(o[a]);this.ref("location");for(let[o,a]of Object.entries(e.fields))this.field(o,B(_({},a),{extractor:i(o)}));for(let o of r)this.add(o,{boost:o.boost})})}search(e){if(e=e.replace(new RegExp("\\p{sc=Han}+","gu"),s=>[...he(s,this.index.invertedIndex)].join("* ")),e=ue(e),!e)return{items:[]};let r=ce(e).filter(s=>s.presence!==lunr.Query.presence.PROHIBITED),n=this.index.search(e).reduce((s,{ref:o,score:a,matchData:u})=>{let c=this.map.get(o);if(typeof c!="undefined"){c=_({},c),c.tags&&(c.tags=[...c.tags]);let f=le(r,Object.keys(u.metadata));for(let l of this.index.fields){if(typeof c[l]=="undefined")continue;let m=[];for(let d of Object.values(u.metadata))typeof d[l]!="undefined"&&m.push(...d[l].position);if(!m.length)continue;let x=this.table.get([c.location,l].join(":")),v=Array.isArray(c[l])?q:se;c[l]=v(c[l],x,m,l!=="text")}let g=+!c.parent+Object.values(f).filter(l=>l).length/Object.keys(f).length;s.push(B(_({},c),{score:a*(1+Z(g,2)),terms:f}))}return s},[]).sort((s,o)=>o.score-s.score).reduce((s,o)=>{let a=this.map.get(o.location);if(typeof a!="undefined"){let u=a.parent?a.parent.location:a.location;s.set(u,[...s.get(u)||[],o])}return s},new Map);for(let[s,o]of n)if(!o.find(a=>a.location===s)){let a=this.map.get(s);o.push(B(_({},a),{score:0,terms:{}}))}let i;if(this.options.suggest){let s=this.index.query(o=>{for(let a of r)o.term(a.term,{fields:["title"],presence:lunr.Query.presence.REQUIRED,wildcard:lunr.Query.wildcard.TRAILING})});i=s.length?Object.keys(s[0].matchData.metadata):[]}return _({items:[...n.values()]},typeof i!="undefined"&&{suggest:i})}};var fe;function Ie(t){return W(this,null,function*(){let e="../lunr";if(typeof parent!="undefined"&&"IFrameWorker"in parent){let n=re("script[src]"),[i]=n.src.split("/worker");e=e.replace("..",i)}let r=[];for(let n of t.lang){switch(n){case"ja":r.push(`${e}/tinyseg.js`);break;case"hi":case"th":r.push(`${e}/wordcut.js`);break}n!=="en"&&r.push(`${e}/min/lunr.${n}.min.js`)}t.lang.length>1&&r.push(`${e}/min/lunr.multi.min.js`),r.length&&(yield importScripts(`${e}/min/lunr.stemmer.support.min.js`,...r))})}function Fe(t){return W(this,null,function*(){switch(t.type){case 0:return yield Ie(t.data.config),fe=new U(t.data),{type:1};case 2:let e=t.data;try{return{type:3,data:fe.search(e)}}catch(r){return console.warn(`Invalid query: ${e} \u2013 see https://bit.ly/2s3ChXG`),console.warn(r),{type:3,data:{items:[]}}}default:throw new TypeError("Invalid message type")}})}self.lunr=de.default;addEventListener("message",t=>W(void 0,null,function*(){postMessage(yield Fe(t.data))}));})(); diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 000000000..bd207c1e7 Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/stylesheets/main.52c0e027.min.css b/assets/stylesheets/main.52c0e027.min.css new file mode 100644 index 000000000..60af3b8eb --- /dev/null +++ b/assets/stylesheets/main.52c0e027.min.css @@ -0,0 +1 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em;position:relative}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:1fr;opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:1fr;opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:#0000008a;cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.234375em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem #0000;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:#00000042;border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:#ffffff1f}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem #00000012;color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:#0000;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::placeholder{transition:color .25s}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.984375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:#0000}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>.md-icon{margin-left:.2rem}[dir=rtl] .md-search__options>.md-icon{margin-right:.2rem}.md-search__options>.md-icon{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>.md-icon:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.984375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more>summary{cursor:pointer;display:block;outline:none;position:sticky;scroll-snap-align:start;top:0;z-index:1}.md-search-result__more>summary::marker{display:none}.md-search-result__more>summary::-webkit-details-marker{display:none}.md-search-result__more>summary>div{color:var(--md-typeset-a-color);font-size:.64rem;padding:.75em .8rem;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more>summary>div{padding-left:2.2rem}[dir=rtl] .md-search-result__more>summary>div{padding-right:2.2rem}}.md-search-result__more>summary:focus>div,.md-search-result__more>summary:hover>div{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more[open]>summary{background-color:var(--md-default-bg-color)}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.984375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result .md-typeset{color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.6}.md-search-result .md-typeset h1{color:var(--md-default-fg-color);font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result .md-typeset h1 mark{text-decoration:none}.md-search-result .md-typeset h2{color:var(--md-default-fg-color);font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result .md-typeset h2 mark{text-decoration:none}.md-search-result__terms{color:var(--md-default-fg-color);display:block;font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:initial;color:var(--md-accent-fg-color);text-decoration:underline}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-style:normal;font-weight:400;outline:none;text-align:initial;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:xxx;list-style:none}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(xxx);counter-increment:xxx;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{-webkit-backface-visibility:hidden;backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__alias{margin-left:.3rem;opacity:.7}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.md-typeset [role=dialog] .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset [role=dialog] .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset [role=dialog] .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset [role=dialog] .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset [role=dialog] .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset [role=dialog] .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset [role=dialog] .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset [role=dialog] .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset [role=dialog] .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset [role=dialog] .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset [role=dialog] .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset [role=dialog] .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset [role=dialog] .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset [role=dialog] .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset [role=dialog] .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset [role=dialog] .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset [role=dialog] .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset [role=dialog] .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset [role=dialog] .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset [role=dialog] .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),[role=dialog] .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,[role=dialog] .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),[role=dialog] .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),[role=dialog] .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),[role=dialog] .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),[role=dialog] .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),[role=dialog] .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),[role=dialog] .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),[role=dialog] .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),[role=dialog] .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),[role=dialog] .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),[role=dialog] .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),[role=dialog] .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),[role=dialog] .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),[role=dialog] .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),[role=dialog] .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),[role=dialog] .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),[role=dialog] .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),[role=dialog] .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),[role=dialog] .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file diff --git a/assets/stylesheets/palette.ab4e12ef.min.css b/assets/stylesheets/palette.ab4e12ef.min.css new file mode 100644 index 000000000..75aaf8425 --- /dev/null +++ b/assets/stylesheets/palette.ab4e12ef.min.css @@ -0,0 +1 @@ +@media screen{[data-md-color-scheme=slate]{--md-default-fg-color:hsla(var(--md-hue),15%,90%,0.82);--md-default-fg-color--light:hsla(var(--md-hue),15%,90%,0.56);--md-default-fg-color--lighter:hsla(var(--md-hue),15%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),15%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,14%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,14%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,14%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,14%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,0.82);--md-code-bg-color:hsla(var(--md-hue),15%,18%,1);--md-code-bg-color--light:hsla(var(--md-hue),15%,18%,0.9);--md-code-bg-color--lighter:hsla(var(--md-hue),15%,18%,0.54);--md-code-hl-color:#2977ff;--md-code-hl-color--light:#2977ff1a;--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-kbd-color:hsla(var(--md-hue),15%,90%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,90%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-mark-color:#4287ff4d;--md-typeset-table-color:hsla(var(--md-hue),15%,95%,0.12);--md-typeset-table-color--light:hsla(var(--md-hue),15%,95%,0.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-bg-color:hsla(var(--md-hue),15%,10%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,8%,1);--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #00000040,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0006,0 0 0.05rem #00000059;color-scheme:dark}[data-md-color-scheme=slate] img[src$="#gh-light-mode-only"],[data-md-color-scheme=slate] img[src$="#only-light"]{display:none}[data-md-color-scheme=slate][data-md-color-primary=pink]{--md-typeset-a-color:#ed5487}[data-md-color-scheme=slate][data-md-color-primary=purple]{--md-typeset-a-color:#c46fd3}[data-md-color-scheme=slate][data-md-color-primary=deep-purple]{--md-typeset-a-color:#a47bea}[data-md-color-scheme=slate][data-md-color-primary=indigo]{--md-typeset-a-color:#5488e8}[data-md-color-scheme=slate][data-md-color-primary=teal]{--md-typeset-a-color:#00ccb8}[data-md-color-scheme=slate][data-md-color-primary=green]{--md-typeset-a-color:#71c174}[data-md-color-scheme=slate][data-md-color-primary=deep-orange]{--md-typeset-a-color:#ff764d}[data-md-color-scheme=slate][data-md-color-primary=brown]{--md-typeset-a-color:#c1775c}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=blue-grey],[data-md-color-scheme=slate][data-md-color-primary=grey],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#5e8bde}[data-md-color-switching] *,[data-md-color-switching] :after,[data-md-color-switching] :before{transition-duration:0ms!important}}[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:#ff19471a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:#f500561a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:#df41fb1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:#7c4dff1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:#4287ff1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:#0091eb1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:#00bad61a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:#00bda41a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:#00c7531a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:#63de171a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:#b0eb001a;--md-accent-bg-color:#000000de;--md-accent-bg-color--light:#0000008a}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:#ffd5001a;--md-accent-bg-color:#000000de;--md-accent-bg-color--light:#0000008a}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:#ffaa001a;--md-accent-bg-color:#000000de;--md-accent-bg-color--light:#0000008a}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:#ff91001a;--md-accent-bg-color:#000000de;--md-accent-bg-color--light:#0000008a}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:#ff6e421a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:#000000de;--md-primary-bg-color--light:#0000008a}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:#000000de;--md-primary-bg-color--light:#0000008a}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:#000000de;--md-primary-bg-color--light:#0000008a}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:#000000de;--md-primary-bg-color--light:#0000008a}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-typeset-a-color:#4051b5}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-typeset-a-color:#4051b5}[data-md-color-primary=light-green]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#72ad2e}[data-md-color-primary=lime]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#8b990a}[data-md-color-primary=yellow]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#b8a500}[data-md-color-primary=amber]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#d19d00}[data-md-color-primary=orange]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#e68a00}[data-md-color-primary=white]{--md-primary-fg-color:hsla(var(--md-hue),0%,100%,1);--md-primary-fg-color--light:hsla(var(--md-hue),0%,100%,0.7);--md-primary-fg-color--dark:hsla(var(--md-hue),0%,0%,0.07);--md-primary-bg-color:hsla(var(--md-hue),0%,0%,0.87);--md-primary-bg-color--light:hsla(var(--md-hue),0%,0%,0.54);--md-typeset-a-color:#4051b5}[data-md-color-primary=white] .md-button{color:var(--md-typeset-a-color)}[data-md-color-primary=white] .md-button--primary{background-color:var(--md-typeset-a-color);border-color:var(--md-typeset-a-color);color:hsla(var(--md-hue),0%,100%,1)}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:hsla(var(--md-hue),0%,0%,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:hsla(var(--md-hue),0%,0%,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:hsla(var(--md-hue),0%,0%,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid #00000012}}[data-md-color-primary=black]{--md-primary-fg-color:hsla(var(--md-hue),15%,9%,1);--md-primary-fg-color--light:hsla(var(--md-hue),15%,9%,0.54);--md-primary-fg-color--dark:hsla(var(--md-hue),15%,9%,1);--md-primary-bg-color:hsla(var(--md-hue),15%,100%,1);--md-primary-bg-color--light:hsla(var(--md-hue),15%,100%,0.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-button{color:var(--md-typeset-a-color)}[data-md-color-primary=black] .md-button--primary{background-color:var(--md-typeset-a-color);border-color:var(--md-typeset-a-color);color:hsla(var(--md-hue),0%,100%,1)}[data-md-color-primary=black] .md-header{background-color:hsla(var(--md-hue),15%,9%,1)}@media screen and (max-width:59.984375em){[data-md-color-primary=black] .md-nav__source{background-color:hsla(var(--md-hue),15%,11%,.87)}}@media screen and (max-width:76.234375em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:hsla(var(--md-hue),15%,9%,1)}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:hsla(var(--md-hue),15%,9%,1)}} \ No newline at end of file diff --git a/commands/index.html b/commands/index.html new file mode 100644 index 000000000..111cc45a6 --- /dev/null +++ b/commands/index.html @@ -0,0 +1,3334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Commands - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    Commands

    + +

    Codeception commands provided by the library

    +

    The library provides some custom commands that can be added to the project Codeception configuration file ( +either codeception.yml or codeception.dist.yml).

    +

    run and codeception:run

    +

    Enable the commands with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\RunOriginal"
    +    - "lucatume\\WPBrowser\\Command\\RunAll"
    +
    +

    WordPress extensive use of global variables, constants and side effectes makes it difficult to run multiple test suites +in the same process without running into conflicts due to leaking state and side effects. +For this reason the project replaces Codeception run command with one that will run each suite in a separate process. +You can invoke the original Codeception command using the codeception:run command. +Just like the original, the run command accepts all the arguments and options of the original Codeception +command.

    +

    Run all the suites, each one in a separate process:

    +
    vendor/bin/codecept run
    +
    +

    Run only the Integration suite:

    +
    vendor/bin/codecept run Integration
    +
    +

    Run a specific test file:

    +
    vendor/bin/codecept run Integration tests/Integration/MyTest.php
    +
    +

    Run a specific test method:

    +
    vendor/bin/codecept run Integration tests/Integration/MyTest.php:testMyMethod
    +
    +

    Read the Codeception documentation for more information about the run command.

    +

    dev:start

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\DevStart"
    +
    +

    If not already running, start the services required to run the tests. +The started services are read from the Codeception configuration file (either codeception.yml +or codeception.dist.yml), from the extensions section, under the config key.

    +

    Given the following configuration:

    +
    extensions:
    +  enabled:
    +    - lucatume\WPBrowser\Extension\ChromeDriverController
    +    - lucatume\WPBrowser\Extension\BuiltInServerController
    +    - lucatume\WPBrowser\Extension\DockerComposeController
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\ChromeDriverController":
    +      port: '%CHROMEDRIVER_PORT%'
    +    "lucatume\\WPBrowser\\Extension\\BuiltInServerController":
    +      docroot: '%WORDPRESS_ROOT_DIR%'
    +      workers: 5
    +      port: '%BUILT_IN_SERVER_PORT%'
    +    "lucatume\\WPBrowser\\Extension\\DockerComposeController":
    +      compose-file: 'tests/docker-compose.yml'
    +      env-file: 'tests/.env'
    +
    +

    Running the command will start ChromeDriver, the built-in PHP server and Docker Compose.

    +

    dev:stop

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\DevStop"
    +
    +

    If running, stop the services required to run the tests. +The stopped services are read from the Codeception configuration file (either codeception.yml +or codeception.dist.yml), from the extensions section, under the config key.

    +

    Given the following configuration:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\ChromeDriverController"
    +    - "lucatume\\WPBrowser\\Extension\\BuiltInServerController"
    +    - "lucatume\\WPBrowser\\Extension\\DockerComposeController"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\ChromeDriverController":
    +      port: '%CHROMEDRIVER_PORT%'
    +    "lucatume\\WPBrowser\\Extension\\BuiltInServerController":
    +      docroot: '%WORDPRESS_ROOT_DIR%'
    +      workers: 5
    +      port: '%BUILT_IN_SERVER_PORT%'
    +    "lucatume\\WPBrowser\\Extension\\DockerComposeController":
    +      compose-file: 'tests/docker-compose.yml'
    +      env-file: 'tests/.env'
    +
    +

    Running the command will stop ChromeDriver, the built-in PHP server and Docker Compose.

    +

    dev:restart

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\DevRestart"
    +
    +

    This command is just a shortcut to run dev:stop and dev:start in sequence.

    +

    dev:info

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\DevInfo"
    +
    +

    Provides information about the local testing stack managed by +the DockerComposeController, BuiltInServerController +and ChromeDriverController extensions.

    +

    wp:db:import

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\DbImport"
    +
    +

    You can use WP CLI to interact with your WordPress installation, but WP CLI does not support SQLite databases in +the context of the wp db import command. +This command fills that gap by providing a database dump file import command that will support MySQL and SQLite +databases.

    +

    wp:db:export

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\DbExport"
    +
    +

    You can use WP CLI to interact with your WordPress installation, but WP CLI does not support SQLite databases in +the context of the wp db export command. +This command fills that gap by providing a database dump file export command that will support MySQL and SQLite +databases.

    +

    chromedriver:update

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\ChromedriverUpdate"
    +
    +

    If you're using Chromedriver as a binary installed in the Composer vendor directory (vendor/bin by default), you can +use this command to update it. +This command will download the latest version of Chromedriver compatible with the Chrome version installed on your +machine in the Composer vendor directory.

    +
    +

    Note: if the download fails, it might be a certificate issue.

    +
    +

    generate:wpunit

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPUnit"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPTestCase class. +The class incorporates the WordPress test case from the wordpress-develop repository and adds some utility +methods to make testing easier in the context of Codeception.

    +

    The lucatume\WPBrowser\TestCase\WPTestCase class is the one that should be used when writing tests for WordPress +code when using the WPLoader module.

    +

    Together with the WPLoader module, the WPTestCase class provides a number of functionalities to clean up the +database +after each test method and to reset the global state of WordPress.

    +

    Every test method runs in a transaction

    +

    Database queries running in the context of test methods of a test case extending the WPTestCase class will run in a +transaction that is rolled back after the test method is run. This means that any database change happening in the +context of a test method will not appear in the database while the test is running and after the test is run.

    +

    generate:wpajax

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPAjax"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPAjaxTestCase class. This class is a version of the WPTestCase designed to test AJAX requests.

    +

    generate:wpcanonical

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPCanonical"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPCanonicalTestCase class. This class is a version of the WPTestCase designed to test canonical redirects.

    +

    generate:wprestapi

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPRestApi"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPRestApiTestCase class. This class is a version of the WPTestCase designed to test the handling of REST API requests.

    +

    generate:wprestcontroller

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPRestController"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPRestControllerTestCase class. This class is a version of the WPTestCase designed to unit-test REST API controllers.

    +

    generate:wprestposttypecontroller

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPRestPostTypeController"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPRestPostTypeControllerTestCase class. This class is a version of the WPTestCase designed to unit-test REST API controllers for post types.

    +

    generate:wpxml

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPXML"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPXMLTestCase class. This class is a version of the WPTestCase designed to test the production of XML data.

    +

    generate:wpxmlrpc

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\GenerateWPXMLRPC"
    +
    +

    Generate a test case extending the lucatume\WPBrowser\TestCase\WPXMLRPCTestCase class. This class is a version of the WPTestCase designed to test the XML-RPC API.

    +

    monkey:cache:path

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\MonkeyCachePath"
    +
    +

    Get the path to the monkey-patching cache directory.

    +

    Use the --porcelain or -p option to get the path without any additional output.

    +

    monkey:cache:clear

    +

    Enable the command with:

    +
    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\MonkeyCacheClear"
    +
    +

    Clear the monkey-patching cache.

    +

    Use the --porcelain or -p option to suppress any confirmation output.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/custom-configuration/index.html b/custom-configuration/index.html new file mode 100644 index 000000000..0311c42cc --- /dev/null +++ b/custom-configuration/index.html @@ -0,0 +1,3086 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom configuration - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    Custom configuration

    + +

    Custom testing configuration

    +

    Any non default configuration is considered a custom configuration.
    +If your project requires a tailored set up, this is the configuration for you.

    +

    Using a custom configuration to run tests

    +

    If you decide to skip the default configuration, or are working +on a project that cannot use the default configuration +you will be able to set up wp-browser to suit your needs using a custom configuration.

    +

    Choose "no", to not use the default configuration, when running the vendor/bin/codecept init wpbrowser command.

    +

    The command will set up the file structure to be able to run integration and end-to-end tests and will +leverage Codeception dynamic configuration using parameters to control the testing stack using the tests/.env +file.

    +

    Walkthrough of the tests/.env file

    +
      +
    • WORDPRESS_ROOT_DIR - the path to the root WordPress installation directory. This is the directory that contains + WordPress files, like wp-load.php. This path can be absolute or relative to the root project directory; + e.g. vendor/wordpress (relative) or /var/www/wordpress (absolute) will work.
    • +
    • WORDPRESS_URL - the URL of the WordPress installation. This is the URL that will be used by the browser to access + the WordPress + installation in the context of end-to-end tests; e.g. http://localhost:8080 or https://wordpress.local.
    • +
    • WORDPRESS_DOMAIN - the domain of the WordPress installation; this value should follow the WORDPRESS_URL value. + E.g. if WORDPRESS_URL is http://localhost:8080 the WORDPRESS_DOMAIN value should be localhost:8080; + if WORDPRESS_URL is https://wordpress.local the WORDPRESS_DOMAIN value should be wordpress.local.
    • +
    • WORDPRESS_DB_URL - the user, password, host, and name of the database used by the tests. If the database is a MySQL + database, the value should be in the form mysql://user:password@host:port/database_name. + If the database is a SQLite database, the value should be in the form sqlite://path/to/database/file.
    • +
    • WORDPRESS_TABLE_PREFIX - the database table prefix used by the WordPress installation, the one served + at WORDPRESS_URL. + This value is usually wp_ but can be different if the WordPress installation has been configured to use a different + prefix.
    • +
    • TEST_TABLE_PREFIX - the database table prefix used by the WPLoader module to + install WordPress and run the tests. This value is usually test_ and should be different from + the WORDPRESS_TABLE_PREFIX value.
    • +
    • WORDPRESS_ADMIN_USER - the username of the WordPress administrator user. E.g. admin.
    • +
    • WORDPRESS_ADMIN_PASSWORD - the password of the WordPress administrator user. E.g. secret!password.
    • +
    • CHROMEDRIVER_HOST - the host of the Chromedriver server. This value is usually localhost if you're running + Chromedriver on the same machine as the tests. If you're running your tests using a container stack, it will be the + name of the container running Chromedriver, e.g. chromedriver.
    • +
    • CHROMEDRIVER_PORT - the port of the Chromedriver server. This value is usually 9515 if you're running Chromedriver + on the same machine as the tests. If you're running your tests using a container stack, it will be the port exposed by + the container running Chromedriver, e.g. 4444. Note the default configuration will set + this value to a random port during set up to avoid conflicts with other services running on the same machine.
    • +
    +

    Handling custom file structures

    +

    If your site uses a customized file structure to manage WordPress, you will need to further +configure the WPLoader module to correctly look for the site content. +Read more about setting up WPLoader to correctly load plugins and themes from custom locations here.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/default-configuration/index.html b/default-configuration/index.html new file mode 100644 index 000000000..93690ef04 --- /dev/null +++ b/default-configuration/index.html @@ -0,0 +1,3192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default configuration - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    Default configuration

    + +

    Default testing configuration

    +

    The recommended configuration for most projects. +It allows you to get into WordPress integration and end-to-end testing quickly and easily.

    +

    Requirements

    +

    The default configuration will set up Codeception and wp-browser to use SQLite as the database engine, PHP built-in +server to serve the test site on localhost and your local version of Chrome, driven by Chromedriver, to run end-to-end +tests.

    +

    As such, the default configuration has the following requirements:

    +
      +
    • the sqlite3 PHP extension; you can check if if's installed by running php -m | grep sqlite3 in your terminal
    • +
    • the pdo_sqlite PHP extension; you can check if if's installed by running php -m | grep pdo_sqlite in your terminal
    • +
    • PHP built-in server can work with only one thread, but it will be faster using multiple threads; multiple threads are + not supported on Windows, but they are supported on WSL.
    • +
    • the Chrome browser installed on your machine
    • +
    +

    Overview - plugin and theme project

    +

    If you're configuring wp-browser for a plugin or theme project, the default configuration will install WordPress in +the tests/_wordpress directory and configure the installation to run using SQLite as a database engine. +The SQLite Database Integration plugin) will be placed in the installation must-use plugins directory.

    +

    If your plugin or theme project requires additional plugins or theme to work, you can place them in +the tests/_worpdress/wp-content/plugins and tests/_wordpress/wp-content/themes directories respectively.

    +

    When adding, or removing, plugin and themes, remember to +update the WPLoader module configuration to load the correct plugins and themes in +your integration tests.

    +

    On the same note, update the database dump used by the WPDb module to reflect the +changes in the dump loaded in the end-to-end tests. +The easiest way to update the database fixture is to load the current database dump +using the wp:db:import command, manually setting up the site interacting with it and then +exporting the database dump using the wp:db:export command.

    +

    You can find out about the URL of the site served by the PHP built-in web server by +running the dev:info command.

    +

    Overview - site project

    +

    If you're configuring wp-browser for a site project, the default configuration will use a combination of PHP built-in +web server and the SQLite Database Integration plugin to run the tests and serve your site.

    +

    The router file used by the PHP built-in web server will force the site, when served on localhost, to use SQLite as +database engine leaving your existing local MySQL database untouched.

    +

    Your existing WordPress installation will be picked up as it is, with all the plugins and themes found in the contents +directory.

    +

    Existing plugins and themes are not added to WPLoader module configuration by +wp-browser, you have to do that manually.

    +

    Similarly, the database dump used by the WPDb module is, by default, an empty WordPress +installation where no plugins and themes are active. +You have to update the database dump used by the module to reflect the state of your site. +You can do that by loading the current database dump using the wp:db:import command, +manually setting up the site interacting with it and then +exporting the database dump using the wp:db:export command.

    +

    You can find out about the URL of the site served by the PHP built-in web server by +running the dev:info command.

    +

    When not to use the default configuration

    +

    The default configuration is the recommended one for most projects, but some projects might require you to use a custom +configuration to make the most out of wp-browser.

    +

    Database drop-in

    +

    The default configuration will use the SQLite Database Integration plugin to use SQLite as the database engine. +This requires placing a db.php drop-in file in the WordPress content directory.

    +

    If your project already requires a db.php drop-in file, you will have to use a custom configuration.

    +

    Multisite with sub-domains

    +

    While Chrome will handle sub-domains correctly, even on localhost, WordPress will not. +If you're testing a multisite installation with sub-domains, you will have to use a custom configuration.

    +

    Custom site structure

    +

    If your site uses a customized file structure to manage WordPress, you will need to configure wp-browser using a custom +configuration. +This is usually true for some site projects, and will most likely not be an issue for plugin and theme projects.

    +

    Using a custom configuration is not that difficult +though: read more about using a custom configuration here.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/BuiltInServerController/index.html b/extensions/BuiltInServerController/index.html new file mode 100644 index 000000000..322b7d8c6 --- /dev/null +++ b/extensions/BuiltInServerController/index.html @@ -0,0 +1,3054 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PHP Built-in Server Controller - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    PHP Built-in Server Controller

    + +

    This extension will start and stop the PHP built-in web server before and after the tests run.

    +

    Configuration

    +

    The extension can be configured with the following parameters:

    +
      +
    • required
        +
      • docroot - the document root to use for the PHP Built-in server; it can be either an absolute path or a path + relative to the Codeception root directory. Note the lowercase r in the parameter name.
      • +
      +
    • +
    • optional
        +
      • suites - an array of Codeception suites to run the server for; if not set the server will be started for all the + suites.
      • +
      • port - the port to use for the PHP Built-in server, if not set the server will use port 2389.
      • +
      • workers - the number of workers to use for the PHP Built-in server, if not set the server will use 5 workers. + This is the equivalent of the PHP_CLI_SERVER_WORKERS environment variable.
      • +
      +
    • +
    +
    +

    Note: if you run PHP built-in server on Windows, the workers parameter will be ignored and the server will always +run with a single worker. This limit is not present in WSL.

    +
    +

    Configuration Examples

    +

    Example configuration starting the server for all suites:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\BuiltInServerController"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\BuiltInServerController":
    +      docroot: /var/www/html
    +      workers: 5
    +
    +

    The extension can access environment variables defined in the tests configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\BuiltInServerController"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\BuiltInServerController":
    +      suites:
    +        - EndToEnd
    +        - WebApp
    +      docroot: '%WORDPRESS_ROOT_DIR%'
    +      port: '%BUILT_IN_SERVER_PORT%'
    +      workers: '%BUILT_IN_SERVER_WORKERS%'
    +
    +

    This is a service extension

    +

    This is a service extension that will be started and stopped by the dev:start +and dev:stop commands.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/ChromeDriverController/index.html b/extensions/ChromeDriverController/index.html new file mode 100644 index 000000000..17b0c1c7d --- /dev/null +++ b/extensions/ChromeDriverController/index.html @@ -0,0 +1,3046 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ChromeDriver Controller - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    ChromeDriver Controller

    + +

    This extension will start and stop the ChromeDriver before and after the tests are run.

    +

    Configuration

    +

    The extension can be configured with the following parameters:

    +
      +
    • optional
        +
      • suites - an array of Codeception suites to run the server for; if not set the server will be started for all the + suites.
      • +
      • port - the port to use for the ChromeDriver, if not set the server will use port 9515.
      • +
      • binary - the path to the ChromeDriver binary, if not set the server will use the chromedriver binary in the + Composer bin directory.
      • +
      +
    • +
    +

    Configuration Examples

    +

    Example configuration starting the server for all suites:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\ChromeDriverController"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\ChromeDriverController":
    +      port: 4444
    +      binary: /usr/local/bin/chromedriver
    +
    +

    The extension can access environment variables defined in the tests configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\ChromeDriverController"
    +  config:
    +    suites:
    +      - EndToEnd
    +      - WebApp
    +    "lucatume\\WPBrowser\\Extension\\ChromeDriverController":
    +      port: '%CHROMEDRIVER_PORT%'
    +      binary: '%CHROMEDRIVER_BINARY%'
    +
    +

    You can use the chromedriver:update command to download the latest version of +ChromeDriver compatible with your Chrome browser version and place it in the Composer bin directory.

    +

    This is a service extension

    +

    This is a service extension that will be started and stopped by the dev:start +and dev:stop commands.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/DockerComposeController/index.html b/extensions/DockerComposeController/index.html new file mode 100644 index 000000000..da2cefa05 --- /dev/null +++ b/extensions/DockerComposeController/index.html @@ -0,0 +1,3042 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Docker Compose Controller - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    Docker Compose Controller

    + +

    This extension will start and stop a docker compose stack before and after the tests are run.

    +

    Configuration

    +

    The extension can be configured with the following parameters:

    +
      +
    • required
        +
      • compose-file - the path to the docker compose file to use; it can be either an absolute path or a path + relative to the Codeception root directory.
      • +
      +
    • +
    • optional
        +
      • env-file- the path to the environment file to use; it can be either an absolute path or a path.
      • +
      +
    • +
    +

    Configuration Examples

    +

    Example configuration starting the server for all suites:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\DockerComposeController"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\DockerComposeController":
    +      compose-file: /var/www/html/docker-compose.yml
    +      env-file: /var/www/html/.env
    +
    +

    The extension can access environment variables defined in the tests configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\DockerComposeController"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\DockerComposeController":
    +      compose-file: '%DOCKER_COMPOSE_FILE%'
    +      env-file: '%DOCKER_COMPOSE_ENV_FILE%'
    +
    +

    This is a service extension

    +

    This is a service extension that will be started and stopped by the dev:start +and wp:dev-stop commands.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/EventDispatcherBridge/index.html b/extensions/EventDispatcherBridge/index.html new file mode 100644 index 000000000..49ec26df5 --- /dev/null +++ b/extensions/EventDispatcherBridge/index.html @@ -0,0 +1,3140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Event Dispatcher Bridge - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    Event Dispatcher Bridge

    + +

    This extension connects the event dispatcher system provided by Codeception, and normally available only through the +use of custom extensions, to make it available through calls to the lucatume\WPBrowser\Events\Dispatcher class +API.

    +

    If not using this extension, then the only way to subscribe to events dispatched by Codeception is to use custom +extensions.

    +

    Configuration

    +

    The extension does not require configuration, it just needs to be enabled in the Codeception configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\EventDispatcherBridge"
    +
    +

    Usage

    +

    The extension will automatically hook into the event dispatcher system provided by Codeception, normally available only +through the use of custom extensions, and inject user-defined event listeners in it.

    +

    Once the extension is enabled, you can use the lucatume\WPBrowser\Events\Dispatcher class to subscribe to Codeception +events.
    +This is typically be done in either the global bootstrap file, or in a suite bootstrap file.

    +

    You can subscribe to the following events dispatched by Codeception in either the global bootstrap file +(usually tests/_bootstrap.php), or in a suite bootstrap file (usually tests/<suite>/_bootstrap.php):

    +
      +
    • Codeception\Events::SUITE_BEFORE
    • +
    • Codeception\Events::SUITE_AFTER
    • +
    • CodeceptionventsEvents::TEST_START
    • +
    • CodeceptionventsEvents::TEST_BEFORE
    • +
    • CodeceptionventsEvents::STEP_BEFORE
    • +
    • CodeceptionventsEvents::STEP_AFTER
    • +
    • CodeceptionventsEvents::TEST_FAIL
    • +
    • CodeceptionventsEvents::TEST_ERROR
    • +
    • CodeceptionventsEvents::TEST_PARSED
    • +
    • CodeceptionventsEvents::TEST_INCOMPLETE
    • +
    • CodeceptionventsEvents::TEST_SKIPPED
    • +
    • CodeceptionventsEvents::TEST_WARNING
    • +
    • CodeceptionventsEvents::TEST_USELESS
    • +
    • CodeceptionventsEvents::TEST_SUCCESS
    • +
    • CodeceptionventsEvents::TEST_AFTER
    • +
    • CodeceptionventsEvents::TEST_END
    • +
    • CodeceptionventsEvents::TEST_FAIL_PRINT
    • +
    • CodeceptionventsEvents::RESULT_PRINT_AFTER
    • +
    +

    Due to order-of-operations, the earliest Codeception dispatched Event you can subscribe to is the SUITE_BEFORE one.
    +To subscribe to the following earlier events, you must implement an extension following the custom extension +approach:

    +
      +
    • Codeception\Events::MODULE_INIT
    • +
    • Codeception\Events::SUITE_INIT
    • +
    +

    The Dispatcher API documentation provides more details about the events dispatched by Codeception and wp-browser +and examples on how to subscribe to them.

    +

    Usage Examples

    +

    In the global bootstrap file (usually tests/_bootstrap.php), or the suite bootstrap file (usually +tests/<suite>/_bootstrap.php), subscribe to the Codeception events by providing a callback function that will accept +different parameters depending on the event being dispatched:

    +
    <?php
    +
    +use Codeception\Events;
    +use Codeception\Event\SuiteEvent
    +use Codeception\Event\TestEvent;
    +use Codeception\Event\StepEvent;
    +use Codeception\Event\PrintResultEvent;
    +use lucatume\WPBrowser\Events\Dispatcher;
    +
    +Dispatcher::addListener(Events::SUITE_BEFORE, function (SuiteEvent $suiteEvent) {
    +    codecept_debug('Running on SUITE BEFORE');
    +});
    +
    +Dispatcher::addListener(Events::SUITE_AFTER, function (SuiteEvent $suiteEvent) {
    +    codecept_debug('Running on SUITE AFTER');
    +});
    +
    +Dispatcher::addListener(Events::TEST_START, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST START');
    +});
    +
    +Dispatcher::addListener(Events::TEST_BEFORE, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST BEFORE');
    +});
    +
    +Dispatcher::addListener(Events::STEP_BEFORE, function (StepEvent $stepEvent) {
    +    codecept_debug('Running on STEP BEFORE');
    +});
    +
    +Dispatcher::addListener(Events::STEP_AFTER, function (StepEvent $stepEvent) {
    +    codecept_debug('Running on STEP AFTER');
    +});
    +
    +Dispatcher::addListener(Events::TEST_FAIL, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST FAIL');
    +});
    +
    +Dispatcher::addListener(Events::TEST_ERROR, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST ERROR');
    +});
    +
    +Dispatcher::addListener(Events::TEST_PARSED, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST PARSED');
    +});
    +
    +Dispatcher::addListener(Events::TEST_INCOMPLETE, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST INCOMPLETE');
    +});
    +
    +Dispatcher::addListener(Events::TEST_SKIPPED, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST SKIPPED');
    +});
    +
    +Dispatcher::addListener(Events::TEST_WARNING, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST WARNING');
    +});
    +
    +Dispatcher::addListener(Events::TEST_USELESS, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST USELESS');
    +});
    +
    +Dispatcher::addListener(Events::TEST_SUCCESS, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST SUCCESS');
    +});
    +
    +Dispatcher::addListener(Events::TEST_AFTER, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST AFTER');
    +});
    +
    +Dispatcher::addListener(Events::TEST_END, function (TestEvent $testEvent) {
    +    codecept_debug('Running on TEST END');
    +});
    +
    +Dispatcher::addListener(Events::TEST_FAIL_PRINT, function (PrintResultEvent $printResultEvent) {
    +    codecept_debug('Running on TEST FAIL PRINT');
    +});
    +
    +Dispatcher::addListener(Events::RESULT_PRINT_AFTER, function (PrintResultEvent $printResultEvent) {
    +    codecept_debug('Running on RESULT PRINT AFTER');
    +});
    +
    +

    Read more about the Dispatcher API here.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/IsolationSupport/index.html b/extensions/IsolationSupport/index.html new file mode 100644 index 000000000..58e095208 --- /dev/null +++ b/extensions/IsolationSupport/index.html @@ -0,0 +1,3020 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Isolation Support - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    Isolation Support

    + +

    This extension provides support for the PHPUnit annotations @runInSeparateProcess and @runTestsInSeparateProcesses, +and the PHPUnit attributes (PHPUnit 10+) #[RunInSeparateProcess] and #[RunTestsInSeparateProcesses].
    +You can read more about these annotations and attributes in the PHPUnit documentation about test isolation.

    +

    Codeception does not natively support these annotations and attributes, this extension provides support for them.

    +

    Configuration

    +

    You can enable the extension in the Codeception configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\IsolationSupport"
    +
    +

    In your tests, you can use the annotations or attributes as you would in a PHPUnit test:

    +
    <?php
    +
    +use lucatume\WPBrowser\TestCase\WPTestCase;
    +
    +class IsolationExampleTest extends WPTestCase {
    +    /**
    +     * @runInSeparateProcess
    +     */
    +    public function test_in_admin_context() {
    +        define('WP_ADMIN', true);
    +
    +        $this->assertTrue(is_admin());
    +    }
    +
    +    #[RunTestsInSeparateProcesses]
    +    public function test_in_admin_context_with_attribute() {
    +        define('WP_ADMIN', true);
    +
    +        $this->assertTrue(is_admin());
    +    }
    +
    +    public function test_constant_is_not_set() {
    +        $this->assertFalse(defined('WP_ADMIN'));
    +    }
    +}
    +
    +#[RunTestsInSeparateProcesses]
    +class RunAllTestsInSeparateProcesses extends WPTestCase {
    +    public function test_one() {
    +        definen('TEST_CONST', 'one');
    +
    +        $this->assertEquals('one', TEST_CONST);
    +    }
    +
    +    public function test_two() {
    +        definen('TEST_CONST', 'two');
    +
    +        $this->assertEquals('two', TEST_CONST);
    +    }
    +}
    +
    +
    +

    Previous versions of the test isolation support required the @backupGlobals disabled annotation to be used when +running tests in isolation. This is no longer required.

    +
    +

    Isolation support is based around monkey-patching the file at runtime. Look into the monkey:cache:clear +and monkey:cache:path commands to manage the monkey-patching cache.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/MySqlServerController/index.html b/extensions/MySqlServerController/index.html new file mode 100644 index 000000000..3de57e498 --- /dev/null +++ b/extensions/MySqlServerController/index.html @@ -0,0 +1,3107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MySqlServer Controller - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    MySqlServer Controller

    + +

    This extension will start and stop the MySQL server before and after the tests run.
    +The extension will take care of downloading the MySQL Community Server archive from +the MySQL Community Server site, place it in the _mysql-server +directory under the codeception output directory and initialize the server in the same directory.

    +

    The aim of this extension is to allow running integration tests against a real MySQL server, without having to +install and configure a MySQL server on the machine.

    +
    +

    Warning

    +

    Currently the MySQL Community Server version installed by this extension (8.4.2 LTS) is not available for Windows on ARM.

    +

    If you are running Windows on ARM, you can either:
    +- Use a custom binary, see the configuration examples below
    +- Use the Docker controller extension to run the database from a Docker container.

    +
    +

    Configuration

    +

    The extension can be configured with the following parameters:

    +
      +
    • required
        +
      • port - the localhost port to use for the MySQL server, defaults to 8906.
      • +
      • database - the database that will be created when starting the server, defaults to wordpress.
      • +
      • user - the user that will be created when starting the server, defaults to wordpress. The user will be granted + all privileges on the database specified by the database parameter. If the user is root, no further user will + be created.
      • +
      • password - the password to use for the user specified by the user parameter, defaults to wordpress. If the + user is root, the root user will be set to the password specified by this parameter.
      • +
      +
    • +
    • optional
        +
      • suites - an array of Codeception suites to run the server for; if not set the server will be started for all the + suites.
      • +
      • binary - the path to the MySQL server binary to use, defaults to mysqld, defaults to null to download and + initialize the correct version of MySQL server for the current platform and architecture.
      • +
      • shareDir - the path to the directory to use for the MySQL server share, defaults to null. This is required + when providing a custom binary.
      • +
      +
    • +
    +

    Configuration Examples

    +

    Example configuration starting the server for all suites:

    +
    extensions:
    +  enabled:
    +    - "lucatume\WPBrowser\Extension\MySqlServerController":
    +      port: 8906
    +      database: wordpress
    +      user: wordpress
    +      password: wordpress
    +
    +

    The extension can access environment variables defined in the tests configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\WPBrowser\Extension\MySqlServerController":
    +      port: '%MYSQL_SERVER_PORT%'
    +      database: '%MYSQL_SERVER_DATABASE%'
    +      user: '%MYSQL_SERVER_USER%'
    +      password: '%MYSQL_SERVER_PASSWORD%'
    +
    +

    Example configuration using the root user:

    +
    extensions:
    +  enabled:
    +    - "lucatume\WPBrowser\Extension\MySqlServerController":
    +      port: 33446
    +      database: wordpress
    +      user: root
    +      password: secret
    +
    +

    Using a custom MySQL server binary

    +

    The extension can be configured to use a custom MySQL server binary by setting the binary configuration parameter to +the absolute path to the binary:

    +
    extensions:
    +  enabled:
    +    - "lucatume\WPBrowser\Extension\MySqlServerController":
    +      port: 33446
    +      database: wordpress
    +      user: root
    +      password: secret
    +      binary: /usr/local/mysql/bin/mysqld
    +
    +

    This is a service extension

    +

    This is a service extension that will be started and stopped by the dev:start +and dev:stop commands.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/Symlinker/index.html b/extensions/Symlinker/index.html new file mode 100644 index 000000000..6bc406a62 --- /dev/null +++ b/extensions/Symlinker/index.html @@ -0,0 +1,2961 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Symlinker - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    Symlinker

    + +

    This extension will symlink the plugins and themes specified in the plugins and themes configuration parameters to +the WordPress installation plugins and themes directories, respectively.

    +

    The plugins and themes will be symlinked before each suite, and removed after each suite.

    +

    Configuration

    +

    The extension can be configured with the following parameters:

    +
      +
    • required
        +
      • wpRootFolder - the relative (to the current working directory) or absolute path to the WordPress installation + root folder, the directory that contains the wp-load.php file.
      • +
      +
    • +
    • optional
        +
      • cleanupAfterSuite - default false, a boolean value to indicate if the symlinks created by the extension + sshould be removed after the suite ran.
      • +
      • plugins- a list of plugin directories to symlink to the WordPress installation plugins directory, if not set + the plugin symlinking will be skipped.
      • +
      • themes- a list of theme directories to symlink to the WordPress installation themes directory, if not set + the theme symlinking will be skipped.
      • +
      +
    • +
    +

    Configuration Examples

    +

    Example configuration symbolically linking the plugins and themes to the WordPress installation plugins and themes +directories:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\Symlinker"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\Symlinker":
    +      wpRootFolder: /var/www/html
    +      plugins:
    +        - '.' # Relative path, the current working directory.
    +        - /home/plugins/plugin-1 # Absolute path to a plugin directory.
    +        - vendor/acme/plugin-2 # Relative path to a plugin directory.
    +      themes:
    +        - /home/theme-1 # Absolute path to a theme directory.
    +        - vendor/acme/theme-2 # Relative path to a theme directory.
    +
    +

    The extension can access environment variables defined in the tests configuration file:

    +
    extensions:
    +  enabled:
    +    - "lucatume\\WPBrowser\\Extension\\Symlinker"
    +  config:
    +    "lucatume\\WPBrowser\\Extension\\Symlinker":
    +      wpRootFolder: '%WP_ROOT_FOLDER%'
    +      plugins:
    +        - '%PLUGIN_STORAGE%/plugin-1'
    +        - '%PLUGIN_STORAGE%/plugin-2'
    +      themes:
    +        - '%THEME_STORAGE%/theme-1'
    +        - '%THEME_STORAGE%/theme-2'
    +
    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/extensions/index.html b/extensions/index.html new file mode 100644 index 000000000..bf69e5d85 --- /dev/null +++ b/extensions/index.html @@ -0,0 +1,2885 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extensions - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + + +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..574cb7608 --- /dev/null +++ b/index.html @@ -0,0 +1,3175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Getting started - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    + +
    + + + +
    + +
    + + + + + + + + +

    Getting started

    + +
    +

    This is the documentation for version 4 of the project, the current version. +Documentation for the previous version of the project, version 3, can be found here.

    +
    +

    The wp-browser library provides a set of Codeception modules and middleware to enable the testing of WordPress sites, plugins and themes.

    +

    Requirements

    +

    Depending on the nature of your project, there are different requirements it will need to satisfy before getting started.

    +

    Site

    +
      +
    • Ensure you're running the vendor/bin/codecept init wpbrowser command from the root directory of your WordPress site.
    • +
    • Ensure the directory contains the WordPress installation files. In a standard scenario you should have extracted WordPress files in this directory.
    • +
    • Ensure your installation is configured: it should contain a wp-config.php file.
    • +
    +

    Plugin

    +
      +
    • Ensure you're running the vendor/bin/codecept init wpbrowser command from the root directory of your plugin; this should be the directory that contains the PHP file defining the plugin header.
    • +
    +

    Theme

    +
      +
    • Ensure you're running the vendor/bin/codecept init wpbrowser command from the root directory of your theme; this should be the directory that contains the style.css file defining the theme header.
    • +
    +

    If you decide to use the quick installation, then your PHP version should have the sqlite3 extensions installed and activated. You can check this using the php -m command and verifying the sqlite3 extension is among the active extensions.

    +

    Installation

    +

    Add wp-browser to your project as a development dependency using Composer

    +
    cd my-wordrpess-project
    +composer require --dev lucatume/wp-browser
    +
    +

    Initialize wp-browser to quickly configured to suite your project and setup:

    +
    vendor/bin/codecept init wpbrowser
    +
    +

    The command will set up your project to run integration and end-to-end tests using:

    +
      +
    • SQLite as the database engine, leveraging the SQLite Database Integration plugin
    • +
    • PHP built-in web server to serve the WordPress site on localhost (e.g. http://localhost:8080)
    • +
    • Chromedriver to drive the local version of Chrome installed on your machine
    • +
    +

    If you're working on a plugin or theme project, the default configuration will add some extra steps:

    +
      +
    • install the latest version of WordPress in the tests/_wordpress directory
    • +
    • create a tests/_plugins directory: any file or directory in this directory will be symlinked into the WordPress + installation in tests/_wordpress/wp-content/plugins
    • +
    • create a tests/_themes directory: any file or directory in this directory will be symlinked into the WordPress + installation in tests/_wordpress/wp-content/themes
    • +
    +

    For most projects this configuration will be enough to get started with testing.

    +

    You can run your tests immediately using the vendor/bin/codecept run command.

    +

    Read more about the commands provided by the library here.

    +

    Using a custom configuration

    +

    If you decide to skip the default configuration, you will be able to set up wp-browser to suit your needs and local +setup by editing the tests/.env file. +The inline documentation in the file will guide you through the configuration process.

    +

    Read more about using a custom configuration here.

    +

    Getting support for wp-browser configuration and usage

    +

    The best place to get support for wp-browser is the project documentation.
    +Since this project builds on top of PHPUnit and Codeception, you can also refer to their documentation.

    +

    If you can't find the answer to your question here you can ask on +the "Issues" section of the wp-browser repository taking care to provide as much information as possible.

    +

    Finally, you can contact me directly to set up a call to discuss your +project needs and how wp-browser can help you.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/migration/index.html b/migration/index.html new file mode 100644 index 000000000..7c1658596 --- /dev/null +++ b/migration/index.html @@ -0,0 +1,3215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Migrating to newer versions - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    Migrating to newer versions

    + +

    Depending on your project PHP compatibility, you have three options to choose from:

    + +

    Version 3.5 and 4.0

    +

    Version 3.5 and 4.0 are the latest versions of wp-browser.
    +Version 3.5 is a transpile of version 4 to be compatible with PHP 7.1 to 7.4 that contains, for all intents and +purposes, the same facilities and systems contained in version 4 of wp-browser adapter to work on lower PHP versions +and version 4 of Codeception.

    +

    Future development of wp-browser will happen on version 4 and will be transpiled to version 3.5 for +back-compatibility purposes.

    +

    Migrate from version 3 to 3.5

    +
      +
    1. Update the required version of wp-browser in your composer.json file to 3.5: +
      {
      +  "require-dev": {
      +    "lucatume/wp-browser": "^3.5"
      +  }
      +}
      +
    2. +
    3. See the changes common to version 3.5 and 4.0
    4. +
    +

    Migrate from version 3 to 4

    +
      +
    1. Update the required version of wp-browser in your composer.json file to 4.0: +
      {
      +  "require-dev": {
      +    "lucatume/wp-browser": "^4.0"
      +  }
      +}
      +
    2. +
    3. See the changes common to version 3.5 and 4.0
    4. +
    +

    Changes common to version 3.5 and 4.0

    +
      +
    1. Update your main Codeception configuration file (e.g. codeception.yml) to enable the new commands:
    2. +
    +

    extensions:
    +  commands:
    +    - "lucatume\\WPBrowser\\Command\\RunOriginal"
    +    - "lucatume\\WPBrowser\\Command\\RunAll"
    +    - "lucatume\\WPBrowser\\Command\\DbExport"
    +    - "lucatume\\WPBrowser\\Command\\DbImport"
    +    - "lucatume\\WPBrowser\\Command\\MonkeyCachePath"
    +    - "lucatume\\WPBrowser\\Command\\MonkeyCacheClear"
    +
    +2. Along with the new commands, update the existing commands to use the lucatume\WPBrowser\Command\ namespace:

    +

    extensions:
    +  commands:
    +-    - "Codeception\\Command\\GenerateWPUnit"
    +-    - "Codeception\\Command\\GenerateWPRestApi"
    +-    - "Codeception\\Command\\GenerateWPRestController"
    +-    - "Codeception\\Command\\GenerateWPRestPostTypeController"
    +-    - "Codeception\\Command\\GenerateWPAjax"
    +-    - "Codeception\\Command\\GenerateWPCanonical"
    +-    - "Codeception\\Command\\GenerateWPXMLRPC"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPUnit"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPRestApi"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPRestController"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPRestPostTypeController"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPAjax"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPCanonical"
    ++    - "lucatume\\WPBrowser\\Command\\GenerateWPXMLRPC"
    +
    +3. If your test code is loading deprecated functions, arguments, classes, files, or hooks, you need to update your test + code to let the test case know using the setExpectedDeprecated method: +
    <?php
    +
    +use lucatume\WPBrowser\TestCase\WPTestCase;
    +
    +class MyTestUsingDeprecatedCode extends WPTestCase {
    +    public function test_deprecatd_function() {
    +        // add_filter( 'deprecated_function_trigger_error', '__return_false' );
    +        $this->setExpectedDeprecated( 'my_deprecated_function' );
    +        my_deprecated_function();
    +    }
    +
    +    public function test_deprecated_class(){
    +        // add_filter( 'deprecated_class_trigger_error', '__return_false' );
    +        $this->setExpectedDeprecated( 'MyDeprecatedClass' );
    +        new MyDeprecatedClass();
    +    }
    +
    +    public function test_deprecated_file(){
    +        // add_filter( 'deprecated_file_trigger_error', '__return_false' );
    +        $this->setExpectedDeprecated( '/path/to/my_deprecated_file.php' );
    +        require_once 'my_deprecated_file.php';
    +    }
    +
    +    public function test_deprecated_hook(){
    +        // add_filter( 'deprecated_hook_trigger_error', '__return_false' );
    +        $this->setExpectedDeprecated( 'my_deprecated_hook' );
    +        do_action( 'my_deprecated_hook' );
    +    }
    +}
    +
    + Previously, your code could just filter + the deprecated_function_trigger_error, deprecated_argument_trigger_error, deprecated_class_trigger_error, deprecated_file_trigger_error, and deprecated_hook_trigger_error, hooks to return false to tolerate the deprecation notices in tests.
    +4. If your test code is directly modifying properties like $expected_deprecated or $expected_doing_it_wrong directly, you need to update your test code to use the setExpectedDeprecated and setExpectedIncorrectUsage methods: +
    <?php
    +
    +use lucatume\WPBrowser\TestCase\WPTestCase;
    +class MyTestUsingDeprecatedCode extends WPTestCase {
    +    public function test_deprecated_function() {
    +        // $this->expected_deprecated[] = 'my_deprecated_function';
    +        $this->setExpectedDeprecated( 'my_deprecated_function' );
    +        my_deprecated_function();
    +    }
    +
    +    public function test_doing_it_wrong(){
    +        // $this->expected_doing_it_wrong[] = 'my_doing_it_wrong';
    +        $this->setExpectedIncorrectUsage( 'my_doing_it_wrong' );
    +        my_doing_it_wrong();
    +    }
    +}
    +
    +5. If your test code is knowingly triggering doing-it-wrong notices, you need to update your test code to let the test + case know using the setExpectedIncorrectUsage method: +
    <?php
    +
    +use lucatume\WPBrowser\TestCase\WPTestCase;
    +class MyTestUsingDoingItWrongTest extends WPTestCase {
    +    public function test_it_can_use_doing_it_wrong() {
    +        $this->setExpectedIncorrectUsage( 'my_doing_it_wrong' );
    +        my_doing_it_wrong();
    +    }
    +}
    +
    + Previously, your code could just filter the doing_it_wrong_trigger_error hook to return false to tolerate the + doing-it-wrong notices in tests.
    +6. Some assertion methods have, in more recent versions of the PHPUnit core suite, adopted stricter type checks when it comes to comparison. E.g., the assertEqualFields will now check the object to check the fields on is actually an object. Depending on how loose your use of assertions was before, you might have to update your work to make it pass the stricter checks: +
    <?php
    +
    +use lucatume\WPBrowser\TestCase\WPTestCase;
    +
    + class MyTestUsingAssertEqualFields extends WPTestCase {
    +      public function test_it_can_use_assert_equal_fields() {
    +         // Cast the array to an object explicitly.
    +         $this->assertEqualFields( (object) [ 'a' => 1 ], [ 'a' => 1 ] );
    +      }
    + }
    +
    +7. Other updates to the Core PHPUnit test case will report use of deprecated functions more promptly; if your code is using deprecated functions that might have escaped previous versions of wp-browser, you will need to update them.
    +8. If you're using the @runInSeparateProcess annotation for tests in your suite, you will need to enable the IsolationSupport extension in your suite configuration file:

    +
    actor: MySuiteTester
    +bootstrap: _bootstrap.php
    +extensions:
    +enabled:
    +   - "lucatume\\WPBrowser\\Extension\\IsolationSupport"
    +modules: # The rest of the module configuration ...
    +
    +

    Alternatively, you can enable the extension in the Codeception main configuration file (e.g. codeception.yml).

    +

    Read more about the extension in the Isolation Support extension documentation.
    +9. Global space cleanup between test is more thorough in more recent versions of the Core PHPUnit test suite. Due to this you might see failures in tests that were passing in previous versions due to a "leaking" global state. Examples of this might be nonces being set by previous tests and not being reset. Update your tests to explicitly set all the global stat variables you require for the test to run.

    +

    Staying on version 3, lower than 3.5

    +

    Update your composer.json file to lock the required version of wp-browser to a version less than 3.5:

    +
    {
    +  "require-dev": {
    +    "lucatume/wp-browser": "<3.5"
    +  }
    +}
    +
    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/AirplaneMode/index.html b/modules/AirplaneMode/index.html new file mode 100644 index 000000000..341a1a29b --- /dev/null +++ b/modules/AirplaneMode/index.html @@ -0,0 +1,3008 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Airplane Mode - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    Airplane Mode

    + +

    AirplaneMode module

    +

    This module allows you to easily put the website under test in "airplane mode", preventing it from making any network requests.

    +

    The module uses the norcross/airplane-mode plugin to add or remove it from the website must-use plugins directory when activated.

    +

    This module should be used together with the WPWebDriver or WPBrowser modules.

    +

    Configuration

    +
      +
    • muPluginsDir - required; the path to the WordPress must-use plugins directory.
    • +
    • symlink - whether to symlink the plugin or copy it. By default, the plugin is copied in the must-use plugins directory and symlink is set to false. If you're not using containers, that will ignore symlinked plugins, you can set symlink to true to symlink the plugin in the must-use plugins directory. Symbolic linking is faster and uses less disk space than copying the plugin.
    • +
    +

    Example configuration to symlink the plugin in the muPluginsDir directory before the tests:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\AirplaneMode:
    +      muPluginsDir: 'var/wordpress/wp-content/mu-plugins'
    +      symlink: true
    +
    +

    Example configuration to copy the plugin in the muPluginsDir directory before the tests:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\AirplaneMode:
    +      muPluginsDir: 'var/wordpress/wp-content/mu-plugins'
    +      symlink: false
    +
    +

    The module will either symlink or copy the plugin in the muPluginsDir directory, depending on the symlink configuration parameter before the test suite runs, and will remove it after the test suite has run.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPBrowser/index.html b/modules/WPBrowser/index.html new file mode 100644 index 000000000..e2aa6a17a --- /dev/null +++ b/modules/WPBrowser/index.html @@ -0,0 +1,5686 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPBrowser - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    WPBrowser

    + +

    WPBrowser module

    +

    Browse and test the site HTML with a fast browser without Javascript support.

    +

    This module trades the WPWebDriver module Javascript support for speed and stability. It is a good +choice for testing sites that don't use Javascript or to make assertions that do not require Javascript support like:

    +
      +
    • testing HTTP return codes
    • +
    • testing HTML structure
    • +
    • testing JSON and XML responses from APIs
    • +
    +

    This module is used together with the WPDb module and the WPFilesystem module to +control the site state, the database, and the site file structure.

    +

    This module is an extension of the Codeception PHPBrowser module, you can reference to the Codeception module +documentation for more information on the module configuration and usage.

    +

    This module should be with Cest and Cept test cases.

    +

    Configuration

    +
      +
    • url - required; the start URL of your WordPress project.
    • +
    • adminUsername - required; the site administrator username to use in actions like loginAsAdmin.
    • +
    • adminPassword - required; the site administrator password to use in actions like loginAsAdmin.
    • +
    • adminPath - the path to the WordPress admin directory; defaults to /wp-admin.
    • +
    +

    More Guzzle request options are available like:

    +

    headers - default headers are set before each test.
    +cookies - default cookies are set before each test.
    +auth - default authentication to be set before each test.

    +

    ... and more.

    +

    The following is an example of the module configuration to run tests on thehttp://localhost:8080 site:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPBrowser:
    +      url: 'http://localhost:8080'
    +      adminUsername: 'admin'
    +      adminPassword: 'password'
    +      adminPath: '/wp-admin'
    +      headers:
    +        X_WPBROWSER_REQUEST: 1
    +        X_TEST_REQUEST: 1
    +        X_APM_REQUEST: 1
    +
    +

    The following configuration uses dynamic configuration parameters to set the module configuration:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPBrowser:
    +      url: '%WORDPRESS_URL%'
    +      adminUsername: '%WORDPRESS_ADMIN_USER%'
    +      adminPassword: '%WORDPRESS_ADMIN_PASSWORD%'
    +      adminPath: '/wp-admin'
    +      headers:
    +        X_WPBROWSER_REQUEST: 1
    +        X_TEST_REQUEST: 1
    +        X_APM_REQUEST: 1
    +
    +

    Methods

    +

    The module provides the following methods:

    + + +

    activatePlugin

    +

    Signature: activatePlugin(array|string $pluginSlug) : void

    +

    In the plugin administration screen activates a plugin clicking the "Activate" link.

    +

    The method will not handle authentication to the admin area.

    +
    <?php
    +// Activate a plugin.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->activatePlugin('hello-dolly');
    +// Activate a list of plugins.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->activatePlugin(['hello-dolly','another-plugin']);
    +
    +

    activateTheme

    +

    Signature: activateTheme(string $slug) : void

    +

    Activates a theme.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    amEditingPostWithId

    +

    Signature: amEditingPostWithId(int $id) : void

    +

    Go to the admin page to edit the post with the specified ID.

    +

    The method will not handle authentication the admin area.

    +
    <?php
    +$I->loginAsAdmin();
    +$postId = $I->havePostInDatabase();
    +$I->amEditingPostWithId($postId);
    +$I->fillField('post_title', 'Post title');
    +
    +

    amEditingUserWithId

    +

    Signature: amEditingUserWithId(int $id) : void

    +

    Go to the admin page to edit the user with the specified ID.

    +

    The method will not handle authentication the admin area.

    +
    <?php
    +$I->loginAsAdmin();
    +$userId = $I->haveUserInDatabase('luca', 'editor');
    +$I->amEditingUserWithId($userId);
    +$I->fillField('email', 'new@example.net');
    +
    +

    amHttpAuthenticated

    +

    Signature: amHttpAuthenticated($username, $password) : void

    +

    amOnAdminAjaxPage

    +

    Signature: amOnAdminAjaxPage([array|string|null $queryVars]) : void

    +

    Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

    +

    The method will not handle authentication, nonces or authorization.

    +
    <?php
    +$I->amOnAdminAjaxPage(['action' => 'my-action', 'data' => ['id' => 23], 'nonce' => $nonce]);
    +
    +

    amOnAdminPage

    +

    Signature: amOnAdminPage(string $page) : void

    +

    Go to a page in the admininstration area of the site.

    +

    This method will not handle authentication to the administration area.

    +
    <?php
    +$I->loginAs('user', 'password');
    +// Go to the plugins management screen.
    +$I->amOnAdminPage('/plugins.php');
    +
    +

    amOnCronPage

    +

    Signature: amOnCronPage([array|string|null $queryVars]) : void

    +

    Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

    +
    <?php
    +// Triggers the cron job with an optional query argument.
    +$I->amOnCronPage('/?some-query-var=some-value');
    +
    +

    amOnPage

    +

    Signature: amOnPage(string $page) : void

    +

    amOnPagesPage

    +

    Signature: amOnPagesPage() : void

    +

    Go the "Pages" administration screen.

    +

    The method will not handle authentication.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPagesPage();
    +$I->see('Add New');
    +
    +

    amOnPluginsPage

    +

    Signature: amOnPluginsPage() : void

    +

    Go to the plugins administration screen.

    +

    The method will not handle authentication.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->activatePlugin('hello-dolly');
    +
    +

    amOnSubdomain

    +

    Signature: amOnSubdomain($subdomain) : void

    +

    amOnThemesPage

    +

    Signature: amOnThemesPage() : void

    +

    Moves to the themes administration page.

    +

    amOnUrl

    +

    Signature: amOnUrl($url) : void

    +

    attachFile

    +

    Signature: attachFile($field, string $filename) : void

    +

    checkOption

    +

    Signature: checkOption($option) : void

    +

    click

    +

    Signature: click($link, [$context]) : void

    +

    deactivatePlugin

    +

    Signature: deactivatePlugin(array|string $pluginSlug) : void

    +

    In the plugin administration screen deactivate a plugin clicking the "Deactivate" link.

    +

    The method will not handle authentication and navigation to the plugins administration page.

    +
    <?php
    +// Deactivate one plugin.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->deactivatePlugin('hello-dolly');
    +// Deactivate a list of plugins.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->deactivatePlugin(['hello-dolly', 'my-plugin']);
    +
    +

    deleteHeader

    +

    Signature: deleteHeader(string $name) : void

    +

    Deletes the header with the passed name. Subsequent requests +will not have the deleted header in its request.

    +

    Example: +

    <?php
    +$I->haveHttpHeader('X-Requested-With', 'Codeception');
    +$I->amOnPage('test-headers.php');
    +// ...
    +$I->deleteHeader('X-Requested-With');
    +$I->amOnPage('some-other-page.php');
    +

    +

    dontSee

    +

    Signature: dontSee(string $text, [$selector]) : void

    +

    dontSeeCheckboxIsChecked

    +

    Signature: dontSeeCheckboxIsChecked($checkbox) : void

    +

    dontSeeCookie

    +

    Signature: dontSeeCookie($cookie, [$params]) : void

    +

    dontSeeCurrentUrlEquals

    +

    Signature: dontSeeCurrentUrlEquals(string $uri) : void

    +

    dontSeeCurrentUrlMatches

    +

    Signature: dontSeeCurrentUrlMatches(string $uri) : void

    +

    dontSeeElement

    +

    Signature: dontSeeElement($selector, [array $attributes]) : void

    +

    dontSeeInCurrentUrl

    +

    Signature: dontSeeInCurrentUrl(string $uri) : void

    +

    dontSeeInField

    +

    Signature: dontSeeInField($field, $value) : void

    +

    dontSeeInFormFields

    +

    Signature: dontSeeInFormFields($formSelector, array $params) : void

    +

    dontSeeInSource

    +

    Signature: dontSeeInSource(string $raw) : void

    +

    dontSeeInTitle

    +

    Signature: dontSeeInTitle($title) : void

    + +

    Signature: dontSeeLink(string $text, [string $url]) : void

    +

    dontSeeOptionIsSelected

    +

    Signature: dontSeeOptionIsSelected($selector, $optionText) : void

    +

    dontSeePluginInstalled

    +

    Signature: dontSeePluginInstalled(string $pluginSlug) : void

    +

    Assert a plugin is not installed in the plugins administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->dontSeePluginInstalled('my-plugin');
    +
    +

    dontSeeResponseCodeIs

    +

    Signature: dontSeeResponseCodeIs(int $code) : void

    +

    Checks that response code is equal to value provided.

    +
    <?php
    +$I->dontSeeResponseCodeIs(200);
    +
    +// recommended \Codeception\Util\HttpCode
    +$I->dontSeeResponseCodeIs(\Codeception\Util\HttpCode::OK);
    +
    +

    executeInGuzzle

    +

    Signature: executeInGuzzle(Closure $function) : void

    +

    Low-level API method. +If Codeception commands are not enough, use Guzzle HTTP Client methods directly

    +

    Example:

    +
    <?php
    +$I->executeInGuzzle(function (\GuzzleHttp\Client $client) {
    +     $client->get('/get', ['query' => ['foo' => 'bar']]);
    +});
    +
    +

    It is not recommended to use this command on a regular basis. +If Codeception lacks important Guzzle Client methods, implement them and submit patches.

    +

    fillField

    +

    Signature: fillField($field, $value) : void

    +

    followRedirect

    +

    Signature: followRedirect() : void

    +

    Follow pending redirect if there is one.

    +
    <?php
    +$I->followRedirect();
    +
    +

    grabActiveTheme

    +

    Signature: grabActiveTheme() : ?string

    +

    Returns the slug of the currently active themes.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    grabAttributeFrom

    +

    Signature: grabAttributeFrom($cssOrXpath, string $attribute) : mixed

    +

    grabAvailableThemes

    +

    Signature: grabAvailableThemes([string $classes]) : array

    +

    Returns the list of available themes.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    grabCookie

    +

    Signature: grabCookie(string $cookie, [array $params]) : mixed

    +

    grabCookiesWithPattern

    +

    Signature: grabCookiesWithPattern(string $cookiePattern) : ?array

    +

    Returns all the cookies whose name matches a regex pattern.

    +
    <?php
    +$I->loginAs('customer','password');
    +$I->amOnPage('/shop');
    +$cartCookies = $I->grabCookiesWithPattern("#^shop_cart\\.*#");
    +
    +

    grabFromCurrentUrl

    +

    Signature: grabFromCurrentUrl([?string $uri]) : mixed

    +

    grabMultiple

    +

    Signature: grabMultiple($cssOrXpath, [?string $attribute]) : array

    +

    grabPageSource

    +

    Signature: grabPageSource() : string

    +

    Grabs current page source code.

    +

    grabTextFrom

    +

    Signature: grabTextFrom($cssOrXPathOrRegex) : mixed

    +

    grabValueFrom

    +

    Signature: grabValueFrom($field) : mixed

    +

    grabWordPressTestCookie

    +

    Signature: grabWordPressTestCookie([?string $name]) : ?Symfony\Component\BrowserKit\Cookie

    +

    Returns WordPress default test cookie object if present.

    +
    <?php
    +// Grab the default WordPress test cookie.
    +$wpTestCookie = $I->grabWordPressTestCookie();
    +// Grab a customized version of the test cookie.
    +$myTestCookie = $I->grabWordPressTestCookie('my_test_cookie');
    +
    +

    haveHttpHeader

    +

    Signature: haveHttpHeader(string $name, string $value) : void

    +

    Sets the HTTP header to the passed value - which is used on +subsequent HTTP requests through PhpBrowser.

    +

    Example: +

    <?php
    +$I->haveHttpHeader('X-Requested-With', 'Codeception');
    +$I->amOnPage('test-headers.php');
    +

    +

    To use special chars in Header Key use HTML Character Entities: +Example: +Header with underscore - 'Client_Id' +should be represented as - 'Client_Id' or 'Client_Id'

    +
    <?php
    +$I->haveHttpHeader('Client&#95;Id', 'Codeception');
    +
    +

    haveServerParameter

    +

    Signature: haveServerParameter(string $name, string $value) : void

    +

    Sets SERVER parameter valid for all next requests.

    +
    <?php
    +$I->haveServerParameter('name', 'value');
    +
    +

    logOut

    +

    Signature: logOut([string|bool $redirectTo]) : void

    +

    Navigate to the default WordPress logout page and click the logout link.

    +
    <?php
    +// Log out using the `wp-login.php` form and return to the current page.
    +$I->logOut(true);
    +// Log out using the `wp-login.php` form and remain there.
    +$I->logOut(false);
    +// Log out using the `wp-login.php` form and move to another page.
    +$I->logOut('/some-other-page');
    +
    +

    loginAs

    +

    Signature: loginAs(string $username, string $password) : void

    +

    Login as the specified user.

    +

    The method will not follow redirection, after the login, to any page.

    +
    <?php
    +$I->loginAs('user', 'password');
    +$I->amOnAdminPage('/');
    +$I->see('Dashboard');
    +
    +

    loginAsAdmin

    +

    Signature: loginAsAdmin() : void

    +

    Login as the administrator user using the credentials specified in the module configuration.

    +

    The method will not follow redirection, after the login, to any page.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnAdminPage('/');
    +$I->see('Dashboard');
    +
    +

    makeHtmlSnapshot

    +

    Signature: makeHtmlSnapshot([?string $name]) : void

    +

    moveBack

    +

    Signature: moveBack([int $numberOfSteps]) : void

    +

    Moves back in history.

    +

    resetCookie

    +

    Signature: resetCookie($cookie, [$params]) : void

    +

    see

    +

    Signature: see(string $text, [$selector]) : void

    +

    seeCheckboxIsChecked

    +

    Signature: seeCheckboxIsChecked($checkbox) : void

    +

    seeCookie

    +

    Signature: seeCookie($cookie, [$params]) : void

    +

    seeCurrentUrlEquals

    +

    Signature: seeCurrentUrlEquals(string $uri) : void

    +

    seeCurrentUrlMatches

    +

    Signature: seeCurrentUrlMatches(string $uri) : void

    +

    seeElement

    +

    Signature: seeElement($selector, [array $attributes]) : void

    +

    seeErrorMessage

    +

    Signature: seeErrorMessage([array|string $classes]) : void

    +

    In an administration screen look for an error admin notice.

    +

    The check is class-based to decouple from internationalization. +The method will not handle authentication and navigation the administration area.

    +
    <?php
    +$I->loginAsAdmin()
    +$I->amOnAdminPage('/');
    +$I->seeErrorMessage('.my-plugin');
    +
    +

    seeInCurrentUrl

    +

    Signature: seeInCurrentUrl(string $uri) : void

    +

    seeInField

    +

    Signature: seeInField($field, $value) : void

    +

    seeInFormFields

    +

    Signature: seeInFormFields($formSelector, array $params) : void

    +

    seeInSource

    +

    Signature: seeInSource(string $raw) : void

    +

    seeInTitle

    +

    Signature: seeInTitle($title) : void

    + +

    Signature: seeLink(string $text, [?string $url]) : void

    +

    seeMessage

    +

    Signature: seeMessage([array|string $classes]) : void

    +

    In an administration screen look for an admin notice.

    +

    The check is class-based to decouple from internationalization. +The method will not handle authentication and navigation the administration area.

    +
    <?php
    +$I->loginAsAdmin()
    +$I->amOnAdminPage('/');
    +$I->seeMessage('.missing-api-token.my-plugin');
    +
    +

    seeNumberOfElements

    +

    Signature: seeNumberOfElements($selector, $expected) : void

    +

    seeOptionIsSelected

    +

    Signature: seeOptionIsSelected($selector, $optionText) : void

    +

    seePageNotFound

    +

    Signature: seePageNotFound() : void

    +

    Asserts that current page has 404 response status code.

    +

    seePluginActivated

    +

    Signature: seePluginActivated(string $pluginSlug) : void

    +

    Assert a plugin is activated in the plugin administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->seePluginActivated('my-plugin');
    +
    +

    seePluginDeactivated

    +

    Signature: seePluginDeactivated(string $pluginSlug) : void

    +

    Assert a plugin is not activated in the plugins administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->seePluginDeactivated('my-plugin');
    +
    +

    seePluginInstalled

    +

    Signature: seePluginInstalled(string $pluginSlug) : void

    +

    Assert a plugin is installed, no matter its activation status, in the plugin administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->seePluginInstalled('my-plugin');
    +
    +

    seeResponseCodeIs

    +

    Signature: seeResponseCodeIs(int $code) : void

    +

    Checks that response code is equal to value provided.

    +
    <?php
    +$I->seeResponseCodeIs(200);
    +
    +// recommended \Codeception\Util\HttpCode
    +$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK);
    +
    +

    seeResponseCodeIsBetween

    +

    Signature: seeResponseCodeIsBetween(int $from, int $to) : void

    +

    Checks that response code is between a certain range. Between actually means [from <= CODE <= to]

    +

    seeResponseCodeIsClientError

    +

    Signature: seeResponseCodeIsClientError() : void

    +

    Checks that the response code is 4xx

    +

    seeResponseCodeIsRedirection

    +

    Signature: seeResponseCodeIsRedirection() : void

    +

    Checks that the response code 3xx

    +

    seeResponseCodeIsServerError

    +

    Signature: seeResponseCodeIsServerError() : void

    +

    Checks that the response code is 5xx

    +

    seeResponseCodeIsSuccessful

    +

    Signature: seeResponseCodeIsSuccessful() : void

    +

    Checks that the response code 2xx

    +

    seeThemeActivated

    +

    Signature: seeThemeActivated(string $slug) : void

    +

    Verifies that a theme is active.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    seeWpDiePage

    +

    Signature: seeWpDiePage() : void

    +

    Checks that the current page is one generated by the wp_die function.

    +

    The method will try to identify the page based on the default WordPress die page HTML attributes.

    +
    <?php
    +$I->loginAs('user', 'password');
    +$I->amOnAdminPage('/forbidden');
    +$I->seeWpDiePage();
    +
    +

    selectOption

    +

    Signature: selectOption($select, $option) : void

    +

    sendAjaxGetRequest

    +

    Signature: sendAjaxGetRequest(string $uri, [array $params]) : void

    +

    Sends an ajax GET request with the passed parameters. +See sendAjaxPostRequest()

    +

    sendAjaxPostRequest

    +

    Signature: sendAjaxPostRequest(string $uri, [array $params]) : void

    +

    Sends an ajax POST request with the passed parameters. +The appropriate HTTP header is added automatically: +X-Requested-With: XMLHttpRequest +Example: +

    <?php
    +$I->sendAjaxPostRequest('/add-task', ['task' => 'lorem ipsum']);
    +
    +Some frameworks (e.g. Symfony) create field names in the form of an "array": +<input type="text" name="form[task]"> +In this case you need to pass the fields like this: +
    <?php
    +$I->sendAjaxPostRequest('/add-task', ['form' => [
    +    'task' => 'lorem ipsum',
    +    'category' => 'miscellaneous',
    +]]);
    +

    +

    sendAjaxRequest

    +

    Signature: sendAjaxRequest(string $method, string $uri, [array $params]) : void

    +

    Sends an ajax request, using the passed HTTP method. +See sendAjaxPostRequest() +Example: +

    <?php
    +$I->sendAjaxRequest('PUT', '/posts/7', ['title' => 'new title']);
    +

    +

    setCookie

    +

    Signature: setCookie($name, $val, [$params]) : void

    +

    setHeader

    +

    Signature: setHeader(string $name, string $value) : void

    +

    Alias to haveHttpHeader

    +

    setMaxRedirects

    +

    Signature: setMaxRedirects(int $maxRedirects) : void

    +

    Sets the maximum number of redirects that the Client can follow.

    +
    <?php
    +$I->setMaxRedirects(2);
    +
    +

    setServerParameters

    +

    Signature: setServerParameters(array $params) : void

    +

    Sets SERVER parameters valid for all next requests. +this will remove old ones.

    +
    <?php
    +$I->setServerParameters([]);
    +
    +

    startFollowingRedirects

    +

    Signature: startFollowingRedirects() : void

    +

    Enables automatic redirects to be followed by the client.

    +
    <?php
    +$I->startFollowingRedirects();
    +
    +

    stopFollowingRedirects

    +

    Signature: stopFollowingRedirects() : void

    +

    Prevents automatic redirects to be followed by the client.

    +
    <?php
    +$I->stopFollowingRedirects();
    +
    +

    submitForm

    +

    Signature: submitForm($selector, array $params, [?string $button]) : void

    +

    switchToIframe

    +

    Signature: switchToIframe(string $name) : void

    +

    Switch to iframe or frame on the page.

    +

    Example: +

    <iframe name="another_frame" src="http://example.com">
    +

    +
    <?php
    +# switch to iframe
    +$I->switchToIframe("another_frame");
    +
    +

    uncheckOption

    +

    Signature: uncheckOption($option) : void

    + + +

    Read more in Codeception documentation.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPCLI/index.html b/modules/WPCLI/index.html new file mode 100644 index 000000000..d4c462887 --- /dev/null +++ b/modules/WPCLI/index.html @@ -0,0 +1,3469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPCLI - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    WPCLI

    + +

    WPCLI module

    +

    Use WP-CLI to interact with the WordPress installation under test and issue commands.

    +

    This module is used in the context of end-to-end testing, together with, or as a replacement for +the WPDb module to manipulate the database and the WPFilesystem module to manipulate the +site file structure.

    +

    This module should be with Cest and Cept test cases.

    +

    Configuration

    +
      +
    • path - required; the path to the WordPress installation under test. This can be a relative path to the + codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation + directory is the directory that contains the wp-load.php file.
    • +
    • url - the URL of the WordPress installation under test. Equivalent to the --url option of the wp command.
    • +
    • user - the user to use to run the wp command. Equivalent to the --user option of the wp command.
    • +
    • skip-plugins - a boolean value to indicate if the wp command should skip loading plugins. Equivalent to the + --skip-plugins option of the wp command.
    • +
    • skip-themes - a boolean value to indicate if the wp command should skip loading themes. Equivalent to the + --skip-themes option of the wp command.
    • +
    • skip-packages - a boolean value to indicate if the wp command should skip loading packages. Equivalent to the + --skip-packages option of the wp command.
    • +
    • require - a list of PHP files to require before running the wp command. Equivalent to the --require option of + the wp command.
    • +
    • exec - PHP code to execute before running the wp command. Equivalent to the --exec option of the wp command.
    • +
    • context - the context to use when running the wp command. Equivalent to the --context option of the wp + command.
    • +
    • color - a boolean value to indicate if the wp command should output in color. Equivalent to the --color option + of the wp command.
    • +
    • no-color - a boolean value to indicate if the wp command should not output in color. Equivalent to the + --no-color option of the wp command.
    • +
    • debug - a boolean value to indicate if the wp command should output debug information. Equivalent to the + --debug option of the wp command.
    • +
    • quiet - a boolean value to indicate if the wp command should suppress informational messages. Equivalent to the + --quiet option of the wp command.
    • +
    • throw - a boolean value to indicate if the wp command should throw an exception if the command fails.
    • +
    • timeout - the timeout to use when running the wp command. When the timeout is reached the command will be + terminated as a failure.
    • +
    • cache-dir - the directory to use to cache the files WPCLI might downloads. Equivalent to setting + the WP_CLI_CACHE_DIR + environment variable.
    • +
    • config-path - the path to the wp-cli.yml file to use. Equivalent to setting the WP_CLI_CONFIG_PATH + environment variable.
    • +
    • custom-shell - the shell to use to run the wp command. Equivalent to setting the WP_CLI_SHELL environment + variable.
    • +
    • packages-dir - the directory to use to store the packages downloaded by the wp package command. Equivalent to + setting the WP_CLI_PACKAGES_DIR environment variable.
    • +
    +

    The following is an example of the module configuration to run WPCLI commands on the /var/wordpress directory:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPCLI:
    +      path: /var/wordpress
    +      throw: true
    +
    +

    The following configuration uses dynamic configuration parameters to set the module configuration:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPCLI:
    +      path: '%WP_ROOT_DIR%'
    +      throw: true
    +
    +

    Methods

    +

    The module provides the following methods:

    + + +

    changeWpcliPath

    +

    Signature: changeWpcliPath(string $path) : void

    +

    Changes the path to the WordPress installation that WPCLI should use.

    +

    This is the equivalent of the --path option.

    +
    <?php
    +// Operate on the installation specified in the `path` config parameter.
    +$I->cli(['core','version']);
    +// Change to another installation and run a command there.
    +$I->changeWpcliPath('var/wordpress-installation-two');
    +$I->cli(['core','version']);
    +
    +

    cli

    +

    Signature: cli([array|string $command], [?array $env], [mixed $input]) : int

    +

    Executes a wp-cli command targeting the test WordPress installation.

    +
    <?php
    +// Activate a plugin via wp-cli in the test WordPress site.
    +$I->cli(['plugin', 'activate', 'my-plugin']);
    +// Change a user password.
    +$I->cli(['user', 'update', 'luca', '--user_pass=newpassword']);
    +
    +

    cliToArray

    +

    Signature: cliToArray(array $command, [?callable $splitCallback], [?array $env], [mixed $input]) : array

    +

    Returns the output of a wp-cli command as an array optionally allowing a callback to process the output.

    +
    <?php
    +// Return a list of inactive themes, like ['twentyfourteen', 'twentyfifteen'].
    +$inactiveThemes = $I->cliToArray(['theme', 'list', '--status=inactive', '--field=name']);
    +// Get the list of installed plugins and only keep the ones starting with "foo".
    +$fooPlugins = $I->cliToArray(['plugin', 'list', '--field=name'], function($output){
    +     return array_filter(explode(PHP_EOL, $output), function($name){
    +             return strpos(trim($name), 'foo') === 0;
    +     });
    +});
    +
    +

    cliToString

    +

    Signature: cliToString(array $command, [?array $env], [mixed $input]) : string

    +

    Returns the output of a wp-cli command as a string.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$adminEmail = $I->cliToString('option get admin_email');
    +// Get the list of active plugins in JSON format, two ways.
    +$activePlugins = $I->cliToString(['plugin', 'list','--status=active', '--format=json']);
    +$activePlugins = $I->cliToString(['option', 'get', 'active_plugins' ,'--format=json']);
    +
    +

    dontSeeInShellOutput

    +

    Signature: dontSeeInShellOutput(string $text) : void

    +

    Checks that output from last command doesn't contain text.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$I->cli('plugin list --status=active');
    +$I->dontSeeInShellOutput('my-inactive/plugin.php');
    +
    +

    dontSeeShellOutputMatches

    +

    Signature: dontSeeShellOutputMatches(string $regex) : void

    +

    Checks that output from the last command doesn't match a given regular expression.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$I->cli('option get siteurl');
    +$I->dontSeeShellOutputMatches('/^http/');
    +
    +

    grabLastCliProcess

    +

    Signature: grabLastCliProcess() : lucatume\WPBrowser\WordPress\CliProcess

    +

    grabLastShellErrorOutput

    +

    Signature: grabLastShellErrorOutput() : string

    +

    Returns the shell error output of the last command.

    +

    grabLastShellOutput

    +

    Signature: grabLastShellOutput() : string

    +

    Returns the shell output of the last command.

    +

    seeInShellOutput

    +

    Signature: seeInShellOutput(string $text) : void

    +

    Checks that output from last command contains text.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$I->cli('option get admin_email');
    +$I->seeInShellOutput('admin@example.org');
    +
    +

    seeResultCodeIs

    +

    Signature: seeResultCodeIs(int $code) : void

    +

    Checks the result code from the last command.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$I->cli('option get admin_email');
    +$I->seeResultCodeIs(0);
    +
    +

    seeResultCodeIsNot

    +

    Signature: seeResultCodeIsNot(int $code) : void

    +

    Checks the result code from the last command.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$I->cli('invalid command');
    +$I->seeResultCodeIsNot(0);
    +
    +

    seeShellOutputMatches

    +

    Signature: seeShellOutputMatches(string $regex) : void

    +

    Checks that output from the last command matches a given regular expression.

    +
    <?php
    +// Return the current site administrator email, using string command format.
    +$I->cli('option get admin_email');
    +$I->seeShellOutputMatches('/^\S+@\S+$/');
    +
    + + +

    Explore the WP-CLI documentation for more information on the available commands.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPDb/index.html b/modules/WPDb/index.html new file mode 100644 index 000000000..9b12f7ca6 --- /dev/null +++ b/modules/WPDb/index.html @@ -0,0 +1,7832 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPDb - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    WPDb

    + +

    WPDb module

    +

    This module allows to manipulate the database of the WordPress installation under test directly, without using the +WordPress API.

    +

    The module is used together with the WPBrowser module, WPWebDriver +and WPFilesystem modules to control the site state, the database, and the site file structure.

    +

    Note about interaction with the WPLoader module: both this module and the WPLoader one can be used to +control the state of the database before tests and set up fixtures: use either this or WPLoader, do not use both. +This module should be used in end-to-end testing, the WPLoader module should be used in integration +testing. +If you're using this module to load a database dump before integration tests, +use the WPLoader module dump configuration parameter instead.

    +

    This module should be with Cest and Cept test cases.

    +

    Configuration

    +

    This module extends the Codeception Db module adding some configuration options and functions that are specific to +WordPress.

    +
      +
    • dbUrl - required; the URL to use to connect to the database. The URL must be in the form + mysql://user:password@host:port/database if you're using a MySQL database for your tests, or in the form + sqlite://path/to/database/file if you're using a SQLite database for your tests ( + like the default configuration does)
    • +
    • dsn - required; the DSN to use to connect to the database; required if not using the dbUrl parameter.
    • +
    • user - required; the user to use to connect to the database; required if not using the dbUrl parameter.
    • +
    • password - required; the password to use to connect to the database; required if not using the dbUrl + parameter.
    • +
    • url - required;the URL of the WordPress installation under test. E.g. http://localhost:8080 + or https://wordpress.test.
    • +
    • tablePrefix - the table prefix to use when interacting with the database; defaults to wp_.
    • +
    • dump - the path to a database dump file, or a set of database files, to load before running tests. The path can be + relative to the project root directory, e.g. tests/_data/dump.sql, or absolute.
    • +
    • populate - a boolean value to indicate if the database should be populated importing the dump file(s) at the start + of the suite.
    • +
    • cleanup - a boolean value to indicate if the database should be populated importing the dump file(s) before each + test.
    • +
    • reconnect - a boolean value to indicate if the database connection should be re-established before each test.
    • +
    • populator - a command to use to populate the database instead of using + PHP; read more on the Codeception documentation.
    • +
    • urlReplacement - a boolean value to indicate if the database dump file(s) should be searched for the siteurl + and home options and replaced with the url parameter value. This is required since WordPress hard-codes URLs in + the database, the original URL is inferred, if the originalUrl parameter is not provided.
    • +
    • originalUrl - if provided together with the urlReplacement parameter, the module will not try to infer the + original URL from the database dump file(s) but use the provided value instead.
    • +
    • waitlock - the number of seconds to wait for a database lock to be released before failing the test. Defaults to + 10 meaning that the test will fail if the database lock is not released after 10 seconds.
    • +
    • createIfNotExists - a boolean value to indicate if the database should be created if it does not exist. Defaults to + false.
    • +
    +

    The following is an example of the module configuration to run tests on thehttp://localhost:8080 site:

    +
    modules:
    +  enabled:
    +    - lucatume\WPBrowser\Module\WPDb:
    +        dbUrl: 'mysql://root:password@localhost:3306/wordpress'
    +        url: 'http://localhost:8080'
    +        tablePrefix: 'wp_'
    +        dump: 'tests/_data/dump.sql'
    +        populate: true
    +        cleanup: true
    +        reconnect: false
    +        urlReplacement: true
    +        originalUrl: http://wordpress.test
    +        waitlock: 10
    +        createIfNotExists: true
    +
    +

    The following configuration uses dynamic configuration parameters to set the module configuration:

    +
    modules:
    +  enabled:
    +    - lucatume\WPBrowser\Module\WPDb:
    +        dbUrl: '%DB_URL%'
    +        url: '%WORDPRESS_URL%'
    +        tablePrefix: '%WORDPRESS_TABLE_PREFIX%'
    +        dump: '%DB_DUMP%'
    +        populate: true
    +        cleanup: true
    +        reconnect: false
    +        urlReplacement: true
    +        originalUrl: '%WORDPRESS_ORIGINAL_URL%'
    +        waitlock: 10
    +        createIfNotExists: true
    +
    +

    The following configuration uses a SQLite database:

    +
    modules:
    +  enabled:
    +    - lucatume\WPBrowser\Module\WPDb:
    +        dbUrl: 'sqlite://tests/database.sqlite'
    +        url: 'http://localhost:8080'
    +        tablePrefix: 'wp_'
    +        dump: 'tests/_data/dump.sql'
    +        populate: true
    +        cleanup: true
    +        reconnect: false
    +        urlReplacement: true
    +        originalUrl: http://wordpress.test
    +        waitlock: 10
    +        createIfNotExists: true
    +
    +

    Methods

    + + +

    amConnectedToDatabase

    +

    Signature: amConnectedToDatabase(string $databaseKey) : void

    +

    Make sure you are connected to the right database.

    +
    <?php
    +$I->seeNumRecords(2, 'users');   //executed on default database
    +$I->amConnectedToDatabase('db_books');
    +$I->seeNumRecords(30, 'books');  //executed on db_books database
    +//All the next queries will be on db_books
    +
    +

    countRowsInDatabase

    +

    Signature: countRowsInDatabase(string $table, [array $criteria]) : int

    +

    Returns the number of table rows matching a criteria.

    +
    <?php
    +$I->haveManyPostsInDatabase(3, ['post_status' => 'draft' ]);
    +$I->haveManyPostsInDatabase(3, ['post_status' => 'private' ]);
    +// Make sure there are now the expected number of draft posts.
    +$postsTable = $I->grabPostsTableName();
    +$draftsCount = $I->countRowsInDatabase($postsTable, ['post_status' => 'draft']);
    +
    +

    dontHaveAttachmentFilesInDatabase

    +

    Signature: dontHaveAttachmentFilesInDatabase(array|int $attachmentIds) : void

    +

    Removes all the files attached with an attachment post, it will not remove the database entries. +Requires the WPFilesystem module to be loaded in the suite.

    +
    <?php
    +$posts = $I->grabPostsTableName();
    +$attachmentIds = $I->grabColumnFromDatabase($posts, 'ID', ['post_type' => 'attachment']);
    +// This will only remove the files, not the database entries.
    +$I->dontHaveAttachmentFilesInDatabase($attachmentIds);
    +
    +

    dontHaveAttachmentInDatabase

    +

    Signature: dontHaveAttachmentInDatabase(array $criteria, [bool $purgeMeta], [bool $removeFiles]) : void

    +

    Removes an attachment from the posts table.

    +
    $postmeta = $I->grabpostmetatablename();
    +$thumbnailId = $I->grabFromDatabase($postmeta, 'meta_value', [
    +     'post_id' => $id,
    +     'meta_key'=>'thumbnail_id'
    +]);
    +// Remove only the database entry (including postmeta) but not the files.
    +$I->dontHaveAttachmentInDatabase($thumbnailId);
    +// Remove the database entry (including postmeta) and the files.
    +$I->dontHaveAttachmentInDatabase($thumbnailId, true, true);
    +
    +

    dontHaveBlogInDatabase

    +

    Signature: dontHaveBlogInDatabase(array $criteria, [bool $removeTables], [bool $removeUploads]) : void

    +

    Removes one ore more blogs from the database.

    +
    <?php
    +// Remove the blog, all its tables and files.
    +$I->dontHaveBlogInDatabase(['path' => 'test/one']);
    +// Remove the blog entry, not the tables though.
    +$I->dontHaveBlogInDatabase(['blog_id' => $blogId]);
    +// Remove multiple blogs.
    +$I->dontHaveBlogInDatabase(['domain' => 'test']);
    +
    +

    dontHaveCommentInDatabase

    +

    Signature: dontHaveCommentInDatabase(array $criteria, [bool $purgeMeta]) : void

    +

    Removes an entry from the comments table.

    +
    <?php
    +$I->dontHaveCommentInDatabase(['comment_post_ID' => 23, 'comment_url' => 'http://example.copm']);
    +
    +

    dontHaveCommentMetaInDatabase

    +

    Signature: dontHaveCommentMetaInDatabase(array $criteria) : void

    +

    Removes a post comment meta from the database

    +
    <?php
    +// Remove all meta for the comment with an ID of 23.
    +$I->dontHaveCommentMetaInDatabase(['comment_id' => 23]);
    +// Remove the `count` comment meta for the comment with an ID of 23.
    +$I->dontHaveCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'count']);
    +
    +

    dontHaveInDatabase

    +

    Signature: dontHaveInDatabase(string $table, array $criteria) : void

    +

    Deletes a database entry.

    +
    <?php
    +$I->dontHaveInDatabase('custom_table', ['book_ID' => 23, 'book_genre' => 'fiction']);
    +
    +

    dontHaveLinkInDatabase

    +

    Signature: dontHaveLinkInDatabase(array $criteria) : void

    +

    Removes a link from the database.

    +
    <?php
    +$I->dontHaveLinkInDatabase(['link_url' => 'http://example.com']);
    +
    +

    dontHaveOptionInDatabase

    +

    Signature: dontHaveOptionInDatabase(string $key, [mixed $value]) : void

    +

    Removes an entry from the options table.

    +
    <?php
    +// Remove the `foo` option.
    +$I->dontHaveOptionInDatabase('foo');
    +// Remove the 'bar' option only if it has the `baz` value.
    +$I->dontHaveOptionInDatabase('bar', 'baz');
    +
    +

    dontHavePostInDatabase

    +

    Signature: dontHavePostInDatabase(array $criteria, [bool $purgeMeta]) : void

    +

    Removes an entry from the posts table.

    +
    <?php
    +$posts = $I->haveManyPostsInDatabase(3, ['post_title' => 'Test {{n}}']);
    +$I->dontHavePostInDatabase(['post_title' => 'Test 2']);
    +
    +

    dontHavePostMetaInDatabase

    +

    Signature: dontHavePostMetaInDatabase(array $criteria) : void

    +

    Removes an entry from the postmeta table.

    +
    <?php
    +$postId = $I->havePostInDatabase(['meta_input' => ['rating' => 23]]);
    +$I->dontHavePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'rating']);
    +
    +

    dontHavePostThumbnailInDatabase

    +

    Signature: dontHavePostThumbnailInDatabase(int $postId) : void

    +

    Remove the thumbnail (featured image) from a post, if any.

    +

    Please note: the method will NOT remove the attachment post, post meta and file.

    +
    <?php
    +$attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));
    +$postId = $I->havePostInDatabase();
    +// Attach the thumbnail to the post.
    +$I->havePostThumbnailInDatabase($postId, $attachmentId);
    +// Remove the thumbnail from the post.
    +$I->dontHavePostThumbnailInDatabase($postId);
    +
    +

    dontHaveSiteOptionInDatabase

    +

    Signature: dontHaveSiteOptionInDatabase(string $key, [mixed $value]) : void

    +

    Removes a site option from the database.

    +
    <?php
    +// Remove the `foo_count` option.
    +$I->dontHaveSiteOptionInDatabase('foo_count');
    +// Remove the `foo_count` option only if its value is `23`.
    +$I->dontHaveSiteOptionInDatabase('foo_count', 23);
    +
    +

    dontHaveSiteTransientInDatabase

    +

    Signature: dontHaveSiteTransientInDatabase(string $key) : void

    +

    Removes a site transient from the database.

    +
    <?php
    +$I->dontHaveSiteTransientInDatabase(['my_plugin_site_buffer']);
    +
    +

    dontHaveTableInDatabase

    +

    Signature: dontHaveTableInDatabase(string $fullTableName) : void

    +

    Removes a table from the database. +The case where a table does not exist is handled without raising an error.

    +
    <?php
    +$ordersTable = $I->grabPrefixedTableNameFor('orders');
    +$I->dontHaveTableInDatabase($ordersTable);
    +
    +

    dontHaveTermInDatabase

    +

    Signature: dontHaveTermInDatabase(array $criteria, [bool $purgeMeta]) : void

    +

    Removes a term from the database.

    +
    <?php
    +$I->dontHaveTermInDatabase(['name' => 'romance']);
    +$I->dontHaveTermInDatabase(['slug' => 'genre--romance']);
    +
    +

    dontHaveTermMetaInDatabase

    +

    Signature: dontHaveTermMetaInDatabase(array $criteria) : void

    +

    Removes a term meta from the database.

    +
    <?php
    +// Remove the "karma" key.
    +$I->dontHaveTermMetaInDatabase(['term_id' => $termId, 'meta_key' => 'karma']);
    +// Remove all meta for the term.
    +$I->dontHaveTermMetaInDatabase(['term_id' => $termId]);
    +
    +

    dontHaveTermRelationshipInDatabase

    +

    Signature: dontHaveTermRelationshipInDatabase(array $criteria) : void

    +

    Removes an entry from the term_relationships table.

    +
    <?php
    +// Remove the relation between a post and a category.
    +$I->dontHaveTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $ttaxId]);
    +// Remove all terms for a post.
    +$I->dontHaveTermMetaInDatabase(['object_id' => $postId]);
    +
    +

    dontHaveTermTaxonomyInDatabase

    +

    Signature: dontHaveTermTaxonomyInDatabase(array $criteria) : void

    +

    Removes an entry from the term_taxonomy table.

    +
    <?php
    +// Remove a specific term from the genre taxonomy.
    +$I->dontHaveTermTaxonomyInDatabase(['term_id' => $postId, 'taxonomy' => 'genre']);
    +// Remove all terms for a taxonomy.
    +$I->dontHaveTermTaxonomyInDatabase(['taxonomy' => 'genre']);
    +
    +

    dontHaveTransientInDatabase

    +

    Signature: dontHaveTransientInDatabase(string $transient) : void

    +

    Removes a transient from the database.

    +
    <?php
    +// Removes the `tweets` transient from the database, if set.
    +$I->dontHaveTransientInDatabase('tweets');
    +
    +

    dontHaveUserInDatabase

    +

    Signature: dontHaveUserInDatabase(string|int $userIdOrLogin, [bool $purgeMeta]) : void

    +

    Removes a user from the database.

    +
    <?php
    +$bob = $I->haveUserInDatabase('bob');
    +$alice = $I->haveUserInDatabase('alice');
    +// Remove Bob's user and meta.
    +$I->dontHaveUserInDatabase('bob');
    +// Remove Alice's user but not meta.
    +$I->dontHaveUserInDatabase($alice);
    +
    +

    dontHaveUserInDatabaseWithEmail

    +

    Signature: dontHaveUserInDatabaseWithEmail(string $userEmail, [bool $purgeMeta]) : array

    +

    Removes a user(s) from the database using the user email address.

    +
    <?php
    +$luca = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);
    +$I->dontHaveUserInDatabaseWithEmail('luca@exampl.org');
    +
    +

    dontHaveUserMetaInDatabase

    +

    Signature: dontHaveUserMetaInDatabase(array $criteria) : void

    +

    Removes an entry from the usermeta table.

    +
    <?php
    +// Remove the `karma` user meta for a user.
    +$I->dontHaveUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);
    +// Remove all the user meta for a user.
    +$I->dontHaveUserMetaInDatabase(['user_id' => 23]);
    +
    +

    dontSeeAttachmentInDatabase

    +

    Signature: dontSeeAttachmentInDatabase(array $criteria) : void

    +

    Checks that an attachment is not in the database.

    +
    <?php
    +$url = 'https://example.org/images/foo.png';
    +$I->dontSeeAttachmentInDatabase(['guid' => $url]);
    +
    +

    dontSeeBlogInDatabase

    +

    Signature: dontSeeBlogInDatabase(array $criteria) : void

    +

    Checks that a row is not present in the blogs table.

    +
    <?php
    +$I->haveManyBlogsInDatabase(2, ['path' => 'test-{{n}}'], false)
    +$I->dontSeeBlogInDatabase(['path' => '/test-3/'])
    +
    +

    dontSeeCommentInDatabase

    +

    Signature: dontSeeCommentInDatabase(array $criteria) : void

    +

    Checks that a comment is not in the database.

    +

    Will look up the "comments" table.

    +
    <?php
    +// Checks for one comment.
    +$I->dontSeeCommentInDatabase(['comment_ID' => 23]);
    +// Checks for comments from a user.
    +$I->dontSeeCommentInDatabase(['user_id' => 89]);
    +
    +

    dontSeeCommentMetaInDatabase

    +

    Signature: dontSeeCommentMetaInDatabase(array $criteria) : void

    +

    Checks that a comment meta value is not in the database.

    +

    Will look up the "commentmeta" table.

    +
    <?php
    +// Delete a comment `karma` meta.
    +$I->dontSeeCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'karma']);
    +// Delete all meta for a comment.
    +$I->dontSeeCommentMetaInDatabase(['comment_id' => 23]);
    +
    +

    dontSeeInDatabase

    +

    Signature: dontSeeInDatabase(string $table, [array $criteria]) : void

    +

    dontSeeLinkInDatabase

    +

    Signature: dontSeeLinkInDatabase(array $criteria) : void

    +

    Checks that a link is not in the links database table.

    +
    <?php
    +$I->dontSeeLinkInDatabase(['link_url' => 'http://example.com']);
    +$I->dontSeeLinkInDatabase(['link_url' => 'http://example.com', 'link_name' => 'example']);
    +
    +

    dontSeeOptionInDatabase

    +

    Signature: dontSeeOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    +

    Checks that an option is not in the database for the current blog.

    +

    If the value is an object or an array then the serialized option will be checked.

    +
    <?php
    +$I->dontHaveOptionInDatabase('posts_per_page');
    +$I->dontSeeOptionInDatabase('posts_per_page');
    +$I->dontSeeOptionInDatabase('posts_per_page', 23);
    +$I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page']);
    +$I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page', 'option_value' => 23]);
    +
    +

    dontSeePageInDatabase

    +

    Signature: dontSeePageInDatabase(array $criteria) : void

    +

    Checks that a page is not in the database.

    +
    <?php
    +// Assert a page with an ID does not exist.
    +$I->dontSeePageInDatabase(['ID' => 23]);
    +// Assert a page with a slug and ID.
    +$I->dontSeePageInDatabase(['post_name' => 'test', 'ID' => 23]);
    +
    +

    dontSeePostInDatabase

    +

    Signature: dontSeePostInDatabase(array $criteria) : void

    +

    Checks that a post is not in the database.

    +
    <?php
    +// Asserts a post with title 'Test' is not in the database.
    +$I->dontSeePostInDatabase(['post_title' => 'Test']);
    +// Asserts a post with title 'Test' and content 'Test content' is not in the database.
    +$I->dontSeePostInDatabase(['post_title' => 'Test', 'post_content' => 'Test content']);
    +
    +

    dontSeePostMetaInDatabase

    +

    Signature: dontSeePostMetaInDatabase(array $criteria) : void

    +

    Checks that a post meta value does not exist.

    +

    If the meta value is an object or an array then the check will be made on its serialized version.

    +
    <?php
    +$postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']]);
    +$I->dontSeePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'woot']);
    +
    +

    dontSeePostWithTermInDatabase

    +

    Signature: dontSeePostWithTermInDatabase(int $post_id, int $term_taxonomy_id, [?int $term_order], [?string $taxonomy]) : void

    +

    Checks that a post to term relation does not exist in the database.

    +

    The method will check the "term_relationships" table.

    +
    <?php
    +$fiction = $I->haveTermInDatabase('fiction', 'genre');
    +$nonFiction = $I->haveTermInDatabase('non-fiction', 'genre');
    +$postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);
    +$I->dontSeePostWithTermInDatabase($postId, $nonFiction['term_taxonomy_id], );
    +
    +

    dontSeeSiteOptionInDatabase

    +

    Signature: dontSeeSiteOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    +

    Checks that a site option is not in the database.

    +
    <?php
    +// Check that the option is not set in the database.
    +$I->dontSeeSiteOptionInDatabase('foo_count');
    +// Check that the option is not set with a specific value.
    +$I->dontSeeSiteOptionInDatabase('foo_count', 23);
    +$I->dontSeeSiteOptionInDatabase(['option_name => 'foo_count', 'option_value' => 23]);
    +
    +

    dontSeeSiteTransientInDatabase

    +

    Signature: dontSeeSiteTransientInDatabase(string $transient, [mixed $value]) : void

    +

    Checks that a site transient is not in the database.

    +
    <?php
    +$I->dontSeeSiteTransientInDatabase('foo');
    +$I->dontSeeSiteTransientInDatabase('foo', 23);
    +
    +

    dontSeeTableInDatabase

    +

    Signature: dontSeeTableInDatabase(string $table) : void

    +

    Checks that a table is not in the database.

    +
    <?php
    +$options = $I->grabPrefixedTableNameFor('options');
    +$I->dontHaveTableInDatabase($options)
    +$I->dontSeeTableInDatabase($options);
    +
    +

    dontSeeTermInDatabase

    +

    Signature: dontSeeTermInDatabase(array $criteria) : void

    +

    Makes sure a term is not in the database.

    +

    Looks up both the terms table and the term_taxonomy tables.

    +
    <?php
    +// Asserts a 'fiction' term is not in the database.
    +$I->dontSeeTermInDatabase(['name' => 'fiction']);
    +// Asserts a 'fiction' term with slug 'genre--fiction' is not in the database.
    +$I->dontSeeTermInDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);
    +
    +

    dontSeeTermMetaInDatabase

    +

    Signature: dontSeeTermMetaInDatabase(array $criteria) : void

    +

    Checks that a term meta is not in the database.

    +
    <?php
    +list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
    +$I->haveTermMetaInDatabase($termId, 'rating', 4);
    +$I->dontSeeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'average_review']);
    +
    +

    dontSeeTermTaxonomyInDatabase

    +

    Signature: dontSeeTermTaxonomyInDatabase(array $criteria) : void

    +

    Checks that a term taxonomy is not in the database.

    +
    <?php
    +list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
    +$I->dontSeeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'country']);
    +
    +

    dontSeeTransientInDatabase

    +

    Signature: dontSeeTransientInDatabase(string $transient, [mixed $value]) : void

    +

    Checks that a transient is not in the database.

    +
    <?php
    +$I->dontSeeTransientInDatabase('foo');
    +$I->dontSeeTransientInDatabase('foo', 23);
    +
    +

    dontSeeUserInDatabase

    +

    Signature: dontSeeUserInDatabase(array $criteria) : void

    +

    Checks that a user is not in the database.

    +
    <?php
    +// Asserts a user does not exist in the database.
    +$I->dontSeeUserInDatabase(['user_login' => 'luca']);
    +// Asserts a user with email and login is not in the database.
    +$I->dontSeeUserInDatabase(['user_login' => 'luca', 'user_email' => 'luca@theaveragedev.com']);
    +
    +

    dontSeeUserMetaInDatabase

    +

    Signature: dontSeeUserMetaInDatabase(array $criteria) : void

    +

    Check that a user meta value is not in the database.

    +
    <?php
    +// Asserts a user does not have a 'karma' meta assigned.
    +$I->dontSeeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);
    +// Asserts no user has any 'karma' meta assigned.
    +$I->dontSeeUserMetaInDatabase(['meta_key' => 'karma']);
    +
    +

    getSiteDomain

    +

    Signature: getSiteDomain() : string

    +

    Returns the site domain inferred from the url set in the config.

    +
    <?php
    +$domain = $I->getSiteDomain();
    +// We should be redirected to the HTTPS version when visiting the HTTP version.
    +$I->amOnPage('http://' . $domain);
    +$I->seeCurrentUrlEquals('https://' . $domain);
    +
    +

    getUsersTableName

    +

    Signature: getUsersTableName() : string

    +

    Returns the prefixed users table name.

    +
    <?php
    +// Given a `wp_` table prefix returns `wp_users`.
    +$usersTable = $I->getUsersTableName();
    +// Given a `wp_` table prefix returns `wp_users`.
    +$I->useBlog(23);
    +$usersTable = $I->getUsersTableName();
    +
    +

    grabAllFromDatabase

    +

    Signature: grabAllFromDatabase(string $table, string $column, array $criteria) : array

    +

    Returns all entries matching a criteria from the database.

    +
    <?php
    +$books = $I->grabPrefixedTableNameFor('books');
    +$I->grabAllFromDatabase($books, 'title', ['genre' => 'fiction']);
    +
    +

    grabAttachmentAttachedFile

    +

    Signature: grabAttachmentAttachedFile(int $attachmentPostId) : string

    +

    Returns the path, as stored in the database, of an attachment _wp_attached_file meta. +The attached file is, usually, an attachment origal file.

    +
    <?php
    +$file = $I->grabAttachmentAttachedFile($attachmentId);
    +$fileInfo = new SplFileInfo($file);
    +$I->assertEquals('jpg', $fileInfo->getExtension());
    +
    +

    grabAttachmentMetadata

    +

    Signature: grabAttachmentMetadata(int $attachmentPostId) : array

    +

    Returns the metadata array for an attachment post. +This is the value of the _wp_attachment_metadata meta.

    +
    <?php
    +$metadata = $I->grabAttachmentMetadata($attachmentId);
    +$I->assertEquals(['thumbnail', 'medium', 'medium_large'], array_keys($metadata['sizes']);
    +
    +

    grabBlogDomain

    +

    Signature: grabBlogDomain(int $blogId) : string

    +

    Returns a blog domain given its ID.

    +
    <?php
    +$blogIds = $I->haveManyBlogsInDatabase(3);
    +$domains = array_map(function($blogId){
    +     return $I->grabBlogDomain($blogId);
    +}, $blogIds);
    +
    +

    grabBlogPath

    +

    Signature: grabBlogPath(int $blogId) : string

    +

    Grabs a blog domain from the blogs table.

    +
    <?php
    +$blogId = $I->haveBlogInDatabase('test');
    +$path = $I->grabBlogDomain($blogId);
    +$I->amOnSubdomain($path);
    +$I->amOnPage('/');
    +
    +

    grabBlogTableName

    +

    Signature: grabBlogTableName(int $blogId, string $table) : string

    +

    Returns the full name of a table for a blog from a multisite installation database.

    +
    <?php
    +$blogOptionTable = $I->grabBlogTableName($blogId, 'option');
    +
    +

    grabBlogTableNames

    +

    Signature: grabBlogTableNames(int $blogId) : array

    +

    Returns a list of tables for a blog ID.

    +
    <?php
    +     $blogId = $I->haveBlogInDatabase('test');
    +     $tables = $I->grabBlogTableNames($blogId);
    +     $options = array_filter($tables, function($tableName){
    +     return str_pos($tableName, 'options') !== false;
    +});
    +
    +

    grabBlogTablePrefix

    +

    Signature: grabBlogTablePrefix(int $blogId) : string

    +

    Returns the table prefix for a blog.

    +
    <?php
    +$blogId = $I->haveBlogInDatabase('test');
    +$blogTablePrefix = $I->getBlogTablePrefix($blogId);
    +$blogOrders = $I->blogTablePrefix . 'orders';
    +
    +

    grabBlogUrl

    +

    Signature: grabBlogUrl([int $blogId]) : string

    +

    Gets the blog URL from the Blog ID.

    +

    grabBlogVersionsTableName

    +

    Signature: grabBlogVersionsTableName() : string

    +

    Gets the prefixed blog_versions table name.

    +
    <?php
    +// Assuming a `wp_` table prefix it will return `wp_blog_versions`.
    +$blogVersionsTable = $I->grabBlogVersionsTableName();
    +$I->useBlog(23);
    +// Assuming a `wp_` table prefix it will return `wp_blog_versions`.
    +$blogVersionsTable = $I->grabBlogVersionsTableName();
    +
    +

    grabBlogsTableName

    +

    Signature: grabBlogsTableName() : string

    +

    Gets the prefixed blogs table name.

    +
    <?php
    +// Assuming a `wp_` table prefix it will return `wp_blogs`.
    +$blogVersionsTable = $I->grabBlogsTableName();
    +$I->useBlog(23);
    +// Assuming a `wp_` table prefix it will return `wp_blogs`.
    +$blogVersionsTable = $I->grabBlogsTableName();
    +
    +

    grabColumnFromDatabase

    +

    Signature: grabColumnFromDatabase(string $table, string $column, [array $criteria]) : array

    +

    Fetches all values from the column in database. +Provide table name, desired column and criteria.

    +
    <?php
    +$mails = $I->grabColumnFromDatabase('users', 'email', array('name' => 'RebOOter'));
    +
    +

    grabCommentmetaTableName

    +

    Signature: grabCommentmetaTableName() : string

    +

    Returns the prefixed comment meta table name.

    +
    <?php
    +// Get all the values of 'karma' for all comments.
    +$commentMeta = $I->grabCommentmetaTableName();
    +$I->grabAllFromDatabase($commentMeta, 'meta_value', ['meta_key' => 'karma']);
    +
    +

    grabCommentsTableName

    +

    Signature: grabCommentsTableName() : string

    +

    Gets the comments table name.

    +
    <?php
    +// Will be `wp_comments`.
    +$comments = $I->grabCommentsTableName();
    +// Will be `wp_23_comments`.
    +$I->useBlog(23);
    +$comments = $I->grabCommentsTableName();
    +
    +

    grabEntriesFromDatabase

    +

    Signature: grabEntriesFromDatabase(string $table, [array $criteria]) : array

    +

    Fetches a set of entries from a database. +Provide table name and criteria.

    +

    <?php
    +$mail = $I->grabEntriesFromDatabase('users', array('name' => 'Davert'));
    +
    +Comparison expressions can be used as well:

    +
    <?php
    +$post = $I->grabEntriesFromDatabase('posts', ['num_comments >=' => 100]);
    +$user = $I->grabEntriesFromDatabase('users', ['email like' => 'miles%']);
    +
    +

    Supported operators: <, >, >=, <=, !=, like.

    +

    grabEntryFromDatabase

    +

    Signature: grabEntryFromDatabase(string $table, [array $criteria]) : array

    +

    Fetches a whole entry from a database. +Make the test fail if the entry is not found. +Provide table name, desired column and criteria.

    +

    <?php
    +$mail = $I->grabEntryFromDatabase('users', array('name' => 'Davert'));
    +
    +Comparison expressions can be used as well:

    +
    <?php
    +$post = $I->grabEntryFromDatabase('posts', ['num_comments >=' => 100]);
    +$user = $I->grabEntryFromDatabase('users', ['email like' => 'miles%']);
    +
    +

    Supported operators: <, >, >=, <=, !=, like.

    +

    grabFromDatabase

    +

    Signature: grabFromDatabase(string $table, string $column, [array $criteria]) : void

    +

    Fetches a single column value from a database. +Provide table name, desired column and criteria.

    +

    <?php
    +$mail = $I->grabFromDatabase('users', 'email', array('name' => 'Davert'));
    +
    +Comparison expressions can be used as well:

    +
    <?php
    +$postNum = $I->grabFromDatabase('posts', 'num_comments', ['num_comments >=' => 100]);
    +$mail = $I->grabFromDatabase('users', 'email', ['email like' => 'miles%']);
    +
    +

    Supported operators: <, >, >=, <=, !=, like.

    +

    grabLatestEntryByFromDatabase

    +

    Signature: grabLatestEntryByFromDatabase(string $tableName, [string $idColumn]) : int

    +

    Returns the id value of the last table entry.

    +
    <?php
    +$I->haveManyPostsInDatabase();
    +$postsTable = $I->grabPostsTableName();
    +$last = $I->grabLatestEntryByFromDatabase($postsTable, 'ID');
    +
    +

    grabLinksTableName

    +

    Signature: grabLinksTableName() : string

    +

    Returns the prefixed links table name.

    +
    <?php
    +// Given a `wp_` table prefix returns `wp_links`.
    +$linksTable = $I->grabLinksTableName();
    +// Given a `wp_` table prefix returns `wp_23_links`.
    +$I->useBlog(23);
    +$linksTable = $I->grabLinksTableName();
    +
    +

    grabNumRecords

    +

    Signature: grabNumRecords(string $table, [array $criteria]) : int

    +

    Returns the number of rows in a database

    +

    grabOptionFromDatabase

    +

    Signature: grabOptionFromDatabase(string $option_name) : mixed

    +

    Gets an option value from the database.

    +
    <?php
    +$count = $I->grabOptionFromDatabase('foo_count');
    +
    +

    grabPostFieldFromDatabase

    +

    Signature: grabPostFieldFromDatabase(int $postId, string $field) : mixed

    +

    Returns the value of a post field for a post, from the posts table.

    +
    <?php
    +$title = $I->grabPostFieldFromDatabase(1, 'post_title');
    +$type = $I->grabPostFieldFromDatabase(1, 'post_type');
    +
    +

    grabPostMetaFromDatabase

    +

    Signature: grabPostMetaFromDatabase(int $postId, string $metaKey, [bool $single]) : mixed

    +

    Gets the value of one or more post meta values from the database.

    +
    <?php
    +$thumbnail_id = $I->grabPostMetaFromDatabase($postId, '_thumbnail_id', true);
    +
    +

    grabPostmetaTableName

    +

    Signature: grabPostmetaTableName() : string

    +

    Returns the prefixed post meta table name.

    +
    <?php
    +// Returns 'wp_postmeta'.
    +$I->grabPostmetaTableName();
    +// Returns 'wp_23_postmeta'.
    +$I->useBlog(23);
    +$I->grabPostmetaTableName();
    +
    +

    grabPostsTableName

    +

    Signature: grabPostsTableName() : string

    +

    Gets the posts prefixed table name.

    +
    <?php
    +// Given a `wp_` table prefix returns `wp_posts`.
    +$postsTable = $I->grabPostsTableName();
    +// Given a `wp_` table prefix returns `wp_23_posts`.
    +$I->useBlog(23);
    +$postsTable = $I->grabPostsTableName();
    +
    +

    grabPrefixedTableNameFor

    +

    Signature: grabPrefixedTableNameFor([string $tableName]) : string

    +

    Returns a prefixed table name for the current blog.

    +

    If the table is not one to be prefixed (e.g. users) then the proper table name will be returned.

    +
    <?php
    +// Will return wp_users.
    +$usersTable = $I->grabPrefixedTableNameFor('users');
    +// Will return wp_options.
    +$optionsTable = $I->grabPrefixedTableNameFor('options');
    +// Use a different blog and get its options table.
    +$I->useBlog(2);
    +$blogOptionsTable = $I->grabPrefixedTableNameFor('options');
    +
    +

    grabRegistrationLogTableName

    +

    Signature: grabRegistrationLogTableName() : string

    +

    Gets the prefixed registration_log table name.

    +
    <?php
    +// Assuming a `wp_` table prefix it will return `wp_registration_log`.
    +$blogVersionsTable = $I->grabRegistrationLogTableName();
    +$I->useBlog(23);
    +// Assuming a `wp_` table prefix it will return `wp_registration_log`.
    +$blogVersionsTable = $I->grabRegistrationLogTableName();
    +
    +

    grabSignupsTableName

    +

    Signature: grabSignupsTableName() : string

    +

    Gets the prefixed signups table name.

    +
    <?php
    +// Assuming a `wp_` table prefix it will return `wp_signups`.
    +$blogVersionsTable = $I->grabSignupsTableName();
    +$I->useBlog(23);
    +// Assuming a `wp_` table prefix it will return `wp_signups`.
    +$blogVersionsTable = $I->grabSignupsTableName();
    +
    +

    grabSiteMetaFromDatabase

    +

    Signature: grabSiteMetaFromDatabase(int $blogId, string $key, bool $single) : mixed

    +

    Returns a single or all meta values for a site meta key.

    +
    <?php
    +$I->haveSiteMetaInDatabase(1, 'foo', 'bar');
    +$value = $I->grabSiteMetaFromDatabase(1, 'foo', true);
    +$values = $I->grabSiteMetaFromDatabase(1, 'foo', false);
    +
    +

    grabSiteMetaTableName

    +

    Signature: grabSiteMetaTableName() : string

    +

    Gets the prefixed sitemeta table name.

    +
    <?php
    +// Assuming a `wp_` table prefix it will return `wp_sitemeta`.
    +$blogVersionsTable = $I->grabSiteMetaTableName();
    +$I->useBlog(23);
    +// Assuming a `wp_` table prefix it will return `wp_sitemeta`.
    +$blogVersionsTable = $I->grabSiteMetaTableName();
    +
    +

    grabSiteOptionFromDatabase

    +

    Signature: grabSiteOptionFromDatabase(string $key) : mixed

    +

    Gets a site option from the database.

    +
    <?php
    +$fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');
    +
    +

    grabSiteTableName

    +

    Signature: grabSiteTableName() : string

    +

    Gets the prefixed site table name.

    +
    <?php
    +// Assuming a `wp_` table prefix it will return `wp_site`.
    +$blogVersionsTable = $I->grabSiteTableName();
    +$I->useBlog(23);
    +// Assuming a `wp_` table prefix it will return `wp_site`.
    +$blogVersionsTable = $I->grabSiteTableName();
    +
    +

    grabSiteTransientFromDatabase

    +

    Signature: grabSiteTransientFromDatabase(string $key) : mixed

    +

    Gets a site transient from the database.

    +
    <?php
    +$I->grabSiteTransientFromDatabase('total_comments');
    +$I->grabSiteTransientFromDatabase('api_data');
    +
    +

    grabSiteUrl

    +

    Signature: grabSiteUrl([?string $path]) : string

    +

    Returns the current site URL as specified in the module configuration.

    +
    <?php
    +$shopPath = $I->grabSiteUrl('/shop');
    +
    +

    grabTablePrefix

    +

    Signature: grabTablePrefix() : string

    +

    Returns the table prefix, namespaced for secondary blogs if selected.

    +
    <?php
    +// Assuming a table prefix of `wp_` it will return `wp_`;
    +$tablePrefix = $I->grabTablePrefix();
    +$I->useBlog(23);
    +// Assuming a table prefix of `wp_` it will return `wp_23_`;
    +$tablePrefix = $I->grabTablePrefix();
    +
    +

    grabTermIdFromDatabase

    +

    Signature: grabTermIdFromDatabase(array $criteria) : int|false

    +

    Gets a term ID from the database. +Looks up the prefixed terms table, e.g. wp_terms.

    +
    <?php
    +// Return the 'fiction' term 'term_id'.
    +$termId = $I->grabTermIdFromDatabase(['name' => 'fiction']);
    +// Get a term ID by more stringent criteria.
    +$termId = $I->grabTermIdFromDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);
    +// Return the 'term_id' of the first term for a group.
    +$termId = $I->grabTermIdFromDatabase(['term_group' => 23]);
    +
    +

    grabTermMetaTableName

    +

    Signature: grabTermMetaTableName() : string

    +

    Gets the terms meta table prefixed name.

    +
    <?php
    +// Returns 'wp_termmeta'.
    +$I->grabTermMetaTableName();
    +// Returns 'wp_23_termmeta'.
    +$I->useBlog(23);
    +$I->grabTermMetaTableName();
    +
    +

    grabTermRelationshipsTableName

    +

    Signature: grabTermRelationshipsTableName() : string

    +

    Gets the prefixed term relationships table name, e.g. wp_term_relationships.

    +
    <?php
    +$I->grabTermRelationshipsTableName();
    +
    +

    grabTermTaxonomyIdFromDatabase

    +

    Signature: grabTermTaxonomyIdFromDatabase(array $criteria) : int|false

    +

    Gets a term_taxonomy_id from the database.

    +

    Looks up the prefixed terms_relationships table, e.g. wp_term_relationships.

    +
    <?php
    +// Get the `term_taxonomy_id` for a term and a taxonomy.
    +$I->grabTermTaxonomyIdFromDatabase(['term_id' => $fictionId, 'taxonomy' => 'genre']);
    +// Get the `term_taxonomy_id` for the first term with a count of 23.
    +$I->grabTermTaxonomyIdFromDatabase(['count' => 23]);
    +
    +

    grabTermTaxonomyTableName

    +

    Signature: grabTermTaxonomyTableName() : string

    +

    Gets the prefixed term and taxonomy table name, e.g. wp_term_taxonomy.

    +
    <?php
    +// Returns 'wp_term_taxonomy'.
    +$I->grabTermTaxonomyTableName();
    +// Returns 'wp_23_term_taxonomy'.
    +$I->useBlog(23);
    +$I->grabTermTaxonomyTableName();
    +
    +

    grabTermsTableName

    +

    Signature: grabTermsTableName() : string

    +

    Gets the prefixed terms table name, e.g. wp_terms.

    +
    <?php
    +// Returns 'wp_terms'.
    +$I->grabTermsTableName();
    +// Returns 'wp_23_terms'.
    +$I->useBlog(23);
    +$I->grabTermsTableName();
    +
    +

    grabTransientFromDatabase

    +

    Signature: grabTransientFromDatabase(string $transient) : mixed

    +

    Fetches the value of a transient from the database.

    +
    <?php
    +$I->haveTransientInDatabase('foo', 23);
    +$transientValue = $I->grabTransientFromDatabase('foo');
    +$I->assertEquals(23, $transientValue);
    +
    +

    grabUserIdFromDatabase

    +

    Signature: grabUserIdFromDatabase(string $userLogin) : int|false

    +

    Gets the a user ID from the database using the user login.

    +
    <?php
    +$userId = $I->grabUserIdFromDatabase('luca');
    +
    +

    grabUserMetaFromDatabase

    +

    Signature: grabUserMetaFromDatabase(int $userId, string $meta_key, [bool $single]) : mixed

    +

    Gets a user meta from the database.

    +
    <?php
    +// Returns a user 'karma' value.
    +$I->grabUserMetaFromDatabase($userId, 'karma');
    +// Returns an array, the unserialized version of the value stored in the database.
    +$I->grabUserMetaFromDatabase($userId, 'api_data');
    +
    +

    grabUsermetaTableName

    +

    Signature: grabUsermetaTableName() : string

    +

    Returns the prefixed users meta table name.

    +
    <?php
    +// Given a `wp_` table prefix returns `wp_usermeta`.
    +$usermetaTable = $I->grabUsermetaTableName();
    +// Given a `wp_` table prefix returns `wp_usermeta`.
    +$I->useBlog(23);
    +$usermetaTable = $I->grabUsermetaTableName();
    +
    +

    grabUsersTableName

    +

    Signature: grabUsersTableName() : string

    +

    Returns the prefixed users table name.

    +
    <?php
    +// Given a `wp_` table prefix returns `wp_users`.
    +$usersTable = $I->grabUsersTableName();
    +// Given a `wp_` table prefix returns `wp_users`.
    +$I->useBlog(23);
    +$usersTable = $I->grabUsersTableName();
    +
    +

    haveAttachmentInDatabase

    +

    Signature: haveAttachmentInDatabase(string $file, [string|int $date], [array $overrides], [?array $imageSizes]) : int

    +

    Creates the database entries representing an attachment and moves the attachment file to the right location.

    +
    <?php
    +$file = codecept_data_dir('images/test.png');
    +$attachmentId = $I->haveAttachmentInDatabase($file);
    +$image = codecept_data_dir('images/test-2.png');
    +$lastWeekAttachment = $I->haveAttachmentInDatabase($image, '-1 week');
    +
    +

    Requires the WPFilesystem module.

    +

    haveBlogInDatabase

    +

    Signature: haveBlogInDatabase(string $domainOrPath, [array $overrides], [bool $subdomain]) : int

    +

    Inserts a blog in the blogs table.

    +
    <?php
    +// Create the `test` subdomain blog.
    +$blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId]);
    +// Create the `/test` subfolder blog.
    +$blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId], false);
    +
    +

    haveCommentInDatabase

    +

    Signature: haveCommentInDatabase(int $comment_post_ID, [array $data]) : int

    +

    Inserts a comment in the database.

    +
    <?php
    +$I->haveCommentInDatabase($postId, ['comment_content' => 'Test Comment', 'comment_karma' => 23]);
    +
    +

    haveCommentMetaInDatabase

    +

    Signature: haveCommentMetaInDatabase(int $comment_id, string $meta_key, mixed $meta_value) : int

    +

    Inserts a comment meta field in the database. +Array and object meta values will be serialized.

    +
    <?php
    +$I->haveCommentMetaInDatabase($commentId, 'api_ID', 23);
    +// The value will be serialized.
    +$apiData = ['ID' => 23, 'user' => 89, 'origin' => 'twitter'];
    +$I->haveCommentMetaInDatabase($commentId, 'api_data', $apiData);
    +
    +

    haveInDatabase

    +

    Signature: haveInDatabase(string $table, array $data) : int

    +

    Inserts an SQL record into a database. This record will be erased after the test, +unless you've configured "skip_cleanup_if_failed", and the test fails.

    +
    <?php
    +$I->haveInDatabase('users', array('name' => 'miles', 'email' => 'miles@davis.com'));
    +
    +

    haveLinkInDatabase

    +

    Signature: haveLinkInDatabase([array $overrides]) : int

    +

    Inserts a link in the database.

    +
    <?php
    +$linkId = $I->haveLinkInDatabase(['link_url' => 'http://example.org']);
    +
    +

    haveManyBlogsInDatabase

    +

    Signature: haveManyBlogsInDatabase(int $count, [array $overrides], [bool $subdomain]) : array

    +

    Inserts many blogs in the database.

    +
    <?php
    +     $blogIds = $I->haveManyBlogsInDatabase(3, ['domain' =>'test-{{n}}']);
    +     foreach($blogIds as $blogId){
    +     $I->useBlog($blogId);
    +     $I->haveManuPostsInDatabase(3);
    +}
    +
    +

    haveManyCommentsInDatabase

    +

    Signature: haveManyCommentsInDatabase(int $count, int $comment_post_ID, [array $overrides]) : array

    +

    Inserts many comments in the database.

    +
    <?php
    +// Insert 3 random comments for a post.
    +$I->haveManyCommentsInDatabase(3, $postId);
    +// Insert 3 random comments for a post.
    +$I->haveManyCommentsInDatabase(3, $postId, ['comment_content' => 'Comment {{n}}']);
    +
    +

    haveManyLinksInDatabase

    +

    Signature: haveManyLinksInDatabase(int $count, [array $overrides]) : array

    +

    Inserts many links in the database links table.

    +
    <?php
    +// Insert 3 randomly generated links in the database.
    +$linkIds = $I->haveManyLinksInDatabase(3);
    +// Inserts links in the database replacing the `n` placeholder.
    +$linkIds = $I->haveManyLinksInDatabase(3, ['link_url' => 'http://example.org/test-{{n}}']);
    +
    +

    haveManyPostsInDatabase

    +

    Signature: haveManyPostsInDatabase(int $count, [array $overrides]) : array

    +

    Inserts many posts in the database returning their IDs.

    +
    <?php
    +// Insert 3 random posts.
    +$I->haveManyPostsInDatabase(3);
    +// Insert 3 posts with generated titles.
    +$I->haveManyPostsInDatabase(3, ['post_title' => 'Test post {{n}}']);
    +
    +

    haveManyTermsInDatabase

    +

    Signature: haveManyTermsInDatabase(int $count, string $name, string $taxonomy, [array $overrides]) : array

    +

    Inserts many terms in the database.

    +
    <?php
    +$terms = $I->haveManyTermsInDatabase(3, 'genre-{{n}}', 'genre');
    +$termIds = array_column($terms, 0);
    +$termTaxonomyIds = array_column($terms, 1);
    +
    +

    haveManyUsersInDatabase

    +

    Signature: haveManyUsersInDatabase(int $count, string $user_login, [string $role], [array $overrides]) : array

    +

    Inserts many users in the database.

    +
    <?php
    +$subscribers = $I->haveManyUsersInDatabase(5, 'user-{{n}}');
    +$editors = $I->haveManyUsersInDatabase(
    +     5,
    +     'user-{{n}}',
    +     'editor',
    +     ['user_email' => 'user-{{n}}@example.org']
    +);
    +
    +

    haveMenuInDatabase

    +

    Signature: haveMenuInDatabase(string $slug, string $location, [array $overrides]) : array

    +

    Creates and adds a menu to a theme location in the database.

    +
    <?php
    +list($termId, $termTaxId) = $I->haveMenuInDatabase('test', 'sidebar');
    +
    +

    haveMenuItemInDatabase

    +

    Signature: haveMenuItemInDatabase(string $menuSlug, string $title, [?int $menuOrder], [array $meta]) : int

    +

    Adds a menu element to a menu for the current theme.

    +
    <?php
    +$I->haveMenuInDatabase('test', 'sidebar');
    +$I->haveMenuItemInDatabase('test', 'Test one', 0);
    +$I->haveMenuItemInDatabase('test', 'Test two', 1);
    +
    +

    haveOptionInDatabase

    +

    Signature: haveOptionInDatabase(string $option_name, mixed $option_value, [string $autoload]) : int

    +

    Inserts an option in the database.

    +
    <?php
    +$I->haveOptionInDatabase('posts_per_page', 23);
    +$I->haveOptionInDatabase('my_plugin_options', ['key_one' => 'value_one', 'key_two' => 89]);
    +
    +

    If the option value is an object or an array then the value will be serialized.

    +

    havePageInDatabase

    +

    Signature: havePageInDatabase([array $overrides]) : int

    +

    Inserts a page in the database.

    +
    <?php
    +// Creates a test page in the database with random values.
    +$randomPageId = $I->havePageInDatabase();
    +// Creates a test page in the database defining its title.
    +$testPageId = $I->havePageInDatabase(['post_title' => 'Test page']);
    +
    +

    havePostInDatabase

    +

    Signature: havePostInDatabase([array $data]) : int

    +

    Inserts a post in the database.

    +
    <?php
    +// Insert a post with random values in the database.
    +$randomPostId = $I->havePostInDatabase();
    +// Insert a post with specific values in the database.
    +$I->havePostInDatabase([
    +'post_type' => 'book',
    +'post_title' => 'Alice in Wonderland',
    +'meta_input' => [
    +'readers_count' => 23
    +],
    +'tax_input' => [
    +['genre' => 'fiction']
    +]
    +]);
    +
    +

    havePostThumbnailInDatabase

    +

    Signature: havePostThumbnailInDatabase(int $postId, int $thumbnailId) : int

    +

    Assigns the specified attachment ID as thumbnail (featured image) to a post.

    +
    <?php
    +$attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));
    +$postId = $I->havePostInDatabase();
    +$I->havePostThumbnailInDatabase($postId, $attachmentId);
    +
    +

    havePostmetaInDatabase

    +

    Signature: havePostmetaInDatabase(int $postId, string $meta_key, mixed $meta_value) : int

    +

    Adds one or more meta key and value couples in the database for a post.

    +
    <?php
    +// Set the post-meta for a post.
    +$I->havePostmetaInDatabase($postId, 'karma', 23);
    +// Set an array post-meta for a post, it will be serialized in the db.
    +$I->havePostmetaInDatabase($postId, 'data', ['one', 'two']);
    +// Use a loop to insert one meta per row.
    +foreach( ['one', 'two'] as $value){
    +     $I->havePostmetaInDatabase($postId, 'data', $value);
    +}
    +
    +

    haveSiteMetaInDatabase

    +

    Signature: haveSiteMetaInDatabase(int $blogId, string $string, mixed $value) : int

    +

    Adds a meta key and value for a site in the database.

    +
    <?php
    +$I->haveSiteMetaInDatabase(1, 'foo', 'bar');
    +$insertedId = $I->haveSiteMetaInDatabase(2, 'foo', ['bar' => 'baz']);
    +
    +

    haveSiteOptionInDatabase

    +

    Signature: haveSiteOptionInDatabase(string $key, mixed $value) : int

    +

    Inserts a site option in the database.

    +

    If the value is an array or an object then the value will be serialized.

    +
    <?php
    +$fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');
    +
    +

    haveSiteTransientInDatabase

    +

    Signature: haveSiteTransientInDatabase(string $key, mixed $value) : int

    +

    Inserts a site transient in the database. +If the value is an array or an object then the value will be serialized.

    +
    <?php
    +$I->haveSiteTransientInDatabase('total_comments_count', 23);
    +// This value will be serialized.
    +$I->haveSiteTransientInDatabase('api_data', ['user' => 'luca', 'token' => '11ae3ijns-j83']);
    +
    +

    haveTermInDatabase

    +

    Signature: haveTermInDatabase(string $name, string $taxonomy, [array $overrides]) : array

    +

    Inserts a term in the database.

    +
    <?php
    +// Insert a random 'genre' term in the database.
    +$I->haveTermInDatabase('non-fiction', 'genre');
    +// Insert a term in the database with term meta.
    +$I->haveTermInDatabase('fiction', 'genre', [
    +     'slug' => 'genre--fiction',
    +     'meta' => [
    +        'readers_count' => 23
    +     ]
    +]);
    +
    +

    haveTermMetaInDatabase

    +

    Signature: haveTermMetaInDatabase(int $term_id, string $meta_key, mixed $meta_value) : int

    +

    Inserts a term meta row in the database. +Objects and array meta values will be serialized.

    +
    <?php
    +$I->haveTermMetaInDatabase($fictionId, 'readers_count', 23);
    +// Insert some meta that will be serialized.
    +$I->haveTermMetaInDatabase($fictionId, 'flags', [3, 4, 89]);
    +// Use a loop to insert one meta per row.
    +foreach([3, 4, 89] as $value) {
    +     $I->haveTermMetaInDatabase($fictionId, 'flag', $value);
    +}
    +
    +

    haveTermRelationshipInDatabase

    +

    Signature: haveTermRelationshipInDatabase(int $object_id, int $term_taxonomy_id, [int $term_order]) : void

    +

    Creates a term relationship in the database.

    +

    No check about the consistency of the insertion is made. E.g. a post could be assigned a term from +a taxonomy that's not registered for that post type.

    +
    <?php
    +// Assign the `fiction` term to a book.
    +$I->haveTermRelationshipInDatabase($bookId, $fictionId);
    +
    +

    haveTransientInDatabase

    +

    Signature: haveTransientInDatabase(string $transient, mixed $value) : int

    +

    Inserts a transient in the database.

    +

    If the value is an array or an object then the value will be serialized. +Since the transients are set in the context of tests it's not possible to +set an expiration directly.

    +
    <?php
    +// Store an array in the `tweets` transient.
    +$I->haveTransientInDatabase('tweets', $tweets);
    +
    +

    haveUserCapabilitiesInDatabase

    +

    Signature: haveUserCapabilitiesInDatabase(int $userId, array|string $role) : array

    +

    Sets a user capabilities in the database.

    +
    <?php
    +// Assign one user a role in a blog.
    +$blogId = $I->haveBlogInDatabase('test');
    +$editor = $I->haveUserInDatabase('luca', 'editor');
    +$capsIds = $I->haveUserCapabilitiesInDatabase($editor, [$blogId => 'editor']);
    +
    +// Assign a user two roles in blog 1.
    +$capsIds = $I->haveUserCapabilitiesInDatabase($userId, ['editor', 'subscriber']);
    +
    +// Assign one user different roles in different blogs.
    +$capsIds = $I->haveUserCapabilitiesInDatabase($userId, [$blogId1 => 'editor', $blogId2 => 'author']);
    +
    +// Assign a user a role and an additional capability in blog 1.
    +$I->haveUserCapabilitiesInDatabase($userId, ['editor' => true, 'edit_themes' => true]);
    +
    +// Assign a user a mix of roles and capabilities in different blogs.
    +$capsIds = $I->haveUserCapabilitiesInDatabase(
    +     $userId,
    +     [
    +         $blogId1 => ['editor' => true, 'edit_themes' => true],
    +         $blogId2 => ['administrator' => true, 'edit_themes' => false]
    +     ]
    +);
    +
    +

    haveUserInDatabase

    +

    Signature: haveUserInDatabase(string $user_login, [array|string $role], [array $overrides]) : int

    +

    Inserts a user and its meta in the database.

    +
    <?php
    +// Create an editor user in blog 1 w/ specific email.
    +$userId = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);
    +
    +// Create a subscriber user in blog 1.
    +$subscriberId = $I->haveUserInDatabase('subscriber');
    +
    +// Create a user editor in blog 1, author in blog 2, administrator in blog 3.
    +$userWithMeta = $I->haveUserInDatabase('luca',
    +     [
    +         1 => 'editor',
    +         2 => 'author',
    +         3 => 'administrator'
    +     ], [
    +         'user_email' => 'luca@example.org'
    +         'meta' => ['a meta_key' => 'a_meta_value']
    +     ]
    +);
    +
    +// Create editor in blog 1 w/ `edit_themes` cap, author in blog 2, admin in blog 3 w/o `manage_options` cap.
    +$userWithMeta = $I->haveUserInDatabase('luca',
    +     [
    +         1 => ['editor', 'edit_themes'],
    +         2 => 'author',
    +         3 => ['administrator' => true, 'manage_options' => false]
    +     ]
    +);
    +
    +// Create a user w/o role.
    +$userId = $I->haveUserInDatabase('luca', '');
    +
    +

    haveUserLevelsInDatabase

    +

    Signature: haveUserLevelsInDatabase(int $userId, array|string $role) : array

    +

    Sets the user access level meta in the database for a user.

    +
    <?php
    +$userId = $I->haveUserInDatabase('luca', 'editor');
    +$moreThanAnEditorLessThanAnAdmin = 8;
    +$I->haveUserLevelsInDatabase($userId, $moreThanAnEditorLessThanAnAdmin);
    +
    +

    haveUserMetaInDatabase

    +

    Signature: haveUserMetaInDatabase(int $userId, string $meta_key, mixed $meta_value) : array

    +

    Sets a user meta in the database.

    +
    <?php
    +$userId = $I->haveUserInDatabase('luca', 'editor');
    +$I->haveUserMetaInDatabase($userId, 'karma', 23);
    +
    +

    importSql

    +

    Signature: importSql(array $sql) : void

    +

    Loads a set SQL code lines in the current database.

    +
    <?php
    +// Import a SQL string.
    +$I->importSql([$sqlString]);
    +// Import a set of SQL strings.
    +$I->importSql($sqlStrings);
    +// Import a prepared set of SQL strings.
    +$preparedSqlStrings = array_map(function($line){
    +    return str_replace('{{date}}', date('Y-m-d H:i:s'), $line);
    +}, $sqlTemplate);
    +$I->importSql($preparedSqlStrings);
    +
    +

    importSqlDumpFile

    +

    Signature: importSqlDumpFile([?string $dumpFile]) : void

    +

    Import the SQL dump file if populate is enabled.

    +
    <?php
    +// Import a dump file passing the absolute path.
    +$I->importSqlDumpFile(codecept_data_dir('dumps/start.sql'));
    +
    +

    Specifying a dump file that file will be imported.

    +

    performInDatabase

    +

    Signature: performInDatabase($databaseKey, $actions) : void

    +

    Can be used with a callback if you don't want to change the current database in your test.

    +

    <?php
    +$I->seeNumRecords(2, 'users');   //executed on default database
    +$I->performInDatabase('db_books', function($I) {
    +    $I->seeNumRecords(30, 'books');  //executed on db_books database
    +});
    +$I->seeNumRecords(2, 'users');  //executed on default database
    +
    +List of actions can be pragmatically built using Codeception\Util\ActionSequence:

    +

    <?php
    +$I->performInDatabase('db_books', ActionSequence::build()
    +    ->seeNumRecords(30, 'books')
    +);
    +
    +Alternatively an array can be used:

    +
    <?php
    +$I->performInDatabase('db_books', ['seeNumRecords' => [30, 'books']]);
    +
    +

    Choose the syntax you like the most and use it,

    +

    Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to +exception on failure.

    +

    seeAttachmentInDatabase

    +

    Signature: seeAttachmentInDatabase(array $criteria) : void

    +

    Checks for an attachment in the database.

    +
    <?php
    +$url = 'https://example.org/images/foo.png';
    +$I->seeAttachmentInDatabase(['guid' => $url]);
    +
    +

    seeBlogInDatabase

    +

    Signature: seeBlogInDatabase(array $criteria) : void

    +

    Checks for a blog in the blogs table.

    +
    <?php
    +// Search for a blog by `blog_id`.
    +$I->seeBlogInDatabase(['blog_id' => 23]);
    +// Search for all blogs on a path.
    +$I->seeBlogInDatabase(['path' => '/sub-path/']);
    +
    +

    seeCommentInDatabase

    +

    Signature: seeCommentInDatabase(array $criteria) : void

    +

    Checks for a comment in the database.

    +

    Will look up the "comments" table.

    +
    <?php
    +$I->seeCommentInDatabase(['comment_ID' => 23]);
    +
    +

    seeCommentMetaInDatabase

    +

    Signature: seeCommentMetaInDatabase(array $criteria) : void

    +

    Checks that a comment meta value is in the database. +Will look up the "commentmeta" table.

    +
    <?php
    +// Assert a specified meta for a comment exists.
    +$I->seeCommentMetaInDatabase(['comment_ID' => $commentId, 'meta_key' => 'karma', 'meta_value' => 23]);
    +// Assert the comment has at least one meta set.
    +$I->seeCommentMetaInDatabase(['comment_ID' => $commentId]);
    +
    +

    seeInDatabase

    +

    Signature: seeInDatabase(string $table, [array $criteria]) : void

    +

    seeLinkInDatabase

    +

    Signature: seeLinkInDatabase(array $criteria) : void

    +

    Checks for a link in the links table of the database.

    +
    <?php
    +// Asserts a link exists by name.
    +$I->seeLinkInDatabase(['link_name' => 'my-link']);
    +// Asserts at least one link exists for the user.
    +$I->seeLinkInDatabase(['link_owner' => $userId]);
    +
    +

    seeNumRecords

    +

    Signature: seeNumRecords(int $expectedNumber, string $table, [array $criteria]) : void

    +

    Asserts that the given number of records were found in the database.

    +
    <?php
    +$I->seeNumRecords(1, 'users', ['name' => 'davert'])
    +
    +

    seeOptionInDatabase

    +

    Signature: seeOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    +

    Checks if an option is in the database for the current blog, either by criteria or by name and value.

    +

    If checking for an array or an object then the serialized version will be checked for.

    +
    <?php
    +// Checks an option is in the database.
    +$I->seeOptionInDatabase('tables_version');
    +// Checks an option is in the database and has a specific value.
    +$I->seeOptionInDatabase('tables_version', '1.0');
    +$I->seeOptionInDatabase(['option_name' => 'tables_version', 'option_value' => 1.0']);
    +
    +

    seePageInDatabase

    +

    Signature: seePageInDatabase(array $criteria) : void

    +

    Checks for a page in the database.

    +
    <?php
    +// Asserts a page with an exists in the database.
    +$I->seePageInDatabase(['ID' => 23]);
    +// Asserts a page with a slug and ID exists in the database.
    +$I->seePageInDatabase(['post_title' => 'Test Page', 'ID' => 23]);
    +
    +

    seePostInDatabase

    +

    Signature: seePostInDatabase(array $criteria) : void

    +

    Checks for a post in the database.

    +
    <?php
    +// Assert a post exists in the database.
    +$I->seePostInDatabase(['ID' => 23]);
    +// Assert a post with a slug and ID exists in the database.
    +$I->seePostInDatabase(['post_content' => 'test content', 'ID' => 23]);
    +
    +

    seePostMetaInDatabase

    +

    Signature: seePostMetaInDatabase(array $criteria) : void

    +

    Checks for a post meta value in the database for the current blog.

    +

    If the meta_value is an object or an array then the check will be made for serialized values.

    +
    <?php
    +$postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']];
    +$I->seePostMetaInDatabase(['post_id' => '$postId', 'meta_key' => 'foo']);
    +
    +

    seePostWithTermInDatabase

    +

    Signature: seePostWithTermInDatabase(int $post_id, int $term_taxonomy_id, [?int $term_order], [?string $taxonomy]) : void

    +

    Checks that a post to term relation exists in the database.

    +

    The method will check the "term_relationships" table.

    +
    <?php
    +$fiction = $I->haveTermInDatabase('fiction', 'genre');
    +$postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);
    +$I->seePostWithTermInDatabase($postId, $fiction['term_taxonomy_id']);
    +
    +

    seeSiteOptionInDatabase

    +

    Signature: seeSiteOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    +

    Checks that a site option is in the database.

    +
    <?php
    +// Check that the option is set in the database.
    +$I->seeSiteOptionInDatabase('foo_count');
    +// Check that the option is set and has a specific value.
    +$I->seeSiteOptionInDatabase('foo_count', 23);
    +
    +

    seeSiteSiteTransientInDatabase

    +

    Signature: seeSiteSiteTransientInDatabase(string $key, [mixed $value]) : void

    +

    Checks that a site option is in the database.

    +
    <?php
    +// Check a transient exists.
    +$I->seeSiteSiteTransientInDatabase('total_counts');
    +// Check a transient exists and has a specific value.
    +$I->seeSiteSiteTransientInDatabase('total_counts', 23);
    +
    +

    seeSiteTransientInDatabase

    +

    Signature: seeSiteTransientInDatabase(string $transient, [mixed $value]) : void

    +

    Checks that a site transient is in the database.

    +
    <?php
    +$I->haveSiteTransientInDatabase('foo', 23);
    +$I->seeSiteTransientInDatabase('foo');
    +$I->seeSiteTransientInDatabase('foo', 23);
    +
    +

    seeTableInDatabase

    +

    Signature: seeTableInDatabase(string $table) : void

    +

    Checks that a table is in the database.

    +
    <?php
    +$options = $I->grabPrefixedTableNameFor('options');
    +$I->seeTableInDatabase($options);
    +
    +

    seeTermInDatabase

    +

    Signature: seeTermInDatabase(array $criteria) : void

    +

    Checks for a term in the database. +Looks up the terms and term_taxonomy prefixed tables.

    +
    <?php
    +$I->seeTermInDatabase(['slug' => 'genre--fiction']);
    +$I->seeTermInDatabase(['name' => 'Fiction', 'slug' => 'genre--fiction']);
    +
    +

    seeTermMetaInDatabase

    +

    Signature: seeTermMetaInDatabase(array $criteria) : void

    +

    Checks for a term meta in the database.

    +
    <?php
    +list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
    +$I->haveTermMetaInDatabase($termId, 'rating', 4);
    +$I->seeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'rating', 'meta_value' => 4]);
    +
    +

    seeTermRelationshipInDatabase

    +

    Signature: seeTermRelationshipInDatabase(array $criteria) : void

    +

    Checks for a term relationship in the database.

    +
    <?php
    +$postId = $I->havePostInDatabase(['tax_input' => ['category' => 'one']]);
    +$I->seeTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $oneTermTaxId]);
    +
    +

    seeTermTaxonomyInDatabase

    +

    Signature: seeTermTaxonomyInDatabase(array $criteria) : void

    +

    Checks for a taxonomy taxonomy in the database.

    +
    <?php
    +list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
    +$I->seeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'genre']);
    +
    +

    seeTransientInDatabase

    +

    Signature: seeTransientInDatabase(string $name, [mixed $value]) : void

    +

    Checks that a transient is in the database.

    +
    <?php
    +$I->haveTransientInDatabase('foo', 23);
    +$I->seeTransientInDatabase('foo');
    +$I->seeTransientInDatabase('foo', 23);
    +
    +

    seeUserInDatabase

    +

    Signature: seeUserInDatabase(array $criteria) : void

    +

    Checks that a user is in the database.

    +

    The method will check the "users" table.

    +
    <?php
    +$I->seeUserInDatabase([
    +    "user_email" => "test@example.org",
    +    "user_login" => "login name"
    +])
    +
    +

    seeUserMetaInDatabase

    +

    Signature: seeUserMetaInDatabase(array $criteria) : void

    +

    Checks for a user meta value in the database.

    +
    <?php
    +$I->seeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);
    +
    +

    updateInDatabase

    +

    Signature: updateInDatabase(string $table, array $data, [array $criteria]) : void

    +

    Update an SQL record into a database.

    +
    <?php
    +$I->updateInDatabase('users', array('isAdmin' => true), array('email' => 'miles@davis.com'));
    +
    +

    useBlog

    +

    Signature: useBlog([int $blogId]) : void

    +

    Sets the blog to be used.

    +

    This has nothing to do with WordPress switch_to_blog function, this code will affect the table prefixes used.

    +

    useMainBlog

    +

    Signature: useMainBlog() : void

    +

    Sets the current blog to the main one (blog_id 1).

    +
    <?php
    +// Switch to the blog with ID 23.
    +$I->useBlog(23);
    +// Switch back to the main blog.
    +$I->useMainBlog();
    +
    +

    useTheme

    +

    Signature: useTheme(string $stylesheet, [?string $template], [?string $themeName]) : void

    +

    Sets the current theme options.

    +
    <?php
    +$I->useTheme('twentyseventeen');
    +$I->useTheme('child-of-twentyseventeen', 'twentyseventeen');
    +$I->useTheme('acme', 'acme', 'Acme Theme');
    +
    + + +

    Read more in Codeception documentation for the Db module.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPFilesystem/index.html b/modules/WPFilesystem/index.html new file mode 100644 index 000000000..c76cfe3de --- /dev/null +++ b/modules/WPFilesystem/index.html @@ -0,0 +1,4783 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPFilesystem - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    WPFilesystem

    + +

    WPFilesystem module

    +

    Interact and make assertions on the WordPress file structure.

    +

    This module is used together with the WPDb module to manage the state of the WordPress installation in the +context of end-to-end tests.

    +

    This module extends the Filesystem module from Codeception, you can reference to the Codeception documentation to +find out more about the module configuration and usage.

    +

    This module should be with Cest and Cept test cases.

    +

    Configuration

    +

    wpRootFolder - required; the path to the WordPress installation root folder. This can be a relative path to the +codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation +directory is the directory that contains the wp-load.php file. +themes - the path, relative to the path specified in the wpRootFolder parameter, to the themes directory. By +default, +it's /wp-content/themes. +plugins - the path, relative to the path specified in the wpRootFolder parameter, to the plugins directory. By +default, it's /wp-content/plugins. +mu-plugins - the path, relative to the path specified in the wpRootFolder parameter, to the must-use plugins. By +default, it's /wp-content/mu-plugins. directory. +uploads - the path, relative to the path specified in the wpRootFolder parameter, to the uploads directory. By +default, it's /wp-content/uploads.

    +

    The following is an example of the module configuration to run tests on the /var/wordpress site:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPFilesystem:
    +      wpRootFolder: /var/wordpress
    +      themes: wp-content/themes
    +      plugins: wp-content/plugins
    +      mu-plugins: wp-content/mu-plugins
    +      uploads: wp-content/uploads
    +
    +

    The following configuration uses dynamic configuration parameters to set the module configuration:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPFilesystem:
    +      wpRootFolder: '%WP_ROOT_FOLDER%'
    +
    +

    Methods

    +

    The module provides the following methods:

    + + +

    amInMuPluginPath

    +

    Signature: amInMuPluginPath(string $path) : void

    +

    Sets the current working folder to a folder in a mu-plugin.

    +
    $I->amInMuPluginPath('mu-plugin');
    +
    +

    amInPath

    +

    Signature: amInPath(string $path) : void

    +

    Enters a directory In local filesystem. +Project root directory is used by default

    +

    amInPluginPath

    +

    Signature: amInPluginPath(string $path) : void

    +

    Sets the current working folder to a folder in a plugin.

    +
    $I->amInPluginPath('my-plugin');
    +
    +

    amInThemePath

    +

    Signature: amInThemePath(string $path) : void

    +

    Sets the current working folder to a folder in a theme.

    +
    $I->amInThemePath('my-theme');
    +
    +

    amInUploadsPath

    +

    Signature: amInUploadsPath([?string $path]) : void

    +

    Enters, changing directory, to the uploads folder in the local filesystem.

    +
    <?php
    +$I->amInUploadsPath('/logs');
    +$I->seeFileFound('shop.log');
    +
    +

    assertDirectoryExists

    +

    Signature: assertDirectoryExists(string $directory, [string $message]) : void

    +

    cleanDir

    +

    Signature: cleanDir(string $dirname) : void

    +

    Erases directory contents

    +
    <?php
    +$I->cleanDir('logs');
    +
    +

    cleanMuPluginDir

    +

    Signature: cleanMuPluginDir(string $dir) : void

    +

    Cleans, emptying it, a folder in a mu-plugin folder.

    +
    $I->cleanMuPluginDir('mu-plugin1/foo');
    +
    +

    cleanPluginDir

    +

    Signature: cleanPluginDir(string $dir) : void

    +

    Cleans, emptying it, a folder in a plugin folder.

    +
    $I->cleanPluginDir('my-plugin/foo');
    +
    +

    cleanThemeDir

    +

    Signature: cleanThemeDir(string $dir) : void

    +

    Clears, emptying it, a folder in a theme folder.

    +
    $I->cleanThemeDir('my-theme/foo');
    +
    +

    cleanUploadsDir

    +

    Signature: cleanUploadsDir([?string $dir], [DateTime|string|int|null $date]) : void

    +

    Clears a folder in the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->cleanUploadsDir('some/folder');
    +$I->cleanUploadsDir('some/folder', 'today');
    +
    +

    copyDir

    +

    Signature: copyDir(string $src, string $dst) : void

    +

    Copies directory with all contents

    +
    <?php
    +$I->copyDir('vendor','old_vendor');
    +
    +

    copyDirToMuPlugin

    +

    Signature: copyDirToMuPlugin(string $src, string $pluginDst) : void

    +

    Copies a folder to a folder in a mu-plugin.

    +
    $I->copyDirToMuPlugin(codecept_data_dir('foo'), 'mu-plugin/foo');
    +
    +

    copyDirToPlugin

    +

    Signature: copyDirToPlugin(string $src, string $pluginDst) : void

    +

    Copies a folder to a folder in a plugin.

    +
    // Copy the 'foo' folder to the 'foo' folder in the plugin.
    +$I->copyDirToPlugin(codecept_data_dir('foo'), 'my-plugin/foo');
    +
    +

    copyDirToTheme

    +

    Signature: copyDirToTheme(string $src, string $themeDst) : void

    +

    Copies a folder in a theme folder.

    +
    $I->copyDirToTheme(codecept_data_dir('foo'), 'my-theme');
    +
    +

    copyDirToUploads

    +

    Signature: copyDirToUploads(string $src, string $dst, [DateTime|string|int|null $date]) : void

    +

    Copies a folder to the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo');
    +$I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo', 'today');
    +
    +

    deleteDir

    +

    Signature: deleteDir(string $dirname) : void

    +

    Deletes directory with all subdirectories

    +
    <?php
    +$I->deleteDir('vendor');
    +
    +

    deleteFile

    +

    Signature: deleteFile(string $filename) : void

    +

    Deletes a file

    +
    <?php
    +$I->deleteFile('composer.lock');
    +
    +

    deleteMuPluginFile

    +

    Signature: deleteMuPluginFile(string $file) : void

    +

    Deletes a file in a mu-plugin folder.

    +
    $I->deleteMuPluginFile('mu-plugin1/some-file.txt');
    +
    +

    deletePluginFile

    +

    Signature: deletePluginFile(string $file) : void

    +

    Deletes a file in a plugin folder.

    +
    $I->deletePluginFile('my-plugin/some-file.txt');
    +
    +

    deleteThemeFile

    +

    Signature: deleteThemeFile(string $file) : void

    +

    Deletes a file in a theme folder.

    +
    $I->deleteThemeFile('my-theme/some-file.txt');
    +
    +

    deleteThisFile

    +

    Signature: deleteThisFile() : void

    +

    Deletes a file

    +

    deleteUploadedDir

    +

    Signature: deleteUploadedDir(string $dir, [DateTime|string|int|null $date]) : void

    +

    Deletes a dir in the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->deleteUploadedDir('folder');
    +$I->deleteUploadedDir('folder', 'today');
    +
    +

    deleteUploadedFile

    +

    Signature: deleteUploadedFile(string $file, [string|int|null $date]) : void

    +

    Deletes a file in the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->deleteUploadedFile('some-file.txt');
    +$I->deleteUploadedFile('some-file.txt', 'today');
    +
    +

    dontSeeFileFound

    +

    Signature: dontSeeFileFound(string $filename, [string $path]) : void

    +

    Checks if file does not exist in path

    +

    dontSeeInMuPluginFile

    +

    Signature: dontSeeInMuPluginFile(string $file, string $contents) : void

    +

    Checks that a file in a mu-plugin folder does not contain a string.

    +
    $I->dontSeeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');
    +
    +

    dontSeeInPluginFile

    +

    Signature: dontSeeInPluginFile(string $file, string $contents) : void

    +

    Checks that a file in a plugin folder does not contain a string.

    +
    $I->dontSeeInPluginFile('my-plugin/some-file.txt', 'foo');
    +
    +

    dontSeeInThemeFile

    +

    Signature: dontSeeInThemeFile(string $file, string $contents) : void

    +

    Checks that a file in a theme folder does not contain a string.

    +
    $I->dontSeeInThemeFile('my-theme/some-file.txt', 'foo');
    +
    +

    dontSeeInThisFile

    +

    Signature: dontSeeInThisFile(string $text) : void

    +

    Checks If opened file doesn't contain text in it

    +
    <?php
    +$I->openFile('composer.json');
    +$I->dontSeeInThisFile('codeception/codeception');
    +
    +

    dontSeeInUploadedFile

    +

    Signature: dontSeeInUploadedFile(string $file, string $contents, [string|int|null $date]) : void

    +

    Checks that a file in the uploads folder does contain a string.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    <?php
    +$I->dontSeeInUploadedFile('some-file.txt', 'foo');
    +$I->dontSeeInUploadedFile('some-file.txt','foo', 'today');
    +
    +

    dontSeeMuPluginFileFound

    +

    Signature: dontSeeMuPluginFileFound(string $file) : void

    +

    Checks that a file is not found in a mu-plugin folder.

    +
    $I->dontSeeMuPluginFileFound('mu-plugin1/some-file.txt');
    +
    +

    dontSeePluginFileFound

    +

    Signature: dontSeePluginFileFound(string $file) : void

    +

    Checks that a file is not found in a plugin folder.

    +
    $I->dontSeePluginFileFound('my-plugin/some-file.txt');
    +
    +

    dontSeeThemeFileFound

    +

    Signature: dontSeeThemeFileFound(string $file) : void

    +

    Checks that a file is not found in a theme folder.

    +
    $I->dontSeeThemeFileFound('my-theme/some-file.txt');
    +
    +

    dontSeeUploadedFileFound

    +

    Signature: dontSeeUploadedFileFound(string $file, [string|int|null $date]) : void

    +

    Checks thata a file does not exist in the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->dontSeeUploadedFileFound('some-file.txt');
    +$I->dontSeeUploadedFileFound('some-file.txt','today');
    +
    +

    getBlogUploadsPath

    +

    Signature: getBlogUploadsPath(int $blogId, [string $file], [DateTimeImmutable|DateTime|string|null $date]) : string

    +

    Returns the absolute path to a blog uploads folder or file.

    +
    <?php
    +$blogId = $I->haveBlogInDatabase('test');
    +$testTodayUploads = $I->getBlogUploadsPath($blogId);
    +$testLastMonthLogs = $I->getBlogUploadsPath($blogId, '/logs', '-1 month');
    +
    +

    getUploadsPath

    +

    Signature: getUploadsPath([string $file], [mixed $date]) : string

    +

    Returns the path to the specified uploads file of folder.

    +

    Not providing a value for $file and $date will return the uploads folder path.

    +
    <?php
    +$todaysPath = $I->getUploadsPath();
    +$lastWeek = $I->getUploadsPath('', '-1 week');
    +
    +

    getWpRootFolder

    +

    Signature: getWpRootFolder() : string

    +

    Returns the absolute path to WordPress root folder without trailing slash.

    +
    <?php
    +$rootFolder = $I->getWpRootFolder();
    +$I->assertFileExists($rootFolder . 'wp-load.php');
    +
    +

    haveMuPlugin

    +

    Signature: haveMuPlugin(string $filename, string $code) : void

    +

    Creates a mu-plugin file, including plugin header, in the mu-plugins folder.

    +

    The code can not contain the opening '<?php' tag.

    +
    $code = 'echo "Hello world!"';
    +$I->haveMuPlugin('foo-mu-plugin.php', $code);
    +// Load the code from a file.
    +$code = file_get_contents(codecept_data_dir('code/mu-plugin.php'));
    +$I->haveMuPlugin('foo-mu-plugin.php', $code);
    +
    +

    havePlugin

    +

    Signature: havePlugin(string $path, string $code) : void

    +

    Creates a plugin file, including plugin header, in the plugins folder.

    +

    The plugin is just created and not activated; the code can not contain the opening '<?php' tag.

    +
    $code = 'echo "Hello world!"';
    +$I->havePlugin('foo/plugin.php', $code);
    +// Load the code from a file.
    +$code = file_get_contents(codecept_data_dir('code/plugin.php'));
    +$I->havePlugin('foo/plugin.php', $code);
    +
    +

    haveTheme

    +

    Signature: haveTheme(string $folder, string $indexFileCode, [string $functionsFileCode]) : void

    +

    Creates a theme file structure, including theme style file and index, in the themes folder.

    +

    The theme is just created and not activated; the code can not contain the opening '<?php' tag.

    +
    $code = 'sayHi();';
    +$functionsCode  = 'function sayHi(){echo "Hello world";};';
    +$I->haveTheme('foo', $indexCode, $functionsCode);
    +// Load the code from a file.
    +$indexCode = file_get_contents(codecept_data_dir('code/index.php'));
    +$functionsCode = file_get_contents(codecept_data_dir('code/functions.php'));
    +$I->haveTheme('foo', $indexCode, $functionsCode);
    +
    +

    makeUploadsDir

    +

    Signature: makeUploadsDir(string $path) : string

    +

    Creates an empty folder in the WordPress installation uploads folder.

    +
    <?php
    +$logsDir = $I->makeUploadsDir('logs/acme');
    +
    +

    openFile

    +

    Signature: openFile(string $filename) : void

    +

    Opens a file and stores it's content.

    +

    Usage:

    +
    <?php
    +$I->openFile('composer.json');
    +$I->seeInThisFile('codeception/codeception');
    +
    +

    openUploadedFile

    +

    Signature: openUploadedFile(string $filename, [DateTime|string|int|null $date]) : void

    +

    Opens a file in the the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->openUploadedFile('some-file.txt');
    +$I->openUploadedFile('some-file.txt', 'time');
    +
    +

    seeFileContentsEqual

    +

    Signature: seeFileContentsEqual(string $text) : void

    +

    Checks the strict matching of file contents. +Unlike seeInThisFile will fail if file has something more than expected lines. +Better to use with HEREDOC strings. +Matching is done after removing "\r" chars from file content.

    +
    <?php
    +$I->openFile('process.pid');
    +$I->seeFileContentsEqual('3192');
    +
    +

    seeFileFound

    +

    Signature: seeFileFound(string $filename, [string $path]) : void

    +

    Checks if file exists in path. +Opens a file when it's exists

    +
    <?php
    +$I->seeFileFound('UserModel.php','app/models');
    +
    +

    seeInMuPluginFile

    +

    Signature: seeInMuPluginFile(string $file, string $contents) : void

    +

    Checks that a file in a mu-plugin folder contains a string.

    +
    $I->seeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');
    +
    +

    seeInPluginFile

    +

    Signature: seeInPluginFile(string $file, string $contents) : void

    +

    Checks that a file in a plugin folder contains a string.

    +
    $I->seeInPluginFile('my-plugin/some-file.txt', 'foo');
    +
    +

    seeInThemeFile

    +

    Signature: seeInThemeFile(string $file, string $contents) : void

    +

    Checks that a file in a theme folder contains a string.

    +
    <?php
    +$I->seeInThemeFile('my-theme/some-file.txt', 'foo');
    +?>
    +
    +

    seeInThisFile

    +

    Signature: seeInThisFile(string $text) : void

    +

    Checks If opened file has text in it.

    +

    Usage:

    +
    <?php
    +$I->openFile('composer.json');
    +$I->seeInThisFile('codeception/codeception');
    +
    +

    seeInUploadedFile

    +

    Signature: seeInUploadedFile(string $file, string $contents, [string|int|null $date]) : void

    +

    Checks that a file in the uploads folder contains a string.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    <?php
    +$I->seeInUploadedFile('some-file.txt', 'foo');
    +$I->seeInUploadedFile('some-file.txt','foo', 'today');
    +
    +

    seeMuPluginFileFound

    +

    Signature: seeMuPluginFileFound(string $file) : void

    +

    Checks that a file is found in a mu-plugin folder.

    +
    $I->seeMuPluginFileFound('mu-plugin1/some-file.txt');
    +
    +

    seeNumberNewLines

    +

    Signature: seeNumberNewLines(int $number) : void

    +

    Checks If opened file has the number of new lines.

    +

    Usage:

    +
    <?php
    +$I->openFile('composer.json');
    +$I->seeNumberNewLines(5);
    +
    +

    seePluginFileFound

    +

    Signature: seePluginFileFound(string $file) : void

    +

    Checks that a file is found in a plugin folder.

    +
    $I->seePluginFileFound('my-plugin/some-file.txt');
    +
    +

    seeThemeFileFound

    +

    Signature: seeThemeFileFound(string $file) : void

    +

    Checks that a file is found in a theme folder.

    +
    $I->seeThemeFileFound('my-theme/some-file.txt');
    +
    +

    seeThisFileMatches

    +

    Signature: seeThisFileMatches(string $regex) : void

    +

    Checks that contents of currently opened file matches $regex

    +

    seeUploadedFileFound

    +

    Signature: seeUploadedFileFound(string $filename, [string|int|null $date]) : void

    +

    Checks if file exists in the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    <?php
    +$I->seeUploadedFileFound('some-file.txt');
    +$I->seeUploadedFileFound('some-file.txt','today');
    +?>
    +
    +

    writeToFile

    +

    Signature: writeToFile(string $filename, string $contents) : void

    +

    Saves contents to file

    +

    writeToMuPluginFile

    +

    Signature: writeToMuPluginFile(string $file, string $data) : void

    +

    Writes a file in a mu-plugin folder.

    +
    $I->writeToMuPluginFile('mu-plugin1/some-file.txt', 'foo');
    +
    +

    writeToPluginFile

    +

    Signature: writeToPluginFile(string $file, string $data) : void

    +

    Writes a file in a plugin folder.

    +
    $I->writeToPluginFile('my-plugin/some-file.txt', 'foo');
    +
    +

    writeToThemeFile

    +

    Signature: writeToThemeFile(string $file, string $data) : void

    +

    Writes a string to a file in a theme folder.

    +
    $I->writeToThemeFile('my-theme/some-file.txt', 'foo');
    +
    +

    writeToUploadedFile

    +

    Signature: writeToUploadedFile(string $filename, string $data, [DateTime|string|int|null $date]) : string

    +

    Writes a string to a file in the the uploads folder.

    +

    The date argument can be a string compatible with strtotime or a Unix +timestamp that will be used to build the Y/m uploads subfolder path.

    +
    $I->writeToUploadedFile('some-file.txt', 'foo bar');
    +$I->writeToUploadedFile('some-file.txt', 'foo bar', 'today');
    +
    + + +

    Read more in Codeception documentation.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPLoader/index.html b/modules/WPLoader/index.html new file mode 100644 index 000000000..d848471e8 --- /dev/null +++ b/modules/WPLoader/index.html @@ -0,0 +1,3574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPLoader - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + + + + +

    WPLoader

    + +

    WPLoader module

    +

    A module to load WordPress and make its code available in tests.

    +

    Depending on the value of the loadOnly configuration parameter, the module will behave differently:

    +
      +
    • loadOnly: false - The module will load WordPress like the Core PHPUnit suite does to run integration tests in a + controlled environment. Use the module in this mode with test cases generated + using the generate:wpunit command.
    • +
    • loadOnly: true - The module will load WordPress to make it available in the context of tests. Use the module in this + mode in Cest, Cept and Codeception unit test cases.
    • +
    +

    Configuration with loadOnly: false

    +

    The module will load WordPress like the Core PHPUnit suite does to run integration tests in a controlled +environment.
    +Together with the test case generated by the generate:wpunit command the module +will:

    +
      +
    • take care of running any test method in a database transaction rolled back after each test
    • +
    • manage and clean up the global environment and context between tests
    • +
    +
    +

    Note

    +

    The module will set the environment variable WPBROWSER_LOAD_ONLY=0 when running in this mode. This environment variable +can be used to detect whether WordPress is being loaded by WPBrowser and in which mode.

    +
    +

    When used in this mode, the module supports the following configuration parameters:

    +
      +
    • loadOnly - false to load WordPress and run tests in a controlled environment.
    • +
    • wpRootFolder - required; the path to the WordPress installation root folder. This can be a relative path to the + codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation + directory is the directory that contains the wp-load.php file.
    • +
    • dbUrl - required; the URL to the database to use to run tests. The URL must be in the form + mysql://username:password@host:port/database to use a MySQL database, or in the form sqlite://path/to/database to + use a SQLite database. Alternatively, you can use the dbName, dbUser, dbPassword, dbHost configuration + parameters to specify the database connection details.
    • +
    • dump - the path to a database dump, or a set of database dumps, to load before running tests. The dump will be + loaded only once, after the tests run.
    • +
    • tablePrefix - the database table prefix to use when loading WordPress, defaults to wp_.
    • +
    • multisite - a boolean value to indicate if WordPress should be loaded and initialized in multisite mode.
    • +
    • dbCharset - the database charset to use when loading WordPress.
    • +
    • dbCollate - the database collate to use when loading WordPress.
    • +
    • domain - the domain to use when loading WordPress. Equivalent to defining the WP_TESTS_DOMAIN constant.
    • +
    • adminEmail - the administrator email to use when loading WordPress. Equivalent to defining the WP_TESTS_EMAIL + constant.
    • +
    • title - the site title to use when loading WordPress. Equivalent to defining the WP_TESTS_TITLE constant.
    • +
    • phpBinary - the path to the PHP binary to use to run tests. Defaults to the WP_PHP_BINARY constant.
    • +
    • language - the language to use when loading WordPress. Equivalent to defining the WPLANG constant.
    • +
    • configFile - a configuration file, or a set of configuration files, to load before the tests to further customize + and control the WordPress testing environment. This file(s) will be loaded before the WordPress installation is loaded.
    • +
    • pluginsFolder - the path to the plugins folder to use when loading WordPress. Equivalent to defining the + WP_PLUGIN_DIR constant. If both this parameter and the WP_PLUGIN_DIR parameter are set, the WP_PLUGIN_DIR + parameter will override the value of this one.
    • +
    • WP_CONTENT_DIR - the path to the content folder to use when loading WordPress in the context of tests. If the + installation used by the WPLoader module defines a WP_CONTENT_DIR constant in its wp-config.php file, the module + will throw an exception if this parameter is set. Setting this parameter will affect the WP_PLUGIN_DIR and the WPMU_PLUGIN_DIR + parameters.
    • +
    • WP_PLUGIN_DIR - the path to the plugins folder to use when loading WordPress in the context of tests. If the + installation used by the WPLoader module defines a WP_PLUGIN_DIR constant in its wp-config.php file, the module + will throw an exception if this parameter is set.
    • +
    • WPMU_PLUGIN_DIR - the path to the mu-plugins folder to use when loading WordPress in the context of tests. If the + installation used by the WPLoader module defines a WPMU_PLUGIN_DIR constant in its wp-config.php file, the module + will throw an exception if this parameter is set.
    • +
    • plugins - a list of plugins to activate and load in the WordPress installation. If the plugin is located in the + WordPress installation plugins directory, then the plugin name can be specified using the directory/file.php format. + If the plugin is located in an arbitrary path inside or outiside of the WordPress installation or project, then the + plugin name must be specified either as an absolute path or as a relative path to the project root folder.
    • +
    • silentlyActivatePlugins - a list of plugins to activate silently, without firing their activation hooks. + Depending on the plugin, a silent activation might cause the plugin to not work correctly. The list must be in the + same format as the plugins parameter and plugin should be activated silently only if they are not working correctly + during normal activation and are known to work correctly when activated silently. Plugin paths can be specified + following the same format of the plugins parameter.
    • +
    • bootstrapActions - a list of actions or callables to call after WordPress is loaded and before the tests run.
    • +
    • theme - the theme to activate and load in the WordPress installation. The theme can be specified in slug format, + e.g., twentytwentythree, to load it from the WordPress installation themes directory. Alternatively, the theme can + be specified as an absolute or relative path to a theme folder, e.g., /home/themes/my-theme + or vendor/acme/vendor-theme. To use both a parent and ha child theme from arbitrary absolute or relative paths, + define the theme parameter as an array of theme paths, e.g., ['/home/themes/parent-theme', '.'].
    • +
    • AUTH_KEY - the AUTH_KEY constant value to use when loading WordPress. If the wpRootFolder path points at a + configured installation, containing the wp-config.php file, then the value of the constant in the configuration file + will be used, else it will be randomly generated.
    • +
    • SECURE_AUTH_KEY - the SECURE_AUTH_KEY constant value to use when loading WordPress. If the wpRootFolder path + points at a configured installation, containing the wp-config.php file, then the value of the constant in the + configuration file will be used, else it will be randomly generated.
    • +
    • LOGGED_IN_KEY - the LOGGED_IN_KEY constant value to use when loading WordPress. If the wpRootFolder path points + at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration + file will be used, else it will be randomly generated.
    • +
    • NONCE_KEY - the NONCE_KEY constant value to use when loading WordPress. If the wpRootFolder path points at a + configured installation, containing the wp-config.php file, then the value of the constant in the configuration file + will be used, else it will be randomly generated.
    • +
    • AUTH_SALT - the AUTH_SALT constant value to use when loading WordPress. If the wpRootFolder path points at a + configured installation, containing the wp-config.php file, then the value of the constant in the configuration file + will be used, else it will be randomly generated.
    • +
    • SECURE_AUTH_SALT - the SECURE_AUTH_SALT constant value to use when loading WordPress. If the wpRootFolder path + points at a configured installation, containing the wp-config.php file, then the value of the constant in the + configuration file will be used, else it will be randomly generated.
    • +
    • LOGGED_IN_SALT - the LOGGED_IN_SALT constant value to use when loading WordPress. If the wpRootFolder path + points at a configured installation, containing the wp-config.php file, then the value of the constant in the + configuration file will be used, else it will be randomly generated.
    • +
    • NONCE_SALT - the NONCE_SALT constant value to use when loading WordPress. If the wpRootFolder path points at a + configured installation, containing the wp-config.php file, then the value of the constant in the configuration file + will be used, else it will be randomly generated.
    • +
    • AUTOMATIC_UPDATER_DISABLED - the AUTOMATIC_UPDATER_DISABLED constant value to use when loading WordPress. If + the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of + the constant in the configuration file will be used, else it will be randomly generated.
    • +
    • WP_HTTP_BLOCK_EXTERNAL - the WP_HTTP_BLOCK_EXTERNAL constant value to use when loading WordPress. If + the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of + the constant in the configuration file will be used, else it will be randomly generated.
    • +
    • backupGlobals - a boolean value to indicate if the global environment should be backed up before each test. Defaults + to true. The globals' backup involves serialization of the global state, plugins or themes that define classes + developed to prevent serialization of the global state will cause the tests to fail. Set this parameter to false to + disable the global environment backup, or use a more refined approach setting the backupGlobalsExcludeList parameter + below. Note that a test case that is explicitly setting the backupGlobals property will override this configuration + parameter.
    • +
    • backupGlobalsExcludeList - a list of global variables to exclude from the global environment backup. The list must + be in the form of array, and it will be merged to the list of globals excluded by default.
    • +
    • backupStaticAttributes - a boolean value to indicate if static attributes of classes should be backed up before each + test. Defaults to true. The static attributes' backup involves serialization of the global state, plugins or themes + that define classes developed to prevent serialization of the global state will cause the tests to fail. Set this + parameter to false to disable the static attributes backup, or use a more refined approanch setting + the backupStaticAttributesExcludeList parameter below. Note that a test case that is explicitly setting + the backupStaticAttributes property will override this configuration parameter.
    • +
    • backupStaticAttributesExcludeList - a list of classes to exclude from the static attributes backup. The list must be + in the form of map from class names to the array of method names to exclude from the backup. See an example below.
    • +
    • skipInstall - a boolean value to indicate if the WordPress installation should be skipped between runs, when already + installed. Defaults to false. During boot, the WPLoader module will re-install WordPress and activate, on top of + the fresh installation, any plugin and theme specified in the plugins and theme configuration parameters: this can + be a time-consuming operation. Set this parameter to true to run the WordPress installation once and just load it on + the following runs. To force the installation to run again, rerun the suite using the WPLoader module using + the --debug flag or delete the _wploader-state.sql file in the suite directory. This configuration parameter is + ignored when the loadOnly parameter is set to true.
    • +
    • beStrictAboutWpdbConnectionId - a boolean value to indicate if the WPTestCase class should throw an exception if + the database connection is closed during any setUpBeforeClass method; default is true.
    • +
    +

    This is an example of an integration suite configured to use the module:

    +
    actor: IntegrationTester
    +bootstrap: _bootstrap.php
    +modules:
    +  enabled:
    +    - \Helper\Integration
    +    - lucatume\WPBrowser\Module\WPLoader:
    +        wpRootFolder: /var/wordpress
    +        dbUrl: mysql://root:root@mysql:3306/wordpress
    +        tablePrefix: test_
    +        domain: wordpress.test
    +        adminEmail: admin@wordpress.test
    +        title: 'Integration Tests'
    +        plugins:
    +          # This plugin will be loaded from the WordPress installation plugins directory.
    +          - hello.php
    +          # This plugin will be loaded from an arbitrary absolute path.
    +          - /home/plugins/woocommerce/woocommerce.php
    +          # This plugin will be loaded from an arbitrary relative path inside the project root folder.
    +          - vendor/acme/project/plugin.php
    +          # This plugin will be loaded from the project root folder.
    +          - my-plugin.php
    +        theme: twentytwentythree # Load the theme from the WordPress installation themes directory.
    +
    +

    The following configuration uses dynamic configuration parameters to set the module configuration:

    +
    actor: IntegrationTester
    +bootstrap: _bootstrap.php
    +modules:
    +  enabled:
    +    - \Helper\Integration
    +    - lucatume\WPBrowser\Module\WPLoader:
    +        wpRootFolder: '%WP_ROOT_FOLDER%'
    +        dbUrl: '%WP_DB_URL%'
    +        tablePrefix: '%WP_TABLE_PREFIX%'
    +        domain: '%WP_DOMAIN%'
    +        adminEmail: '%WP_ADMIN_EMAIL%'
    +        title: '%WP_TITLE%'
    +        plugins:
    +          - hello.php
    +          - /home/plugins/woocommerce/woocommerce.php
    +          - my-plugin.php
    +          - vendor/acme/project/plugin.php
    +        # Parent theme from the WordPress installation themes directory, child theme from absolute path.
    +        theme: [ twentytwentythree, /home/themes/my-theme ]
    +
    +

    The following example configuration uses a SQLite database and loads a database fixture before the tests run:

    +
    actor: IntegrationTester
    +bootstrap: _bootstrap.php
    +modules:
    +  enabled:
    +    - \Helper\Integration
    +    - lucatume\WPBrowser\Module\WPLoader:
    +        wpRootFolder: /var/wordpress
    +        dbUrl: sqlite:///var/wordpress/wp-tests.sqlite
    +        dump:
    +          - tests/_data/products.sql
    +          - tests/_data/users.sql
    +          - tests/_data/orders.sql
    +        tablePrefix: test_
    +        domain: wordpress.test
    +        adminEmail: admin@wordpress.test
    +        title: 'Integration Tests'
    +        plugins:
    +          - hello.php
    +          - woocommerce/woocommerce.php
    +          - my-plugin/my-plugin.php
    +        theme:
    +          # Parent theme from relative path.
    +          - vendor/acme/parent-theme
    +          # Child theme from the current working directory.
    +          - .
    +
    +

    The follow example configuration prevents the backup of globals and static attributes in all the tests of the suite that +are not explicitly overriding the backupGlobals and backupStaticAttributes properties:

    +
    actor: IntegrationTester
    +bootstrap: _bootstrap.php
    +modules:
    +  enabled:
    +    - \Helper\Integration
    +    - lucatume\WPBrowser\Module\WPLoader:
    +        wpRootFolder: /var/wordpress
    +        dbUrl: sqlite:///var/wordpress/wp-tests.sqlite
    +        dump:
    +          - tests/_data/products.sql
    +          - tests/_data/users.sql
    +          - tests/_data/orders.sql
    +        tablePrefix: test_
    +        domain: wordpress.test
    +        adminEmail: admin@wordpress.test
    +        title: 'Integration Tests'
    +        plugins:
    +          - hello.php
    +          - woocommerce/woocommerce.php
    +          - my-plugin/my-plugin.php
    +        theme: twentytwentythree
    +        backupGlobals: false
    +        backupStaticAttributes: false 
    +
    +

    The following configuration prevents the backup of some globals and static attributes:

    +
    actor: IntegrationTester
    +bootstrap: _bootstrap.php
    +modules:
    +  enabled:
    +    - \Helper\Integration
    +    - lucatume\WPBrowser\Module\WPLoader:
    +        wpRootFolder: /var/wordpress
    +        dbUrl: sqlite:///var/wordpress/wp-tests.sqlite
    +        dump:
    +          - tests/_data/products.sql
    +          - tests/_data/users.sql
    +          - tests/_data/orders.sql
    +        tablePrefix: test_
    +        domain: wordpress.test
    +        adminEmail: admin@wordpress.test
    +        title: 'Integration Tests'
    +        plugins:
    +          - hello.php
    +          - woocommerce/woocommerce.php
    +          - my-plugin/my-plugin.php
    +        theme: twentytwentythree
    +        backupGlobalsExcludeList:
    +          - my_plugin_will_explode_on_wakeup
    +          - another_problematic_global
    +        backupStaticAttributesExcludeList:
    +          - MyPlugin\MyClass:
    +              - instance
    +              - anotherStaticAttributeThatWillExplodeOnWakeup
    +          - AnotherPlugin\AnotherClass:
    +              - instance
    +              - yetAnotherStaticAttributeThatWillExplodeOnWakeup
    +
    +

    Handling a custom site structure

    +

    The setup process should just work for standard and non-standard WordPress installations alike.

    +

    Even if you're working on a site project using a custom file structure, e.g. Bedrock, you will be able to set up +your site to run tests using the default configuration based on PHP built-in server, Chromedriver and SQLite database.

    +

    Configuration with loadOnly: true

    +

    The module will load WordPress from the location specified by the wpRootFolder parameter, relying +on the WPDb module to manage the database state.

    +
    +

    Note

    +

    The module will set the environment variable WPBROWSER_LOAD_ONLY=1 when running in this mode. This environment variable +can be used to detect whether WordPress is being loaded by WPBrowser and in which mode.

    +
    +

    When used in this mode, the module supports the following configuration parameters:

    +
      +
    • loadOnly - true to load WordPress and make it available in the context of tests.
    • +
    • wpRootFolder - required; the path to the WordPress installation root folder. This can be a relative path to the + codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation + directory is the directory that contains the wp-load.php file.
    • +
    • dbUrl - required; the URL to the database to use to run tests. The URL must be in the form + mysql://username:password@host:port/database to use a MySQL database, or in the form sqlite://path/to/database to + use a SQLite database. Alternatively, you can use the dbName, dbUser, dbPassword, dbHost configuration + parameters to specify the database connection details.
    • +
    • domain - the domain to use when loading WordPress. Equivalent to defining the WP_TESTS_DOMAIN constant.
    • +
    • configFile - a configuration file, or a set of configuration files, to load before the tests to further customize + and control the WordPress testing environment. This file(s) will be loaded before the WordPress installation is loaded.
    • +
    +
    +

    Warning

    +

    The module will define the DB_NAME, DB_USER, DB_PASSWORD and DB_HOST constants in the context of loading WordPress. +This is done to allow the WordPress database connection to be configured using the dbUrl configuration parameter. +The module will silence the warnings about the redeclaration of these constants, but in some cases with stricter error +checking (e.g. Bedrock) this may not be enough. In those cases, you can use the WPBROWSER_LOAD_ONLY environment +variable to detect whether WordPress is being loaded by WPBrowser and in which mode and configured your installation +accordingly.

    +
    +

    The following is an example of the module configuration to run end-to-end tests on the site served +at http://localhost:8080 URL and served from the /var/wordpress directory:

    +
    actor: EndToEndTester
    +bootstrap: _bootstrap.php
    +modules:
    +  enabled:
    +    - \Helper\Integration
    +    - lucatume\WPBrowser\Module\WPWebDriver:
    +        url: 'http://localhost:8080'
    +        adminUsername: 'admin'
    +        adminPassword: 'password'
    +        adminPath: '/wp-admin'
    +        browser: chrome
    +        host: 'localhost'
    +        port: '4444'
    +        path: '/'
    +        window_size: false
    +        capabilities:
    +          "goog:chromeOptions":
    +            args:
    +              - "--headless"
    +              - "--disable-gpu"
    +              - "--disable-dev-shm-usage"
    +              - "--proxy-server='direct://'"
    +              - "--proxy-bypass-list=*"
    +              - "--no-sandbox"
    +    - lucatume\WPBrowser\Module\WPDb:
    +        dbUrl: 'mysql://root:password@localhost:3306/wordpress'
    +        url: 'http://localhost:8080'
    +        tablePrefix: 'wp_'
    +        dump: 'tests/_data/dump.sql'
    +        populate: true
    +        cleanup: true
    +        reconnect: false
    +        urlReplacement: true
    +        originalUrl: http://wordpress.test
    +        waitlock: 10
    +        createIfNotExists: true
    +    - lucatume\WPBrowser\Module\WPLoader:
    +        loadOnly: true
    +        wpRootFolder: /var/wordpress
    +        dbUrl: 'mysql://root:password@localhost:3306/wordpress'
    +        domain: wordpress.test
    +
    +

    Methods

    +

    The module provides the following methods:

    + + +

    factory

    +

    Signature: factory() : lucatume\WPBrowser\Module\WPLoader\FactoryStore

    +

    Accessor method to get the object storing the factories for things. +This method gives access to the same factories provided by the +Core test suite.

    +

    getContentFolder

    +

    Signature: getContentFolder([string $path]) : string

    +

    Returns the absolute path to the WordPress content directory.

    +

    getInstallation

    +

    Signature: getInstallation() : lucatume\WPBrowser\WordPress\Installation

    +

    getPluginsFolder

    +

    Signature: getPluginsFolder([string $path]) : string

    +

    Returns the absolute path to the plugins directory.

    +

    The value will first look at the WP_PLUGIN_DIR constant, then the pluginsFolder configuration parameter +and will, finally, look in the default path from the WordPress root directory.

    +

    getThemesFolder

    +

    Signature: getThemesFolder([string $path]) : string

    +

    Returns the absolute path to the themes directory.

    +

    getWpRootFolder

    +

    Signature: getWpRootFolder([?string $path]) : string

    +

    Returns the absolute path to the WordPress root folder or a path within it..

    + + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPQueries/index.html b/modules/WPQueries/index.html new file mode 100644 index 000000000..c7b61eb7e --- /dev/null +++ b/modules/WPQueries/index.html @@ -0,0 +1,4104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPQueries - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    WPQueries

    + +

    WPQueries module

    +

    This module provides assertions for WordPress queries.

    +

    This module can be used in any test context where the global $wpdb variable is defined, this usually means in any +suite where the WPLoader module is used.

    +

    Configuration

    +

    The method does not require configuration.

    +

    Methods

    +

    The module provides the following methods:

    + + +

    assertCountQueries

    +

    Signature: assertCountQueries(int $n, [string $message]) : void

    +

    Asserts that n queries have been made.

    +
    <?php
    +$posts = $this->factory()->post->create_many(3);
    +$cachedUsers = $this->factory()->user->create_many(2);
    +$nonCachedUsers = $this->factory()->user->create_many(2);
    +foreach($cachedUsers as $userId){
    +     wp_cache_set('page-posts-for-user-' . $userId, $posts, 'acme');
    +}
    +// Run the same query as different users
    +foreach(array_merge($cachedUsers, $nonCachedUsers) as $userId){
    +     $pagePosts = $plugin->getPagePostsForUser($userId);
    +}
    +$I->assertCountQueries(2, 'A query should be made for each user missing cached posts.')
    +
    +

    assertNotQueries

    +

    Signature: assertNotQueries([string $message]) : void

    +

    Asserts that no queries were made.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$posts = $this->factory()->post->create_many(3);
    +wp_cache_set('page-posts', $posts, 'acme');
    +$pagePosts = $plugin->getPagePosts();
    +$I->assertNotQueries('Queries should not be made if the cache is set.')
    +
    +

    assertNotQueriesByAction

    +

    Signature: assertNotQueriesByAction(string $action, [string $message]) : void

    +

    Asserts that no queries were made as a consequence of the specified action.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_action( 'edit_post', function($postId){
    +        $count = get_option('acme_title_updates_count');
    +        update_option('acme_title_updates_count', ++$count);
    +} );
    +wp_delete_post($bookId);
    +$this->assertNotQueriesByAction('edit_post');
    +
    +

    assertNotQueriesByFilter

    +

    Signature: assertNotQueriesByFilter(string $filter, [string $message]) : void

    +

    Asserts that no queries were made as a consequence of the specified filter.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_filter('the_title', function($title, $postId){
    +     $post = get_post($postId);
    +     if($post->post_type !== 'book'){
    +         return $title;
    +     }
    +     $new = get_option('acme_new_prefix');
    +     return "{$new} - " . $title;
    +});
    +$title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);
    +$this->assertNotQueriesByFilter('the_title');
    +
    +

    assertNotQueriesByFunction

    +

    Signature: assertNotQueriesByFunction(string $function, [string $message]) : void

    +

    Asserts that no queries were made by the specified function.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$this->assertEmpty(Acme\get_orphaned_posts());
    +Acme\delete_orphaned_posts();
    +$this->assertNotQueriesByFunction('Acme\delete_orphaned_posts');
    +
    +

    assertNotQueriesByMethod

    +

    Signature: assertNotQueriesByMethod(string $class, string $method, [string $message]) : void

    +

    Asserts that no queries have been made by the specified class method.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$options = new Acme\Options();
    +$options->update('adsSource', 'not-a-real-url.org');
    +$I->assertNotQueriesByMethod('Acme\Options', 'update');
    +
    +

    assertNotQueriesByStatement

    +

    Signature: assertNotQueriesByStatement(string $statement, [string $message]) : void

    +

    Asserts that no queries have been made by the specified class method.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$bookRepository = new Acme\BookRepository();
    +$repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);
    +$this->assertNotQueriesByStatement('INSERT', 'Deferred write should happen on __destruct');
    +
    +

    assertNotQueriesByStatementAndAction

    +

    Signature: assertNotQueriesByStatementAndAction(string $statement, string $action, [string $message]) : void

    +

    Asserts that no queries were made as a consequence of the specified action containing the SQL query.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_action( 'edit_post', function($postId){
    +        $count = get_option('acme_title_updates_count');
    +        update_option('acme_title_updates_count', ++$count);
    +} );
    +wp_delete_post($bookId);
    +$this->assertNotQueriesByStatementAndAction('DELETE', 'delete_post');
    +
    +

    assertNotQueriesByStatementAndFilter

    +

    Signature: assertNotQueriesByStatementAndFilter(string $statement, string $filter, [string $message]) : void

    +

    Asserts that no queries were made as a consequence of the specified filter containing the specified SQL query.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_filter('the_title', function($title, $postId){
    +     $post = get_post($postId);
    +     if($post->post_type !== 'book'){
    +         return $title;
    +     }
    +     $new = get_option('acme_new_prefix');
    +     return "{$new} - " . $title;
    +});
    +$title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);
    +$this->assertNotQueriesByStatementAndFilter('SELECT', 'the_title');
    +
    +

    assertNotQueriesByStatementAndFunction

    +

    Signature: assertNotQueriesByStatementAndFunction(string $statement, string $function, [string $message]) : void

    +

    Asserts that no queries were made by the specified function starting with the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +wp_insert_post(['ID' => $bookId, 'post_title' => 'The Call of the Wild']);
    +$this->assertNotQueriesByStatementAndFunction('INSERT', 'wp_insert_post');
    +$this->assertQueriesByStatementAndFunction('UPDATE', 'wp_insert_post');
    +
    +

    assertNotQueriesByStatementAndMethod

    +

    Signature: assertNotQueriesByStatementAndMethod(string $statement, string $class, string $method, [string $message]) : void

    +

    Asserts that no queries were made by the specified class method starting with the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +Acme\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();
    +$this->assertQueriesByStatementAndMethod('INSERT', Acme\BookRepository::class, 'commit');
    +
    +

    assertQueries

    +

    Signature: assertQueries([string $message]) : void

    +

    Asserts that at least one query was made during the test.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +wp_cache_delete('page-posts', 'acme');
    +$pagePosts = $plugin->getPagePosts();
    +$I->assertQueries('Queries should be made to set the cache.')
    +
    +

    assertQueriesByAction

    +

    Signature: assertQueriesByAction(string $action, [string $message]) : void

    +

    Asserts that at least one query was made as a consequence of the specified action.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_action( 'edit_post', function($postId){
    +        $count = get_option('acme_title_updates_count');
    +        update_option('acme_title_updates_count', ++$count);
    +} );
    +wp_update_post(['ID' => $bookId, 'post_title' => 'New Title']);
    +$this->assertQueriesByAction('edit_post');
    +
    +

    assertQueriesByFilter

    +

    Signature: assertQueriesByFilter(string $filter, [string $message]) : void

    +

    Asserts that at least one query was made as a consequence of the specified filter.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_filter('the_title', function($title, $postId){
    +     $post = get_post($postId);
    +     if($post->post_type !== 'book'){
    +         return $title;
    +     }
    +     $new = get_option('acme_new_prefix');
    +     return "{$new} - " . $title;
    +});
    +$title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);
    +$this->assertQueriesByFilter('the_title');
    +
    +

    assertQueriesByFunction

    +

    Signature: assertQueriesByFunction(string $function, [string $message]) : void

    +

    Asserts that queries were made by the specified function.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +acme_clean_queue();
    +$this->assertQueriesByFunction('acme_clean_queue');
    +
    +

    assertQueriesByMethod

    +

    Signature: assertQueriesByMethod(string $class, string $method, [string $message]) : void

    +

    Asserts that at least one query has been made by the specified class method.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$options = new Acme\Options();
    +$options->update('showAds', false);
    +$I->assertQueriesByMethod('Acme\Options', 'update');
    +
    +

    assertQueriesByStatement

    +

    Signature: assertQueriesByStatement(string $statement, [string $message]) : void

    +

    Asserts that at least a query starting with the specified statement was made.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +wp_cache_flush();
    +cached_get_posts($args);
    +$I->assertQueriesByStatement('SELECT');
    +
    +

    assertQueriesByStatementAndAction

    +

    Signature: assertQueriesByStatementAndAction(string $statement, string $action, [string $message]) : void

    +

    Asserts that at least one query was made as a consequence of the specified action containing the SQL query.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_action( 'edit_post', function($postId){
    +        $count = get_option('acme_title_updates_count');
    +        update_option('acme_title_updates_count', ++$count);
    +} );
    +wp_update_post(['ID' => $bookId, 'post_title' => 'New']);
    +$this->assertQueriesByStatementAndAction('UPDATE', 'edit_post');
    +
    +

    assertQueriesByStatementAndFilter

    +

    Signature: assertQueriesByStatementAndFilter(string $statement, string $filter, [string $message]) : void

    +

    Asserts that at least one query was made as a consequence of the specified filter containing the SQL query.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_filter('the_title', function($title, $postId){
    +     $post = get_post($postId);
    +     if($post->post_type !== 'book'){
    +         return $title;
    +     }
    +     $new = get_option('acme_new_prefix');
    +     return "{$new} - " . $title;
    +});
    +$title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);
    +$this->assertQueriesByStatementAndFilter('SELECT', 'the_title');
    +
    +

    assertQueriesByStatementAndFunction

    +

    Signature: assertQueriesByStatementAndFunction(string $statement, string $function, [string $message]) : void

    +

    Asserts that queries were made by the specified function starting with the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +wp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);
    +$this->assertQueriesByStatementAndFunction('INSERT', 'wp_insert_post');
    +
    +

    assertQueriesByStatementAndMethod

    +

    Signature: assertQueriesByStatementAndMethod(string $statement, string $class, string $method, [string $message]) : void

    +

    Asserts that queries were made by the specified class method starting with the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +Acme\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();
    +$this->assertQueriesByStatementAndMethod('UPDATE', Acme\BookRepository::class, 'commit');
    +
    +

    assertQueriesCountByAction

    +

    Signature: assertQueriesCountByAction(int $n, string $action, [string $message]) : void

    +

    Asserts that n queries were made as a consequence of the specified action.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_action( 'edit_post', function($postId){
    +        $count = get_option('acme_title_updates_count');
    +        update_option('acme_title_updates_count', ++$count);
    +} );
    +wp_update_post(['ID' => $bookOneId, 'post_title' => 'One']);
    +wp_update_post(['ID' => $bookTwoId, 'post_title' => 'Two']);
    +wp_update_post(['ID' => $bookThreeId, 'post_title' => 'Three']);
    +$this->assertQueriesCountByAction(3, 'edit_post');
    +
    +

    assertQueriesCountByFilter

    +

    Signature: assertQueriesCountByFilter(int $n, string $filter, [string $message]) : void

    +

    Asserts that n queries were made as a consequence of the specified filter.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_filter('the_title', function($title, $postId){
    +     $post = get_post($postId);
    +     if($post->post_type !== 'book'){
    +         return $title;
    +     }
    +     $new = get_option('acme_new_prefix');
    +     return "{$new} - " . $title;
    +});
    +$title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);
    +$title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);
    +$title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);
    +$this->assertQueriesCountByFilter(2, 'the_title');
    +
    +

    assertQueriesCountByFunction

    +

    Signature: assertQueriesCountByFunction(int $n, string $function, [string $message]) : void

    +

    Asserts that n queries were made by the specified function.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$this->assertCount(3, Acme\get_orphaned_posts());
    +Acme\delete_orphaned_posts();
    +$this->assertQueriesCountByFunction(3, 'Acme\delete_orphaned_posts');
    +
    +

    assertQueriesCountByMethod

    +

    Signature: assertQueriesCountByMethod(int $n, string $class, string $method, [string $message]) : void

    +

    Asserts that n queries have been made by the specified class method.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$bookRepository = new Acme\BookRepository();
    +$repository->where('ID', 23)->commit('title', 'Peter Pan');
    +$repository->where('ID', 89)->commit('title', 'Moby-dick');
    +$repository->where('ID', 2389)->commit('title', 'The call of the wild');
    +$this->assertQueriesCountByMethod(3, 'Acme\BookRepository', 'commit');
    +
    +

    assertQueriesCountByStatement

    +

    Signature: assertQueriesCountByStatement(int $n, string $statement, [string $message]) : void

    +

    Asserts that n queries starting with the specified statement were made.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +$bookRepository = new Acme\BookRepository();
    +$repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);
    +$repository->where('ID', 89)->set('title', 'Moby-dick', $deferred = true);
    +$repository->where('ID', 2389)->set('title', 'The call of the wild', $deferred = false);
    +$this->assertQueriesCountByStatement(1, 'INSERT', 'Deferred write should happen on __destruct');
    +
    +

    assertQueriesCountByStatementAndAction

    +

    Signature: assertQueriesCountByStatementAndAction(int $n, string $statement, string $action, [string $message]) : void

    +

    Asserts that n queries were made as a consequence of the specified action containing the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_action( 'edit_post', function($postId){
    +        $count = get_option('acme_title_updates_count');
    +        update_option('acme_title_updates_count', ++$count);
    +} );
    +wp_delete_post($bookOneId);
    +wp_delete_post($bookTwoId);
    +wp_update_post(['ID' => $bookThreeId, 'post_title' => 'New']);
    +$this->assertQueriesCountByStatementAndAction(2, 'DELETE', 'delete_post');
    +$this->assertQueriesCountByStatementAndAction(1, 'INSERT', 'edit_post');
    +
    +

    assertQueriesCountByStatementAndFilter

    +

    Signature: assertQueriesCountByStatementAndFilter(int $n, string $statement, string $filter, [string $message]) : void

    +

    Asserts that n queries were made as a consequence of the specified filter containing the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +add_filter('the_title', function($title, $postId){
    +     $post = get_post($postId);
    +     if($post->post_type !== 'book'){
    +         return $title;
    +     }
    +     $new = get_option('acme_new_prefix');
    +     return "{$new} - " . $title;
    +});
    +// Warm up the cache.
    +$title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);
    +// Cache is warmed up now.
    +$title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);
    +$title = apply_filters('the_title', get_post($bookThreeId)->post_title, $bookThreeId);
    +$this->assertQueriesCountByStatementAndFilter(1, 'SELECT', 'the_title');
    +
    +

    assertQueriesCountByStatementAndFunction

    +

    Signature: assertQueriesCountByStatementAndFunction(int $n, string $statement, string $function, [string $message]) : void

    +

    Asserts that n queries were made by the specified function starting with the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +wp_insert_post(['post_type' => 'book', 'post_title' => 'The Call of the Wild']);
    +wp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);
    +wp_insert_post(['post_type' => 'book', 'post_title' => 'The Chocolate Factory']);
    +$this->assertQueriesCountByStatementAndFunction(3, 'INSERT', 'wp_insert_post');
    +
    +

    assertQueriesCountByStatementAndMethod

    +

    Signature: assertQueriesCountByStatementAndMethod(int $n, string $statement, string $class, string $method, [string $message]) : void

    +

    Asserts that n queries were made by the specified class method starting with the specified SQL statement.

    +

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    +
    <?php
    +Acme\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();
    +Acme\BookRepository::new(['title' => 'Moby-Dick'])->commit();
    +Acme\BookRepository::new(['title' => 'The Call of the Wild'])->commit();
    +$this->assertQueriesCountByStatementAndMethod(3, 'INSERT', Acme\BookRepository::class, 'commit');
    +
    +

    countQueries

    +

    Signature: countQueries([?wpdb $wpdb]) : int

    +

    Returns the current number of queries. +Set-up and tear-down queries performed by the test case are filtered out.

    +
    <?php
    +// In a WPTestCase, using the global $wpdb object.
    +$queriesCount = $this->queries()->countQueries();
    +// In a WPTestCase, using a custom $wpdb object.
    +$queriesCount = $this->queries()->countQueries($customWdbb);
    +
    +

    getQueries

    +

    Signature: getQueries([?wpdb $wpdb]) : array

    +

    Returns the queries currently performed by the global database object or the specified one. +Set-up and tear-down queries performed by the test case are filtered out.

    +
    <?php
    +// In a WPTestCase, using the global $wpdb object.
    +$queries = $this->queries()->getQueries();
    +// In a WPTestCase, using a custom $wpdb object.
    +$queries = $this->queries()->getQueries($customWdbb);
    +
    + + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/modules/WPWebDriver/index.html b/modules/WPWebDriver/index.html new file mode 100644 index 000000000..6e93ae794 --- /dev/null +++ b/modules/WPWebDriver/index.html @@ -0,0 +1,6743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPWebDriver - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + +

    WPWebDriver

    + +

    WPWebDriver module

    +

    This module drives a browser using a solution like Selenium or Chromedriver to simulate user interactions with +the WordPress project.

    +

    The module has full Javascript support, differently from the WPBrowser module, and can be used to test +sites that use Javascript to render the page or to make assertions that require Javascript support.

    +

    The method extends the Codeception WebDriver module and is used in the context of Cest and Cept test +cases.

    +

    Configuration

    +
      +
    • browser - the browser to use; e.g. 'chrome'
    • +
    • host - the host to use; e.g. 'localhost'. This is the host of the Selenium server or the Chromedriver server.
    • +
    • port - the port to use; e.g. '4444'. This is the port of the Selenium server or the Chromedriver server.
    • +
    • path - the path to use; e.g. '/wd/hub' or '/'. Use '/' for Chrome.
    • +
    • url - required; the start URL of your WordPress project.
    • +
    • adminUsername - required; the site administrator username to use in actions like loginAsAdmin.
    • +
    • adminPassword - required; the site administrator password to use in actions like loginAsAdmin.
    • +
    • adminPath - the path to the WordPress admin directory; defaults to /wp-admin.
    • +
    +

    More configuration options, and their explanation, are available in the Codeception WebDriver module documentation.

    +

    The following is an example of the module configuration to run tests on thehttp://localhost:8080 site:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPBrowser:
    +      url: 'http://localhost:8080'
    +      adminUsername: 'admin'
    +      adminPassword: 'password'
    +      adminPath: '/wp-admin'
    +      browser: chrome
    +      host: 'localhost'
    +      port: '4444'
    +      path: '/'
    +      window_size: false
    +      capabilities:
    +        "goog:chromeOptions":
    +          args:
    +            - "--headless"
    +            - "--disable-gpu"
    +            - "--disable-dev-shm-usage"
    +            - "--proxy-server='direct://'"
    +            - "--proxy-bypass-list=*"
    +            - "--no-sandbox"
    +
    +

    The following configuration uses dynamic configuration parameters to set the module configuration:

    +
    modules:
    +  enabled:
    +    lucatume\WPBrowser\Module\WPBrowser:
    +      url: 'http://localhost:8080'
    +      adminUsername: 'admin'
    +      adminPassword: 'password'
    +      adminPath: '/wp-admin'
    +      browser: chrome
    +      host: '%CHROME_HOST%'
    +      port: '%CHROME_PORT%'
    +      path: '/'
    +      window_size: `1920,1080`
    +      capabilities:
    +        "goog:chromeOptions":
    +          args:
    +            - "--headless"
    +            - "--disable-gpu"
    +            - "--disable-dev-shm-usage"
    +            - "--proxy-server='direct://'"
    +            - "--proxy-bypass-list=*"
    +            - "--no-sandbox"
    +
    +

    Furthermore, the above configuration will not run Chrome in headless mode: the browser window will be visible.

    +

    Methods

    +

    The module provides the following methods:

    + + +

    acceptPopup

    +

    Signature: acceptPopup() : void

    +

    Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt. +Don't confuse popups with modal windows, +as created by various libraries.

    +

    activatePlugin

    +

    Signature: activatePlugin(array|string $pluginSlug) : void

    +

    In the plugin administration screen activates one or more plugins clicking the "Activate" link.

    +

    The method will not handle authentication and navigation to the plugins administration page.

    +
    <?php
    +// Activate a plugin.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->activatePlugin('hello-dolly');
    +// Activate a list of plugins.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->activatePlugin(['hello-dolly','another-plugin']);
    +
    +

    activateTheme

    +

    Signature: activateTheme(string $slug) : void

    +

    Activates a theme.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    amEditingPostWithId

    +

    Signature: amEditingPostWithId(int $id) : void

    +

    Go to the admin page to edit the post with the specified ID.

    +

    The method will not handle authentication the admin area.

    +
    <?php
    +$I->loginAsAdmin();
    +$postId = $I->havePostInDatabase();
    +$I->amEditingPostWithId($postId);
    +$I->fillField('post_title', 'Post title');
    +
    +

    amEditingUserWithId

    +

    Signature: amEditingUserWithId(int $id) : void

    +

    Go to the admin page to edit the user with the specified ID.

    +

    The method will not handle authentication the admin area.

    +
    <?php
    +$I->loginAsAdmin();
    +$userId = $I->haveUserInDatabase('luca', 'editor');
    +$I->amEditingUserWithId($userId);
    +$I->fillField('email', 'new@example.net');
    +
    +

    amOnAdminAjaxPage

    +

    Signature: amOnAdminAjaxPage([array|string|null $queryVars]) : void

    +

    Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

    +

    The method will not handle authentication, nonces or authorization.

    +
    <?php
    +$I->amOnAdminAjaxPage(['action' => 'my-action', 'data' => ['id' => 23], 'nonce' => $nonce]);
    +
    +

    amOnAdminPage

    +

    Signature: amOnAdminPage(string $page) : void

    +

    Go to a page in the admininstration area of the site.

    +

    This method will not handle authentication to the administration area.

    +
    <?php
    +$I->loginAs('user', 'password');
    +// Go to the plugins management screen.
    +$I->amOnAdminPage('/plugins.php');
    +
    +

    amOnCronPage

    +

    Signature: amOnCronPage([array|string|null $queryVars]) : void

    +

    Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

    +
    <?php
    +// Triggers the cron job with an optional query argument.
    +$I->amOnCronPage('/?some-query-var=some-value');
    +
    +

    amOnPage

    +

    Signature: amOnPage($page) : void

    +

    amOnPagesPage

    +

    Signature: amOnPagesPage() : void

    +

    Go the "Pages" administration screen.

    +

    The method will not handle authentication.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPagesPage();
    +$I->see('Add New');
    +
    +

    amOnPluginsPage

    +

    Signature: amOnPluginsPage() : void

    +

    Go to the plugins administration screen.

    +

    The method will not handle authentication.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->activatePlugin('hello-dolly');
    +
    +

    amOnSubdomain

    +

    Signature: amOnSubdomain(string $subdomain) : void

    +

    amOnThemesPage

    +

    Signature: amOnThemesPage() : void

    +

    Moves to the themes administration page.

    +

    amOnUrl

    +

    Signature: amOnUrl($url) : void

    +

    appendField

    +

    Signature: appendField($field, string $value) : void

    +

    Append the given text to the given element. +Can also add a selection to a select box.

    +
    <?php
    +$I->appendField('#mySelectbox', 'SelectValue');
    +$I->appendField('#myTextField', 'appended');
    +
    +

    attachFile

    +

    Signature: attachFile($field, string $filename) : void

    +

    cancelPopup

    +

    Signature: cancelPopup() : void

    +

    Dismisses the active JavaScript popup, as created by window.alert, window.confirm, or window.prompt.

    +

    checkOption

    +

    Signature: checkOption($option) : void

    +

    clearField

    +

    Signature: clearField($field) : void

    +

    Clears given field which isn't empty.

    +
    <?php
    +$I->clearField('#username');
    +
    +

    click

    +

    Signature: click($link, [$context]) : void

    +

    clickWithLeftButton

    +

    Signature: clickWithLeftButton([$cssOrXPath], [?int $offsetX], [?int $offsetY]) : void

    +

    Performs click with the left mouse button on an element. +If the first parameter null then the offset is relative to the actual mouse position. +If the second and third parameters are given, +then the mouse is moved to an offset of the element's top-left corner. +Otherwise, the mouse is moved to the center of the element.

    +
    <?php
    +$I->clickWithLeftButton(['css' => '.checkout']);
    +$I->clickWithLeftButton(null, 20, 50);
    +$I->clickWithLeftButton(['css' => '.checkout'], 20, 50);
    +
    +

    clickWithRightButton

    +

    Signature: clickWithRightButton([$cssOrXPath], [?int $offsetX], [?int $offsetY]) : void

    +

    Performs contextual click with the right mouse button on an element. +If the first parameter null then the offset is relative to the actual mouse position. +If the second and third parameters are given, +then the mouse is moved to an offset of the element's top-left corner. +Otherwise, the mouse is moved to the center of the element.

    +
    <?php
    +$I->clickWithRightButton(['css' => '.checkout']);
    +$I->clickWithRightButton(null, 20, 50);
    +$I->clickWithRightButton(['css' => '.checkout'], 20, 50);
    +
    +

    closeTab

    +

    Signature: closeTab() : void

    +

    Closes current browser tab and switches to previous active tab.

    +
    <?php
    +$I->closeTab();
    +
    +

    deactivatePlugin

    +

    Signature: deactivatePlugin(array|string $pluginSlug) : void

    +

    In the plugin administration screen deactivate a plugin clicking the "Deactivate" link.

    +

    The method will not handle authentication and navigation to the plugins administration page.

    +
    <?php
    +// Deactivate one plugin.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->deactivatePlugin('hello-dolly');
    +// Deactivate a list of plugins.
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->deactivatePlugin(['hello-dolly', 'my-plugin']);
    +
    +

    debugWebDriverLogs

    +

    Signature: debugWebDriverLogs([?Codeception\TestInterface $test]) : void

    +

    Print out latest Selenium Logs in debug mode

    +

    deleteSessionSnapshot

    +

    Signature: deleteSessionSnapshot($name) : void

    +

    dontSee

    +

    Signature: dontSee($text, [$selector]) : void

    +

    dontSeeCheckboxIsChecked

    +

    Signature: dontSeeCheckboxIsChecked($checkbox) : void

    +

    dontSeeCookie

    +

    Signature: dontSeeCookie($cookie, [array $params], [bool $showDebug]) : void

    +

    dontSeeCurrentUrlEquals

    +

    Signature: dontSeeCurrentUrlEquals(string $uri) : void

    +

    dontSeeCurrentUrlMatches

    +

    Signature: dontSeeCurrentUrlMatches(string $uri) : void

    +

    dontSeeElement

    +

    Signature: dontSeeElement($selector, [array $attributes]) : void

    +

    dontSeeElementInDOM

    +

    Signature: dontSeeElementInDOM($selector, [array $attributes]) : void

    +

    Opposite of seeElementInDOM.

    +

    dontSeeInCurrentUrl

    +

    Signature: dontSeeInCurrentUrl(string $uri) : void

    +

    dontSeeInField

    +

    Signature: dontSeeInField($field, $value) : void

    +

    dontSeeInFormFields

    +

    Signature: dontSeeInFormFields($formSelector, array $params) : void

    +

    dontSeeInPageSource

    +

    Signature: dontSeeInPageSource(string $text) : void

    +

    Checks that the page source doesn't contain the given string.

    +

    dontSeeInPopup

    +

    Signature: dontSeeInPopup(string $text) : void

    +

    Checks that the active JavaScript popup, +as created by window.alert|window.confirm|window.prompt, does NOT contain the given string.

    +

    dontSeeInSource

    +

    Signature: dontSeeInSource($raw) : void

    +

    dontSeeInTitle

    +

    Signature: dontSeeInTitle($title) : void

    + +

    Signature: dontSeeLink(string $text, [string $url]) : void

    +

    dontSeeOptionIsSelected

    +

    Signature: dontSeeOptionIsSelected($selector, $optionText) : void

    +

    dontSeePluginInstalled

    +

    Signature: dontSeePluginInstalled(string $pluginSlug) : void

    +

    Assert a plugin is not installed in the plugins administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->dontSeePluginInstalled('my-plugin');
    +
    +

    doubleClick

    +

    Signature: doubleClick($cssOrXPath) : void

    +

    Performs a double click on an element matched by CSS or XPath.

    +

    dragAndDrop

    +

    Signature: dragAndDrop($source, $target) : void

    +

    Performs a simple mouse drag-and-drop operation.

    +
    <?php
    +$I->dragAndDrop('#drag', '#drop');
    +
    +

    executeAsyncJS

    +

    Signature: executeAsyncJS(string $script, [array $arguments]) : void

    +

    Executes asynchronous JavaScript. +A callback should be executed by JavaScript to exit from a script. +Callback is passed as a last element in arguments array. +Additional arguments can be passed as array in second parameter.

    +
    // wait for 1200 milliseconds my running `setTimeout`
    +* $I->executeAsyncJS('setTimeout(arguments[0], 1200)');
    +
    +$seconds = 1200; // or seconds are passed as argument
    +$I->executeAsyncJS('setTimeout(arguments[1], arguments[0])', [$seconds]);
    +
    +

    executeInSelenium

    +

    Signature: executeInSelenium(Closure $function) : void

    +

    Low-level API method. +If Codeception commands are not enough, this allows you to use Selenium WebDriver methods directly:

    +
    $I->executeInSelenium(function(\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
    +  $webdriver->get('https://google.com');
    +});
    +
    +

    This runs in the context of the +RemoteWebDriver class. +Try not to use this command on a regular basis. +If Codeception lacks a feature you need, please implement it and submit a patch.

    +

    executeJS

    +

    Signature: executeJS(string $script, [array $arguments]) : void

    +

    Executes custom JavaScript.

    +

    This example uses jQuery to get a value and assigns that value to a PHP variable:

    +
    <?php
    +$myVar = $I->executeJS('return $("#myField").val()');
    +
    +// additional arguments can be passed as array
    +// Example shows `Hello World` alert:
    +$I->executeJS("window.alert(arguments[0])", ['Hello world']);
    +
    +

    fillField

    +

    Signature: fillField($field, $value) : void

    +

    grabActiveTheme

    +

    Signature: grabActiveTheme() : ?string

    +

    Returns the slug of the currently active themes.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    grabAttributeFrom

    +

    Signature: grabAttributeFrom($cssOrXpath, $attribute) : ?string

    +

    grabAvailableThemes

    +

    Signature: grabAvailableThemes([string $classes]) : array

    +

    Returns the list of available themes.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    grabCookie

    +

    Signature: grabCookie($cookie, [array $params]) : mixed

    +

    grabCookiesWithPattern

    +

    Signature: grabCookiesWithPattern(string $cookiePattern) : ?array

    +

    Returns all the cookies whose name matches a regex pattern.

    +
    <?php
    +$I->loginAs('customer','password');
    +$I->amOnPage('/shop');
    +$cartCookies = $I->grabCookiesWithPattern("#^shop_cart\\.*#");
    +
    +

    grabFromCurrentUrl

    +

    Signature: grabFromCurrentUrl([$uri]) : mixed

    +

    grabFullUrl

    +

    Signature: grabFullUrl() : string

    +

    Grabs the current page full URL including the query vars.

    +
    <?php
    +$today = date('Y-m-d');
    +$I->amOnPage('/concerts?date=' . $today);
    +$I->assertRegExp('#\\/concerts$#', $I->grabFullUrl());
    +
    +

    grabMultiple

    +

    Signature: grabMultiple($cssOrXpath, [$attribute]) : array

    +

    grabPageSource

    +

    Signature: grabPageSource() : string

    +

    Grabs current page source code.

    +

    grabTextFrom

    +

    Signature: grabTextFrom($cssOrXPathOrRegex) : mixed

    +

    grabValueFrom

    +

    Signature: grabValueFrom($field) : ?string

    +

    grabWordPressTestCookie

    +

    Signature: grabWordPressTestCookie([?string $name]) : ?Symfony\Component\BrowserKit\Cookie

    +

    Returns WordPress default test cookie object if present.

    +
    <?php
    +// Grab the default WordPress test cookie.
    +$wpTestCookie = $I->grabWordPressTestCookie();
    +// Grab a customized version of the test cookie.
    +$myTestCookie = $I->grabWordPressTestCookie('my_test_cookie');
    +
    +

    loadSessionSnapshot

    +

    Signature: loadSessionSnapshot($name, [bool $showDebug]) : bool

    +

    logOut

    +

    Signature: logOut([string|bool $redirectTo]) : void

    +

    Navigate to the default WordPress logout page and click the logout link.

    +
    <?php
    +// Log out using the `wp-login.php` form and return to the current page.
    +$I->logOut(true);
    +// Log out using the `wp-login.php` form and remain there.
    +$I->logOut(false);
    +// Log out using the `wp-login.php` form and move to another page.
    +$I->logOut('/some-other-page');
    +
    +

    loginAs

    +

    Signature: loginAs(string $username, string $password, [int $timeout], [int $maxAttempts]) : void

    +

    Login as the specified user.

    +

    The method will not follow redirection, after the login, to any page. +Depending on the driven browser the login might be "too fast" and the server might have not +replied with valid cookies yet; in that case the method will re-attempt the login to obtain +the cookies.

    +
    <?php
    +$I->loginAs('user', 'password');
    +$I->amOnAdminPage('/');
    +$I->see('Dashboard');
    +
    +

    loginAsAdmin

    +

    Signature: loginAsAdmin([int $timeout], [int $maxAttempts]) : void

    +

    Login as the administrator user using the credentials specified in the module configuration.

    +

    The method will not follow redirection, after the login, to any page.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnAdminPage('/');
    +$I->see('Dashboard');
    +
    +

    makeElementScreenshot

    +

    Signature: makeElementScreenshot($selector, [?string $name]) : void

    +

    Takes a screenshot of an element of the current window and saves it to tests/_output/debug.

    +
    <?php
    +$I->amOnPage('/user/edit');
    +$I->makeElementScreenshot('#dialog', 'edit_page');
    +// saved to: tests/_output/debug/edit_page.png
    +$I->makeElementScreenshot('#dialog');
    +// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png
    +
    +

    makeHtmlSnapshot

    +

    Signature: makeHtmlSnapshot([?string $name]) : void

    +

    makeScreenshot

    +

    Signature: makeScreenshot([?string $name]) : void

    +

    Takes a screenshot of the current window and saves it to tests/_output/debug.

    +
    <?php
    +$I->amOnPage('/user/edit');
    +$I->makeScreenshot('edit_page');
    +// saved to: tests/_output/debug/edit_page.png
    +$I->makeScreenshot();
    +// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png
    +
    +

    maximizeWindow

    +

    Signature: maximizeWindow() : void

    +

    Maximizes the current window.

    +

    moveBack

    +

    Signature: moveBack() : void

    +

    Moves back in history.

    +

    moveForward

    +

    Signature: moveForward() : void

    +

    Moves forward in history.

    +

    moveMouseOver

    +

    Signature: moveMouseOver([$cssOrXPath], [?int $offsetX], [?int $offsetY]) : void

    +

    Move mouse over the first element matched by the given locator. +If the first parameter null then the page is used. +If the second and third parameters are given, +then the mouse is moved to an offset of the element's top-left corner. +Otherwise, the mouse is moved to the center of the element.

    +
    <?php
    +$I->moveMouseOver(['css' => '.checkout']);
    +$I->moveMouseOver(null, 20, 50);
    +$I->moveMouseOver(['css' => '.checkout'], 20, 50);
    +
    +

    openNewTab

    +

    Signature: openNewTab() : void

    +

    Opens a new browser tab and switches to it.

    +

    <?php
    +$I->openNewTab();
    +
    +The tab is opened with JavaScript's window.open(), which means: +* Some ad-blockers might restrict it. +* The sessionStorage is copied to the new tab (contrary to a tab that was manually opened by the user)

    +

    performOn

    +

    Signature: performOn($element, $actions, [int $timeout]) : void

    +

    Waits for element and runs a sequence of actions inside its context. +Actions can be defined with array, callback, or Codeception\Util\ActionSequence instance.

    +

    Actions as array are recommended for simple to combine "waitForElement" with assertions; +waitForElement($el) and see('text', $el) can be simplified to:

    +
    <?php
    +$I->performOn($el, ['see' => 'text']);
    +
    +

    List of actions can be pragmatically build using Codeception\Util\ActionSequence:

    +
    <?php
    +$I->performOn('.model', ActionSequence::build()
    +    ->see('Warning')
    +    ->see('Are you sure you want to delete this?')
    +    ->click('Yes')
    +);
    +
    +

    Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to +exception on failure.

    +

    Whenever you need to define more actions a callback can be used. A WebDriver module is passed for argument:

    +
    <?php
    +$I->performOn('.rememberMe', function (WebDriver $I) {
    +     $I->see('Remember me next time');
    +     $I->seeElement('#LoginForm_rememberMe');
    +     $I->dontSee('Login');
    +});
    +
    +

    In 3rd argument you can set number a seconds to wait for element to appear

    +

    pressKey

    +

    Signature: pressKey($element, [...$chars]) : void

    +

    Presses the given key on the given element. +To specify a character and modifier (e.g. Ctrl, Alt, Shift, Meta), pass an array for $char with +the modifier as the first element and the character as the second. +For special keys, use the constants from Facebook\WebDriver\WebDriverKeys.

    +
    <?php
    +// <input id="page" value="old" />
    +$I->pressKey('#page','a'); // => olda
    +$I->pressKey('#page',array('ctrl','a'),'new'); //=> new
    +$I->pressKey('#page',array('shift','111'),'1','x'); //=> old!!!1x
    +$I->pressKey('descendant-or-self::*[@id='page']','u'); //=> oldu
    +$I->pressKey('#name', array('ctrl', 'a'), \Facebook\WebDriver\WebDriverKeys::DELETE); //=>''
    +
    +

    reloadPage

    +

    Signature: reloadPage() : void

    +

    Reloads the current page.

    +

    resetCookie

    +

    Signature: resetCookie($cookie, [array $params], [bool $showDebug]) : void

    +

    resizeWindow

    +

    Signature: resizeWindow(int $width, int $height) : void

    +

    Resize the current window.

    +
    <?php
    +$I->resizeWindow(800, 600);
    +
    +

    saveSessionSnapshot

    +

    Signature: saveSessionSnapshot($name) : void

    +

    scrollTo

    +

    Signature: scrollTo($selector, [?int $offsetX], [?int $offsetY]) : void

    +

    Move to the middle of the given element matched by the given locator. +Extra shift, calculated from the top-left corner of the element, +can be set by passing $offsetX and $offsetY parameters.

    +
    <?php
    +$I->scrollTo(['css' => '.checkout'], 20, 50);
    +
    +

    see

    +

    Signature: see($text, [$selector]) : void

    +

    seeCheckboxIsChecked

    +

    Signature: seeCheckboxIsChecked($checkbox) : void

    +

    seeCookie

    +

    Signature: seeCookie($cookie, [array $params], [bool $showDebug]) : void

    +

    seeCurrentUrlEquals

    +

    Signature: seeCurrentUrlEquals(string $uri) : void

    +

    seeCurrentUrlMatches

    +

    Signature: seeCurrentUrlMatches(string $uri) : void

    +

    seeElement

    +

    Signature: seeElement($selector, [array $attributes]) : void

    +

    seeElementInDOM

    +

    Signature: seeElementInDOM($selector, [array $attributes]) : void

    +

    Checks that the given element exists on the page, even it is invisible.

    +
    <?php
    +$I->seeElementInDOM('//form/input[type=hidden]');
    +
    +

    seeErrorMessage

    +

    Signature: seeErrorMessage([array|string $classes]) : void

    +

    In an administration screen look for an error admin notice.

    +

    The check is class-based to decouple from internationalization. +The method will not handle authentication and navigation the administration area.

    +
    <?php
    +$I->loginAsAdmin()
    +$I->amOnAdminPage('/');
    +$I->seeErrorMessage('.my-plugin');
    +
    +

    seeInCurrentUrl

    +

    Signature: seeInCurrentUrl(string $uri) : void

    +

    seeInField

    +

    Signature: seeInField($field, $value) : void

    +

    seeInFormFields

    +

    Signature: seeInFormFields($formSelector, array $params) : void

    +

    seeInPageSource

    +

    Signature: seeInPageSource(string $text) : void

    +

    Checks that the page source contains the given string.

    +
    <?php
    +$I->seeInPageSource('<link rel="apple-touch-icon"');
    +
    +

    seeInPopup

    +

    Signature: seeInPopup(string $text) : void

    +

    Checks that the active JavaScript popup, +as created by window.alert|window.confirm|window.prompt, contains the given string.

    +

    seeInSource

    +

    Signature: seeInSource($raw) : void

    +

    seeInTitle

    +

    Signature: seeInTitle($title) : void

    + +

    Signature: seeLink(string $text, [?string $url]) : void

    +

    seeMessage

    +

    Signature: seeMessage([array|string $classes]) : void

    +

    In an administration screen look for an admin notice.

    +

    The check is class-based to decouple from internationalization. +The method will not handle authentication and navigation the administration area.

    +
    <?php
    +$I->loginAsAdmin()
    +$I->amOnAdminPage('/');
    +$I->seeMessage('.missing-api-token.my-plugin');
    +
    +

    seeNumberOfElements

    +

    Signature: seeNumberOfElements($selector, $expected) : void

    +

    seeNumberOfElementsInDOM

    +

    Signature: seeNumberOfElementsInDOM($selector, $expected) : void

    +

    seeNumberOfTabs

    +

    Signature: seeNumberOfTabs(int $number) : void

    +

    Checks current number of opened tabs

    +
    <?php
    +$I->seeNumberOfTabs(2);
    +
    +

    seeOptionIsSelected

    +

    Signature: seeOptionIsSelected($selector, $optionText) : void

    +

    seePluginActivated

    +

    Signature: seePluginActivated(string $pluginSlug) : void

    +

    Assert a plugin is activated in the plugin administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->seePluginActivated('my-plugin');
    +
    +

    seePluginDeactivated

    +

    Signature: seePluginDeactivated(string $pluginSlug) : void

    +

    Assert a plugin is not activated in the plugins administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->seePluginDeactivated('my-plugin');
    +
    +

    seePluginInstalled

    +

    Signature: seePluginInstalled(string $pluginSlug) : void

    +

    Assert a plugin is installed, no matter its activation status, in the plugin administration screen.

    +

    The method will not handle authentication and navigation to the plugin administration screen.

    +
    <?php
    +$I->loginAsAdmin();
    +$I->amOnPluginsPage();
    +$I->seePluginInstalled('my-plugin');
    +
    +

    seeThemeActivated

    +

    Signature: seeThemeActivated(string $slug) : void

    +

    Verifies that a theme is active.

    +

    The method will not handle authentication and navigation to the themes administration page.

    +

    seeWpDiePage

    +

    Signature: seeWpDiePage() : void

    +

    Checks that the current page is one generated by the wp_die function.

    +

    The method will try to identify the page based on the default WordPress die page HTML attributes.

    +
    <?php
    +$I->loginAs('user', 'password');
    +$I->amOnAdminPage('/forbidden');
    +$I->seeWpDiePage();
    +
    +

    selectOption

    +

    Signature: selectOption($select, $option) : void

    +

    setCookie

    +

    Signature: setCookie($name, $value, [array $params], [$showDebug]) : void

    +

    submitForm

    +

    Signature: submitForm($selector, array $params, [$button]) : void

    +

    Submits the given form on the page, optionally with the given form +values. Give the form fields values as an array. Note that hidden fields +can't be accessed.

    +

    Skipped fields will be filled by their values from the page. +You don't need to click the 'Submit' button afterwards. +This command itself triggers the request to form's action.

    +

    You can optionally specify what button's value to include +in the request with the last parameter as an alternative to +explicitly setting its value in the second parameter, as +button values are not otherwise included in the request.

    +

    Examples:

    +
    <?php
    +$I->submitForm('#login', [
    +    'login' => 'davert',
    +    'password' => '123456'
    +]);
    +// or
    +$I->submitForm('#login', [
    +    'login' => 'davert',
    +    'password' => '123456'
    +], 'submitButtonName');
    +
    +

    For example, given this sample "Sign Up" form:

    +
    <form action="/sign_up">
    +    Login:
    +    <input type="text" name="user[login]" /><br/>
    +    Password:
    +    <input type="password" name="user[password]" /><br/>
    +    Do you agree to our terms?
    +    <input type="checkbox" name="user[agree]" /><br/>
    +    Select pricing plan:
    +    <select name="plan">
    +        <option value="1">Free</option>
    +        <option value="2" selected="selected">Paid</option>
    +    </select>
    +    <input type="submit" name="submitButton" value="Submit" />
    +</form>
    +
    +

    You could write the following to submit it:

    +

    <?php
    +$I->submitForm(
    +    '#userForm',
    +    [
    +        'user[login]' => 'Davert',
    +        'user[password]' => '123456',
    +        'user[agree]' => true
    +    ],
    +    'submitButton'
    +);
    +
    +Note that "2" will be the submitted value for the "plan" field, as it is +the selected option.

    +

    Also note that this differs from PhpBrowser, in that +'user' => [ 'login' => 'Davert' ] is not supported at the moment. +Named array keys must be included in the name as above.

    +

    Pair this with seeInFormFields for quick testing magic.

    +
    <?php
    +$form = [
    +     'field1' => 'value',
    +     'field2' => 'another value',
    +     'checkbox1' => true,
    +     // ...
    +];
    +$I->submitForm('//form[@id=my-form]', $form, 'submitButton');
    +// $I->amOnPage('/path/to/form-page') may be needed
    +$I->seeInFormFields('//form[@id=my-form]', $form);
    +
    +

    Parameter values must be set to arrays for multiple input fields +of the same name, or multi-select combo boxes. For checkboxes, +either the string value can be used, or boolean values which will +be replaced by the checkbox's value in the DOM.

    +
    <?php
    +$I->submitForm('#my-form', [
    +     'field1' => 'value',
    +     'checkbox' => [
    +         'value of first checkbox',
    +         'value of second checkbox',
    +     ],
    +     'otherCheckboxes' => [
    +         true,
    +         false,
    +         false,
    +     ],
    +     'multiselect' => [
    +         'first option value',
    +         'second option value',
    +     ]
    +]);
    +
    +

    Mixing string and boolean values for a checkbox's value is not supported +and may produce unexpected results.

    +

    Field names ending in "[]" must be passed without the trailing square +bracket characters, and must contain an array for its value. This allows +submitting multiple values with the same name, consider:

    +
    <?php
    +$I->submitForm('#my-form', [
    +    'field[]' => 'value',
    +    'field[]' => 'another value', // 'field[]' is already a defined key
    +]);
    +
    +

    The solution is to pass an array value:

    +
    <?php
    +// this way both values are submitted
    +$I->submitForm('#my-form', [
    +    'field' => [
    +        'value',
    +        'another value',
    +    ]
    +]);
    +
    +

    The $button parameter can be either a string, an array or an instance +of Facebook\WebDriver\WebDriverBy. When it is a string, the +button will be found by its "name" attribute. If $button is an +array then it will be treated as a strict selector and a WebDriverBy +will be used verbatim.

    +

    For example, given the following HTML:

    +
    <input type="submit" name="submitButton" value="Submit" />
    +
    +

    $button could be any one of the following: + - 'submitButton' + - ['name' => 'submitButton'] + - WebDriverBy::name('submitButton')

    +

    switchToFrame

    +

    Signature: switchToFrame([?string $locator]) : void

    +

    Switch to another frame on the page.

    +

    Example: +

    <frame name="another_frame" id="fr1" src="https://example.com">
    +

    +
    <?php
    +# switch to frame by name
    +$I->switchToFrame("another_frame");
    +# switch to frame by CSS or XPath
    +$I->switchToFrame("#fr1");
    +# switch to parent page
    +$I->switchToFrame();
    +
    +

    switchToIFrame

    +

    Signature: switchToIFrame([?string $locator]) : void

    +

    Switch to another iframe on the page.

    +

    Example: +

    <iframe name="another_frame" id="fr1" src="https://example.com">
    +

    +
    <?php
    +# switch to iframe by name
    +$I->switchToIFrame("another_frame");
    +# switch to iframe by CSS or XPath
    +$I->switchToIFrame("#fr1");
    +# switch to parent page
    +$I->switchToIFrame();
    +
    +

    switchToNextTab

    +

    Signature: switchToNextTab([int $offset]) : void

    +

    Switches to next browser tab. +An offset can be specified.

    +
    <?php
    +// switch to next tab
    +$I->switchToNextTab();
    +// switch to 2nd next tab
    +$I->switchToNextTab(2);
    +
    +

    switchToPreviousTab

    +

    Signature: switchToPreviousTab([int $offset]) : void

    +

    Switches to previous browser tab. +An offset can be specified.

    +
    <?php
    +// switch to previous tab
    +$I->switchToPreviousTab();
    +// switch to 2nd previous tab
    +$I->switchToPreviousTab(2);
    +
    +

    switchToWindow

    +

    Signature: switchToWindow([?string $name]) : void

    +

    Switch to another window identified by name.

    +

    The window can only be identified by name. If the $name parameter is blank, the parent window will be used.

    +

    Example: +

    <input type="button" value="Open window" onclick="window.open('https://example.com', 'another_window')">
    +

    +
    <?php
    +$I->click("Open window");
    +# switch to another window
    +$I->switchToWindow("another_window");
    +# switch to parent window
    +$I->switchToWindow();
    +
    +

    If the window has no name, match it by switching to next active tab using switchToNextTab method.

    +

    Or use native Selenium functions to get access to all opened windows:

    +
    <?php
    +$I->executeInSelenium(function (\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
    +     $handles=$webdriver->getWindowHandles();
    +     $last_window = end($handles);
    +     $webdriver->switchTo()->window($last_window);
    +});
    +
    +

    type

    +

    Signature: type(string $text, [int $delay]) : void

    +

    Type in characters on active element. +With a second parameter you can specify delay between key presses.

    +
    <?php
    +// activate input element
    +$I->click('#input');
    +
    +// type text in active element
    +$I->type('Hello world');
    +
    +// type text with a 1sec delay between chars
    +$I->type('Hello World', 1);
    +
    +

    This might be useful when you an input reacts to typing and you need to slow it down to emulate human behavior. +For instance, this is how Credit Card fields can be filled in.

    +

    typeInPopup

    +

    Signature: typeInPopup(string $keys) : void

    +

    Enters text into a native JavaScript prompt popup, as created by window.prompt.

    +

    uncheckOption

    +

    Signature: uncheckOption($option) : void

    +

    unselectOption

    +

    Signature: unselectOption($select, $option) : void

    +

    Unselect an option in the given select box.

    +

    wait

    +

    Signature: wait($timeout) : void

    +

    Wait for $timeout seconds.

    +

    waitForElement

    +

    Signature: waitForElement($element, [int $timeout]) : void

    +

    Waits up to $timeout seconds for an element to appear on the page. +If the element doesn't appear, a timeout exception is thrown.

    +
    <?php
    +$I->waitForElement('#agree_button', 30); // secs
    +$I->click('#agree_button');
    +
    +

    waitForElementChange

    +

    Signature: waitForElementChange($element, Closure $callback, [int $timeout]) : void

    +

    Waits up to $timeout seconds for the given element to change. +Element "change" is determined by a callback function which is called repeatedly +until the return value evaluates to true.

    +
    <?php
    +use \Facebook\WebDriver\WebDriverElement
    +$I->waitForElementChange('#menu', function(WebDriverElement $el) {
    +    return $el->isDisplayed();
    +}, 100);
    +
    +

    waitForElementClickable

    +

    Signature: waitForElementClickable($element, [int $timeout]) : void

    +

    Waits up to $timeout seconds for the given element to be clickable. +If element doesn't become clickable, a timeout exception is thrown.

    +
    <?php
    +$I->waitForElementClickable('#agree_button', 30); // secs
    +$I->click('#agree_button');
    +
    +

    waitForElementNotVisible

    +

    Signature: waitForElementNotVisible($element, [int $timeout]) : void

    +

    Waits up to $timeout seconds for the given element to become invisible. +If element stays visible, a timeout exception is thrown.

    +
    <?php
    +$I->waitForElementNotVisible('#agree_button', 30); // secs
    +
    +

    waitForElementVisible

    +

    Signature: waitForElementVisible($element, [int $timeout]) : void

    +

    Waits up to $timeout seconds for the given element to be visible on the page. +If element doesn't appear, a timeout exception is thrown.

    +
    <?php
    +$I->waitForElementVisible('#agree_button', 30); // secs
    +$I->click('#agree_button');
    +
    +

    waitForJS

    +

    Signature: waitForJS(string $script, [int $timeout]) : void

    +

    Executes JavaScript and waits up to $timeout seconds for it to return true.

    +

    In this example we will wait up to 60 seconds for all jQuery AJAX requests to finish.

    +
    <?php
    +$I->waitForJS("return $.active == 0;", 60);
    +
    +

    waitForJqueryAjax

    +

    Signature: waitForJqueryAjax([int $time]) : void

    +

    Waits for any jQuery triggered AJAX request to be resolved.

    +
    <?php
    +$I->amOnPage('/triggering-ajax-requests');
    +$I->waitForJqueryAjax();
    +$I->see('From AJAX');
    +
    +

    waitForText

    +

    Signature: waitForText(string $text, [int $timeout], [$selector]) : void

    +

    Waits up to $timeout seconds for the given string to appear on the page.

    +

    Can also be passed a selector to search in, be as specific as possible when using selectors. +waitForText() will only watch the first instance of the matching selector / text provided. +If the given text doesn't appear, a timeout exception is thrown.

    +
    <?php
    +$I->waitForText('foo', 30); // secs
    +$I->waitForText('foo', 30, '.title'); // secs
    +
    + + +

    Read more in Codeception documentation.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 000000000..7180726a3 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Getting started","text":"

    This is the documentation for version 4 of the project, the current version. Documentation for the previous version of the project, version 3, can be found here.

    The wp-browser library provides a set of Codeception modules and middleware to enable the testing of WordPress sites, plugins and themes.

    "},{"location":"#requirements","title":"Requirements","text":"

    Depending on the nature of your project, there are different requirements it will need to satisfy before getting started.

    "},{"location":"#site","title":"Site","text":"
    • Ensure you're running the vendor/bin/codecept init wpbrowser command from the root directory of your WordPress site.
    • Ensure the directory contains the WordPress installation files. In a standard scenario you should have extracted WordPress files in this directory.
    • Ensure your installation is configured: it should contain a wp-config.php file.
    "},{"location":"#plugin","title":"Plugin","text":"
    • Ensure you're running the vendor/bin/codecept init wpbrowser command from the root directory of your plugin; this should be the directory that contains the PHP file defining the plugin header.
    "},{"location":"#theme","title":"Theme","text":"
    • Ensure you're running the vendor/bin/codecept init wpbrowser command from the root directory of your theme; this should be the directory that contains the style.css file defining the theme header.

    If you decide to use the quick installation, then your PHP version should have the sqlite3 extensions installed and activated. You can check this using the php -m command and verifying the sqlite3 extension is among the active extensions.

    "},{"location":"#installation","title":"Installation","text":"

    Add wp-browser to your project as a development dependency using Composer

    cd my-wordrpess-project\ncomposer require --dev lucatume/wp-browser\n

    Initialize wp-browser to quickly configured to suite your project and setup:

    vendor/bin/codecept init wpbrowser\n

    The command will set up your project to run integration and end-to-end tests using:

    • SQLite as the database engine, leveraging the SQLite Database Integration plugin
    • PHP built-in web server to serve the WordPress site on localhost (e.g. http://localhost:8080)
    • Chromedriver to drive the local version of Chrome installed on your machine

    If you're working on a plugin or theme project, the default configuration will add some extra steps:

    • install the latest version of WordPress in the tests/_wordpress directory
    • create a tests/_plugins directory: any file or directory in this directory will be symlinked into the WordPress installation in tests/_wordpress/wp-content/plugins
    • create a tests/_themes directory: any file or directory in this directory will be symlinked into the WordPress installation in tests/_wordpress/wp-content/themes

    For most projects this configuration will be enough to get started with testing.

    You can run your tests immediately using the vendor/bin/codecept run command.

    Read more about the commands provided by the library here.

    "},{"location":"#using-a-custom-configuration","title":"Using a custom configuration","text":"

    If you decide to skip the default configuration, you will be able to set up wp-browser to suit your needs and local setup by editing the tests/.env file. The inline documentation in the file will guide you through the configuration process.

    Read more about using a custom configuration here.

    "},{"location":"#getting-support-for-wp-browser-configuration-and-usage","title":"Getting support for wp-browser configuration and usage","text":"

    The best place to get support for wp-browser is the project documentation. Since this project builds on top of PHPUnit and Codeception, you can also refer to their documentation.

    If you can't find the answer to your question here you can ask on the \"Issues\" section of the wp-browser repository taking care to provide as much information as possible.

    Finally, you can contact me directly to set up a call to discuss your project needs and how wp-browser can help you.

    "},{"location":"DispatcherAPI/","title":"Dispatcher API","text":"

    An API to dispatch and subscribe to events fired during tests execution.

    "},{"location":"DispatcherAPI/#events-dispatched-by-codeception","title":"Events dispatched by Codeception","text":"

    You can subscribe to the following events dispatched by Codeception in either the global bootstrap file (usually tests/_bootstrap.php), or in a suite bootstrap file (usually tests/<suite>/_bootstrap.php) using the Event Dispatcher Bridge extension:

    • Codeception\\Events::SUITE_BEFORE
    • Codeception\\Events::SUITE_AFTER
    • CodeceptionventsEvents::TEST_START
    • CodeceptionventsEvents::TEST_BEFORE
    • CodeceptionventsEvents::STEP_BEFORE
    • CodeceptionventsEvents::STEP_AFTER
    • CodeceptionventsEvents::TEST_FAIL
    • CodeceptionventsEvents::TEST_ERROR
    • CodeceptionventsEvents::TEST_PARSED
    • CodeceptionventsEvents::TEST_INCOMPLETE
    • CodeceptionventsEvents::TEST_SKIPPED
    • CodeceptionventsEvents::TEST_WARNING
    • CodeceptionventsEvents::TEST_USELESS
    • CodeceptionventsEvents::TEST_SUCCESS
    • CodeceptionventsEvents::TEST_AFTER
    • CodeceptionventsEvents::TEST_END
    • CodeceptionventsEvents::TEST_FAIL_PRINT
    • CodeceptionventsEvents::RESULT_PRINT_AFTER

    In the global bootstrap file (usually tests/_bootstrap.php), or the suite bootstrap file (usually tests/<suite>/_bootstrap.php), subscribe to the Codeception events by providing a callback function that will accept different parameters depending on the event being dispatched:

    <?php\n\nuse Codeception\\Events;\nuse Codeception\\Event\\SuiteEvent\nuse Codeception\\Event\\TestEvent;\nuse Codeception\\Event\\StepEvent;\nuse Codeception\\Event\\PrintResultEvent;\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\n\nDispatcher::addListener(Events::SUITE_BEFORE, function (SuiteEvent $suiteEvent) {\n    codecept_debug('Running on SUITE BEFORE');\n});\n\nDispatcher::addListener(Events::SUITE_AFTER, function (SuiteEvent $suiteEvent) {\n    codecept_debug('Running on SUITE AFTER');\n});\n\nDispatcher::addListener(Events::TEST_START, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST START');\n});\n\nDispatcher::addListener(Events::TEST_BEFORE, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST BEFORE');\n});\n\nDispatcher::addListener(Events::STEP_BEFORE, function (StepEvent $stepEvent) {\n    codecept_debug('Running on STEP BEFORE');\n});\n\nDispatcher::addListener(Events::STEP_AFTER, function (StepEvent $stepEvent) {\n    codecept_debug('Running on STEP AFTER');\n});\n\nDispatcher::addListener(Events::TEST_FAIL, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST FAIL');\n});\n\nDispatcher::addListener(Events::TEST_ERROR, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST ERROR');\n});\n\nDispatcher::addListener(Events::TEST_PARSED, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST PARSED');\n});\n\nDispatcher::addListener(Events::TEST_INCOMPLETE, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST INCOMPLETE');\n});\n\nDispatcher::addListener(Events::TEST_SKIPPED, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST SKIPPED');\n});\n\nDispatcher::addListener(Events::TEST_WARNING, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST WARNING');\n});\n\nDispatcher::addListener(Events::TEST_USELESS, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST USELESS');\n});\n\nDispatcher::addListener(Events::TEST_SUCCESS, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST SUCCESS');\n});\n\nDispatcher::addListener(Events::TEST_AFTER, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST AFTER');\n});\n\nDispatcher::addListener(Events::TEST_END, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST END');\n});\n\nDispatcher::addListener(Events::TEST_FAIL_PRINT, function (PrintResultEvent $printResultEvent) {\n    codecept_debug('Running on TEST FAIL PRINT');\n});\n\nDispatcher::addListener(Events::RESULT_PRINT_AFTER, function (PrintResultEvent $printResultEvent) {\n    codecept_debug('Running on RESULT PRINT AFTER');\n});\n
    "},{"location":"DispatcherAPI/#events-dispatched-by-wp-browser","title":"Events dispatched by wp-browser","text":"

    The project dispatches its own events, allowing you to subscribe to them to control the test state and execution. To subscribe to the events dispatched by wp-browser, you do not need to use the Event Dispatcher Bridge extension.

    "},{"location":"DispatcherAPI/#wploader-module-events","title":"WPLoader Module Events","text":"

    The WPLoader module will dispatch events during its initialization.

    "},{"location":"DispatcherAPI/#event_before_loadonly","title":"EVENT_BEFORE_LOADONLY","text":"

    This event fires before WordPress is loaded by the WPLoader module when loadOnly is set to true.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    WordPress is not loaded yet, so you cannot use functions or classes defined by WordPress, themes or plugins here. You can interact with the WordPress installation and use the lucatume\\WPBrowser\\WordPress\\PreloadFilters class to hook on actions and filters that will be fired by WordPress once loaded.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPLoader;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPLoader::EVENT_BEFORE_LOADONLY, function (Event $event) {\n    /** @var WPLoader $wpLoader */\n    $wpLoader = $event->getOrigin();\n\n    codecept_debug('Running on EVENT_BEFORE_LOADONLY');\n\n    // Interact with the WordPress installation, its filesystem and database.\n    $installation = $wpLoader->getInstallation();\n    $pluginsDir = $installation->getPluginsDir();\n    $db = $installation->getDb();\n    $db->import(codecept_data_dir('some-dump.sql'));\n\n    // Use the PreloadFilters class to hook on WordPress actions and filters.\n    PreloadFilters::addFilter('init', fn() => update_option('some_option', 'some_value'));\n    PreloadFilters::addFilter('pre_option_some_option', fn() => 'some_value');\n});\n
    "},{"location":"DispatcherAPI/#event_after_loadonly","title":"EVENT_AFTER_LOADONLY","text":"

    This event fires after WordPress is loaded by the WPLoader module when loadOnly is set to true.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    At this point, WordPress has been loaded. You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPLoader;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPLoader::EVENT_AFTER_LOADONLY, function (Event $event) {\n    /** @var WPLoader $wpLoader */\n    $wpLoader = $event->getOrigin();\n\n    codecept_debug('Running on EVENT_AFTER_LOADONLY');\n\n    // Interact with the WordPress installation, its filesystem and database.    \n    $installation = $wpLoader->getInstallation();\n    $pluginsDir = $installation->getPluginsDir();\n    $db = $installation->getDb();\n    $db->import(codecept_data_dir('some-dump.sql'));\n\n    // Use WordPress functions and classes.\n    update_option('some_option', 'some_value');\n});\n
    "},{"location":"DispatcherAPI/#event_before_install","title":"EVENT_BEFORE_INSTALL","text":"

    This event fires before WordPress is installed by the WPLoader module when loadOnly is set to false.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    WordPress is not loaded yet, so you cannot use functions or classes defined by WordPress, themes or plugins here. You can interact with the WordPress installation and use the lucatume\\WPBrowser\\WordPress\\PreloadFilters class to hook on actions and filters that will be fired by WordPress once loaded.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPLoader;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPLoader::EVENT_BEFORE_INSTALL, function (Event $event) {\n    /** @var WPLoader $wpLoader */\n    $wpLoader = $event->getOrigin();\n\n    codecept_debug('Running on EVENT_BEFORE_INSTALL');\n\n    // Interact with the WordPress installation, its filesystem and database.\n    $installation = $wpLoader->getInstallation();\n    $pluginsDir = $installation->getPluginsDir();\n    $db = $installation->getDb();\n    $db->import(codecept_data_dir('some-dump.sql'));\n\n    // Use the PreloadFilters class to hook on WordPress actions and filters.\n    PreloadFilters::addFilter('init', fn() => update_option('some_option', 'some_value'));\n    PreloadFilters::addFilter('pre_option_some_option', fn() => 'some_value');\n});\n
    "},{"location":"DispatcherAPI/#event_after_install","title":"EVENT_AFTER_INSTALL","text":"

    This event fires after WordPress is installed by the WPLoader module when loadOnly is set to false.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    At this point, WordPress has been installed and loaded. You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins. This event fires before dump files specified in the dump configuration parameter of the WPLoader module are imported.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPLoader;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPLoader::EVENT_AFTER_INSTALL, function (Event $event) {\n    /** @var WPLoader $wpLoader */\n    $wpLoader = $event->getOrigin();\n\n    codecept_debug('Running on EVENT_AFTER_INSTALL');\n\n    // Interact with the WordPress installation, its filesystem and database.    \n    $installation = $wpLoader->getInstallation();\n    $pluginsDir = $installation->getPluginsDir();\n    $db = $installation->getDb();\n    $db->import(codecept_data_dir('some-dump.sql'));\n\n    // Use WordPress functions and classes.    \n    update_option('some_option', 'some_value');\n});\n
    "},{"location":"DispatcherAPI/#event_after_install_1","title":"EVENT_AFTER_INSTALL","text":"

    This event fires after WordPress is installed by the WPLoader module when loadOnly is set to false.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    At this point, WordPress has been installed and loaded. You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPLoader;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPLoader::EVENT_AFTER_INSTALL, function (Event $event) {\n    /** @var WPLoader $wpLoader */\n    $wpLoader = $event->getOrigin();\n\n    codecept_debug('Running on EVENT_AFTER_INSTALL');\n\n    // Interact with the WordPress installation, its filesystem and database.    \n    $installation = $wpLoader->getInstallation();\n    $pluginsDir = $installation->getPluginsDir();\n    $db = $installation->getDb();\n    $db->import(codecept_data_dir('some-dump.sql'));\n\n    // Use WordPress functions and classes.\n    update_option('some_option', 'some_value');\n});\n
    "},{"location":"DispatcherAPI/#event_after_bootstrap","title":"EVENT_AFTER_BOOTSTRAP","text":"

    This event fires after the WPLoader module has finished bootstrapping the WordPress installation and dump files specified in the dump configuration parameter of the WPLoader module are imported.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    You can interact with the WordPress installation using functions and classes defined by WordPress, themes or plugins.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPLoader;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPLoader::EVENT_AFTER_BOOTSTRAP, function (Event $event) {\n    /** @var WPLoader $wpLoader */\n    $wpLoader = $event->getOrigin();\n\n    codecept_debug('Running on EVENT_AFTER_BOOTSTRAP');\n\n    // Interact with the WordPress installation, its filesystem and database.    \n    $installation = $wpLoader->getInstallation();\n    $pluginsDir = $installation->getPluginsDir();\n    $db = $installation->getDb();\n    $db->import(codecept_data_dir('some-dump.sql'));\n\n    // Use WordPress functions and classes.\n    update_option('some_option', 'some_value');\n});\n
    "},{"location":"DispatcherAPI/#wpdb-module-events","title":"WPDb Module Events","text":""},{"location":"DispatcherAPI/#event_before_suite","title":"EVENT_BEFORE_SUITE","text":"

    This event fires after the WPDb module has run its _beforeSuite method.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    At this point the module has connected to the database, cleaned up and populated the database with the dump files.

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPDb;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPDb::EVENT_BEFORE_SUITE, function (Event $event) {\n    /** @var WPDb $wpDb */\n    $wpDb = $event->getOrigin();    \n\n    codecept_debug('Running on EVENT_BEFORE_SUIT\n    E');\n});\n
    "},{"location":"DispatcherAPI/#event_before_initialize","title":"EVENT_BEFORE_INITIALIZE","text":"

    This event fires before the WPDb module initializes.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Module\\WPDb;\nuse lucatume\\WPBrowser\\Events\\Event;\n\nDispatcher::addListener(WPDb::EVENT_BEFORE_INITIALIZE, function (Event $event) {\n    /** @var WPDb $wpDb */\n    $wpDb = $event->getOrigin();    \n\n    codecept_debug('Running on EVENT_BEFORE_INITIALIZE');\n});\n
    "},{"location":"DispatcherAPI/#event_after_initialize","title":"EVENT_AFTER_INITIALIZE","text":"

    This event fires after the WPDb module has initialized.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;  \nuse lucatume\\WPBrowser\\Module\\WPDb;  \nuse lucatume\\WPBrowser\\Events\\Event;  \n\nDispatcher::addListener(WPDb::EVENT_AFTER_INITIALIZE, function (Event $event) {\n    /** @var WPDb $wpDb */\n    $wpDb = $event->getOrigin();    \n\n    codecept_debug('Running on EVENT_AFTER_INITIALIZE');\n});\n
    "},{"location":"DispatcherAPI/#event_after_db_prepare","title":"EVENT_AFTER_DB_PREPARE","text":"

    This event fires after the WPDb module has prepared the database setting up some default values for quality-of-life improvements.

    Due to order-of-operations, you can hook on this event only in the global bootstrap file (usually tests/_bootstrap.php).

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;  \nuse lucatume\\WPBrowser\\Module\\WPDb;  \nuse lucatume\\WPBrowser\\Events\\Event;  \n\nDispatcher::addListener(WPDb::EVENT_AFTER_DB_PREPARE, function (Event $event) {\n    /** @var WPDb $wpDb */\n    $wpDb = $event->getOrigin();    \n\n    codecept_debug('Running on EVENT_AFTER_DB_PREPARE');\n});\n
    "},{"location":"DispatcherAPI/#dispatching-custom-events","title":"Dispatching custom events","text":"

    You can use the Dispatcher::dispatch method to dispatch and subscribe to custom events:

    <?php\n\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\nuse lucatume\\WPBrowser\\Events\\Event;  \n\nDispatcher::dispatch('my-event', 'my-origin', ['foo' => 'bar']);\n\n// Some other code...\nDispatcher::addListener('my-event', function (Event $event) {\n    $origin = $event->getOrigin();\n    $foo = $event->get('foo');\n    codecept_debug('Running on my custom event');\n});\n
    "},{"location":"commands/","title":"Commands","text":""},{"location":"commands/#codeception-commands-provided-by-the-library","title":"Codeception commands provided by the library","text":"

    The library provides some custom commands that can be added to the project Codeception configuration file ( either codeception.yml or codeception.dist.yml).

    "},{"location":"commands/#run-and-codeceptionrun","title":"run and codeception:run","text":"

    Enable the commands with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\RunOriginal\"\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\RunAll\"\n

    WordPress extensive use of global variables, constants and side effectes makes it difficult to run multiple test suites in the same process without running into conflicts due to leaking state and side effects. For this reason the project replaces Codeception run command with one that will run each suite in a separate process. You can invoke the original Codeception command using the codeception:run command. Just like the original, the run command accepts all the arguments and options of the original Codeception command.

    Run all the suites, each one in a separate process:

    vendor/bin/codecept run\n

    Run only the Integration suite:

    vendor/bin/codecept run Integration\n

    Run a specific test file:

    vendor/bin/codecept run Integration tests/Integration/MyTest.php\n

    Run a specific test method:

    vendor/bin/codecept run Integration tests/Integration/MyTest.php:testMyMethod\n

    Read the Codeception documentation for more information about the run command.

    "},{"location":"commands/#devstart","title":"dev:start","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DevStart\"\n

    If not already running, start the services required to run the tests. The started services are read from the Codeception configuration file (either codeception.yml or codeception.dist.yml), from the extensions section, under the config key.

    Given the following configuration:

    extensions:\n  enabled:\n    - lucatume\\WPBrowser\\Extension\\ChromeDriverController\n    - lucatume\\WPBrowser\\Extension\\BuiltInServerController\n    - lucatume\\WPBrowser\\Extension\\DockerComposeController\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\":\n      port: '%CHROMEDRIVER_PORT%'\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\":\n      docroot: '%WORDPRESS_ROOT_DIR%'\n      workers: 5\n      port: '%BUILT_IN_SERVER_PORT%'\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\":\n      compose-file: 'tests/docker-compose.yml'\n      env-file: 'tests/.env'\n

    Running the command will start ChromeDriver, the built-in PHP server and Docker Compose.

    "},{"location":"commands/#devstop","title":"dev:stop","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DevStop\"\n

    If running, stop the services required to run the tests. The stopped services are read from the Codeception configuration file (either codeception.yml or codeception.dist.yml), from the extensions section, under the config key.

    Given the following configuration:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\"\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\"\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\":\n      port: '%CHROMEDRIVER_PORT%'\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\":\n      docroot: '%WORDPRESS_ROOT_DIR%'\n      workers: 5\n      port: '%BUILT_IN_SERVER_PORT%'\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\":\n      compose-file: 'tests/docker-compose.yml'\n      env-file: 'tests/.env'\n

    Running the command will stop ChromeDriver, the built-in PHP server and Docker Compose.

    "},{"location":"commands/#devrestart","title":"dev:restart","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DevRestart\"\n

    This command is just a shortcut to run dev:stop and dev:start in sequence.

    "},{"location":"commands/#devinfo","title":"dev:info","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DevInfo\"\n

    Provides information about the local testing stack managed by the DockerComposeController, BuiltInServerController and ChromeDriverController extensions.

    "},{"location":"commands/#wpdbimport","title":"wp:db:import","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DbImport\"\n

    You can use WP CLI to interact with your WordPress installation, but WP CLI does not support SQLite databases in the context of the wp db import command. This command fills that gap by providing a database dump file import command that will support MySQL and SQLite databases.

    "},{"location":"commands/#wpdbexport","title":"wp:db:export","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DbExport\"\n

    You can use WP CLI to interact with your WordPress installation, but WP CLI does not support SQLite databases in the context of the wp db export command. This command fills that gap by providing a database dump file export command that will support MySQL and SQLite databases.

    "},{"location":"commands/#chromedriverupdate","title":"chromedriver:update","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\ChromedriverUpdate\"\n

    If you're using Chromedriver as a binary installed in the Composer vendor directory (vendor/bin by default), you can use this command to update it. This command will download the latest version of Chromedriver compatible with the Chrome version installed on your machine in the Composer vendor directory.

    Note: if the download fails, it might be a certificate issue.

    "},{"location":"commands/#generatewpunit","title":"generate:wpunit","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPUnit\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPTestCase class. The class incorporates the WordPress test case from the wordpress-develop repository and adds some utility methods to make testing easier in the context of Codeception.

    The lucatume\\WPBrowser\\TestCase\\WPTestCase class is the one that should be used when writing tests for WordPress code when using the WPLoader module.

    Together with the WPLoader module, the WPTestCase class provides a number of functionalities to clean up the database after each test method and to reset the global state of WordPress.

    "},{"location":"commands/#every-test-method-runs-in-a-transaction","title":"Every test method runs in a transaction","text":"

    Database queries running in the context of test methods of a test case extending the WPTestCase class will run in a transaction that is rolled back after the test method is run. This means that any database change happening in the context of a test method will not appear in the database while the test is running and after the test is run.

    "},{"location":"commands/#generatewpajax","title":"generate:wpajax","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPAjax\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPAjaxTestCase class. This class is a version of the WPTestCase designed to test AJAX requests.

    "},{"location":"commands/#generatewpcanonical","title":"generate:wpcanonical","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPCanonical\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPCanonicalTestCase class. This class is a version of the WPTestCase designed to test canonical redirects.

    "},{"location":"commands/#generatewprestapi","title":"generate:wprestapi","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPRestApi\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPRestApiTestCase class. This class is a version of the WPTestCase designed to test the handling of REST API requests.

    "},{"location":"commands/#generatewprestcontroller","title":"generate:wprestcontroller","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPRestController\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPRestControllerTestCase class. This class is a version of the WPTestCase designed to unit-test REST API controllers.

    "},{"location":"commands/#generatewprestposttypecontroller","title":"generate:wprestposttypecontroller","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPRestPostTypeController\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPRestPostTypeControllerTestCase class. This class is a version of the WPTestCase designed to unit-test REST API controllers for post types.

    "},{"location":"commands/#generatewpxml","title":"generate:wpxml","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPXML\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPXMLTestCase class. This class is a version of the WPTestCase designed to test the production of XML data.

    "},{"location":"commands/#generatewpxmlrpc","title":"generate:wpxmlrpc","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPXMLRPC\"\n

    Generate a test case extending the lucatume\\WPBrowser\\TestCase\\WPXMLRPCTestCase class. This class is a version of the WPTestCase designed to test the XML-RPC API.

    "},{"location":"commands/#monkeycachepath","title":"monkey:cache:path","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\MonkeyCachePath\"\n

    Get the path to the monkey-patching cache directory.

    Use the --porcelain or -p option to get the path without any additional output.

    "},{"location":"commands/#monkeycacheclear","title":"monkey:cache:clear","text":"

    Enable the command with:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\MonkeyCacheClear\"\n

    Clear the monkey-patching cache.

    Use the --porcelain or -p option to suppress any confirmation output.

    "},{"location":"custom-configuration/","title":"Custom configuration","text":""},{"location":"custom-configuration/#custom-testing-configuration","title":"Custom testing configuration","text":"

    Any non default configuration is considered a custom configuration. If your project requires a tailored set up, this is the configuration for you.

    "},{"location":"custom-configuration/#using-a-custom-configuration-to-run-tests","title":"Using a custom configuration to run tests","text":"

    If you decide to skip the default configuration, or are working on a project that cannot use the default configuration you will be able to set up wp-browser to suit your needs using a custom configuration.

    Choose \"no\", to not use the default configuration, when running the vendor/bin/codecept init wpbrowser command.

    The command will set up the file structure to be able to run integration and end-to-end tests and will leverage Codeception dynamic configuration using parameters to control the testing stack using the tests/.env file.

    "},{"location":"custom-configuration/#walkthrough-of-the-testsenv-file","title":"Walkthrough of the tests/.env file","text":"
    • WORDPRESS_ROOT_DIR - the path to the root WordPress installation directory. This is the directory that contains WordPress files, like wp-load.php. This path can be absolute or relative to the root project directory; e.g. vendor/wordpress (relative) or /var/www/wordpress (absolute) will work.
    • WORDPRESS_URL - the URL of the WordPress installation. This is the URL that will be used by the browser to access the WordPress installation in the context of end-to-end tests; e.g. http://localhost:8080 or https://wordpress.local.
    • WORDPRESS_DOMAIN - the domain of the WordPress installation; this value should follow the WORDPRESS_URL value. E.g. if WORDPRESS_URL is http://localhost:8080 the WORDPRESS_DOMAIN value should be localhost:8080; if WORDPRESS_URL is https://wordpress.local the WORDPRESS_DOMAIN value should be wordpress.local.
    • WORDPRESS_DB_URL - the user, password, host, and name of the database used by the tests. If the database is a MySQL database, the value should be in the form mysql://user:password@host:port/database_name. If the database is a SQLite database, the value should be in the form sqlite://path/to/database/file.
    • WORDPRESS_TABLE_PREFIX - the database table prefix used by the WordPress installation, the one served at WORDPRESS_URL. This value is usually wp_ but can be different if the WordPress installation has been configured to use a different prefix.
    • TEST_TABLE_PREFIX - the database table prefix used by the WPLoader module to install WordPress and run the tests. This value is usually test_ and should be different from the WORDPRESS_TABLE_PREFIX value.
    • WORDPRESS_ADMIN_USER - the username of the WordPress administrator user. E.g. admin.
    • WORDPRESS_ADMIN_PASSWORD - the password of the WordPress administrator user. E.g. secret!password.
    • CHROMEDRIVER_HOST - the host of the Chromedriver server. This value is usually localhost if you're running Chromedriver on the same machine as the tests. If you're running your tests using a container stack, it will be the name of the container running Chromedriver, e.g. chromedriver.
    • CHROMEDRIVER_PORT - the port of the Chromedriver server. This value is usually 9515 if you're running Chromedriver on the same machine as the tests. If you're running your tests using a container stack, it will be the port exposed by the container running Chromedriver, e.g. 4444. Note the default configuration will set this value to a random port during set up to avoid conflicts with other services running on the same machine.
    "},{"location":"custom-configuration/#handling-custom-file-structures","title":"Handling custom file structures","text":"

    If your site uses a customized file structure to manage WordPress, you will need to further configure the WPLoader module to correctly look for the site content. Read more about setting up WPLoader to correctly load plugins and themes from custom locations here.

    "},{"location":"default-configuration/","title":"Default configuration","text":""},{"location":"default-configuration/#default-testing-configuration","title":"Default testing configuration","text":"

    The recommended configuration for most projects. It allows you to get into WordPress integration and end-to-end testing quickly and easily.

    "},{"location":"default-configuration/#requirements","title":"Requirements","text":"

    The default configuration will set up Codeception and wp-browser to use SQLite as the database engine, PHP built-in server to serve the test site on localhost and your local version of Chrome, driven by Chromedriver, to run end-to-end tests.

    As such, the default configuration has the following requirements:

    • the sqlite3 PHP extension; you can check if if's installed by running php -m | grep sqlite3 in your terminal
    • the pdo_sqlite PHP extension; you can check if if's installed by running php -m | grep pdo_sqlite in your terminal
    • PHP built-in server can work with only one thread, but it will be faster using multiple threads; multiple threads are not supported on Windows, but they are supported on WSL.
    • the Chrome browser installed on your machine
    "},{"location":"default-configuration/#overview-plugin-and-theme-project","title":"Overview - plugin and theme project","text":"

    If you're configuring wp-browser for a plugin or theme project, the default configuration will install WordPress in the tests/_wordpress directory and configure the installation to run using SQLite as a database engine. The SQLite Database Integration plugin) will be placed in the installation must-use plugins directory.

    If your plugin or theme project requires additional plugins or theme to work, you can place them in the tests/_worpdress/wp-content/plugins and tests/_wordpress/wp-content/themes directories respectively.

    When adding, or removing, plugin and themes, remember to update the WPLoader module configuration to load the correct plugins and themes in your integration tests.

    On the same note, update the database dump used by the WPDb module to reflect the changes in the dump loaded in the end-to-end tests. The easiest way to update the database fixture is to load the current database dump using the wp:db:import command, manually setting up the site interacting with it and then exporting the database dump using the wp:db:export command.

    You can find out about the URL of the site served by the PHP built-in web server by running the dev:info command.

    "},{"location":"default-configuration/#overview-site-project","title":"Overview - site project","text":"

    If you're configuring wp-browser for a site project, the default configuration will use a combination of PHP built-in web server and the SQLite Database Integration plugin to run the tests and serve your site.

    The router file used by the PHP built-in web server will force the site, when served on localhost, to use SQLite as database engine leaving your existing local MySQL database untouched.

    Your existing WordPress installation will be picked up as it is, with all the plugins and themes found in the contents directory.

    Existing plugins and themes are not added to WPLoader module configuration by wp-browser, you have to do that manually.

    Similarly, the database dump used by the WPDb module is, by default, an empty WordPress installation where no plugins and themes are active. You have to update the database dump used by the module to reflect the state of your site. You can do that by loading the current database dump using the wp:db:import command, manually setting up the site interacting with it and then exporting the database dump using the wp:db:export command.

    You can find out about the URL of the site served by the PHP built-in web server by running the dev:info command.

    "},{"location":"default-configuration/#when-not-to-use-the-default-configuration","title":"When not to use the default configuration","text":"

    The default configuration is the recommended one for most projects, but some projects might require you to use a custom configuration to make the most out of wp-browser.

    "},{"location":"default-configuration/#database-drop-in","title":"Database drop-in","text":"

    The default configuration will use the SQLite Database Integration plugin to use SQLite as the database engine. This requires placing a db.php drop-in file in the WordPress content directory.

    If your project already requires a db.php drop-in file, you will have to use a custom configuration.

    "},{"location":"default-configuration/#multisite-with-sub-domains","title":"Multisite with sub-domains","text":"

    While Chrome will handle sub-domains correctly, even on localhost, WordPress will not. If you're testing a multisite installation with sub-domains, you will have to use a custom configuration.

    "},{"location":"default-configuration/#custom-site-structure","title":"Custom site structure","text":"

    If your site uses a customized file structure to manage WordPress, you will need to configure wp-browser using a custom configuration. This is usually true for some site projects, and will most likely not be an issue for plugin and theme projects.

    Using a custom configuration is not that difficult though: read more about using a custom configuration here.

    "},{"location":"extensions/","title":"Extensions","text":"

    The library provides custom Codeception extensions that can be added to the project configuration file, codeception.yml or codeception.dist.yml by default, in the extensions section.

    • BuiltInServerController
    • ChromeDriverController
    • DockerComposeController
    • IsolationSupport
    • Symlinker
    • EventDispatcherBridge
    • MySqlServerController
    "},{"location":"migration/","title":"Migrating to newer versions","text":"

    Depending on your project PHP compatibility, you have three options to choose from:

    • Your project supports PHP 7.1 to 7.4: migrate to wp-browser version 3.5
    • Your project supports PHP 8.0 or above: migrate to wp-browser version 4.0
    • You cannot, or do not want, to migrate from version 3 of wp-browser to a new version: see how you can lock your reuirements to avoid the upgrade
    "},{"location":"migration/#version-35-and-40","title":"Version 3.5 and 4.0","text":"

    Version 3.5 and 4.0 are the latest versions of wp-browser. Version 3.5 is a transpile of version 4 to be compatible with PHP 7.1 to 7.4 that contains, for all intents and purposes, the same facilities and systems contained in version 4 of wp-browser adapter to work on lower PHP versions and version 4 of Codeception.

    Future development of wp-browser will happen on version 4 and will be transpiled to version 3.5 for back-compatibility purposes.

    "},{"location":"migration/#migrate-from-version-3-to-35","title":"Migrate from version 3 to 3.5","text":"
    1. Update the required version of wp-browser in your composer.json file to 3.5:
      {\n  \"require-dev\": {\n    \"lucatume/wp-browser\": \"^3.5\"\n  }\n}\n
    2. See the changes common to version 3.5 and 4.0
    "},{"location":"migration/#migrate-from-version-3-to-4","title":"Migrate from version 3 to 4","text":"
    1. Update the required version of wp-browser in your composer.json file to 4.0:
      {\n  \"require-dev\": {\n    \"lucatume/wp-browser\": \"^4.0\"\n  }\n}\n
    2. See the changes common to version 3.5 and 4.0
    "},{"location":"migration/#changes-common-to-version-35-and-40","title":"Changes common to version 3.5 and 4.0","text":"
    1. Update your main Codeception configuration file (e.g. codeception.yml) to enable the new commands:

    extensions:\n  commands:\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\RunOriginal\"\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\RunAll\"\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DbExport\"\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\DbImport\"\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\MonkeyCachePath\"\n    - \"lucatume\\\\WPBrowser\\\\Command\\\\MonkeyCacheClear\"\n
    2. Along with the new commands, update the existing commands to use the lucatume\\WPBrowser\\Command\\ namespace:

    extensions:\n  commands:\n-    - \"Codeception\\\\Command\\\\GenerateWPUnit\"\n-    - \"Codeception\\\\Command\\\\GenerateWPRestApi\"\n-    - \"Codeception\\\\Command\\\\GenerateWPRestController\"\n-    - \"Codeception\\\\Command\\\\GenerateWPRestPostTypeController\"\n-    - \"Codeception\\\\Command\\\\GenerateWPAjax\"\n-    - \"Codeception\\\\Command\\\\GenerateWPCanonical\"\n-    - \"Codeception\\\\Command\\\\GenerateWPXMLRPC\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPUnit\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPRestApi\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPRestController\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPRestPostTypeController\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPAjax\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPCanonical\"\n+    - \"lucatume\\\\WPBrowser\\\\Command\\\\GenerateWPXMLRPC\"\n
    3. If your test code is loading deprecated functions, arguments, classes, files, or hooks, you need to update your test code to let the test case know using the setExpectedDeprecated method:
    <?php\n\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTestUsingDeprecatedCode extends WPTestCase {\n    public function test_deprecatd_function() {\n        // add_filter( 'deprecated_function_trigger_error', '__return_false' );\n        $this->setExpectedDeprecated( 'my_deprecated_function' );\n        my_deprecated_function();\n    }\n\n    public function test_deprecated_class(){\n        // add_filter( 'deprecated_class_trigger_error', '__return_false' );\n        $this->setExpectedDeprecated( 'MyDeprecatedClass' );\n        new MyDeprecatedClass();\n    }\n\n    public function test_deprecated_file(){\n        // add_filter( 'deprecated_file_trigger_error', '__return_false' );\n        $this->setExpectedDeprecated( '/path/to/my_deprecated_file.php' );\n        require_once 'my_deprecated_file.php';\n    }\n\n    public function test_deprecated_hook(){\n        // add_filter( 'deprecated_hook_trigger_error', '__return_false' );\n        $this->setExpectedDeprecated( 'my_deprecated_hook' );\n        do_action( 'my_deprecated_hook' );\n    }\n}\n
    Previously, your code could just filter the deprecated_function_trigger_error, deprecated_argument_trigger_error, deprecated_class_trigger_error, deprecated_file_trigger_error, and deprecated_hook_trigger_error, hooks to return false to tolerate the deprecation notices in tests. 4. If your test code is directly modifying properties like $expected_deprecated or $expected_doing_it_wrong directly, you need to update your test code to use the setExpectedDeprecated and setExpectedIncorrectUsage methods:
    <?php\n\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\nclass MyTestUsingDeprecatedCode extends WPTestCase {\n    public function test_deprecated_function() {\n        // $this->expected_deprecated[] = 'my_deprecated_function';\n        $this->setExpectedDeprecated( 'my_deprecated_function' );\n        my_deprecated_function();\n    }\n\n    public function test_doing_it_wrong(){\n        // $this->expected_doing_it_wrong[] = 'my_doing_it_wrong';\n        $this->setExpectedIncorrectUsage( 'my_doing_it_wrong' );\n        my_doing_it_wrong();\n    }\n}\n
    5. If your test code is knowingly triggering doing-it-wrong notices, you need to update your test code to let the test case know using the setExpectedIncorrectUsage method:
    <?php\n\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\nclass MyTestUsingDoingItWrongTest extends WPTestCase {\n    public function test_it_can_use_doing_it_wrong() {\n        $this->setExpectedIncorrectUsage( 'my_doing_it_wrong' );\n        my_doing_it_wrong();\n    }\n}\n
    Previously, your code could just filter the doing_it_wrong_trigger_error hook to return false to tolerate the doing-it-wrong notices in tests. 6. Some assertion methods have, in more recent versions of the PHPUnit core suite, adopted stricter type checks when it comes to comparison. E.g., the assertEqualFields will now check the object to check the fields on is actually an object. Depending on how loose your use of assertions was before, you might have to update your work to make it pass the stricter checks:
    <?php\n\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\n class MyTestUsingAssertEqualFields extends WPTestCase {\n      public function test_it_can_use_assert_equal_fields() {\n         // Cast the array to an object explicitly.\n         $this->assertEqualFields( (object) [ 'a' => 1 ], [ 'a' => 1 ] );\n      }\n }\n
    7. Other updates to the Core PHPUnit test case will report use of deprecated functions more promptly; if your code is using deprecated functions that might have escaped previous versions of wp-browser, you will need to update them. 8. If you're using the @runInSeparateProcess annotation for tests in your suite, you will need to enable the IsolationSupport extension in your suite configuration file:

    actor: MySuiteTester\nbootstrap: _bootstrap.php\nextensions:\nenabled:\n   - \"lucatume\\\\WPBrowser\\\\Extension\\\\IsolationSupport\"\nmodules: # The rest of the module configuration ...\n

    Alternatively, you can enable the extension in the Codeception main configuration file (e.g. codeception.yml).

    Read more about the extension in the Isolation Support extension documentation. 9. Global space cleanup between test is more thorough in more recent versions of the Core PHPUnit test suite. Due to this you might see failures in tests that were passing in previous versions due to a \"leaking\" global state. Examples of this might be nonces being set by previous tests and not being reset. Update your tests to explicitly set all the global stat variables you require for the test to run.

    "},{"location":"migration/#staying-on-version-3-lower-than-35","title":"Staying on version 3, lower than 3.5","text":"

    Update your composer.json file to lock the required version of wp-browser to a version less than 3.5:

    {\n  \"require-dev\": {\n    \"lucatume/wp-browser\": \"<3.5\"\n  }\n}\n
    "},{"location":"troubleshooting/","title":"Troubleshooting","text":""},{"location":"troubleshooting/#troubleshooting-common-issues","title":"Troubleshooting common issues","text":""},{"location":"troubleshooting/#downloads-fail-in-windows","title":"Downloads fail in Windows","text":"

    If you're using code or commands, e.g. the chromedriver:update one, that download files and those keep failing with a message like the following:

    File ... download failed: SSL certificate problem: unable to get local issuer certificate\n

    It's likely the issue originates from PHP not having access to the system certificate store.

    You can fix this by downloading the certificates file and setting the curl.cainfo and openssl.cafile PHP configuration options to point to it:

    curl.cainfo = \"C:\\path\\to\\cacert.pem\"\nopenssl.cafile = \"C:\\path\\to\\cacert.pem\"\n
    "},{"location":"extensions/BuiltInServerController/","title":"PHP Built-in Server Controller","text":"

    This extension will start and stop the PHP built-in web server before and after the tests run.

    "},{"location":"extensions/BuiltInServerController/#configuration","title":"Configuration","text":"

    The extension can be configured with the following parameters:

    • required
      • docroot - the document root to use for the PHP Built-in server; it can be either an absolute path or a path relative to the Codeception root directory. Note the lowercase r in the parameter name.
    • optional
      • suites - an array of Codeception suites to run the server for; if not set the server will be started for all the suites.
      • port - the port to use for the PHP Built-in server, if not set the server will use port 2389.
      • workers - the number of workers to use for the PHP Built-in server, if not set the server will use 5 workers. This is the equivalent of the PHP_CLI_SERVER_WORKERS environment variable.

    Note: if you run PHP built-in server on Windows, the workers parameter will be ignored and the server will always run with a single worker. This limit is not present in WSL.

    "},{"location":"extensions/BuiltInServerController/#configuration-examples","title":"Configuration Examples","text":"

    Example configuration starting the server for all suites:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\":\n      docroot: /var/www/html\n      workers: 5\n

    The extension can access environment variables defined in the tests configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\BuiltInServerController\":\n      suites:\n        - EndToEnd\n        - WebApp\n      docroot: '%WORDPRESS_ROOT_DIR%'\n      port: '%BUILT_IN_SERVER_PORT%'\n      workers: '%BUILT_IN_SERVER_WORKERS%'\n
    "},{"location":"extensions/BuiltInServerController/#this-is-a-service-extension","title":"This is a service extension","text":"

    This is a service extension that will be started and stopped by the dev:start and dev:stop commands.

    "},{"location":"extensions/ChromeDriverController/","title":"ChromeDriver Controller","text":"

    This extension will start and stop the ChromeDriver before and after the tests are run.

    "},{"location":"extensions/ChromeDriverController/#configuration","title":"Configuration","text":"

    The extension can be configured with the following parameters:

    • optional
      • suites - an array of Codeception suites to run the server for; if not set the server will be started for all the suites.
      • port - the port to use for the ChromeDriver, if not set the server will use port 9515.
      • binary - the path to the ChromeDriver binary, if not set the server will use the chromedriver binary in the Composer bin directory.
    "},{"location":"extensions/ChromeDriverController/#configuration-examples","title":"Configuration Examples","text":"

    Example configuration starting the server for all suites:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\":\n      port: 4444\n      binary: /usr/local/bin/chromedriver\n

    The extension can access environment variables defined in the tests configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\"\n  config:\n    suites:\n      - EndToEnd\n      - WebApp\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\ChromeDriverController\":\n      port: '%CHROMEDRIVER_PORT%'\n      binary: '%CHROMEDRIVER_BINARY%'\n

    You can use the chromedriver:update command to download the latest version of ChromeDriver compatible with your Chrome browser version and place it in the Composer bin directory.

    "},{"location":"extensions/ChromeDriverController/#this-is-a-service-extension","title":"This is a service extension","text":"

    This is a service extension that will be started and stopped by the dev:start and dev:stop commands.

    "},{"location":"extensions/DockerComposeController/","title":"Docker Compose Controller","text":"

    This extension will start and stop a docker compose stack before and after the tests are run.

    "},{"location":"extensions/DockerComposeController/#configuration","title":"Configuration","text":"

    The extension can be configured with the following parameters:

    • required
      • compose-file - the path to the docker compose file to use; it can be either an absolute path or a path relative to the Codeception root directory.
    • optional
      • env-file- the path to the environment file to use; it can be either an absolute path or a path.
    "},{"location":"extensions/DockerComposeController/#configuration-examples","title":"Configuration Examples","text":"

    Example configuration starting the server for all suites:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\":\n      compose-file: /var/www/html/docker-compose.yml\n      env-file: /var/www/html/.env\n

    The extension can access environment variables defined in the tests configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\DockerComposeController\":\n      compose-file: '%DOCKER_COMPOSE_FILE%'\n      env-file: '%DOCKER_COMPOSE_ENV_FILE%'\n
    "},{"location":"extensions/DockerComposeController/#this-is-a-service-extension","title":"This is a service extension","text":"

    This is a service extension that will be started and stopped by the dev:start and wp:dev-stop commands.

    "},{"location":"extensions/EventDispatcherBridge/","title":"Event Dispatcher Bridge","text":"

    This extension connects the event dispatcher system provided by Codeception, and normally available only through the use of custom extensions, to make it available through calls to the lucatume\\WPBrowser\\Events\\Dispatcher class API.

    If not using this extension, then the only way to subscribe to events dispatched by Codeception is to use custom extensions.

    "},{"location":"extensions/EventDispatcherBridge/#configuration","title":"Configuration","text":"

    The extension does not require configuration, it just needs to be enabled in the Codeception configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\EventDispatcherBridge\"\n
    "},{"location":"extensions/EventDispatcherBridge/#usage","title":"Usage","text":"

    The extension will automatically hook into the event dispatcher system provided by Codeception, normally available only through the use of custom extensions, and inject user-defined event listeners in it.

    Once the extension is enabled, you can use the lucatume\\WPBrowser\\Events\\Dispatcher class to subscribe to Codeception events. This is typically be done in either the global bootstrap file, or in a suite bootstrap file.

    You can subscribe to the following events dispatched by Codeception in either the global bootstrap file (usually tests/_bootstrap.php), or in a suite bootstrap file (usually tests/<suite>/_bootstrap.php):

    • Codeception\\Events::SUITE_BEFORE
    • Codeception\\Events::SUITE_AFTER
    • CodeceptionventsEvents::TEST_START
    • CodeceptionventsEvents::TEST_BEFORE
    • CodeceptionventsEvents::STEP_BEFORE
    • CodeceptionventsEvents::STEP_AFTER
    • CodeceptionventsEvents::TEST_FAIL
    • CodeceptionventsEvents::TEST_ERROR
    • CodeceptionventsEvents::TEST_PARSED
    • CodeceptionventsEvents::TEST_INCOMPLETE
    • CodeceptionventsEvents::TEST_SKIPPED
    • CodeceptionventsEvents::TEST_WARNING
    • CodeceptionventsEvents::TEST_USELESS
    • CodeceptionventsEvents::TEST_SUCCESS
    • CodeceptionventsEvents::TEST_AFTER
    • CodeceptionventsEvents::TEST_END
    • CodeceptionventsEvents::TEST_FAIL_PRINT
    • CodeceptionventsEvents::RESULT_PRINT_AFTER

    Due to order-of-operations, the earliest Codeception dispatched Event you can subscribe to is the SUITE_BEFORE one. To subscribe to the following earlier events, you must implement an extension following the custom extension approach:

    • Codeception\\Events::MODULE_INIT
    • Codeception\\Events::SUITE_INIT

    The Dispatcher API documentation provides more details about the events dispatched by Codeception and wp-browser and examples on how to subscribe to them.

    "},{"location":"extensions/EventDispatcherBridge/#usage-examples","title":"Usage Examples","text":"

    In the global bootstrap file (usually tests/_bootstrap.php), or the suite bootstrap file (usually tests/<suite>/_bootstrap.php), subscribe to the Codeception events by providing a callback function that will accept different parameters depending on the event being dispatched:

    <?php\n\nuse Codeception\\Events;\nuse Codeception\\Event\\SuiteEvent\nuse Codeception\\Event\\TestEvent;\nuse Codeception\\Event\\StepEvent;\nuse Codeception\\Event\\PrintResultEvent;\nuse lucatume\\WPBrowser\\Events\\Dispatcher;\n\nDispatcher::addListener(Events::SUITE_BEFORE, function (SuiteEvent $suiteEvent) {\n    codecept_debug('Running on SUITE BEFORE');\n});\n\nDispatcher::addListener(Events::SUITE_AFTER, function (SuiteEvent $suiteEvent) {\n    codecept_debug('Running on SUITE AFTER');\n});\n\nDispatcher::addListener(Events::TEST_START, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST START');\n});\n\nDispatcher::addListener(Events::TEST_BEFORE, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST BEFORE');\n});\n\nDispatcher::addListener(Events::STEP_BEFORE, function (StepEvent $stepEvent) {\n    codecept_debug('Running on STEP BEFORE');\n});\n\nDispatcher::addListener(Events::STEP_AFTER, function (StepEvent $stepEvent) {\n    codecept_debug('Running on STEP AFTER');\n});\n\nDispatcher::addListener(Events::TEST_FAIL, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST FAIL');\n});\n\nDispatcher::addListener(Events::TEST_ERROR, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST ERROR');\n});\n\nDispatcher::addListener(Events::TEST_PARSED, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST PARSED');\n});\n\nDispatcher::addListener(Events::TEST_INCOMPLETE, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST INCOMPLETE');\n});\n\nDispatcher::addListener(Events::TEST_SKIPPED, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST SKIPPED');\n});\n\nDispatcher::addListener(Events::TEST_WARNING, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST WARNING');\n});\n\nDispatcher::addListener(Events::TEST_USELESS, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST USELESS');\n});\n\nDispatcher::addListener(Events::TEST_SUCCESS, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST SUCCESS');\n});\n\nDispatcher::addListener(Events::TEST_AFTER, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST AFTER');\n});\n\nDispatcher::addListener(Events::TEST_END, function (TestEvent $testEvent) {\n    codecept_debug('Running on TEST END');\n});\n\nDispatcher::addListener(Events::TEST_FAIL_PRINT, function (PrintResultEvent $printResultEvent) {\n    codecept_debug('Running on TEST FAIL PRINT');\n});\n\nDispatcher::addListener(Events::RESULT_PRINT_AFTER, function (PrintResultEvent $printResultEvent) {\n    codecept_debug('Running on RESULT PRINT AFTER');\n});\n

    Read more about the Dispatcher API here.

    "},{"location":"extensions/IsolationSupport/","title":"Isolation Support","text":"

    This extension provides support for the PHPUnit annotations @runInSeparateProcess and @runTestsInSeparateProcesses, and the PHPUnit attributes (PHPUnit 10+) #[RunInSeparateProcess] and #[RunTestsInSeparateProcesses]. You can read more about these annotations and attributes in the PHPUnit documentation about test isolation.

    Codeception does not natively support these annotations and attributes, this extension provides support for them.

    "},{"location":"extensions/IsolationSupport/#configuration","title":"Configuration","text":"

    You can enable the extension in the Codeception configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\IsolationSupport\"\n

    In your tests, you can use the annotations or attributes as you would in a PHPUnit test:

    <?php\n\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass IsolationExampleTest extends WPTestCase {\n    /**\n     * @runInSeparateProcess\n     */\n    public function test_in_admin_context() {\n        define('WP_ADMIN', true);\n\n        $this->assertTrue(is_admin());\n    }\n\n    #[RunTestsInSeparateProcesses]\n    public function test_in_admin_context_with_attribute() {\n        define('WP_ADMIN', true);\n\n        $this->assertTrue(is_admin());\n    }\n\n    public function test_constant_is_not_set() {\n        $this->assertFalse(defined('WP_ADMIN'));\n    }\n}\n\n#[RunTestsInSeparateProcesses]\nclass RunAllTestsInSeparateProcesses extends WPTestCase {\n    public function test_one() {\n        definen('TEST_CONST', 'one');\n\n        $this->assertEquals('one', TEST_CONST);\n    }\n\n    public function test_two() {\n        definen('TEST_CONST', 'two');\n\n        $this->assertEquals('two', TEST_CONST);\n    }\n}\n

    Previous versions of the test isolation support required the @backupGlobals disabled annotation to be used when running tests in isolation. This is no longer required.

    Isolation support is based around monkey-patching the file at runtime. Look into the monkey:cache:clear and monkey:cache:path commands to manage the monkey-patching cache.

    "},{"location":"extensions/MySqlServerController/","title":"MySqlServer Controller","text":"

    This extension will start and stop the MySQL server before and after the tests run. The extension will take care of downloading the MySQL Community Server archive from the MySQL Community Server site, place it in the _mysql-server directory under the codeception output directory and initialize the server in the same directory.

    The aim of this extension is to allow running integration tests against a real MySQL server, without having to install and configure a MySQL server on the machine.

    Warning

    Currently the MySQL Community Server version installed by this extension (8.4.2 LTS) is not available for Windows on ARM.

    If you are running Windows on ARM, you can either: - Use a custom binary, see the configuration examples below - Use the Docker controller extension to run the database from a Docker container.

    "},{"location":"extensions/MySqlServerController/#configuration","title":"Configuration","text":"

    The extension can be configured with the following parameters:

    • required
      • port - the localhost port to use for the MySQL server, defaults to 8906.
      • database - the database that will be created when starting the server, defaults to wordpress.
      • user - the user that will be created when starting the server, defaults to wordpress. The user will be granted all privileges on the database specified by the database parameter. If the user is root, no further user will be created.
      • password - the password to use for the user specified by the user parameter, defaults to wordpress. If the user is root, the root user will be set to the password specified by this parameter.
    • optional
      • suites - an array of Codeception suites to run the server for; if not set the server will be started for all the suites.
      • binary - the path to the MySQL server binary to use, defaults to mysqld, defaults to null to download and initialize the correct version of MySQL server for the current platform and architecture.
      • shareDir - the path to the directory to use for the MySQL server share, defaults to null. This is required when providing a custom binary.
    "},{"location":"extensions/MySqlServerController/#configuration-examples","title":"Configuration Examples","text":"

    Example configuration starting the server for all suites:

    extensions:\n  enabled:\n    - \"lucatume\\WPBrowser\\Extension\\MySqlServerController\":\n      port: 8906\n      database: wordpress\n      user: wordpress\n      password: wordpress\n

    The extension can access environment variables defined in the tests configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\WPBrowser\\Extension\\MySqlServerController\":\n      port: '%MYSQL_SERVER_PORT%'\n      database: '%MYSQL_SERVER_DATABASE%'\n      user: '%MYSQL_SERVER_USER%'\n      password: '%MYSQL_SERVER_PASSWORD%'\n

    Example configuration using the root user:

    extensions:\n  enabled:\n    - \"lucatume\\WPBrowser\\Extension\\MySqlServerController\":\n      port: 33446\n      database: wordpress\n      user: root\n      password: secret\n
    "},{"location":"extensions/MySqlServerController/#using-a-custom-mysql-server-binary","title":"Using a custom MySQL server binary","text":"

    The extension can be configured to use a custom MySQL server binary by setting the binary configuration parameter to the absolute path to the binary:

    extensions:\n  enabled:\n    - \"lucatume\\WPBrowser\\Extension\\MySqlServerController\":\n      port: 33446\n      database: wordpress\n      user: root\n      password: secret\n      binary: /usr/local/mysql/bin/mysqld\n
    "},{"location":"extensions/MySqlServerController/#this-is-a-service-extension","title":"This is a service extension","text":"

    This is a service extension that will be started and stopped by the dev:start and dev:stop commands.

    "},{"location":"extensions/Symlinker/","title":"Symlinker","text":"

    This extension will symlink the plugins and themes specified in the plugins and themes configuration parameters to the WordPress installation plugins and themes directories, respectively.

    The plugins and themes will be symlinked before each suite, and removed after each suite.

    "},{"location":"extensions/Symlinker/#configuration","title":"Configuration","text":"

    The extension can be configured with the following parameters:

    • required
      • wpRootFolder - the relative (to the current working directory) or absolute path to the WordPress installation root folder, the directory that contains the wp-load.php file.
    • optional
      • cleanupAfterSuite - default false, a boolean value to indicate if the symlinks created by the extension sshould be removed after the suite ran.
      • plugins- a list of plugin directories to symlink to the WordPress installation plugins directory, if not set the plugin symlinking will be skipped.
      • themes- a list of theme directories to symlink to the WordPress installation themes directory, if not set the theme symlinking will be skipped.
    "},{"location":"extensions/Symlinker/#configuration-examples","title":"Configuration Examples","text":"

    Example configuration symbolically linking the plugins and themes to the WordPress installation plugins and themes directories:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\Symlinker\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\Symlinker\":\n      wpRootFolder: /var/www/html\n      plugins:\n        - '.' # Relative path, the current working directory.\n        - /home/plugins/plugin-1 # Absolute path to a plugin directory.\n        - vendor/acme/plugin-2 # Relative path to a plugin directory.\n      themes:\n        - /home/theme-1 # Absolute path to a theme directory.\n        - vendor/acme/theme-2 # Relative path to a theme directory.\n

    The extension can access environment variables defined in the tests configuration file:

    extensions:\n  enabled:\n    - \"lucatume\\\\WPBrowser\\\\Extension\\\\Symlinker\"\n  config:\n    \"lucatume\\\\WPBrowser\\\\Extension\\\\Symlinker\":\n      wpRootFolder: '%WP_ROOT_FOLDER%'\n      plugins:\n        - '%PLUGIN_STORAGE%/plugin-1'\n        - '%PLUGIN_STORAGE%/plugin-2'\n      themes:\n        - '%THEME_STORAGE%/theme-1'\n        - '%THEME_STORAGE%/theme-2'\n
    "},{"location":"modules/AirplaneMode/","title":"Airplane Mode","text":""},{"location":"modules/AirplaneMode/#airplanemode-module","title":"AirplaneMode module","text":"

    This module allows you to easily put the website under test in \"airplane mode\", preventing it from making any network requests.

    The module uses the norcross/airplane-mode plugin to add or remove it from the website must-use plugins directory when activated.

    This module should be used together with the WPWebDriver or WPBrowser modules.

    "},{"location":"modules/AirplaneMode/#configuration","title":"Configuration","text":"
    • muPluginsDir - required; the path to the WordPress must-use plugins directory.
    • symlink - whether to symlink the plugin or copy it. By default, the plugin is copied in the must-use plugins directory and symlink is set to false. If you're not using containers, that will ignore symlinked plugins, you can set symlink to true to symlink the plugin in the must-use plugins directory. Symbolic linking is faster and uses less disk space than copying the plugin.

    Example configuration to symlink the plugin in the muPluginsDir directory before the tests:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\AirplaneMode:\n      muPluginsDir: 'var/wordpress/wp-content/mu-plugins'\n      symlink: true\n

    Example configuration to copy the plugin in the muPluginsDir directory before the tests:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\AirplaneMode:\n      muPluginsDir: 'var/wordpress/wp-content/mu-plugins'\n      symlink: false\n

    The module will either symlink or copy the plugin in the muPluginsDir directory, depending on the symlink configuration parameter before the test suite runs, and will remove it after the test suite has run.

    "},{"location":"modules/WPBrowser/","title":"WPBrowser","text":""},{"location":"modules/WPBrowser/#wpbrowser-module","title":"WPBrowser module","text":"

    Browse and test the site HTML with a fast browser without Javascript support.

    This module trades the WPWebDriver module Javascript support for speed and stability. It is a good choice for testing sites that don't use Javascript or to make assertions that do not require Javascript support like:

    • testing HTTP return codes
    • testing HTML structure
    • testing JSON and XML responses from APIs

    This module is used together with the WPDb module and the WPFilesystem module to control the site state, the database, and the site file structure.

    This module is an extension of the Codeception PHPBrowser module, you can reference to the Codeception module documentation for more information on the module configuration and usage.

    This module should be with Cest and Cept test cases.

    "},{"location":"modules/WPBrowser/#configuration","title":"Configuration","text":"
    • url - required; the start URL of your WordPress project.
    • adminUsername - required; the site administrator username to use in actions like loginAsAdmin.
    • adminPassword - required; the site administrator password to use in actions like loginAsAdmin.
    • adminPath - the path to the WordPress admin directory; defaults to /wp-admin.

    More Guzzle request options are available like:

    headers - default headers are set before each test. cookies - default cookies are set before each test. auth - default authentication to be set before each test.

    ... and more.

    The following is an example of the module configuration to run tests on thehttp://localhost:8080 site:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPBrowser:\n      url: 'http://localhost:8080'\n      adminUsername: 'admin'\n      adminPassword: 'password'\n      adminPath: '/wp-admin'\n      headers:\n        X_WPBROWSER_REQUEST: 1\n        X_TEST_REQUEST: 1\n        X_APM_REQUEST: 1\n

    The following configuration uses dynamic configuration parameters to set the module configuration:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPBrowser:\n      url: '%WORDPRESS_URL%'\n      adminUsername: '%WORDPRESS_ADMIN_USER%'\n      adminPassword: '%WORDPRESS_ADMIN_PASSWORD%'\n      adminPath: '/wp-admin'\n      headers:\n        X_WPBROWSER_REQUEST: 1\n        X_TEST_REQUEST: 1\n        X_APM_REQUEST: 1\n
    "},{"location":"modules/WPBrowser/#methods","title":"Methods","text":"

    The module provides the following methods:

    "},{"location":"modules/WPBrowser/#activateplugin","title":"activatePlugin","text":"

    Signature: activatePlugin(array|string $pluginSlug) : void

    In the plugin administration screen activates a plugin clicking the \"Activate\" link.

    The method will not handle authentication to the admin area.

    <?php\n// Activate a plugin.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->activatePlugin('hello-dolly');\n// Activate a list of plugins.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->activatePlugin(['hello-dolly','another-plugin']);\n
    "},{"location":"modules/WPBrowser/#activatetheme","title":"activateTheme","text":"

    Signature: activateTheme(string $slug) : void

    Activates a theme.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPBrowser/#ameditingpostwithid","title":"amEditingPostWithId","text":"

    Signature: amEditingPostWithId(int $id) : void

    Go to the admin page to edit the post with the specified ID.

    The method will not handle authentication the admin area.

    <?php\n$I->loginAsAdmin();\n$postId = $I->havePostInDatabase();\n$I->amEditingPostWithId($postId);\n$I->fillField('post_title', 'Post title');\n
    "},{"location":"modules/WPBrowser/#ameditinguserwithid","title":"amEditingUserWithId","text":"

    Signature: amEditingUserWithId(int $id) : void

    Go to the admin page to edit the user with the specified ID.

    The method will not handle authentication the admin area.

    <?php\n$I->loginAsAdmin();\n$userId = $I->haveUserInDatabase('luca', 'editor');\n$I->amEditingUserWithId($userId);\n$I->fillField('email', 'new@example.net');\n
    "},{"location":"modules/WPBrowser/#amhttpauthenticated","title":"amHttpAuthenticated","text":"

    Signature: amHttpAuthenticated($username, $password) : void

    "},{"location":"modules/WPBrowser/#amonadminajaxpage","title":"amOnAdminAjaxPage","text":"

    Signature: amOnAdminAjaxPage([array|string|null $queryVars]) : void

    Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

    The method will not handle authentication, nonces or authorization.

    <?php\n$I->amOnAdminAjaxPage(['action' => 'my-action', 'data' => ['id' => 23], 'nonce' => $nonce]);\n
    "},{"location":"modules/WPBrowser/#amonadminpage","title":"amOnAdminPage","text":"

    Signature: amOnAdminPage(string $page) : void

    Go to a page in the admininstration area of the site.

    This method will not handle authentication to the administration area.

    <?php\n$I->loginAs('user', 'password');\n// Go to the plugins management screen.\n$I->amOnAdminPage('/plugins.php');\n
    "},{"location":"modules/WPBrowser/#amoncronpage","title":"amOnCronPage","text":"

    Signature: amOnCronPage([array|string|null $queryVars]) : void

    Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

    <?php\n// Triggers the cron job with an optional query argument.\n$I->amOnCronPage('/?some-query-var=some-value');\n
    "},{"location":"modules/WPBrowser/#amonpage","title":"amOnPage","text":"

    Signature: amOnPage(string $page) : void

    "},{"location":"modules/WPBrowser/#amonpagespage","title":"amOnPagesPage","text":"

    Signature: amOnPagesPage() : void

    Go the \"Pages\" administration screen.

    The method will not handle authentication.

    <?php\n$I->loginAsAdmin();\n$I->amOnPagesPage();\n$I->see('Add New');\n
    "},{"location":"modules/WPBrowser/#amonpluginspage","title":"amOnPluginsPage","text":"

    Signature: amOnPluginsPage() : void

    Go to the plugins administration screen.

    The method will not handle authentication.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->activatePlugin('hello-dolly');\n
    "},{"location":"modules/WPBrowser/#amonsubdomain","title":"amOnSubdomain","text":"

    Signature: amOnSubdomain($subdomain) : void

    "},{"location":"modules/WPBrowser/#amonthemespage","title":"amOnThemesPage","text":"

    Signature: amOnThemesPage() : void

    Moves to the themes administration page.

    "},{"location":"modules/WPBrowser/#amonurl","title":"amOnUrl","text":"

    Signature: amOnUrl($url) : void

    "},{"location":"modules/WPBrowser/#attachfile","title":"attachFile","text":"

    Signature: attachFile($field, string $filename) : void

    "},{"location":"modules/WPBrowser/#checkoption","title":"checkOption","text":"

    Signature: checkOption($option) : void

    "},{"location":"modules/WPBrowser/#click","title":"click","text":"

    Signature: click($link, [$context]) : void

    "},{"location":"modules/WPBrowser/#deactivateplugin","title":"deactivatePlugin","text":"

    Signature: deactivatePlugin(array|string $pluginSlug) : void

    In the plugin administration screen deactivate a plugin clicking the \"Deactivate\" link.

    The method will not handle authentication and navigation to the plugins administration page.

    <?php\n// Deactivate one plugin.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->deactivatePlugin('hello-dolly');\n// Deactivate a list of plugins.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->deactivatePlugin(['hello-dolly', 'my-plugin']);\n
    "},{"location":"modules/WPBrowser/#deleteheader","title":"deleteHeader","text":"

    Signature: deleteHeader(string $name) : void

    Deletes the header with the passed name. Subsequent requests will not have the deleted header in its request.

    Example:

    <?php\n$I->haveHttpHeader('X-Requested-With', 'Codeception');\n$I->amOnPage('test-headers.php');\n// ...\n$I->deleteHeader('X-Requested-With');\n$I->amOnPage('some-other-page.php');\n

    "},{"location":"modules/WPBrowser/#dontsee","title":"dontSee","text":"

    Signature: dontSee(string $text, [$selector]) : void

    "},{"location":"modules/WPBrowser/#dontseecheckboxischecked","title":"dontSeeCheckboxIsChecked","text":"

    Signature: dontSeeCheckboxIsChecked($checkbox) : void

    "},{"location":"modules/WPBrowser/#dontseecookie","title":"dontSeeCookie","text":"

    Signature: dontSeeCookie($cookie, [$params]) : void

    "},{"location":"modules/WPBrowser/#dontseecurrenturlequals","title":"dontSeeCurrentUrlEquals","text":"

    Signature: dontSeeCurrentUrlEquals(string $uri) : void

    "},{"location":"modules/WPBrowser/#dontseecurrenturlmatches","title":"dontSeeCurrentUrlMatches","text":"

    Signature: dontSeeCurrentUrlMatches(string $uri) : void

    "},{"location":"modules/WPBrowser/#dontseeelement","title":"dontSeeElement","text":"

    Signature: dontSeeElement($selector, [array $attributes]) : void

    "},{"location":"modules/WPBrowser/#dontseeincurrenturl","title":"dontSeeInCurrentUrl","text":"

    Signature: dontSeeInCurrentUrl(string $uri) : void

    "},{"location":"modules/WPBrowser/#dontseeinfield","title":"dontSeeInField","text":"

    Signature: dontSeeInField($field, $value) : void

    "},{"location":"modules/WPBrowser/#dontseeinformfields","title":"dontSeeInFormFields","text":"

    Signature: dontSeeInFormFields($formSelector, array $params) : void

    "},{"location":"modules/WPBrowser/#dontseeinsource","title":"dontSeeInSource","text":"

    Signature: dontSeeInSource(string $raw) : void

    "},{"location":"modules/WPBrowser/#dontseeintitle","title":"dontSeeInTitle","text":"

    Signature: dontSeeInTitle($title) : void

    "},{"location":"modules/WPBrowser/#dontseelink","title":"dontSeeLink","text":"

    Signature: dontSeeLink(string $text, [string $url]) : void

    "},{"location":"modules/WPBrowser/#dontseeoptionisselected","title":"dontSeeOptionIsSelected","text":"

    Signature: dontSeeOptionIsSelected($selector, $optionText) : void

    "},{"location":"modules/WPBrowser/#dontseeplugininstalled","title":"dontSeePluginInstalled","text":"

    Signature: dontSeePluginInstalled(string $pluginSlug) : void

    Assert a plugin is not installed in the plugins administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->dontSeePluginInstalled('my-plugin');\n
    "},{"location":"modules/WPBrowser/#dontseeresponsecodeis","title":"dontSeeResponseCodeIs","text":"

    Signature: dontSeeResponseCodeIs(int $code) : void

    Checks that response code is equal to value provided.

    <?php\n$I->dontSeeResponseCodeIs(200);\n\n// recommended \\Codeception\\Util\\HttpCode\n$I->dontSeeResponseCodeIs(\\Codeception\\Util\\HttpCode::OK);\n
    "},{"location":"modules/WPBrowser/#executeinguzzle","title":"executeInGuzzle","text":"

    Signature: executeInGuzzle(Closure $function) : void

    Low-level API method. If Codeception commands are not enough, use Guzzle HTTP Client methods directly

    Example:

    <?php\n$I->executeInGuzzle(function (\\GuzzleHttp\\Client $client) {\n     $client->get('/get', ['query' => ['foo' => 'bar']]);\n});\n

    It is not recommended to use this command on a regular basis. If Codeception lacks important Guzzle Client methods, implement them and submit patches.

    "},{"location":"modules/WPBrowser/#fillfield","title":"fillField","text":"

    Signature: fillField($field, $value) : void

    "},{"location":"modules/WPBrowser/#followredirect","title":"followRedirect","text":"

    Signature: followRedirect() : void

    Follow pending redirect if there is one.

    <?php\n$I->followRedirect();\n
    "},{"location":"modules/WPBrowser/#grabactivetheme","title":"grabActiveTheme","text":"

    Signature: grabActiveTheme() : ?string

    Returns the slug of the currently active themes.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPBrowser/#grabattributefrom","title":"grabAttributeFrom","text":"

    Signature: grabAttributeFrom($cssOrXpath, string $attribute) : mixed

    "},{"location":"modules/WPBrowser/#grabavailablethemes","title":"grabAvailableThemes","text":"

    Signature: grabAvailableThemes([string $classes]) : array

    Returns the list of available themes.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPBrowser/#grabcookie","title":"grabCookie","text":"

    Signature: grabCookie(string $cookie, [array $params]) : mixed

    "},{"location":"modules/WPBrowser/#grabcookieswithpattern","title":"grabCookiesWithPattern","text":"

    Signature: grabCookiesWithPattern(string $cookiePattern) : ?array

    Returns all the cookies whose name matches a regex pattern.

    <?php\n$I->loginAs('customer','password');\n$I->amOnPage('/shop');\n$cartCookies = $I->grabCookiesWithPattern(\"#^shop_cart\\\\.*#\");\n
    "},{"location":"modules/WPBrowser/#grabfromcurrenturl","title":"grabFromCurrentUrl","text":"

    Signature: grabFromCurrentUrl([?string $uri]) : mixed

    "},{"location":"modules/WPBrowser/#grabmultiple","title":"grabMultiple","text":"

    Signature: grabMultiple($cssOrXpath, [?string $attribute]) : array

    "},{"location":"modules/WPBrowser/#grabpagesource","title":"grabPageSource","text":"

    Signature: grabPageSource() : string

    Grabs current page source code.

    "},{"location":"modules/WPBrowser/#grabtextfrom","title":"grabTextFrom","text":"

    Signature: grabTextFrom($cssOrXPathOrRegex) : mixed

    "},{"location":"modules/WPBrowser/#grabvaluefrom","title":"grabValueFrom","text":"

    Signature: grabValueFrom($field) : mixed

    "},{"location":"modules/WPBrowser/#grabwordpresstestcookie","title":"grabWordPressTestCookie","text":"

    Signature: grabWordPressTestCookie([?string $name]) : ?Symfony\\Component\\BrowserKit\\Cookie

    Returns WordPress default test cookie object if present.

    <?php\n// Grab the default WordPress test cookie.\n$wpTestCookie = $I->grabWordPressTestCookie();\n// Grab a customized version of the test cookie.\n$myTestCookie = $I->grabWordPressTestCookie('my_test_cookie');\n
    "},{"location":"modules/WPBrowser/#havehttpheader","title":"haveHttpHeader","text":"

    Signature: haveHttpHeader(string $name, string $value) : void

    Sets the HTTP header to the passed value - which is used on subsequent HTTP requests through PhpBrowser.

    Example:

    <?php\n$I->haveHttpHeader('X-Requested-With', 'Codeception');\n$I->amOnPage('test-headers.php');\n

    To use special chars in Header Key use HTML Character Entities: Example: Header with underscore - 'Client_Id' should be represented as - 'Client_Id' or 'Client_Id'

    <?php\n$I->haveHttpHeader('Client&#95;Id', 'Codeception');\n
    "},{"location":"modules/WPBrowser/#haveserverparameter","title":"haveServerParameter","text":"

    Signature: haveServerParameter(string $name, string $value) : void

    Sets SERVER parameter valid for all next requests.

    <?php\n$I->haveServerParameter('name', 'value');\n
    "},{"location":"modules/WPBrowser/#logout","title":"logOut","text":"

    Signature: logOut([string|bool $redirectTo]) : void

    Navigate to the default WordPress logout page and click the logout link.

    <?php\n// Log out using the `wp-login.php` form and return to the current page.\n$I->logOut(true);\n// Log out using the `wp-login.php` form and remain there.\n$I->logOut(false);\n// Log out using the `wp-login.php` form and move to another page.\n$I->logOut('/some-other-page');\n
    "},{"location":"modules/WPBrowser/#loginas","title":"loginAs","text":"

    Signature: loginAs(string $username, string $password) : void

    Login as the specified user.

    The method will not follow redirection, after the login, to any page.

    <?php\n$I->loginAs('user', 'password');\n$I->amOnAdminPage('/');\n$I->see('Dashboard');\n
    "},{"location":"modules/WPBrowser/#loginasadmin","title":"loginAsAdmin","text":"

    Signature: loginAsAdmin() : void

    Login as the administrator user using the credentials specified in the module configuration.

    The method will not follow redirection, after the login, to any page.

    <?php\n$I->loginAsAdmin();\n$I->amOnAdminPage('/');\n$I->see('Dashboard');\n
    "},{"location":"modules/WPBrowser/#makehtmlsnapshot","title":"makeHtmlSnapshot","text":"

    Signature: makeHtmlSnapshot([?string $name]) : void

    "},{"location":"modules/WPBrowser/#moveback","title":"moveBack","text":"

    Signature: moveBack([int $numberOfSteps]) : void

    Moves back in history.

    "},{"location":"modules/WPBrowser/#resetcookie","title":"resetCookie","text":"

    Signature: resetCookie($cookie, [$params]) : void

    "},{"location":"modules/WPBrowser/#see","title":"see","text":"

    Signature: see(string $text, [$selector]) : void

    "},{"location":"modules/WPBrowser/#seecheckboxischecked","title":"seeCheckboxIsChecked","text":"

    Signature: seeCheckboxIsChecked($checkbox) : void

    "},{"location":"modules/WPBrowser/#seecookie","title":"seeCookie","text":"

    Signature: seeCookie($cookie, [$params]) : void

    "},{"location":"modules/WPBrowser/#seecurrenturlequals","title":"seeCurrentUrlEquals","text":"

    Signature: seeCurrentUrlEquals(string $uri) : void

    "},{"location":"modules/WPBrowser/#seecurrenturlmatches","title":"seeCurrentUrlMatches","text":"

    Signature: seeCurrentUrlMatches(string $uri) : void

    "},{"location":"modules/WPBrowser/#seeelement","title":"seeElement","text":"

    Signature: seeElement($selector, [array $attributes]) : void

    "},{"location":"modules/WPBrowser/#seeerrormessage","title":"seeErrorMessage","text":"

    Signature: seeErrorMessage([array|string $classes]) : void

    In an administration screen look for an error admin notice.

    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

    <?php\n$I->loginAsAdmin()\n$I->amOnAdminPage('/');\n$I->seeErrorMessage('.my-plugin');\n
    "},{"location":"modules/WPBrowser/#seeincurrenturl","title":"seeInCurrentUrl","text":"

    Signature: seeInCurrentUrl(string $uri) : void

    "},{"location":"modules/WPBrowser/#seeinfield","title":"seeInField","text":"

    Signature: seeInField($field, $value) : void

    "},{"location":"modules/WPBrowser/#seeinformfields","title":"seeInFormFields","text":"

    Signature: seeInFormFields($formSelector, array $params) : void

    "},{"location":"modules/WPBrowser/#seeinsource","title":"seeInSource","text":"

    Signature: seeInSource(string $raw) : void

    "},{"location":"modules/WPBrowser/#seeintitle","title":"seeInTitle","text":"

    Signature: seeInTitle($title) : void

    "},{"location":"modules/WPBrowser/#seelink","title":"seeLink","text":"

    Signature: seeLink(string $text, [?string $url]) : void

    "},{"location":"modules/WPBrowser/#seemessage","title":"seeMessage","text":"

    Signature: seeMessage([array|string $classes]) : void

    In an administration screen look for an admin notice.

    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

    <?php\n$I->loginAsAdmin()\n$I->amOnAdminPage('/');\n$I->seeMessage('.missing-api-token.my-plugin');\n
    "},{"location":"modules/WPBrowser/#seenumberofelements","title":"seeNumberOfElements","text":"

    Signature: seeNumberOfElements($selector, $expected) : void

    "},{"location":"modules/WPBrowser/#seeoptionisselected","title":"seeOptionIsSelected","text":"

    Signature: seeOptionIsSelected($selector, $optionText) : void

    "},{"location":"modules/WPBrowser/#seepagenotfound","title":"seePageNotFound","text":"

    Signature: seePageNotFound() : void

    Asserts that current page has 404 response status code.

    "},{"location":"modules/WPBrowser/#seepluginactivated","title":"seePluginActivated","text":"

    Signature: seePluginActivated(string $pluginSlug) : void

    Assert a plugin is activated in the plugin administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->seePluginActivated('my-plugin');\n
    "},{"location":"modules/WPBrowser/#seeplugindeactivated","title":"seePluginDeactivated","text":"

    Signature: seePluginDeactivated(string $pluginSlug) : void

    Assert a plugin is not activated in the plugins administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->seePluginDeactivated('my-plugin');\n
    "},{"location":"modules/WPBrowser/#seeplugininstalled","title":"seePluginInstalled","text":"

    Signature: seePluginInstalled(string $pluginSlug) : void

    Assert a plugin is installed, no matter its activation status, in the plugin administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->seePluginInstalled('my-plugin');\n
    "},{"location":"modules/WPBrowser/#seeresponsecodeis","title":"seeResponseCodeIs","text":"

    Signature: seeResponseCodeIs(int $code) : void

    Checks that response code is equal to value provided.

    <?php\n$I->seeResponseCodeIs(200);\n\n// recommended \\Codeception\\Util\\HttpCode\n$I->seeResponseCodeIs(\\Codeception\\Util\\HttpCode::OK);\n
    "},{"location":"modules/WPBrowser/#seeresponsecodeisbetween","title":"seeResponseCodeIsBetween","text":"

    Signature: seeResponseCodeIsBetween(int $from, int $to) : void

    Checks that response code is between a certain range. Between actually means [from <= CODE <= to]

    "},{"location":"modules/WPBrowser/#seeresponsecodeisclienterror","title":"seeResponseCodeIsClientError","text":"

    Signature: seeResponseCodeIsClientError() : void

    Checks that the response code is 4xx

    "},{"location":"modules/WPBrowser/#seeresponsecodeisredirection","title":"seeResponseCodeIsRedirection","text":"

    Signature: seeResponseCodeIsRedirection() : void

    Checks that the response code 3xx

    "},{"location":"modules/WPBrowser/#seeresponsecodeisservererror","title":"seeResponseCodeIsServerError","text":"

    Signature: seeResponseCodeIsServerError() : void

    Checks that the response code is 5xx

    "},{"location":"modules/WPBrowser/#seeresponsecodeissuccessful","title":"seeResponseCodeIsSuccessful","text":"

    Signature: seeResponseCodeIsSuccessful() : void

    Checks that the response code 2xx

    "},{"location":"modules/WPBrowser/#seethemeactivated","title":"seeThemeActivated","text":"

    Signature: seeThemeActivated(string $slug) : void

    Verifies that a theme is active.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPBrowser/#seewpdiepage","title":"seeWpDiePage","text":"

    Signature: seeWpDiePage() : void

    Checks that the current page is one generated by the wp_die function.

    The method will try to identify the page based on the default WordPress die page HTML attributes.

    <?php\n$I->loginAs('user', 'password');\n$I->amOnAdminPage('/forbidden');\n$I->seeWpDiePage();\n
    "},{"location":"modules/WPBrowser/#selectoption","title":"selectOption","text":"

    Signature: selectOption($select, $option) : void

    "},{"location":"modules/WPBrowser/#sendajaxgetrequest","title":"sendAjaxGetRequest","text":"

    Signature: sendAjaxGetRequest(string $uri, [array $params]) : void

    Sends an ajax GET request with the passed parameters. See sendAjaxPostRequest()

    "},{"location":"modules/WPBrowser/#sendajaxpostrequest","title":"sendAjaxPostRequest","text":"

    Signature: sendAjaxPostRequest(string $uri, [array $params]) : void

    Sends an ajax POST request with the passed parameters. The appropriate HTTP header is added automatically: X-Requested-With: XMLHttpRequest Example:

    <?php\n$I->sendAjaxPostRequest('/add-task', ['task' => 'lorem ipsum']);\n
    Some frameworks (e.g. Symfony) create field names in the form of an \"array\": <input type=\"text\" name=\"form[task]\"> In this case you need to pass the fields like this:
    <?php\n$I->sendAjaxPostRequest('/add-task', ['form' => [\n    'task' => 'lorem ipsum',\n    'category' => 'miscellaneous',\n]]);\n

    "},{"location":"modules/WPBrowser/#sendajaxrequest","title":"sendAjaxRequest","text":"

    Signature: sendAjaxRequest(string $method, string $uri, [array $params]) : void

    Sends an ajax request, using the passed HTTP method. See sendAjaxPostRequest() Example:

    <?php\n$I->sendAjaxRequest('PUT', '/posts/7', ['title' => 'new title']);\n

    "},{"location":"modules/WPBrowser/#setcookie","title":"setCookie","text":"

    Signature: setCookie($name, $val, [$params]) : void

    "},{"location":"modules/WPBrowser/#setheader","title":"setHeader","text":"

    Signature: setHeader(string $name, string $value) : void

    Alias to haveHttpHeader

    "},{"location":"modules/WPBrowser/#setmaxredirects","title":"setMaxRedirects","text":"

    Signature: setMaxRedirects(int $maxRedirects) : void

    Sets the maximum number of redirects that the Client can follow.

    <?php\n$I->setMaxRedirects(2);\n
    "},{"location":"modules/WPBrowser/#setserverparameters","title":"setServerParameters","text":"

    Signature: setServerParameters(array $params) : void

    Sets SERVER parameters valid for all next requests. this will remove old ones.

    <?php\n$I->setServerParameters([]);\n
    "},{"location":"modules/WPBrowser/#startfollowingredirects","title":"startFollowingRedirects","text":"

    Signature: startFollowingRedirects() : void

    Enables automatic redirects to be followed by the client.

    <?php\n$I->startFollowingRedirects();\n
    "},{"location":"modules/WPBrowser/#stopfollowingredirects","title":"stopFollowingRedirects","text":"

    Signature: stopFollowingRedirects() : void

    Prevents automatic redirects to be followed by the client.

    <?php\n$I->stopFollowingRedirects();\n
    "},{"location":"modules/WPBrowser/#submitform","title":"submitForm","text":"

    Signature: submitForm($selector, array $params, [?string $button]) : void

    "},{"location":"modules/WPBrowser/#switchtoiframe","title":"switchToIframe","text":"

    Signature: switchToIframe(string $name) : void

    Switch to iframe or frame on the page.

    Example:

    <iframe name=\"another_frame\" src=\"http://example.com\">\n

    <?php\n# switch to iframe\n$I->switchToIframe(\"another_frame\");\n
    "},{"location":"modules/WPBrowser/#uncheckoption","title":"uncheckOption","text":"

    Signature: uncheckOption($option) : void

    Read more in Codeception documentation.

    "},{"location":"modules/WPCLI/","title":"WPCLI","text":""},{"location":"modules/WPCLI/#wpcli-module","title":"WPCLI module","text":"

    Use WP-CLI to interact with the WordPress installation under test and issue commands.

    This module is used in the context of end-to-end testing, together with, or as a replacement for the WPDb module to manipulate the database and the WPFilesystem module to manipulate the site file structure.

    This module should be with Cest and Cept test cases.

    "},{"location":"modules/WPCLI/#configuration","title":"Configuration","text":"
    • path - required; the path to the WordPress installation under test. This can be a relative path to the codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation directory is the directory that contains the wp-load.php file.
    • url - the URL of the WordPress installation under test. Equivalent to the --url option of the wp command.
    • user - the user to use to run the wp command. Equivalent to the --user option of the wp command.
    • skip-plugins - a boolean value to indicate if the wp command should skip loading plugins. Equivalent to the --skip-plugins option of the wp command.
    • skip-themes - a boolean value to indicate if the wp command should skip loading themes. Equivalent to the --skip-themes option of the wp command.
    • skip-packages - a boolean value to indicate if the wp command should skip loading packages. Equivalent to the --skip-packages option of the wp command.
    • require - a list of PHP files to require before running the wp command. Equivalent to the --require option of the wp command.
    • exec - PHP code to execute before running the wp command. Equivalent to the --exec option of the wp command.
    • context - the context to use when running the wp command. Equivalent to the --context option of the wp command.
    • color - a boolean value to indicate if the wp command should output in color. Equivalent to the --color option of the wp command.
    • no-color - a boolean value to indicate if the wp command should not output in color. Equivalent to the --no-color option of the wp command.
    • debug - a boolean value to indicate if the wp command should output debug information. Equivalent to the --debug option of the wp command.
    • quiet - a boolean value to indicate if the wp command should suppress informational messages. Equivalent to the --quiet option of the wp command.
    • throw - a boolean value to indicate if the wp command should throw an exception if the command fails.
    • timeout - the timeout to use when running the wp command. When the timeout is reached the command will be terminated as a failure.
    • cache-dir - the directory to use to cache the files WPCLI might downloads. Equivalent to setting the WP_CLI_CACHE_DIR environment variable.
    • config-path - the path to the wp-cli.yml file to use. Equivalent to setting the WP_CLI_CONFIG_PATH environment variable.
    • custom-shell - the shell to use to run the wp command. Equivalent to setting the WP_CLI_SHELL environment variable.
    • packages-dir - the directory to use to store the packages downloaded by the wp package command. Equivalent to setting the WP_CLI_PACKAGES_DIR environment variable.

    The following is an example of the module configuration to run WPCLI commands on the /var/wordpress directory:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPCLI:\n      path: /var/wordpress\n      throw: true\n

    The following configuration uses dynamic configuration parameters to set the module configuration:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPCLI:\n      path: '%WP_ROOT_DIR%'\n      throw: true\n
    "},{"location":"modules/WPCLI/#methods","title":"Methods","text":"

    The module provides the following methods:

    "},{"location":"modules/WPCLI/#changewpclipath","title":"changeWpcliPath","text":"

    Signature: changeWpcliPath(string $path) : void

    Changes the path to the WordPress installation that WPCLI should use.

    This is the equivalent of the --path option.

    <?php\n// Operate on the installation specified in the `path` config parameter.\n$I->cli(['core','version']);\n// Change to another installation and run a command there.\n$I->changeWpcliPath('var/wordpress-installation-two');\n$I->cli(['core','version']);\n
    "},{"location":"modules/WPCLI/#cli","title":"cli","text":"

    Signature: cli([array|string $command], [?array $env], [mixed $input]) : int

    Executes a wp-cli command targeting the test WordPress installation.

    <?php\n// Activate a plugin via wp-cli in the test WordPress site.\n$I->cli(['plugin', 'activate', 'my-plugin']);\n// Change a user password.\n$I->cli(['user', 'update', 'luca', '--user_pass=newpassword']);\n
    "},{"location":"modules/WPCLI/#clitoarray","title":"cliToArray","text":"

    Signature: cliToArray(array $command, [?callable $splitCallback], [?array $env], [mixed $input]) : array

    Returns the output of a wp-cli command as an array optionally allowing a callback to process the output.

    <?php\n// Return a list of inactive themes, like ['twentyfourteen', 'twentyfifteen'].\n$inactiveThemes = $I->cliToArray(['theme', 'list', '--status=inactive', '--field=name']);\n// Get the list of installed plugins and only keep the ones starting with \"foo\".\n$fooPlugins = $I->cliToArray(['plugin', 'list', '--field=name'], function($output){\n     return array_filter(explode(PHP_EOL, $output), function($name){\n             return strpos(trim($name), 'foo') === 0;\n     });\n});\n
    "},{"location":"modules/WPCLI/#clitostring","title":"cliToString","text":"

    Signature: cliToString(array $command, [?array $env], [mixed $input]) : string

    Returns the output of a wp-cli command as a string.

    <?php\n// Return the current site administrator email, using string command format.\n$adminEmail = $I->cliToString('option get admin_email');\n// Get the list of active plugins in JSON format, two ways.\n$activePlugins = $I->cliToString(['plugin', 'list','--status=active', '--format=json']);\n$activePlugins = $I->cliToString(['option', 'get', 'active_plugins' ,'--format=json']);\n
    "},{"location":"modules/WPCLI/#dontseeinshelloutput","title":"dontSeeInShellOutput","text":"

    Signature: dontSeeInShellOutput(string $text) : void

    Checks that output from last command doesn't contain text.

    <?php\n// Return the current site administrator email, using string command format.\n$I->cli('plugin list --status=active');\n$I->dontSeeInShellOutput('my-inactive/plugin.php');\n
    "},{"location":"modules/WPCLI/#dontseeshelloutputmatches","title":"dontSeeShellOutputMatches","text":"

    Signature: dontSeeShellOutputMatches(string $regex) : void

    Checks that output from the last command doesn't match a given regular expression.

    <?php\n// Return the current site administrator email, using string command format.\n$I->cli('option get siteurl');\n$I->dontSeeShellOutputMatches('/^http/');\n
    "},{"location":"modules/WPCLI/#grablastcliprocess","title":"grabLastCliProcess","text":"

    Signature: grabLastCliProcess() : lucatume\\WPBrowser\\WordPress\\CliProcess

    "},{"location":"modules/WPCLI/#grablastshellerroroutput","title":"grabLastShellErrorOutput","text":"

    Signature: grabLastShellErrorOutput() : string

    Returns the shell error output of the last command.

    "},{"location":"modules/WPCLI/#grablastshelloutput","title":"grabLastShellOutput","text":"

    Signature: grabLastShellOutput() : string

    Returns the shell output of the last command.

    "},{"location":"modules/WPCLI/#seeinshelloutput","title":"seeInShellOutput","text":"

    Signature: seeInShellOutput(string $text) : void

    Checks that output from last command contains text.

    <?php\n// Return the current site administrator email, using string command format.\n$I->cli('option get admin_email');\n$I->seeInShellOutput('admin@example.org');\n
    "},{"location":"modules/WPCLI/#seeresultcodeis","title":"seeResultCodeIs","text":"

    Signature: seeResultCodeIs(int $code) : void

    Checks the result code from the last command.

    <?php\n// Return the current site administrator email, using string command format.\n$I->cli('option get admin_email');\n$I->seeResultCodeIs(0);\n
    "},{"location":"modules/WPCLI/#seeresultcodeisnot","title":"seeResultCodeIsNot","text":"

    Signature: seeResultCodeIsNot(int $code) : void

    Checks the result code from the last command.

    <?php\n// Return the current site administrator email, using string command format.\n$I->cli('invalid command');\n$I->seeResultCodeIsNot(0);\n
    "},{"location":"modules/WPCLI/#seeshelloutputmatches","title":"seeShellOutputMatches","text":"

    Signature: seeShellOutputMatches(string $regex) : void

    Checks that output from the last command matches a given regular expression.

    <?php\n// Return the current site administrator email, using string command format.\n$I->cli('option get admin_email');\n$I->seeShellOutputMatches('/^\\S+@\\S+$/');\n

    Explore the WP-CLI documentation for more information on the available commands.

    "},{"location":"modules/WPDb/","title":"WPDb","text":""},{"location":"modules/WPDb/#wpdb-module","title":"WPDb module","text":"

    This module allows to manipulate the database of the WordPress installation under test directly, without using the WordPress API.

    The module is used together with the WPBrowser module, WPWebDriver and WPFilesystem modules to control the site state, the database, and the site file structure.

    Note about interaction with the WPLoader module: both this module and the WPLoader one can be used to control the state of the database before tests and set up fixtures: use either this or WPLoader, do not use both. This module should be used in end-to-end testing, the WPLoader module should be used in integration testing. If you're using this module to load a database dump before integration tests, use the WPLoader module dump configuration parameter instead.

    This module should be with Cest and Cept test cases.

    "},{"location":"modules/WPDb/#configuration","title":"Configuration","text":"

    This module extends the Codeception Db module adding some configuration options and functions that are specific to WordPress.

    • dbUrl - required; the URL to use to connect to the database. The URL must be in the form mysql://user:password@host:port/database if you're using a MySQL database for your tests, or in the form sqlite://path/to/database/file if you're using a SQLite database for your tests ( like the default configuration does)
    • dsn - required; the DSN to use to connect to the database; required if not using the dbUrl parameter.
    • user - required; the user to use to connect to the database; required if not using the dbUrl parameter.
    • password - required; the password to use to connect to the database; required if not using the dbUrl parameter.
    • url - required;the URL of the WordPress installation under test. E.g. http://localhost:8080 or https://wordpress.test.
    • tablePrefix - the table prefix to use when interacting with the database; defaults to wp_.
    • dump - the path to a database dump file, or a set of database files, to load before running tests. The path can be relative to the project root directory, e.g. tests/_data/dump.sql, or absolute.
    • populate - a boolean value to indicate if the database should be populated importing the dump file(s) at the start of the suite.
    • cleanup - a boolean value to indicate if the database should be populated importing the dump file(s) before each test.
    • reconnect - a boolean value to indicate if the database connection should be re-established before each test.
    • populator - a command to use to populate the database instead of using PHP; read more on the Codeception documentation.
    • urlReplacement - a boolean value to indicate if the database dump file(s) should be searched for the siteurl and home options and replaced with the url parameter value. This is required since WordPress hard-codes URLs in the database, the original URL is inferred, if the originalUrl parameter is not provided.
    • originalUrl - if provided together with the urlReplacement parameter, the module will not try to infer the original URL from the database dump file(s) but use the provided value instead.
    • waitlock - the number of seconds to wait for a database lock to be released before failing the test. Defaults to 10 meaning that the test will fail if the database lock is not released after 10 seconds.
    • createIfNotExists - a boolean value to indicate if the database should be created if it does not exist. Defaults to false.

    The following is an example of the module configuration to run tests on thehttp://localhost:8080 site:

    modules:\n  enabled:\n    - lucatume\\WPBrowser\\Module\\WPDb:\n        dbUrl: 'mysql://root:password@localhost:3306/wordpress'\n        url: 'http://localhost:8080'\n        tablePrefix: 'wp_'\n        dump: 'tests/_data/dump.sql'\n        populate: true\n        cleanup: true\n        reconnect: false\n        urlReplacement: true\n        originalUrl: http://wordpress.test\n        waitlock: 10\n        createIfNotExists: true\n

    The following configuration uses dynamic configuration parameters to set the module configuration:

    modules:\n  enabled:\n    - lucatume\\WPBrowser\\Module\\WPDb:\n        dbUrl: '%DB_URL%'\n        url: '%WORDPRESS_URL%'\n        tablePrefix: '%WORDPRESS_TABLE_PREFIX%'\n        dump: '%DB_DUMP%'\n        populate: true\n        cleanup: true\n        reconnect: false\n        urlReplacement: true\n        originalUrl: '%WORDPRESS_ORIGINAL_URL%'\n        waitlock: 10\n        createIfNotExists: true\n

    The following configuration uses a SQLite database:

    modules:\n  enabled:\n    - lucatume\\WPBrowser\\Module\\WPDb:\n        dbUrl: 'sqlite://tests/database.sqlite'\n        url: 'http://localhost:8080'\n        tablePrefix: 'wp_'\n        dump: 'tests/_data/dump.sql'\n        populate: true\n        cleanup: true\n        reconnect: false\n        urlReplacement: true\n        originalUrl: http://wordpress.test\n        waitlock: 10\n        createIfNotExists: true\n
    "},{"location":"modules/WPDb/#methods","title":"Methods","text":""},{"location":"modules/WPDb/#amconnectedtodatabase","title":"amConnectedToDatabase","text":"

    Signature: amConnectedToDatabase(string $databaseKey) : void

    Make sure you are connected to the right database.

    <?php\n$I->seeNumRecords(2, 'users');   //executed on default database\n$I->amConnectedToDatabase('db_books');\n$I->seeNumRecords(30, 'books');  //executed on db_books database\n//All the next queries will be on db_books\n
    "},{"location":"modules/WPDb/#countrowsindatabase","title":"countRowsInDatabase","text":"

    Signature: countRowsInDatabase(string $table, [array $criteria]) : int

    Returns the number of table rows matching a criteria.

    <?php\n$I->haveManyPostsInDatabase(3, ['post_status' => 'draft' ]);\n$I->haveManyPostsInDatabase(3, ['post_status' => 'private' ]);\n// Make sure there are now the expected number of draft posts.\n$postsTable = $I->grabPostsTableName();\n$draftsCount = $I->countRowsInDatabase($postsTable, ['post_status' => 'draft']);\n
    "},{"location":"modules/WPDb/#donthaveattachmentfilesindatabase","title":"dontHaveAttachmentFilesInDatabase","text":"

    Signature: dontHaveAttachmentFilesInDatabase(array|int $attachmentIds) : void

    Removes all the files attached with an attachment post, it will not remove the database entries. Requires the WPFilesystem module to be loaded in the suite.

    <?php\n$posts = $I->grabPostsTableName();\n$attachmentIds = $I->grabColumnFromDatabase($posts, 'ID', ['post_type' => 'attachment']);\n// This will only remove the files, not the database entries.\n$I->dontHaveAttachmentFilesInDatabase($attachmentIds);\n
    "},{"location":"modules/WPDb/#donthaveattachmentindatabase","title":"dontHaveAttachmentInDatabase","text":"

    Signature: dontHaveAttachmentInDatabase(array $criteria, [bool $purgeMeta], [bool $removeFiles]) : void

    Removes an attachment from the posts table.

    $postmeta = $I->grabpostmetatablename();\n$thumbnailId = $I->grabFromDatabase($postmeta, 'meta_value', [\n     'post_id' => $id,\n     'meta_key'=>'thumbnail_id'\n]);\n// Remove only the database entry (including postmeta) but not the files.\n$I->dontHaveAttachmentInDatabase($thumbnailId);\n// Remove the database entry (including postmeta) and the files.\n$I->dontHaveAttachmentInDatabase($thumbnailId, true, true);\n
    "},{"location":"modules/WPDb/#donthaveblogindatabase","title":"dontHaveBlogInDatabase","text":"

    Signature: dontHaveBlogInDatabase(array $criteria, [bool $removeTables], [bool $removeUploads]) : void

    Removes one ore more blogs from the database.

    <?php\n// Remove the blog, all its tables and files.\n$I->dontHaveBlogInDatabase(['path' => 'test/one']);\n// Remove the blog entry, not the tables though.\n$I->dontHaveBlogInDatabase(['blog_id' => $blogId]);\n// Remove multiple blogs.\n$I->dontHaveBlogInDatabase(['domain' => 'test']);\n
    "},{"location":"modules/WPDb/#donthavecommentindatabase","title":"dontHaveCommentInDatabase","text":"

    Signature: dontHaveCommentInDatabase(array $criteria, [bool $purgeMeta]) : void

    Removes an entry from the comments table.

    <?php\n$I->dontHaveCommentInDatabase(['comment_post_ID' => 23, 'comment_url' => 'http://example.copm']);\n
    "},{"location":"modules/WPDb/#donthavecommentmetaindatabase","title":"dontHaveCommentMetaInDatabase","text":"

    Signature: dontHaveCommentMetaInDatabase(array $criteria) : void

    Removes a post comment meta from the database

    <?php\n// Remove all meta for the comment with an ID of 23.\n$I->dontHaveCommentMetaInDatabase(['comment_id' => 23]);\n// Remove the `count` comment meta for the comment with an ID of 23.\n$I->dontHaveCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'count']);\n
    "},{"location":"modules/WPDb/#donthaveindatabase","title":"dontHaveInDatabase","text":"

    Signature: dontHaveInDatabase(string $table, array $criteria) : void

    Deletes a database entry.

    <?php\n$I->dontHaveInDatabase('custom_table', ['book_ID' => 23, 'book_genre' => 'fiction']);\n
    "},{"location":"modules/WPDb/#donthavelinkindatabase","title":"dontHaveLinkInDatabase","text":"

    Signature: dontHaveLinkInDatabase(array $criteria) : void

    Removes a link from the database.

    <?php\n$I->dontHaveLinkInDatabase(['link_url' => 'http://example.com']);\n
    "},{"location":"modules/WPDb/#donthaveoptionindatabase","title":"dontHaveOptionInDatabase","text":"

    Signature: dontHaveOptionInDatabase(string $key, [mixed $value]) : void

    Removes an entry from the options table.

    <?php\n// Remove the `foo` option.\n$I->dontHaveOptionInDatabase('foo');\n// Remove the 'bar' option only if it has the `baz` value.\n$I->dontHaveOptionInDatabase('bar', 'baz');\n
    "},{"location":"modules/WPDb/#donthavepostindatabase","title":"dontHavePostInDatabase","text":"

    Signature: dontHavePostInDatabase(array $criteria, [bool $purgeMeta]) : void

    Removes an entry from the posts table.

    <?php\n$posts = $I->haveManyPostsInDatabase(3, ['post_title' => 'Test {{n}}']);\n$I->dontHavePostInDatabase(['post_title' => 'Test 2']);\n
    "},{"location":"modules/WPDb/#donthavepostmetaindatabase","title":"dontHavePostMetaInDatabase","text":"

    Signature: dontHavePostMetaInDatabase(array $criteria) : void

    Removes an entry from the postmeta table.

    <?php\n$postId = $I->havePostInDatabase(['meta_input' => ['rating' => 23]]);\n$I->dontHavePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'rating']);\n
    "},{"location":"modules/WPDb/#donthavepostthumbnailindatabase","title":"dontHavePostThumbnailInDatabase","text":"

    Signature: dontHavePostThumbnailInDatabase(int $postId) : void

    Remove the thumbnail (featured image) from a post, if any.

    Please note: the method will NOT remove the attachment post, post meta and file.

    <?php\n$attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));\n$postId = $I->havePostInDatabase();\n// Attach the thumbnail to the post.\n$I->havePostThumbnailInDatabase($postId, $attachmentId);\n// Remove the thumbnail from the post.\n$I->dontHavePostThumbnailInDatabase($postId);\n
    "},{"location":"modules/WPDb/#donthavesiteoptionindatabase","title":"dontHaveSiteOptionInDatabase","text":"

    Signature: dontHaveSiteOptionInDatabase(string $key, [mixed $value]) : void

    Removes a site option from the database.

    <?php\n// Remove the `foo_count` option.\n$I->dontHaveSiteOptionInDatabase('foo_count');\n// Remove the `foo_count` option only if its value is `23`.\n$I->dontHaveSiteOptionInDatabase('foo_count', 23);\n
    "},{"location":"modules/WPDb/#donthavesitetransientindatabase","title":"dontHaveSiteTransientInDatabase","text":"

    Signature: dontHaveSiteTransientInDatabase(string $key) : void

    Removes a site transient from the database.

    <?php\n$I->dontHaveSiteTransientInDatabase(['my_plugin_site_buffer']);\n
    "},{"location":"modules/WPDb/#donthavetableindatabase","title":"dontHaveTableInDatabase","text":"

    Signature: dontHaveTableInDatabase(string $fullTableName) : void

    Removes a table from the database. The case where a table does not exist is handled without raising an error.

    <?php\n$ordersTable = $I->grabPrefixedTableNameFor('orders');\n$I->dontHaveTableInDatabase($ordersTable);\n
    "},{"location":"modules/WPDb/#donthavetermindatabase","title":"dontHaveTermInDatabase","text":"

    Signature: dontHaveTermInDatabase(array $criteria, [bool $purgeMeta]) : void

    Removes a term from the database.

    <?php\n$I->dontHaveTermInDatabase(['name' => 'romance']);\n$I->dontHaveTermInDatabase(['slug' => 'genre--romance']);\n
    "},{"location":"modules/WPDb/#donthavetermmetaindatabase","title":"dontHaveTermMetaInDatabase","text":"

    Signature: dontHaveTermMetaInDatabase(array $criteria) : void

    Removes a term meta from the database.

    <?php\n// Remove the \"karma\" key.\n$I->dontHaveTermMetaInDatabase(['term_id' => $termId, 'meta_key' => 'karma']);\n// Remove all meta for the term.\n$I->dontHaveTermMetaInDatabase(['term_id' => $termId]);\n
    "},{"location":"modules/WPDb/#donthavetermrelationshipindatabase","title":"dontHaveTermRelationshipInDatabase","text":"

    Signature: dontHaveTermRelationshipInDatabase(array $criteria) : void

    Removes an entry from the term_relationships table.

    <?php\n// Remove the relation between a post and a category.\n$I->dontHaveTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $ttaxId]);\n// Remove all terms for a post.\n$I->dontHaveTermMetaInDatabase(['object_id' => $postId]);\n
    "},{"location":"modules/WPDb/#donthavetermtaxonomyindatabase","title":"dontHaveTermTaxonomyInDatabase","text":"

    Signature: dontHaveTermTaxonomyInDatabase(array $criteria) : void

    Removes an entry from the term_taxonomy table.

    <?php\n// Remove a specific term from the genre taxonomy.\n$I->dontHaveTermTaxonomyInDatabase(['term_id' => $postId, 'taxonomy' => 'genre']);\n// Remove all terms for a taxonomy.\n$I->dontHaveTermTaxonomyInDatabase(['taxonomy' => 'genre']);\n
    "},{"location":"modules/WPDb/#donthavetransientindatabase","title":"dontHaveTransientInDatabase","text":"

    Signature: dontHaveTransientInDatabase(string $transient) : void

    Removes a transient from the database.

    <?php\n// Removes the `tweets` transient from the database, if set.\n$I->dontHaveTransientInDatabase('tweets');\n
    "},{"location":"modules/WPDb/#donthaveuserindatabase","title":"dontHaveUserInDatabase","text":"

    Signature: dontHaveUserInDatabase(string|int $userIdOrLogin, [bool $purgeMeta]) : void

    Removes a user from the database.

    <?php\n$bob = $I->haveUserInDatabase('bob');\n$alice = $I->haveUserInDatabase('alice');\n// Remove Bob's user and meta.\n$I->dontHaveUserInDatabase('bob');\n// Remove Alice's user but not meta.\n$I->dontHaveUserInDatabase($alice);\n
    "},{"location":"modules/WPDb/#donthaveuserindatabasewithemail","title":"dontHaveUserInDatabaseWithEmail","text":"

    Signature: dontHaveUserInDatabaseWithEmail(string $userEmail, [bool $purgeMeta]) : array

    Removes a user(s) from the database using the user email address.

    <?php\n$luca = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);\n$I->dontHaveUserInDatabaseWithEmail('luca@exampl.org');\n
    "},{"location":"modules/WPDb/#donthaveusermetaindatabase","title":"dontHaveUserMetaInDatabase","text":"

    Signature: dontHaveUserMetaInDatabase(array $criteria) : void

    Removes an entry from the usermeta table.

    <?php\n// Remove the `karma` user meta for a user.\n$I->dontHaveUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);\n// Remove all the user meta for a user.\n$I->dontHaveUserMetaInDatabase(['user_id' => 23]);\n
    "},{"location":"modules/WPDb/#dontseeattachmentindatabase","title":"dontSeeAttachmentInDatabase","text":"

    Signature: dontSeeAttachmentInDatabase(array $criteria) : void

    Checks that an attachment is not in the database.

    <?php\n$url = 'https://example.org/images/foo.png';\n$I->dontSeeAttachmentInDatabase(['guid' => $url]);\n
    "},{"location":"modules/WPDb/#dontseeblogindatabase","title":"dontSeeBlogInDatabase","text":"

    Signature: dontSeeBlogInDatabase(array $criteria) : void

    Checks that a row is not present in the blogs table.

    <?php\n$I->haveManyBlogsInDatabase(2, ['path' => 'test-{{n}}'], false)\n$I->dontSeeBlogInDatabase(['path' => '/test-3/'])\n
    "},{"location":"modules/WPDb/#dontseecommentindatabase","title":"dontSeeCommentInDatabase","text":"

    Signature: dontSeeCommentInDatabase(array $criteria) : void

    Checks that a comment is not in the database.

    Will look up the \"comments\" table.

    <?php\n// Checks for one comment.\n$I->dontSeeCommentInDatabase(['comment_ID' => 23]);\n// Checks for comments from a user.\n$I->dontSeeCommentInDatabase(['user_id' => 89]);\n
    "},{"location":"modules/WPDb/#dontseecommentmetaindatabase","title":"dontSeeCommentMetaInDatabase","text":"

    Signature: dontSeeCommentMetaInDatabase(array $criteria) : void

    Checks that a comment meta value is not in the database.

    Will look up the \"commentmeta\" table.

    <?php\n// Delete a comment `karma` meta.\n$I->dontSeeCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'karma']);\n// Delete all meta for a comment.\n$I->dontSeeCommentMetaInDatabase(['comment_id' => 23]);\n
    "},{"location":"modules/WPDb/#dontseeindatabase","title":"dontSeeInDatabase","text":"

    Signature: dontSeeInDatabase(string $table, [array $criteria]) : void

    "},{"location":"modules/WPDb/#dontseelinkindatabase","title":"dontSeeLinkInDatabase","text":"

    Signature: dontSeeLinkInDatabase(array $criteria) : void

    Checks that a link is not in the links database table.

    <?php\n$I->dontSeeLinkInDatabase(['link_url' => 'http://example.com']);\n$I->dontSeeLinkInDatabase(['link_url' => 'http://example.com', 'link_name' => 'example']);\n
    "},{"location":"modules/WPDb/#dontseeoptionindatabase","title":"dontSeeOptionInDatabase","text":"

    Signature: dontSeeOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    Checks that an option is not in the database for the current blog.

    If the value is an object or an array then the serialized option will be checked.

    <?php\n$I->dontHaveOptionInDatabase('posts_per_page');\n$I->dontSeeOptionInDatabase('posts_per_page');\n$I->dontSeeOptionInDatabase('posts_per_page', 23);\n$I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page']);\n$I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page', 'option_value' => 23]);\n
    "},{"location":"modules/WPDb/#dontseepageindatabase","title":"dontSeePageInDatabase","text":"

    Signature: dontSeePageInDatabase(array $criteria) : void

    Checks that a page is not in the database.

    <?php\n// Assert a page with an ID does not exist.\n$I->dontSeePageInDatabase(['ID' => 23]);\n// Assert a page with a slug and ID.\n$I->dontSeePageInDatabase(['post_name' => 'test', 'ID' => 23]);\n
    "},{"location":"modules/WPDb/#dontseepostindatabase","title":"dontSeePostInDatabase","text":"

    Signature: dontSeePostInDatabase(array $criteria) : void

    Checks that a post is not in the database.

    <?php\n// Asserts a post with title 'Test' is not in the database.\n$I->dontSeePostInDatabase(['post_title' => 'Test']);\n// Asserts a post with title 'Test' and content 'Test content' is not in the database.\n$I->dontSeePostInDatabase(['post_title' => 'Test', 'post_content' => 'Test content']);\n
    "},{"location":"modules/WPDb/#dontseepostmetaindatabase","title":"dontSeePostMetaInDatabase","text":"

    Signature: dontSeePostMetaInDatabase(array $criteria) : void

    Checks that a post meta value does not exist.

    If the meta value is an object or an array then the check will be made on its serialized version.

    <?php\n$postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']]);\n$I->dontSeePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'woot']);\n
    "},{"location":"modules/WPDb/#dontseepostwithtermindatabase","title":"dontSeePostWithTermInDatabase","text":"

    Signature: dontSeePostWithTermInDatabase(int $post_id, int $term_taxonomy_id, [?int $term_order], [?string $taxonomy]) : void

    Checks that a post to term relation does not exist in the database.

    The method will check the \"term_relationships\" table.

    <?php\n$fiction = $I->haveTermInDatabase('fiction', 'genre');\n$nonFiction = $I->haveTermInDatabase('non-fiction', 'genre');\n$postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);\n$I->dontSeePostWithTermInDatabase($postId, $nonFiction['term_taxonomy_id], );\n
    "},{"location":"modules/WPDb/#dontseesiteoptionindatabase","title":"dontSeeSiteOptionInDatabase","text":"

    Signature: dontSeeSiteOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    Checks that a site option is not in the database.

    <?php\n// Check that the option is not set in the database.\n$I->dontSeeSiteOptionInDatabase('foo_count');\n// Check that the option is not set with a specific value.\n$I->dontSeeSiteOptionInDatabase('foo_count', 23);\n$I->dontSeeSiteOptionInDatabase(['option_name => 'foo_count', 'option_value' => 23]);\n
    "},{"location":"modules/WPDb/#dontseesitetransientindatabase","title":"dontSeeSiteTransientInDatabase","text":"

    Signature: dontSeeSiteTransientInDatabase(string $transient, [mixed $value]) : void

    Checks that a site transient is not in the database.

    <?php\n$I->dontSeeSiteTransientInDatabase('foo');\n$I->dontSeeSiteTransientInDatabase('foo', 23);\n
    "},{"location":"modules/WPDb/#dontseetableindatabase","title":"dontSeeTableInDatabase","text":"

    Signature: dontSeeTableInDatabase(string $table) : void

    Checks that a table is not in the database.

    <?php\n$options = $I->grabPrefixedTableNameFor('options');\n$I->dontHaveTableInDatabase($options)\n$I->dontSeeTableInDatabase($options);\n
    "},{"location":"modules/WPDb/#dontseetermindatabase","title":"dontSeeTermInDatabase","text":"

    Signature: dontSeeTermInDatabase(array $criteria) : void

    Makes sure a term is not in the database.

    Looks up both the terms table and the term_taxonomy tables.

    <?php\n// Asserts a 'fiction' term is not in the database.\n$I->dontSeeTermInDatabase(['name' => 'fiction']);\n// Asserts a 'fiction' term with slug 'genre--fiction' is not in the database.\n$I->dontSeeTermInDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);\n
    "},{"location":"modules/WPDb/#dontseetermmetaindatabase","title":"dontSeeTermMetaInDatabase","text":"

    Signature: dontSeeTermMetaInDatabase(array $criteria) : void

    Checks that a term meta is not in the database.

    <?php\nlist($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n$I->haveTermMetaInDatabase($termId, 'rating', 4);\n$I->dontSeeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'average_review']);\n
    "},{"location":"modules/WPDb/#dontseetermtaxonomyindatabase","title":"dontSeeTermTaxonomyInDatabase","text":"

    Signature: dontSeeTermTaxonomyInDatabase(array $criteria) : void

    Checks that a term taxonomy is not in the database.

    <?php\nlist($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n$I->dontSeeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'country']);\n
    "},{"location":"modules/WPDb/#dontseetransientindatabase","title":"dontSeeTransientInDatabase","text":"

    Signature: dontSeeTransientInDatabase(string $transient, [mixed $value]) : void

    Checks that a transient is not in the database.

    <?php\n$I->dontSeeTransientInDatabase('foo');\n$I->dontSeeTransientInDatabase('foo', 23);\n
    "},{"location":"modules/WPDb/#dontseeuserindatabase","title":"dontSeeUserInDatabase","text":"

    Signature: dontSeeUserInDatabase(array $criteria) : void

    Checks that a user is not in the database.

    <?php\n// Asserts a user does not exist in the database.\n$I->dontSeeUserInDatabase(['user_login' => 'luca']);\n// Asserts a user with email and login is not in the database.\n$I->dontSeeUserInDatabase(['user_login' => 'luca', 'user_email' => 'luca@theaveragedev.com']);\n
    "},{"location":"modules/WPDb/#dontseeusermetaindatabase","title":"dontSeeUserMetaInDatabase","text":"

    Signature: dontSeeUserMetaInDatabase(array $criteria) : void

    Check that a user meta value is not in the database.

    <?php\n// Asserts a user does not have a 'karma' meta assigned.\n$I->dontSeeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);\n// Asserts no user has any 'karma' meta assigned.\n$I->dontSeeUserMetaInDatabase(['meta_key' => 'karma']);\n
    "},{"location":"modules/WPDb/#getsitedomain","title":"getSiteDomain","text":"

    Signature: getSiteDomain() : string

    Returns the site domain inferred from the url set in the config.

    <?php\n$domain = $I->getSiteDomain();\n// We should be redirected to the HTTPS version when visiting the HTTP version.\n$I->amOnPage('http://' . $domain);\n$I->seeCurrentUrlEquals('https://' . $domain);\n
    "},{"location":"modules/WPDb/#getuserstablename","title":"getUsersTableName","text":"

    Signature: getUsersTableName() : string

    Returns the prefixed users table name.

    <?php\n// Given a `wp_` table prefix returns `wp_users`.\n$usersTable = $I->getUsersTableName();\n// Given a `wp_` table prefix returns `wp_users`.\n$I->useBlog(23);\n$usersTable = $I->getUsersTableName();\n
    "},{"location":"modules/WPDb/#graballfromdatabase","title":"grabAllFromDatabase","text":"

    Signature: grabAllFromDatabase(string $table, string $column, array $criteria) : array

    Returns all entries matching a criteria from the database.

    <?php\n$books = $I->grabPrefixedTableNameFor('books');\n$I->grabAllFromDatabase($books, 'title', ['genre' => 'fiction']);\n
    "},{"location":"modules/WPDb/#grabattachmentattachedfile","title":"grabAttachmentAttachedFile","text":"

    Signature: grabAttachmentAttachedFile(int $attachmentPostId) : string

    Returns the path, as stored in the database, of an attachment _wp_attached_file meta. The attached file is, usually, an attachment origal file.

    <?php\n$file = $I->grabAttachmentAttachedFile($attachmentId);\n$fileInfo = new SplFileInfo($file);\n$I->assertEquals('jpg', $fileInfo->getExtension());\n
    "},{"location":"modules/WPDb/#grabattachmentmetadata","title":"grabAttachmentMetadata","text":"

    Signature: grabAttachmentMetadata(int $attachmentPostId) : array

    Returns the metadata array for an attachment post. This is the value of the _wp_attachment_metadata meta.

    <?php\n$metadata = $I->grabAttachmentMetadata($attachmentId);\n$I->assertEquals(['thumbnail', 'medium', 'medium_large'], array_keys($metadata['sizes']);\n
    "},{"location":"modules/WPDb/#grabblogdomain","title":"grabBlogDomain","text":"

    Signature: grabBlogDomain(int $blogId) : string

    Returns a blog domain given its ID.

    <?php\n$blogIds = $I->haveManyBlogsInDatabase(3);\n$domains = array_map(function($blogId){\n     return $I->grabBlogDomain($blogId);\n}, $blogIds);\n
    "},{"location":"modules/WPDb/#grabblogpath","title":"grabBlogPath","text":"

    Signature: grabBlogPath(int $blogId) : string

    Grabs a blog domain from the blogs table.

    <?php\n$blogId = $I->haveBlogInDatabase('test');\n$path = $I->grabBlogDomain($blogId);\n$I->amOnSubdomain($path);\n$I->amOnPage('/');\n
    "},{"location":"modules/WPDb/#grabblogtablename","title":"grabBlogTableName","text":"

    Signature: grabBlogTableName(int $blogId, string $table) : string

    Returns the full name of a table for a blog from a multisite installation database.

    <?php\n$blogOptionTable = $I->grabBlogTableName($blogId, 'option');\n
    "},{"location":"modules/WPDb/#grabblogtablenames","title":"grabBlogTableNames","text":"

    Signature: grabBlogTableNames(int $blogId) : array

    Returns a list of tables for a blog ID.

    <?php\n     $blogId = $I->haveBlogInDatabase('test');\n     $tables = $I->grabBlogTableNames($blogId);\n     $options = array_filter($tables, function($tableName){\n     return str_pos($tableName, 'options') !== false;\n});\n
    "},{"location":"modules/WPDb/#grabblogtableprefix","title":"grabBlogTablePrefix","text":"

    Signature: grabBlogTablePrefix(int $blogId) : string

    Returns the table prefix for a blog.

    <?php\n$blogId = $I->haveBlogInDatabase('test');\n$blogTablePrefix = $I->getBlogTablePrefix($blogId);\n$blogOrders = $I->blogTablePrefix . 'orders';\n
    "},{"location":"modules/WPDb/#grabblogurl","title":"grabBlogUrl","text":"

    Signature: grabBlogUrl([int $blogId]) : string

    Gets the blog URL from the Blog ID.

    "},{"location":"modules/WPDb/#grabblogversionstablename","title":"grabBlogVersionsTableName","text":"

    Signature: grabBlogVersionsTableName() : string

    Gets the prefixed blog_versions table name.

    <?php\n// Assuming a `wp_` table prefix it will return `wp_blog_versions`.\n$blogVersionsTable = $I->grabBlogVersionsTableName();\n$I->useBlog(23);\n// Assuming a `wp_` table prefix it will return `wp_blog_versions`.\n$blogVersionsTable = $I->grabBlogVersionsTableName();\n
    "},{"location":"modules/WPDb/#grabblogstablename","title":"grabBlogsTableName","text":"

    Signature: grabBlogsTableName() : string

    Gets the prefixed blogs table name.

    <?php\n// Assuming a `wp_` table prefix it will return `wp_blogs`.\n$blogVersionsTable = $I->grabBlogsTableName();\n$I->useBlog(23);\n// Assuming a `wp_` table prefix it will return `wp_blogs`.\n$blogVersionsTable = $I->grabBlogsTableName();\n
    "},{"location":"modules/WPDb/#grabcolumnfromdatabase","title":"grabColumnFromDatabase","text":"

    Signature: grabColumnFromDatabase(string $table, string $column, [array $criteria]) : array

    Fetches all values from the column in database. Provide table name, desired column and criteria.

    <?php\n$mails = $I->grabColumnFromDatabase('users', 'email', array('name' => 'RebOOter'));\n
    "},{"location":"modules/WPDb/#grabcommentmetatablename","title":"grabCommentmetaTableName","text":"

    Signature: grabCommentmetaTableName() : string

    Returns the prefixed comment meta table name.

    <?php\n// Get all the values of 'karma' for all comments.\n$commentMeta = $I->grabCommentmetaTableName();\n$I->grabAllFromDatabase($commentMeta, 'meta_value', ['meta_key' => 'karma']);\n
    "},{"location":"modules/WPDb/#grabcommentstablename","title":"grabCommentsTableName","text":"

    Signature: grabCommentsTableName() : string

    Gets the comments table name.

    <?php\n// Will be `wp_comments`.\n$comments = $I->grabCommentsTableName();\n// Will be `wp_23_comments`.\n$I->useBlog(23);\n$comments = $I->grabCommentsTableName();\n
    "},{"location":"modules/WPDb/#grabentriesfromdatabase","title":"grabEntriesFromDatabase","text":"

    Signature: grabEntriesFromDatabase(string $table, [array $criteria]) : array

    Fetches a set of entries from a database. Provide table name and criteria.

    <?php\n$mail = $I->grabEntriesFromDatabase('users', array('name' => 'Davert'));\n
    Comparison expressions can be used as well:

    <?php\n$post = $I->grabEntriesFromDatabase('posts', ['num_comments >=' => 100]);\n$user = $I->grabEntriesFromDatabase('users', ['email like' => 'miles%']);\n

    Supported operators: <, >, >=, <=, !=, like.

    "},{"location":"modules/WPDb/#grabentryfromdatabase","title":"grabEntryFromDatabase","text":"

    Signature: grabEntryFromDatabase(string $table, [array $criteria]) : array

    Fetches a whole entry from a database. Make the test fail if the entry is not found. Provide table name, desired column and criteria.

    <?php\n$mail = $I->grabEntryFromDatabase('users', array('name' => 'Davert'));\n
    Comparison expressions can be used as well:

    <?php\n$post = $I->grabEntryFromDatabase('posts', ['num_comments >=' => 100]);\n$user = $I->grabEntryFromDatabase('users', ['email like' => 'miles%']);\n

    Supported operators: <, >, >=, <=, !=, like.

    "},{"location":"modules/WPDb/#grabfromdatabase","title":"grabFromDatabase","text":"

    Signature: grabFromDatabase(string $table, string $column, [array $criteria]) : void

    Fetches a single column value from a database. Provide table name, desired column and criteria.

    <?php\n$mail = $I->grabFromDatabase('users', 'email', array('name' => 'Davert'));\n
    Comparison expressions can be used as well:

    <?php\n$postNum = $I->grabFromDatabase('posts', 'num_comments', ['num_comments >=' => 100]);\n$mail = $I->grabFromDatabase('users', 'email', ['email like' => 'miles%']);\n

    Supported operators: <, >, >=, <=, !=, like.

    "},{"location":"modules/WPDb/#grablatestentrybyfromdatabase","title":"grabLatestEntryByFromDatabase","text":"

    Signature: grabLatestEntryByFromDatabase(string $tableName, [string $idColumn]) : int

    Returns the id value of the last table entry.

    <?php\n$I->haveManyPostsInDatabase();\n$postsTable = $I->grabPostsTableName();\n$last = $I->grabLatestEntryByFromDatabase($postsTable, 'ID');\n
    "},{"location":"modules/WPDb/#grablinkstablename","title":"grabLinksTableName","text":"

    Signature: grabLinksTableName() : string

    Returns the prefixed links table name.

    <?php\n// Given a `wp_` table prefix returns `wp_links`.\n$linksTable = $I->grabLinksTableName();\n// Given a `wp_` table prefix returns `wp_23_links`.\n$I->useBlog(23);\n$linksTable = $I->grabLinksTableName();\n
    "},{"location":"modules/WPDb/#grabnumrecords","title":"grabNumRecords","text":"

    Signature: grabNumRecords(string $table, [array $criteria]) : int

    Returns the number of rows in a database

    "},{"location":"modules/WPDb/#graboptionfromdatabase","title":"grabOptionFromDatabase","text":"

    Signature: grabOptionFromDatabase(string $option_name) : mixed

    Gets an option value from the database.

    <?php\n$count = $I->grabOptionFromDatabase('foo_count');\n
    "},{"location":"modules/WPDb/#grabpostfieldfromdatabase","title":"grabPostFieldFromDatabase","text":"

    Signature: grabPostFieldFromDatabase(int $postId, string $field) : mixed

    Returns the value of a post field for a post, from the posts table.

    <?php\n$title = $I->grabPostFieldFromDatabase(1, 'post_title');\n$type = $I->grabPostFieldFromDatabase(1, 'post_type');\n
    "},{"location":"modules/WPDb/#grabpostmetafromdatabase","title":"grabPostMetaFromDatabase","text":"

    Signature: grabPostMetaFromDatabase(int $postId, string $metaKey, [bool $single]) : mixed

    Gets the value of one or more post meta values from the database.

    <?php\n$thumbnail_id = $I->grabPostMetaFromDatabase($postId, '_thumbnail_id', true);\n
    "},{"location":"modules/WPDb/#grabpostmetatablename","title":"grabPostmetaTableName","text":"

    Signature: grabPostmetaTableName() : string

    Returns the prefixed post meta table name.

    <?php\n// Returns 'wp_postmeta'.\n$I->grabPostmetaTableName();\n// Returns 'wp_23_postmeta'.\n$I->useBlog(23);\n$I->grabPostmetaTableName();\n
    "},{"location":"modules/WPDb/#grabpoststablename","title":"grabPostsTableName","text":"

    Signature: grabPostsTableName() : string

    Gets the posts prefixed table name.

    <?php\n// Given a `wp_` table prefix returns `wp_posts`.\n$postsTable = $I->grabPostsTableName();\n// Given a `wp_` table prefix returns `wp_23_posts`.\n$I->useBlog(23);\n$postsTable = $I->grabPostsTableName();\n
    "},{"location":"modules/WPDb/#grabprefixedtablenamefor","title":"grabPrefixedTableNameFor","text":"

    Signature: grabPrefixedTableNameFor([string $tableName]) : string

    Returns a prefixed table name for the current blog.

    If the table is not one to be prefixed (e.g. users) then the proper table name will be returned.

    <?php\n// Will return wp_users.\n$usersTable = $I->grabPrefixedTableNameFor('users');\n// Will return wp_options.\n$optionsTable = $I->grabPrefixedTableNameFor('options');\n// Use a different blog and get its options table.\n$I->useBlog(2);\n$blogOptionsTable = $I->grabPrefixedTableNameFor('options');\n
    "},{"location":"modules/WPDb/#grabregistrationlogtablename","title":"grabRegistrationLogTableName","text":"

    Signature: grabRegistrationLogTableName() : string

    Gets the prefixed registration_log table name.

    <?php\n// Assuming a `wp_` table prefix it will return `wp_registration_log`.\n$blogVersionsTable = $I->grabRegistrationLogTableName();\n$I->useBlog(23);\n// Assuming a `wp_` table prefix it will return `wp_registration_log`.\n$blogVersionsTable = $I->grabRegistrationLogTableName();\n
    "},{"location":"modules/WPDb/#grabsignupstablename","title":"grabSignupsTableName","text":"

    Signature: grabSignupsTableName() : string

    Gets the prefixed signups table name.

    <?php\n// Assuming a `wp_` table prefix it will return `wp_signups`.\n$blogVersionsTable = $I->grabSignupsTableName();\n$I->useBlog(23);\n// Assuming a `wp_` table prefix it will return `wp_signups`.\n$blogVersionsTable = $I->grabSignupsTableName();\n
    "},{"location":"modules/WPDb/#grabsitemetafromdatabase","title":"grabSiteMetaFromDatabase","text":"

    Signature: grabSiteMetaFromDatabase(int $blogId, string $key, bool $single) : mixed

    Returns a single or all meta values for a site meta key.

    <?php\n$I->haveSiteMetaInDatabase(1, 'foo', 'bar');\n$value = $I->grabSiteMetaFromDatabase(1, 'foo', true);\n$values = $I->grabSiteMetaFromDatabase(1, 'foo', false);\n
    "},{"location":"modules/WPDb/#grabsitemetatablename","title":"grabSiteMetaTableName","text":"

    Signature: grabSiteMetaTableName() : string

    Gets the prefixed sitemeta table name.

    <?php\n// Assuming a `wp_` table prefix it will return `wp_sitemeta`.\n$blogVersionsTable = $I->grabSiteMetaTableName();\n$I->useBlog(23);\n// Assuming a `wp_` table prefix it will return `wp_sitemeta`.\n$blogVersionsTable = $I->grabSiteMetaTableName();\n
    "},{"location":"modules/WPDb/#grabsiteoptionfromdatabase","title":"grabSiteOptionFromDatabase","text":"

    Signature: grabSiteOptionFromDatabase(string $key) : mixed

    Gets a site option from the database.

    <?php\n$fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');\n
    "},{"location":"modules/WPDb/#grabsitetablename","title":"grabSiteTableName","text":"

    Signature: grabSiteTableName() : string

    Gets the prefixed site table name.

    <?php\n// Assuming a `wp_` table prefix it will return `wp_site`.\n$blogVersionsTable = $I->grabSiteTableName();\n$I->useBlog(23);\n// Assuming a `wp_` table prefix it will return `wp_site`.\n$blogVersionsTable = $I->grabSiteTableName();\n
    "},{"location":"modules/WPDb/#grabsitetransientfromdatabase","title":"grabSiteTransientFromDatabase","text":"

    Signature: grabSiteTransientFromDatabase(string $key) : mixed

    Gets a site transient from the database.

    <?php\n$I->grabSiteTransientFromDatabase('total_comments');\n$I->grabSiteTransientFromDatabase('api_data');\n
    "},{"location":"modules/WPDb/#grabsiteurl","title":"grabSiteUrl","text":"

    Signature: grabSiteUrl([?string $path]) : string

    Returns the current site URL as specified in the module configuration.

    <?php\n$shopPath = $I->grabSiteUrl('/shop');\n
    "},{"location":"modules/WPDb/#grabtableprefix","title":"grabTablePrefix","text":"

    Signature: grabTablePrefix() : string

    Returns the table prefix, namespaced for secondary blogs if selected.

    <?php\n// Assuming a table prefix of `wp_` it will return `wp_`;\n$tablePrefix = $I->grabTablePrefix();\n$I->useBlog(23);\n// Assuming a table prefix of `wp_` it will return `wp_23_`;\n$tablePrefix = $I->grabTablePrefix();\n
    "},{"location":"modules/WPDb/#grabtermidfromdatabase","title":"grabTermIdFromDatabase","text":"

    Signature: grabTermIdFromDatabase(array $criteria) : int|false

    Gets a term ID from the database. Looks up the prefixed terms table, e.g. wp_terms.

    <?php\n// Return the 'fiction' term 'term_id'.\n$termId = $I->grabTermIdFromDatabase(['name' => 'fiction']);\n// Get a term ID by more stringent criteria.\n$termId = $I->grabTermIdFromDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);\n// Return the 'term_id' of the first term for a group.\n$termId = $I->grabTermIdFromDatabase(['term_group' => 23]);\n
    "},{"location":"modules/WPDb/#grabtermmetatablename","title":"grabTermMetaTableName","text":"

    Signature: grabTermMetaTableName() : string

    Gets the terms meta table prefixed name.

    <?php\n// Returns 'wp_termmeta'.\n$I->grabTermMetaTableName();\n// Returns 'wp_23_termmeta'.\n$I->useBlog(23);\n$I->grabTermMetaTableName();\n
    "},{"location":"modules/WPDb/#grabtermrelationshipstablename","title":"grabTermRelationshipsTableName","text":"

    Signature: grabTermRelationshipsTableName() : string

    Gets the prefixed term relationships table name, e.g. wp_term_relationships.

    <?php\n$I->grabTermRelationshipsTableName();\n
    "},{"location":"modules/WPDb/#grabtermtaxonomyidfromdatabase","title":"grabTermTaxonomyIdFromDatabase","text":"

    Signature: grabTermTaxonomyIdFromDatabase(array $criteria) : int|false

    Gets a term_taxonomy_id from the database.

    Looks up the prefixed terms_relationships table, e.g. wp_term_relationships.

    <?php\n// Get the `term_taxonomy_id` for a term and a taxonomy.\n$I->grabTermTaxonomyIdFromDatabase(['term_id' => $fictionId, 'taxonomy' => 'genre']);\n// Get the `term_taxonomy_id` for the first term with a count of 23.\n$I->grabTermTaxonomyIdFromDatabase(['count' => 23]);\n
    "},{"location":"modules/WPDb/#grabtermtaxonomytablename","title":"grabTermTaxonomyTableName","text":"

    Signature: grabTermTaxonomyTableName() : string

    Gets the prefixed term and taxonomy table name, e.g. wp_term_taxonomy.

    <?php\n// Returns 'wp_term_taxonomy'.\n$I->grabTermTaxonomyTableName();\n// Returns 'wp_23_term_taxonomy'.\n$I->useBlog(23);\n$I->grabTermTaxonomyTableName();\n
    "},{"location":"modules/WPDb/#grabtermstablename","title":"grabTermsTableName","text":"

    Signature: grabTermsTableName() : string

    Gets the prefixed terms table name, e.g. wp_terms.

    <?php\n// Returns 'wp_terms'.\n$I->grabTermsTableName();\n// Returns 'wp_23_terms'.\n$I->useBlog(23);\n$I->grabTermsTableName();\n
    "},{"location":"modules/WPDb/#grabtransientfromdatabase","title":"grabTransientFromDatabase","text":"

    Signature: grabTransientFromDatabase(string $transient) : mixed

    Fetches the value of a transient from the database.

    <?php\n$I->haveTransientInDatabase('foo', 23);\n$transientValue = $I->grabTransientFromDatabase('foo');\n$I->assertEquals(23, $transientValue);\n
    "},{"location":"modules/WPDb/#grabuseridfromdatabase","title":"grabUserIdFromDatabase","text":"

    Signature: grabUserIdFromDatabase(string $userLogin) : int|false

    Gets the a user ID from the database using the user login.

    <?php\n$userId = $I->grabUserIdFromDatabase('luca');\n
    "},{"location":"modules/WPDb/#grabusermetafromdatabase","title":"grabUserMetaFromDatabase","text":"

    Signature: grabUserMetaFromDatabase(int $userId, string $meta_key, [bool $single]) : mixed

    Gets a user meta from the database.

    <?php\n// Returns a user 'karma' value.\n$I->grabUserMetaFromDatabase($userId, 'karma');\n// Returns an array, the unserialized version of the value stored in the database.\n$I->grabUserMetaFromDatabase($userId, 'api_data');\n
    "},{"location":"modules/WPDb/#grabusermetatablename","title":"grabUsermetaTableName","text":"

    Signature: grabUsermetaTableName() : string

    Returns the prefixed users meta table name.

    <?php\n// Given a `wp_` table prefix returns `wp_usermeta`.\n$usermetaTable = $I->grabUsermetaTableName();\n// Given a `wp_` table prefix returns `wp_usermeta`.\n$I->useBlog(23);\n$usermetaTable = $I->grabUsermetaTableName();\n
    "},{"location":"modules/WPDb/#grabuserstablename","title":"grabUsersTableName","text":"

    Signature: grabUsersTableName() : string

    Returns the prefixed users table name.

    <?php\n// Given a `wp_` table prefix returns `wp_users`.\n$usersTable = $I->grabUsersTableName();\n// Given a `wp_` table prefix returns `wp_users`.\n$I->useBlog(23);\n$usersTable = $I->grabUsersTableName();\n
    "},{"location":"modules/WPDb/#haveattachmentindatabase","title":"haveAttachmentInDatabase","text":"

    Signature: haveAttachmentInDatabase(string $file, [string|int $date], [array $overrides], [?array $imageSizes]) : int

    Creates the database entries representing an attachment and moves the attachment file to the right location.

    <?php\n$file = codecept_data_dir('images/test.png');\n$attachmentId = $I->haveAttachmentInDatabase($file);\n$image = codecept_data_dir('images/test-2.png');\n$lastWeekAttachment = $I->haveAttachmentInDatabase($image, '-1 week');\n

    Requires the WPFilesystem module.

    "},{"location":"modules/WPDb/#haveblogindatabase","title":"haveBlogInDatabase","text":"

    Signature: haveBlogInDatabase(string $domainOrPath, [array $overrides], [bool $subdomain]) : int

    Inserts a blog in the blogs table.

    <?php\n// Create the `test` subdomain blog.\n$blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId]);\n// Create the `/test` subfolder blog.\n$blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId], false);\n
    "},{"location":"modules/WPDb/#havecommentindatabase","title":"haveCommentInDatabase","text":"

    Signature: haveCommentInDatabase(int $comment_post_ID, [array $data]) : int

    Inserts a comment in the database.

    <?php\n$I->haveCommentInDatabase($postId, ['comment_content' => 'Test Comment', 'comment_karma' => 23]);\n
    "},{"location":"modules/WPDb/#havecommentmetaindatabase","title":"haveCommentMetaInDatabase","text":"

    Signature: haveCommentMetaInDatabase(int $comment_id, string $meta_key, mixed $meta_value) : int

    Inserts a comment meta field in the database. Array and object meta values will be serialized.

    <?php\n$I->haveCommentMetaInDatabase($commentId, 'api_ID', 23);\n// The value will be serialized.\n$apiData = ['ID' => 23, 'user' => 89, 'origin' => 'twitter'];\n$I->haveCommentMetaInDatabase($commentId, 'api_data', $apiData);\n
    "},{"location":"modules/WPDb/#haveindatabase","title":"haveInDatabase","text":"

    Signature: haveInDatabase(string $table, array $data) : int

    Inserts an SQL record into a database. This record will be erased after the test, unless you've configured \"skip_cleanup_if_failed\", and the test fails.

    <?php\n$I->haveInDatabase('users', array('name' => 'miles', 'email' => 'miles@davis.com'));\n
    "},{"location":"modules/WPDb/#havelinkindatabase","title":"haveLinkInDatabase","text":"

    Signature: haveLinkInDatabase([array $overrides]) : int

    Inserts a link in the database.

    <?php\n$linkId = $I->haveLinkInDatabase(['link_url' => 'http://example.org']);\n
    "},{"location":"modules/WPDb/#havemanyblogsindatabase","title":"haveManyBlogsInDatabase","text":"

    Signature: haveManyBlogsInDatabase(int $count, [array $overrides], [bool $subdomain]) : array

    Inserts many blogs in the database.

    <?php\n     $blogIds = $I->haveManyBlogsInDatabase(3, ['domain' =>'test-{{n}}']);\n     foreach($blogIds as $blogId){\n     $I->useBlog($blogId);\n     $I->haveManuPostsInDatabase(3);\n}\n
    "},{"location":"modules/WPDb/#havemanycommentsindatabase","title":"haveManyCommentsInDatabase","text":"

    Signature: haveManyCommentsInDatabase(int $count, int $comment_post_ID, [array $overrides]) : array

    Inserts many comments in the database.

    <?php\n// Insert 3 random comments for a post.\n$I->haveManyCommentsInDatabase(3, $postId);\n// Insert 3 random comments for a post.\n$I->haveManyCommentsInDatabase(3, $postId, ['comment_content' => 'Comment {{n}}']);\n
    "},{"location":"modules/WPDb/#havemanylinksindatabase","title":"haveManyLinksInDatabase","text":"

    Signature: haveManyLinksInDatabase(int $count, [array $overrides]) : array

    Inserts many links in the database links table.

    <?php\n// Insert 3 randomly generated links in the database.\n$linkIds = $I->haveManyLinksInDatabase(3);\n// Inserts links in the database replacing the `n` placeholder.\n$linkIds = $I->haveManyLinksInDatabase(3, ['link_url' => 'http://example.org/test-{{n}}']);\n
    "},{"location":"modules/WPDb/#havemanypostsindatabase","title":"haveManyPostsInDatabase","text":"

    Signature: haveManyPostsInDatabase(int $count, [array $overrides]) : array

    Inserts many posts in the database returning their IDs.

    <?php\n// Insert 3 random posts.\n$I->haveManyPostsInDatabase(3);\n// Insert 3 posts with generated titles.\n$I->haveManyPostsInDatabase(3, ['post_title' => 'Test post {{n}}']);\n
    "},{"location":"modules/WPDb/#havemanytermsindatabase","title":"haveManyTermsInDatabase","text":"

    Signature: haveManyTermsInDatabase(int $count, string $name, string $taxonomy, [array $overrides]) : array

    Inserts many terms in the database.

    <?php\n$terms = $I->haveManyTermsInDatabase(3, 'genre-{{n}}', 'genre');\n$termIds = array_column($terms, 0);\n$termTaxonomyIds = array_column($terms, 1);\n
    "},{"location":"modules/WPDb/#havemanyusersindatabase","title":"haveManyUsersInDatabase","text":"

    Signature: haveManyUsersInDatabase(int $count, string $user_login, [string $role], [array $overrides]) : array

    Inserts many users in the database.

    <?php\n$subscribers = $I->haveManyUsersInDatabase(5, 'user-{{n}}');\n$editors = $I->haveManyUsersInDatabase(\n     5,\n     'user-{{n}}',\n     'editor',\n     ['user_email' => 'user-{{n}}@example.org']\n);\n
    "},{"location":"modules/WPDb/#havemenuindatabase","title":"haveMenuInDatabase","text":"

    Signature: haveMenuInDatabase(string $slug, string $location, [array $overrides]) : array

    Creates and adds a menu to a theme location in the database.

    <?php\nlist($termId, $termTaxId) = $I->haveMenuInDatabase('test', 'sidebar');\n
    "},{"location":"modules/WPDb/#havemenuitemindatabase","title":"haveMenuItemInDatabase","text":"

    Signature: haveMenuItemInDatabase(string $menuSlug, string $title, [?int $menuOrder], [array $meta]) : int

    Adds a menu element to a menu for the current theme.

    <?php\n$I->haveMenuInDatabase('test', 'sidebar');\n$I->haveMenuItemInDatabase('test', 'Test one', 0);\n$I->haveMenuItemInDatabase('test', 'Test two', 1);\n
    "},{"location":"modules/WPDb/#haveoptionindatabase","title":"haveOptionInDatabase","text":"

    Signature: haveOptionInDatabase(string $option_name, mixed $option_value, [string $autoload]) : int

    Inserts an option in the database.

    <?php\n$I->haveOptionInDatabase('posts_per_page', 23);\n$I->haveOptionInDatabase('my_plugin_options', ['key_one' => 'value_one', 'key_two' => 89]);\n

    If the option value is an object or an array then the value will be serialized.

    "},{"location":"modules/WPDb/#havepageindatabase","title":"havePageInDatabase","text":"

    Signature: havePageInDatabase([array $overrides]) : int

    Inserts a page in the database.

    <?php\n// Creates a test page in the database with random values.\n$randomPageId = $I->havePageInDatabase();\n// Creates a test page in the database defining its title.\n$testPageId = $I->havePageInDatabase(['post_title' => 'Test page']);\n
    "},{"location":"modules/WPDb/#havepostindatabase","title":"havePostInDatabase","text":"

    Signature: havePostInDatabase([array $data]) : int

    Inserts a post in the database.

    <?php\n// Insert a post with random values in the database.\n$randomPostId = $I->havePostInDatabase();\n// Insert a post with specific values in the database.\n$I->havePostInDatabase([\n'post_type' => 'book',\n'post_title' => 'Alice in Wonderland',\n'meta_input' => [\n'readers_count' => 23\n],\n'tax_input' => [\n['genre' => 'fiction']\n]\n]);\n
    "},{"location":"modules/WPDb/#havepostthumbnailindatabase","title":"havePostThumbnailInDatabase","text":"

    Signature: havePostThumbnailInDatabase(int $postId, int $thumbnailId) : int

    Assigns the specified attachment ID as thumbnail (featured image) to a post.

    <?php\n$attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));\n$postId = $I->havePostInDatabase();\n$I->havePostThumbnailInDatabase($postId, $attachmentId);\n
    "},{"location":"modules/WPDb/#havepostmetaindatabase","title":"havePostmetaInDatabase","text":"

    Signature: havePostmetaInDatabase(int $postId, string $meta_key, mixed $meta_value) : int

    Adds one or more meta key and value couples in the database for a post.

    <?php\n// Set the post-meta for a post.\n$I->havePostmetaInDatabase($postId, 'karma', 23);\n// Set an array post-meta for a post, it will be serialized in the db.\n$I->havePostmetaInDatabase($postId, 'data', ['one', 'two']);\n// Use a loop to insert one meta per row.\nforeach( ['one', 'two'] as $value){\n     $I->havePostmetaInDatabase($postId, 'data', $value);\n}\n
    "},{"location":"modules/WPDb/#havesitemetaindatabase","title":"haveSiteMetaInDatabase","text":"

    Signature: haveSiteMetaInDatabase(int $blogId, string $string, mixed $value) : int

    Adds a meta key and value for a site in the database.

    <?php\n$I->haveSiteMetaInDatabase(1, 'foo', 'bar');\n$insertedId = $I->haveSiteMetaInDatabase(2, 'foo', ['bar' => 'baz']);\n
    "},{"location":"modules/WPDb/#havesiteoptionindatabase","title":"haveSiteOptionInDatabase","text":"

    Signature: haveSiteOptionInDatabase(string $key, mixed $value) : int

    Inserts a site option in the database.

    If the value is an array or an object then the value will be serialized.

    <?php\n$fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');\n
    "},{"location":"modules/WPDb/#havesitetransientindatabase","title":"haveSiteTransientInDatabase","text":"

    Signature: haveSiteTransientInDatabase(string $key, mixed $value) : int

    Inserts a site transient in the database. If the value is an array or an object then the value will be serialized.

    <?php\n$I->haveSiteTransientInDatabase('total_comments_count', 23);\n// This value will be serialized.\n$I->haveSiteTransientInDatabase('api_data', ['user' => 'luca', 'token' => '11ae3ijns-j83']);\n
    "},{"location":"modules/WPDb/#havetermindatabase","title":"haveTermInDatabase","text":"

    Signature: haveTermInDatabase(string $name, string $taxonomy, [array $overrides]) : array

    Inserts a term in the database.

    <?php\n// Insert a random 'genre' term in the database.\n$I->haveTermInDatabase('non-fiction', 'genre');\n// Insert a term in the database with term meta.\n$I->haveTermInDatabase('fiction', 'genre', [\n     'slug' => 'genre--fiction',\n     'meta' => [\n        'readers_count' => 23\n     ]\n]);\n
    "},{"location":"modules/WPDb/#havetermmetaindatabase","title":"haveTermMetaInDatabase","text":"

    Signature: haveTermMetaInDatabase(int $term_id, string $meta_key, mixed $meta_value) : int

    Inserts a term meta row in the database. Objects and array meta values will be serialized.

    <?php\n$I->haveTermMetaInDatabase($fictionId, 'readers_count', 23);\n// Insert some meta that will be serialized.\n$I->haveTermMetaInDatabase($fictionId, 'flags', [3, 4, 89]);\n// Use a loop to insert one meta per row.\nforeach([3, 4, 89] as $value) {\n     $I->haveTermMetaInDatabase($fictionId, 'flag', $value);\n}\n
    "},{"location":"modules/WPDb/#havetermrelationshipindatabase","title":"haveTermRelationshipInDatabase","text":"

    Signature: haveTermRelationshipInDatabase(int $object_id, int $term_taxonomy_id, [int $term_order]) : void

    Creates a term relationship in the database.

    No check about the consistency of the insertion is made. E.g. a post could be assigned a term from a taxonomy that's not registered for that post type.

    <?php\n// Assign the `fiction` term to a book.\n$I->haveTermRelationshipInDatabase($bookId, $fictionId);\n
    "},{"location":"modules/WPDb/#havetransientindatabase","title":"haveTransientInDatabase","text":"

    Signature: haveTransientInDatabase(string $transient, mixed $value) : int

    Inserts a transient in the database.

    If the value is an array or an object then the value will be serialized. Since the transients are set in the context of tests it's not possible to set an expiration directly.

    <?php\n// Store an array in the `tweets` transient.\n$I->haveTransientInDatabase('tweets', $tweets);\n
    "},{"location":"modules/WPDb/#haveusercapabilitiesindatabase","title":"haveUserCapabilitiesInDatabase","text":"

    Signature: haveUserCapabilitiesInDatabase(int $userId, array|string $role) : array

    Sets a user capabilities in the database.

    <?php\n// Assign one user a role in a blog.\n$blogId = $I->haveBlogInDatabase('test');\n$editor = $I->haveUserInDatabase('luca', 'editor');\n$capsIds = $I->haveUserCapabilitiesInDatabase($editor, [$blogId => 'editor']);\n\n// Assign a user two roles in blog 1.\n$capsIds = $I->haveUserCapabilitiesInDatabase($userId, ['editor', 'subscriber']);\n\n// Assign one user different roles in different blogs.\n$capsIds = $I->haveUserCapabilitiesInDatabase($userId, [$blogId1 => 'editor', $blogId2 => 'author']);\n\n// Assign a user a role and an additional capability in blog 1.\n$I->haveUserCapabilitiesInDatabase($userId, ['editor' => true, 'edit_themes' => true]);\n\n// Assign a user a mix of roles and capabilities in different blogs.\n$capsIds = $I->haveUserCapabilitiesInDatabase(\n     $userId,\n     [\n         $blogId1 => ['editor' => true, 'edit_themes' => true],\n         $blogId2 => ['administrator' => true, 'edit_themes' => false]\n     ]\n);\n
    "},{"location":"modules/WPDb/#haveuserindatabase","title":"haveUserInDatabase","text":"

    Signature: haveUserInDatabase(string $user_login, [array|string $role], [array $overrides]) : int

    Inserts a user and its meta in the database.

    <?php\n// Create an editor user in blog 1 w/ specific email.\n$userId = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);\n\n// Create a subscriber user in blog 1.\n$subscriberId = $I->haveUserInDatabase('subscriber');\n\n// Create a user editor in blog 1, author in blog 2, administrator in blog 3.\n$userWithMeta = $I->haveUserInDatabase('luca',\n     [\n         1 => 'editor',\n         2 => 'author',\n         3 => 'administrator'\n     ], [\n         'user_email' => 'luca@example.org'\n         'meta' => ['a meta_key' => 'a_meta_value']\n     ]\n);\n\n// Create editor in blog 1 w/ `edit_themes` cap, author in blog 2, admin in blog 3 w/o `manage_options` cap.\n$userWithMeta = $I->haveUserInDatabase('luca',\n     [\n         1 => ['editor', 'edit_themes'],\n         2 => 'author',\n         3 => ['administrator' => true, 'manage_options' => false]\n     ]\n);\n\n// Create a user w/o role.\n$userId = $I->haveUserInDatabase('luca', '');\n
    "},{"location":"modules/WPDb/#haveuserlevelsindatabase","title":"haveUserLevelsInDatabase","text":"

    Signature: haveUserLevelsInDatabase(int $userId, array|string $role) : array

    Sets the user access level meta in the database for a user.

    <?php\n$userId = $I->haveUserInDatabase('luca', 'editor');\n$moreThanAnEditorLessThanAnAdmin = 8;\n$I->haveUserLevelsInDatabase($userId, $moreThanAnEditorLessThanAnAdmin);\n
    "},{"location":"modules/WPDb/#haveusermetaindatabase","title":"haveUserMetaInDatabase","text":"

    Signature: haveUserMetaInDatabase(int $userId, string $meta_key, mixed $meta_value) : array

    Sets a user meta in the database.

    <?php\n$userId = $I->haveUserInDatabase('luca', 'editor');\n$I->haveUserMetaInDatabase($userId, 'karma', 23);\n
    "},{"location":"modules/WPDb/#importsql","title":"importSql","text":"

    Signature: importSql(array $sql) : void

    Loads a set SQL code lines in the current database.

    <?php\n// Import a SQL string.\n$I->importSql([$sqlString]);\n// Import a set of SQL strings.\n$I->importSql($sqlStrings);\n// Import a prepared set of SQL strings.\n$preparedSqlStrings = array_map(function($line){\n    return str_replace('{{date}}', date('Y-m-d H:i:s'), $line);\n}, $sqlTemplate);\n$I->importSql($preparedSqlStrings);\n
    "},{"location":"modules/WPDb/#importsqldumpfile","title":"importSqlDumpFile","text":"

    Signature: importSqlDumpFile([?string $dumpFile]) : void

    Import the SQL dump file if populate is enabled.

    <?php\n// Import a dump file passing the absolute path.\n$I->importSqlDumpFile(codecept_data_dir('dumps/start.sql'));\n

    Specifying a dump file that file will be imported.

    "},{"location":"modules/WPDb/#performindatabase","title":"performInDatabase","text":"

    Signature: performInDatabase($databaseKey, $actions) : void

    Can be used with a callback if you don't want to change the current database in your test.

    <?php\n$I->seeNumRecords(2, 'users');   //executed on default database\n$I->performInDatabase('db_books', function($I) {\n    $I->seeNumRecords(30, 'books');  //executed on db_books database\n});\n$I->seeNumRecords(2, 'users');  //executed on default database\n
    List of actions can be pragmatically built using Codeception\\Util\\ActionSequence:

    <?php\n$I->performInDatabase('db_books', ActionSequence::build()\n    ->seeNumRecords(30, 'books')\n);\n
    Alternatively an array can be used:

    <?php\n$I->performInDatabase('db_books', ['seeNumRecords' => [30, 'books']]);\n

    Choose the syntax you like the most and use it,

    Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to exception on failure.

    "},{"location":"modules/WPDb/#seeattachmentindatabase","title":"seeAttachmentInDatabase","text":"

    Signature: seeAttachmentInDatabase(array $criteria) : void

    Checks for an attachment in the database.

    <?php\n$url = 'https://example.org/images/foo.png';\n$I->seeAttachmentInDatabase(['guid' => $url]);\n
    "},{"location":"modules/WPDb/#seeblogindatabase","title":"seeBlogInDatabase","text":"

    Signature: seeBlogInDatabase(array $criteria) : void

    Checks for a blog in the blogs table.

    <?php\n// Search for a blog by `blog_id`.\n$I->seeBlogInDatabase(['blog_id' => 23]);\n// Search for all blogs on a path.\n$I->seeBlogInDatabase(['path' => '/sub-path/']);\n
    "},{"location":"modules/WPDb/#seecommentindatabase","title":"seeCommentInDatabase","text":"

    Signature: seeCommentInDatabase(array $criteria) : void

    Checks for a comment in the database.

    Will look up the \"comments\" table.

    <?php\n$I->seeCommentInDatabase(['comment_ID' => 23]);\n
    "},{"location":"modules/WPDb/#seecommentmetaindatabase","title":"seeCommentMetaInDatabase","text":"

    Signature: seeCommentMetaInDatabase(array $criteria) : void

    Checks that a comment meta value is in the database. Will look up the \"commentmeta\" table.

    <?php\n// Assert a specified meta for a comment exists.\n$I->seeCommentMetaInDatabase(['comment_ID' => $commentId, 'meta_key' => 'karma', 'meta_value' => 23]);\n// Assert the comment has at least one meta set.\n$I->seeCommentMetaInDatabase(['comment_ID' => $commentId]);\n
    "},{"location":"modules/WPDb/#seeindatabase","title":"seeInDatabase","text":"

    Signature: seeInDatabase(string $table, [array $criteria]) : void

    "},{"location":"modules/WPDb/#seelinkindatabase","title":"seeLinkInDatabase","text":"

    Signature: seeLinkInDatabase(array $criteria) : void

    Checks for a link in the links table of the database.

    <?php\n// Asserts a link exists by name.\n$I->seeLinkInDatabase(['link_name' => 'my-link']);\n// Asserts at least one link exists for the user.\n$I->seeLinkInDatabase(['link_owner' => $userId]);\n
    "},{"location":"modules/WPDb/#seenumrecords","title":"seeNumRecords","text":"

    Signature: seeNumRecords(int $expectedNumber, string $table, [array $criteria]) : void

    Asserts that the given number of records were found in the database.

    <?php\n$I->seeNumRecords(1, 'users', ['name' => 'davert'])\n
    "},{"location":"modules/WPDb/#seeoptionindatabase","title":"seeOptionInDatabase","text":"

    Signature: seeOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    Checks if an option is in the database for the current blog, either by criteria or by name and value.

    If checking for an array or an object then the serialized version will be checked for.

    <?php\n// Checks an option is in the database.\n$I->seeOptionInDatabase('tables_version');\n// Checks an option is in the database and has a specific value.\n$I->seeOptionInDatabase('tables_version', '1.0');\n$I->seeOptionInDatabase(['option_name' => 'tables_version', 'option_value' => 1.0']);\n
    "},{"location":"modules/WPDb/#seepageindatabase","title":"seePageInDatabase","text":"

    Signature: seePageInDatabase(array $criteria) : void

    Checks for a page in the database.

    <?php\n// Asserts a page with an exists in the database.\n$I->seePageInDatabase(['ID' => 23]);\n// Asserts a page with a slug and ID exists in the database.\n$I->seePageInDatabase(['post_title' => 'Test Page', 'ID' => 23]);\n
    "},{"location":"modules/WPDb/#seepostindatabase","title":"seePostInDatabase","text":"

    Signature: seePostInDatabase(array $criteria) : void

    Checks for a post in the database.

    <?php\n// Assert a post exists in the database.\n$I->seePostInDatabase(['ID' => 23]);\n// Assert a post with a slug and ID exists in the database.\n$I->seePostInDatabase(['post_content' => 'test content', 'ID' => 23]);\n
    "},{"location":"modules/WPDb/#seepostmetaindatabase","title":"seePostMetaInDatabase","text":"

    Signature: seePostMetaInDatabase(array $criteria) : void

    Checks for a post meta value in the database for the current blog.

    If the meta_value is an object or an array then the check will be made for serialized values.

    <?php\n$postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']];\n$I->seePostMetaInDatabase(['post_id' => '$postId', 'meta_key' => 'foo']);\n
    "},{"location":"modules/WPDb/#seepostwithtermindatabase","title":"seePostWithTermInDatabase","text":"

    Signature: seePostWithTermInDatabase(int $post_id, int $term_taxonomy_id, [?int $term_order], [?string $taxonomy]) : void

    Checks that a post to term relation exists in the database.

    The method will check the \"term_relationships\" table.

    <?php\n$fiction = $I->haveTermInDatabase('fiction', 'genre');\n$postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);\n$I->seePostWithTermInDatabase($postId, $fiction['term_taxonomy_id']);\n
    "},{"location":"modules/WPDb/#seesiteoptionindatabase","title":"seeSiteOptionInDatabase","text":"

    Signature: seeSiteOptionInDatabase(array|string $criteriaOrName, [mixed $value]) : void

    Checks that a site option is in the database.

    <?php\n// Check that the option is set in the database.\n$I->seeSiteOptionInDatabase('foo_count');\n// Check that the option is set and has a specific value.\n$I->seeSiteOptionInDatabase('foo_count', 23);\n
    "},{"location":"modules/WPDb/#seesitesitetransientindatabase","title":"seeSiteSiteTransientInDatabase","text":"

    Signature: seeSiteSiteTransientInDatabase(string $key, [mixed $value]) : void

    Checks that a site option is in the database.

    <?php\n// Check a transient exists.\n$I->seeSiteSiteTransientInDatabase('total_counts');\n// Check a transient exists and has a specific value.\n$I->seeSiteSiteTransientInDatabase('total_counts', 23);\n
    "},{"location":"modules/WPDb/#seesitetransientindatabase","title":"seeSiteTransientInDatabase","text":"

    Signature: seeSiteTransientInDatabase(string $transient, [mixed $value]) : void

    Checks that a site transient is in the database.

    <?php\n$I->haveSiteTransientInDatabase('foo', 23);\n$I->seeSiteTransientInDatabase('foo');\n$I->seeSiteTransientInDatabase('foo', 23);\n
    "},{"location":"modules/WPDb/#seetableindatabase","title":"seeTableInDatabase","text":"

    Signature: seeTableInDatabase(string $table) : void

    Checks that a table is in the database.

    <?php\n$options = $I->grabPrefixedTableNameFor('options');\n$I->seeTableInDatabase($options);\n
    "},{"location":"modules/WPDb/#seetermindatabase","title":"seeTermInDatabase","text":"

    Signature: seeTermInDatabase(array $criteria) : void

    Checks for a term in the database. Looks up the terms and term_taxonomy prefixed tables.

    <?php\n$I->seeTermInDatabase(['slug' => 'genre--fiction']);\n$I->seeTermInDatabase(['name' => 'Fiction', 'slug' => 'genre--fiction']);\n
    "},{"location":"modules/WPDb/#seetermmetaindatabase","title":"seeTermMetaInDatabase","text":"

    Signature: seeTermMetaInDatabase(array $criteria) : void

    Checks for a term meta in the database.

    <?php\nlist($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n$I->haveTermMetaInDatabase($termId, 'rating', 4);\n$I->seeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'rating', 'meta_value' => 4]);\n
    "},{"location":"modules/WPDb/#seetermrelationshipindatabase","title":"seeTermRelationshipInDatabase","text":"

    Signature: seeTermRelationshipInDatabase(array $criteria) : void

    Checks for a term relationship in the database.

    <?php\n$postId = $I->havePostInDatabase(['tax_input' => ['category' => 'one']]);\n$I->seeTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $oneTermTaxId]);\n
    "},{"location":"modules/WPDb/#seetermtaxonomyindatabase","title":"seeTermTaxonomyInDatabase","text":"

    Signature: seeTermTaxonomyInDatabase(array $criteria) : void

    Checks for a taxonomy taxonomy in the database.

    <?php\nlist($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n$I->seeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'genre']);\n
    "},{"location":"modules/WPDb/#seetransientindatabase","title":"seeTransientInDatabase","text":"

    Signature: seeTransientInDatabase(string $name, [mixed $value]) : void

    Checks that a transient is in the database.

    <?php\n$I->haveTransientInDatabase('foo', 23);\n$I->seeTransientInDatabase('foo');\n$I->seeTransientInDatabase('foo', 23);\n
    "},{"location":"modules/WPDb/#seeuserindatabase","title":"seeUserInDatabase","text":"

    Signature: seeUserInDatabase(array $criteria) : void

    Checks that a user is in the database.

    The method will check the \"users\" table.

    <?php\n$I->seeUserInDatabase([\n    \"user_email\" => \"test@example.org\",\n    \"user_login\" => \"login name\"\n])\n
    "},{"location":"modules/WPDb/#seeusermetaindatabase","title":"seeUserMetaInDatabase","text":"

    Signature: seeUserMetaInDatabase(array $criteria) : void

    Checks for a user meta value in the database.

    <?php\n$I->seeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);\n
    "},{"location":"modules/WPDb/#updateindatabase","title":"updateInDatabase","text":"

    Signature: updateInDatabase(string $table, array $data, [array $criteria]) : void

    Update an SQL record into a database.

    <?php\n$I->updateInDatabase('users', array('isAdmin' => true), array('email' => 'miles@davis.com'));\n
    "},{"location":"modules/WPDb/#useblog","title":"useBlog","text":"

    Signature: useBlog([int $blogId]) : void

    Sets the blog to be used.

    This has nothing to do with WordPress switch_to_blog function, this code will affect the table prefixes used.

    "},{"location":"modules/WPDb/#usemainblog","title":"useMainBlog","text":"

    Signature: useMainBlog() : void

    Sets the current blog to the main one (blog_id 1).

    <?php\n// Switch to the blog with ID 23.\n$I->useBlog(23);\n// Switch back to the main blog.\n$I->useMainBlog();\n
    "},{"location":"modules/WPDb/#usetheme","title":"useTheme","text":"

    Signature: useTheme(string $stylesheet, [?string $template], [?string $themeName]) : void

    Sets the current theme options.

    <?php\n$I->useTheme('twentyseventeen');\n$I->useTheme('child-of-twentyseventeen', 'twentyseventeen');\n$I->useTheme('acme', 'acme', 'Acme Theme');\n

    Read more in Codeception documentation for the Db module.

    "},{"location":"modules/WPFilesystem/","title":"WPFilesystem","text":""},{"location":"modules/WPFilesystem/#wpfilesystem-module","title":"WPFilesystem module","text":"

    Interact and make assertions on the WordPress file structure.

    This module is used together with the WPDb module to manage the state of the WordPress installation in the context of end-to-end tests.

    This module extends the Filesystem module from Codeception, you can reference to the Codeception documentation to find out more about the module configuration and usage.

    This module should be with Cest and Cept test cases.

    "},{"location":"modules/WPFilesystem/#configuration","title":"Configuration","text":"

    wpRootFolder - required; the path to the WordPress installation root folder. This can be a relative path to the codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation directory is the directory that contains the wp-load.php file. themes - the path, relative to the path specified in the wpRootFolder parameter, to the themes directory. By default, it's /wp-content/themes. plugins - the path, relative to the path specified in the wpRootFolder parameter, to the plugins directory. By default, it's /wp-content/plugins. mu-plugins - the path, relative to the path specified in the wpRootFolder parameter, to the must-use plugins. By default, it's /wp-content/mu-plugins. directory. uploads - the path, relative to the path specified in the wpRootFolder parameter, to the uploads directory. By default, it's /wp-content/uploads.

    The following is an example of the module configuration to run tests on the /var/wordpress site:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPFilesystem:\n      wpRootFolder: /var/wordpress\n      themes: wp-content/themes\n      plugins: wp-content/plugins\n      mu-plugins: wp-content/mu-plugins\n      uploads: wp-content/uploads\n

    The following configuration uses dynamic configuration parameters to set the module configuration:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPFilesystem:\n      wpRootFolder: '%WP_ROOT_FOLDER%'\n
    "},{"location":"modules/WPFilesystem/#methods","title":"Methods","text":"

    The module provides the following methods:

    "},{"location":"modules/WPFilesystem/#aminmupluginpath","title":"amInMuPluginPath","text":"

    Signature: amInMuPluginPath(string $path) : void

    Sets the current working folder to a folder in a mu-plugin.

    $I->amInMuPluginPath('mu-plugin');\n
    "},{"location":"modules/WPFilesystem/#aminpath","title":"amInPath","text":"

    Signature: amInPath(string $path) : void

    Enters a directory In local filesystem. Project root directory is used by default

    "},{"location":"modules/WPFilesystem/#aminpluginpath","title":"amInPluginPath","text":"

    Signature: amInPluginPath(string $path) : void

    Sets the current working folder to a folder in a plugin.

    $I->amInPluginPath('my-plugin');\n
    "},{"location":"modules/WPFilesystem/#aminthemepath","title":"amInThemePath","text":"

    Signature: amInThemePath(string $path) : void

    Sets the current working folder to a folder in a theme.

    $I->amInThemePath('my-theme');\n
    "},{"location":"modules/WPFilesystem/#aminuploadspath","title":"amInUploadsPath","text":"

    Signature: amInUploadsPath([?string $path]) : void

    Enters, changing directory, to the uploads folder in the local filesystem.

    <?php\n$I->amInUploadsPath('/logs');\n$I->seeFileFound('shop.log');\n
    "},{"location":"modules/WPFilesystem/#assertdirectoryexists","title":"assertDirectoryExists","text":"

    Signature: assertDirectoryExists(string $directory, [string $message]) : void

    "},{"location":"modules/WPFilesystem/#cleandir","title":"cleanDir","text":"

    Signature: cleanDir(string $dirname) : void

    Erases directory contents

    <?php\n$I->cleanDir('logs');\n
    "},{"location":"modules/WPFilesystem/#cleanmuplugindir","title":"cleanMuPluginDir","text":"

    Signature: cleanMuPluginDir(string $dir) : void

    Cleans, emptying it, a folder in a mu-plugin folder.

    $I->cleanMuPluginDir('mu-plugin1/foo');\n
    "},{"location":"modules/WPFilesystem/#cleanplugindir","title":"cleanPluginDir","text":"

    Signature: cleanPluginDir(string $dir) : void

    Cleans, emptying it, a folder in a plugin folder.

    $I->cleanPluginDir('my-plugin/foo');\n
    "},{"location":"modules/WPFilesystem/#cleanthemedir","title":"cleanThemeDir","text":"

    Signature: cleanThemeDir(string $dir) : void

    Clears, emptying it, a folder in a theme folder.

    $I->cleanThemeDir('my-theme/foo');\n
    "},{"location":"modules/WPFilesystem/#cleanuploadsdir","title":"cleanUploadsDir","text":"

    Signature: cleanUploadsDir([?string $dir], [DateTime|string|int|null $date]) : void

    Clears a folder in the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->cleanUploadsDir('some/folder');\n$I->cleanUploadsDir('some/folder', 'today');\n
    "},{"location":"modules/WPFilesystem/#copydir","title":"copyDir","text":"

    Signature: copyDir(string $src, string $dst) : void

    Copies directory with all contents

    <?php\n$I->copyDir('vendor','old_vendor');\n
    "},{"location":"modules/WPFilesystem/#copydirtomuplugin","title":"copyDirToMuPlugin","text":"

    Signature: copyDirToMuPlugin(string $src, string $pluginDst) : void

    Copies a folder to a folder in a mu-plugin.

    $I->copyDirToMuPlugin(codecept_data_dir('foo'), 'mu-plugin/foo');\n
    "},{"location":"modules/WPFilesystem/#copydirtoplugin","title":"copyDirToPlugin","text":"

    Signature: copyDirToPlugin(string $src, string $pluginDst) : void

    Copies a folder to a folder in a plugin.

    // Copy the 'foo' folder to the 'foo' folder in the plugin.\n$I->copyDirToPlugin(codecept_data_dir('foo'), 'my-plugin/foo');\n
    "},{"location":"modules/WPFilesystem/#copydirtotheme","title":"copyDirToTheme","text":"

    Signature: copyDirToTheme(string $src, string $themeDst) : void

    Copies a folder in a theme folder.

    $I->copyDirToTheme(codecept_data_dir('foo'), 'my-theme');\n
    "},{"location":"modules/WPFilesystem/#copydirtouploads","title":"copyDirToUploads","text":"

    Signature: copyDirToUploads(string $src, string $dst, [DateTime|string|int|null $date]) : void

    Copies a folder to the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo');\n$I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo', 'today');\n
    "},{"location":"modules/WPFilesystem/#deletedir","title":"deleteDir","text":"

    Signature: deleteDir(string $dirname) : void

    Deletes directory with all subdirectories

    <?php\n$I->deleteDir('vendor');\n
    "},{"location":"modules/WPFilesystem/#deletefile","title":"deleteFile","text":"

    Signature: deleteFile(string $filename) : void

    Deletes a file

    <?php\n$I->deleteFile('composer.lock');\n
    "},{"location":"modules/WPFilesystem/#deletemupluginfile","title":"deleteMuPluginFile","text":"

    Signature: deleteMuPluginFile(string $file) : void

    Deletes a file in a mu-plugin folder.

    $I->deleteMuPluginFile('mu-plugin1/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#deletepluginfile","title":"deletePluginFile","text":"

    Signature: deletePluginFile(string $file) : void

    Deletes a file in a plugin folder.

    $I->deletePluginFile('my-plugin/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#deletethemefile","title":"deleteThemeFile","text":"

    Signature: deleteThemeFile(string $file) : void

    Deletes a file in a theme folder.

    $I->deleteThemeFile('my-theme/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#deletethisfile","title":"deleteThisFile","text":"

    Signature: deleteThisFile() : void

    Deletes a file

    "},{"location":"modules/WPFilesystem/#deleteuploadeddir","title":"deleteUploadedDir","text":"

    Signature: deleteUploadedDir(string $dir, [DateTime|string|int|null $date]) : void

    Deletes a dir in the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->deleteUploadedDir('folder');\n$I->deleteUploadedDir('folder', 'today');\n
    "},{"location":"modules/WPFilesystem/#deleteuploadedfile","title":"deleteUploadedFile","text":"

    Signature: deleteUploadedFile(string $file, [string|int|null $date]) : void

    Deletes a file in the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->deleteUploadedFile('some-file.txt');\n$I->deleteUploadedFile('some-file.txt', 'today');\n
    "},{"location":"modules/WPFilesystem/#dontseefilefound","title":"dontSeeFileFound","text":"

    Signature: dontSeeFileFound(string $filename, [string $path]) : void

    Checks if file does not exist in path

    "},{"location":"modules/WPFilesystem/#dontseeinmupluginfile","title":"dontSeeInMuPluginFile","text":"

    Signature: dontSeeInMuPluginFile(string $file, string $contents) : void

    Checks that a file in a mu-plugin folder does not contain a string.

    $I->dontSeeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#dontseeinpluginfile","title":"dontSeeInPluginFile","text":"

    Signature: dontSeeInPluginFile(string $file, string $contents) : void

    Checks that a file in a plugin folder does not contain a string.

    $I->dontSeeInPluginFile('my-plugin/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#dontseeinthemefile","title":"dontSeeInThemeFile","text":"

    Signature: dontSeeInThemeFile(string $file, string $contents) : void

    Checks that a file in a theme folder does not contain a string.

    $I->dontSeeInThemeFile('my-theme/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#dontseeinthisfile","title":"dontSeeInThisFile","text":"

    Signature: dontSeeInThisFile(string $text) : void

    Checks If opened file doesn't contain text in it

    <?php\n$I->openFile('composer.json');\n$I->dontSeeInThisFile('codeception/codeception');\n
    "},{"location":"modules/WPFilesystem/#dontseeinuploadedfile","title":"dontSeeInUploadedFile","text":"

    Signature: dontSeeInUploadedFile(string $file, string $contents, [string|int|null $date]) : void

    Checks that a file in the uploads folder does contain a string.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    <?php\n$I->dontSeeInUploadedFile('some-file.txt', 'foo');\n$I->dontSeeInUploadedFile('some-file.txt','foo', 'today');\n
    "},{"location":"modules/WPFilesystem/#dontseemupluginfilefound","title":"dontSeeMuPluginFileFound","text":"

    Signature: dontSeeMuPluginFileFound(string $file) : void

    Checks that a file is not found in a mu-plugin folder.

    $I->dontSeeMuPluginFileFound('mu-plugin1/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#dontseepluginfilefound","title":"dontSeePluginFileFound","text":"

    Signature: dontSeePluginFileFound(string $file) : void

    Checks that a file is not found in a plugin folder.

    $I->dontSeePluginFileFound('my-plugin/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#dontseethemefilefound","title":"dontSeeThemeFileFound","text":"

    Signature: dontSeeThemeFileFound(string $file) : void

    Checks that a file is not found in a theme folder.

    $I->dontSeeThemeFileFound('my-theme/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#dontseeuploadedfilefound","title":"dontSeeUploadedFileFound","text":"

    Signature: dontSeeUploadedFileFound(string $file, [string|int|null $date]) : void

    Checks thata a file does not exist in the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->dontSeeUploadedFileFound('some-file.txt');\n$I->dontSeeUploadedFileFound('some-file.txt','today');\n
    "},{"location":"modules/WPFilesystem/#getbloguploadspath","title":"getBlogUploadsPath","text":"

    Signature: getBlogUploadsPath(int $blogId, [string $file], [DateTimeImmutable|DateTime|string|null $date]) : string

    Returns the absolute path to a blog uploads folder or file.

    <?php\n$blogId = $I->haveBlogInDatabase('test');\n$testTodayUploads = $I->getBlogUploadsPath($blogId);\n$testLastMonthLogs = $I->getBlogUploadsPath($blogId, '/logs', '-1 month');\n
    "},{"location":"modules/WPFilesystem/#getuploadspath","title":"getUploadsPath","text":"

    Signature: getUploadsPath([string $file], [mixed $date]) : string

    Returns the path to the specified uploads file of folder.

    Not providing a value for $file and $date will return the uploads folder path.

    <?php\n$todaysPath = $I->getUploadsPath();\n$lastWeek = $I->getUploadsPath('', '-1 week');\n
    "},{"location":"modules/WPFilesystem/#getwprootfolder","title":"getWpRootFolder","text":"

    Signature: getWpRootFolder() : string

    Returns the absolute path to WordPress root folder without trailing slash.

    <?php\n$rootFolder = $I->getWpRootFolder();\n$I->assertFileExists($rootFolder . 'wp-load.php');\n
    "},{"location":"modules/WPFilesystem/#havemuplugin","title":"haveMuPlugin","text":"

    Signature: haveMuPlugin(string $filename, string $code) : void

    Creates a mu-plugin file, including plugin header, in the mu-plugins folder.

    The code can not contain the opening '<?php' tag.

    $code = 'echo \"Hello world!\"';\n$I->haveMuPlugin('foo-mu-plugin.php', $code);\n// Load the code from a file.\n$code = file_get_contents(codecept_data_dir('code/mu-plugin.php'));\n$I->haveMuPlugin('foo-mu-plugin.php', $code);\n
    "},{"location":"modules/WPFilesystem/#haveplugin","title":"havePlugin","text":"

    Signature: havePlugin(string $path, string $code) : void

    Creates a plugin file, including plugin header, in the plugins folder.

    The plugin is just created and not activated; the code can not contain the opening '<?php' tag.

    $code = 'echo \"Hello world!\"';\n$I->havePlugin('foo/plugin.php', $code);\n// Load the code from a file.\n$code = file_get_contents(codecept_data_dir('code/plugin.php'));\n$I->havePlugin('foo/plugin.php', $code);\n
    "},{"location":"modules/WPFilesystem/#havetheme","title":"haveTheme","text":"

    Signature: haveTheme(string $folder, string $indexFileCode, [string $functionsFileCode]) : void

    Creates a theme file structure, including theme style file and index, in the themes folder.

    The theme is just created and not activated; the code can not contain the opening '<?php' tag.

    $code = 'sayHi();';\n$functionsCode  = 'function sayHi(){echo \"Hello world\";};';\n$I->haveTheme('foo', $indexCode, $functionsCode);\n// Load the code from a file.\n$indexCode = file_get_contents(codecept_data_dir('code/index.php'));\n$functionsCode = file_get_contents(codecept_data_dir('code/functions.php'));\n$I->haveTheme('foo', $indexCode, $functionsCode);\n
    "},{"location":"modules/WPFilesystem/#makeuploadsdir","title":"makeUploadsDir","text":"

    Signature: makeUploadsDir(string $path) : string

    Creates an empty folder in the WordPress installation uploads folder.

    <?php\n$logsDir = $I->makeUploadsDir('logs/acme');\n
    "},{"location":"modules/WPFilesystem/#openfile","title":"openFile","text":"

    Signature: openFile(string $filename) : void

    Opens a file and stores it's content.

    Usage:

    <?php\n$I->openFile('composer.json');\n$I->seeInThisFile('codeception/codeception');\n
    "},{"location":"modules/WPFilesystem/#openuploadedfile","title":"openUploadedFile","text":"

    Signature: openUploadedFile(string $filename, [DateTime|string|int|null $date]) : void

    Opens a file in the the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->openUploadedFile('some-file.txt');\n$I->openUploadedFile('some-file.txt', 'time');\n
    "},{"location":"modules/WPFilesystem/#seefilecontentsequal","title":"seeFileContentsEqual","text":"

    Signature: seeFileContentsEqual(string $text) : void

    Checks the strict matching of file contents. Unlike seeInThisFile will fail if file has something more than expected lines. Better to use with HEREDOC strings. Matching is done after removing \"\\r\" chars from file content.

    <?php\n$I->openFile('process.pid');\n$I->seeFileContentsEqual('3192');\n
    "},{"location":"modules/WPFilesystem/#seefilefound","title":"seeFileFound","text":"

    Signature: seeFileFound(string $filename, [string $path]) : void

    Checks if file exists in path. Opens a file when it's exists

    <?php\n$I->seeFileFound('UserModel.php','app/models');\n
    "},{"location":"modules/WPFilesystem/#seeinmupluginfile","title":"seeInMuPluginFile","text":"

    Signature: seeInMuPluginFile(string $file, string $contents) : void

    Checks that a file in a mu-plugin folder contains a string.

    $I->seeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#seeinpluginfile","title":"seeInPluginFile","text":"

    Signature: seeInPluginFile(string $file, string $contents) : void

    Checks that a file in a plugin folder contains a string.

    $I->seeInPluginFile('my-plugin/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#seeinthemefile","title":"seeInThemeFile","text":"

    Signature: seeInThemeFile(string $file, string $contents) : void

    Checks that a file in a theme folder contains a string.

    <?php\n$I->seeInThemeFile('my-theme/some-file.txt', 'foo');\n?>\n
    "},{"location":"modules/WPFilesystem/#seeinthisfile","title":"seeInThisFile","text":"

    Signature: seeInThisFile(string $text) : void

    Checks If opened file has text in it.

    Usage:

    <?php\n$I->openFile('composer.json');\n$I->seeInThisFile('codeception/codeception');\n
    "},{"location":"modules/WPFilesystem/#seeinuploadedfile","title":"seeInUploadedFile","text":"

    Signature: seeInUploadedFile(string $file, string $contents, [string|int|null $date]) : void

    Checks that a file in the uploads folder contains a string.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    <?php\n$I->seeInUploadedFile('some-file.txt', 'foo');\n$I->seeInUploadedFile('some-file.txt','foo', 'today');\n
    "},{"location":"modules/WPFilesystem/#seemupluginfilefound","title":"seeMuPluginFileFound","text":"

    Signature: seeMuPluginFileFound(string $file) : void

    Checks that a file is found in a mu-plugin folder.

    $I->seeMuPluginFileFound('mu-plugin1/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#seenumbernewlines","title":"seeNumberNewLines","text":"

    Signature: seeNumberNewLines(int $number) : void

    Checks If opened file has the number of new lines.

    Usage:

    <?php\n$I->openFile('composer.json');\n$I->seeNumberNewLines(5);\n
    "},{"location":"modules/WPFilesystem/#seepluginfilefound","title":"seePluginFileFound","text":"

    Signature: seePluginFileFound(string $file) : void

    Checks that a file is found in a plugin folder.

    $I->seePluginFileFound('my-plugin/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#seethemefilefound","title":"seeThemeFileFound","text":"

    Signature: seeThemeFileFound(string $file) : void

    Checks that a file is found in a theme folder.

    $I->seeThemeFileFound('my-theme/some-file.txt');\n
    "},{"location":"modules/WPFilesystem/#seethisfilematches","title":"seeThisFileMatches","text":"

    Signature: seeThisFileMatches(string $regex) : void

    Checks that contents of currently opened file matches $regex

    "},{"location":"modules/WPFilesystem/#seeuploadedfilefound","title":"seeUploadedFileFound","text":"

    Signature: seeUploadedFileFound(string $filename, [string|int|null $date]) : void

    Checks if file exists in the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    <?php\n$I->seeUploadedFileFound('some-file.txt');\n$I->seeUploadedFileFound('some-file.txt','today');\n?>\n
    "},{"location":"modules/WPFilesystem/#writetofile","title":"writeToFile","text":"

    Signature: writeToFile(string $filename, string $contents) : void

    Saves contents to file

    "},{"location":"modules/WPFilesystem/#writetomupluginfile","title":"writeToMuPluginFile","text":"

    Signature: writeToMuPluginFile(string $file, string $data) : void

    Writes a file in a mu-plugin folder.

    $I->writeToMuPluginFile('mu-plugin1/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#writetopluginfile","title":"writeToPluginFile","text":"

    Signature: writeToPluginFile(string $file, string $data) : void

    Writes a file in a plugin folder.

    $I->writeToPluginFile('my-plugin/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#writetothemefile","title":"writeToThemeFile","text":"

    Signature: writeToThemeFile(string $file, string $data) : void

    Writes a string to a file in a theme folder.

    $I->writeToThemeFile('my-theme/some-file.txt', 'foo');\n
    "},{"location":"modules/WPFilesystem/#writetouploadedfile","title":"writeToUploadedFile","text":"

    Signature: writeToUploadedFile(string $filename, string $data, [DateTime|string|int|null $date]) : string

    Writes a string to a file in the the uploads folder.

    The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

    $I->writeToUploadedFile('some-file.txt', 'foo bar');\n$I->writeToUploadedFile('some-file.txt', 'foo bar', 'today');\n

    Read more in Codeception documentation.

    "},{"location":"modules/WPLoader/","title":"WPLoader","text":""},{"location":"modules/WPLoader/#wploader-module","title":"WPLoader module","text":"

    A module to load WordPress and make its code available in tests.

    Depending on the value of the loadOnly configuration parameter, the module will behave differently:

    • loadOnly: false - The module will load WordPress like the Core PHPUnit suite does to run integration tests in a controlled environment. Use the module in this mode with test cases generated using the generate:wpunit command.
    • loadOnly: true - The module will load WordPress to make it available in the context of tests. Use the module in this mode in Cest, Cept and Codeception unit test cases.
    "},{"location":"modules/WPLoader/#configuration-with-loadonly-false","title":"Configuration with loadOnly: false","text":"

    The module will load WordPress like the Core PHPUnit suite does to run integration tests in a controlled environment. Together with the test case generated by the generate:wpunit command the module will:

    • take care of running any test method in a database transaction rolled back after each test
    • manage and clean up the global environment and context between tests

    Note

    The module will set the environment variable WPBROWSER_LOAD_ONLY=0 when running in this mode. This environment variable can be used to detect whether WordPress is being loaded by WPBrowser and in which mode.

    When used in this mode, the module supports the following configuration parameters:

    • loadOnly - false to load WordPress and run tests in a controlled environment.
    • wpRootFolder - required; the path to the WordPress installation root folder. This can be a relative path to the codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation directory is the directory that contains the wp-load.php file.
    • dbUrl - required; the URL to the database to use to run tests. The URL must be in the form mysql://username:password@host:port/database to use a MySQL database, or in the form sqlite://path/to/database to use a SQLite database. Alternatively, you can use the dbName, dbUser, dbPassword, dbHost configuration parameters to specify the database connection details.
    • dump - the path to a database dump, or a set of database dumps, to load before running tests. The dump will be loaded only once, after the tests run.
    • tablePrefix - the database table prefix to use when loading WordPress, defaults to wp_.
    • multisite - a boolean value to indicate if WordPress should be loaded and initialized in multisite mode.
    • dbCharset - the database charset to use when loading WordPress.
    • dbCollate - the database collate to use when loading WordPress.
    • domain - the domain to use when loading WordPress. Equivalent to defining the WP_TESTS_DOMAIN constant.
    • adminEmail - the administrator email to use when loading WordPress. Equivalent to defining the WP_TESTS_EMAIL constant.
    • title - the site title to use when loading WordPress. Equivalent to defining the WP_TESTS_TITLE constant.
    • phpBinary - the path to the PHP binary to use to run tests. Defaults to the WP_PHP_BINARY constant.
    • language - the language to use when loading WordPress. Equivalent to defining the WPLANG constant.
    • configFile - a configuration file, or a set of configuration files, to load before the tests to further customize and control the WordPress testing environment. This file(s) will be loaded before the WordPress installation is loaded.
    • pluginsFolder - the path to the plugins folder to use when loading WordPress. Equivalent to defining the WP_PLUGIN_DIR constant. If both this parameter and the WP_PLUGIN_DIR parameter are set, the WP_PLUGIN_DIR parameter will override the value of this one.
    • WP_CONTENT_DIR - the path to the content folder to use when loading WordPress in the context of tests. If the installation used by the WPLoader module defines a WP_CONTENT_DIR constant in its wp-config.php file, the module will throw an exception if this parameter is set. Setting this parameter will affect the WP_PLUGIN_DIR and the WPMU_PLUGIN_DIR parameters.
    • WP_PLUGIN_DIR - the path to the plugins folder to use when loading WordPress in the context of tests. If the installation used by the WPLoader module defines a WP_PLUGIN_DIR constant in its wp-config.php file, the module will throw an exception if this parameter is set.
    • WPMU_PLUGIN_DIR - the path to the mu-plugins folder to use when loading WordPress in the context of tests. If the installation used by the WPLoader module defines a WPMU_PLUGIN_DIR constant in its wp-config.php file, the module will throw an exception if this parameter is set.
    • plugins - a list of plugins to activate and load in the WordPress installation. If the plugin is located in the WordPress installation plugins directory, then the plugin name can be specified using the directory/file.php format. If the plugin is located in an arbitrary path inside or outiside of the WordPress installation or project, then the plugin name must be specified either as an absolute path or as a relative path to the project root folder.
    • silentlyActivatePlugins - a list of plugins to activate silently, without firing their activation hooks. Depending on the plugin, a silent activation might cause the plugin to not work correctly. The list must be in the same format as the plugins parameter and plugin should be activated silently only if they are not working correctly during normal activation and are known to work correctly when activated silently. Plugin paths can be specified following the same format of the plugins parameter.
    • bootstrapActions - a list of actions or callables to call after WordPress is loaded and before the tests run.
    • theme - the theme to activate and load in the WordPress installation. The theme can be specified in slug format, e.g., twentytwentythree, to load it from the WordPress installation themes directory. Alternatively, the theme can be specified as an absolute or relative path to a theme folder, e.g., /home/themes/my-theme or vendor/acme/vendor-theme. To use both a parent and ha child theme from arbitrary absolute or relative paths, define the theme parameter as an array of theme paths, e.g., ['/home/themes/parent-theme', '.'].
    • AUTH_KEY - the AUTH_KEY constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • SECURE_AUTH_KEY - the SECURE_AUTH_KEY constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • LOGGED_IN_KEY - the LOGGED_IN_KEY constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • NONCE_KEY - the NONCE_KEY constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • AUTH_SALT - the AUTH_SALT constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • SECURE_AUTH_SALT - the SECURE_AUTH_SALT constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • LOGGED_IN_SALT - the LOGGED_IN_SALT constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • NONCE_SALT - the NONCE_SALT constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • AUTOMATIC_UPDATER_DISABLED - the AUTOMATIC_UPDATER_DISABLED constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • WP_HTTP_BLOCK_EXTERNAL - the WP_HTTP_BLOCK_EXTERNAL constant value to use when loading WordPress. If the wpRootFolder path points at a configured installation, containing the wp-config.php file, then the value of the constant in the configuration file will be used, else it will be randomly generated.
    • backupGlobals - a boolean value to indicate if the global environment should be backed up before each test. Defaults to true. The globals' backup involves serialization of the global state, plugins or themes that define classes developed to prevent serialization of the global state will cause the tests to fail. Set this parameter to false to disable the global environment backup, or use a more refined approach setting the backupGlobalsExcludeList parameter below. Note that a test case that is explicitly setting the backupGlobals property will override this configuration parameter.
    • backupGlobalsExcludeList - a list of global variables to exclude from the global environment backup. The list must be in the form of array, and it will be merged to the list of globals excluded by default.
    • backupStaticAttributes - a boolean value to indicate if static attributes of classes should be backed up before each test. Defaults to true. The static attributes' backup involves serialization of the global state, plugins or themes that define classes developed to prevent serialization of the global state will cause the tests to fail. Set this parameter to false to disable the static attributes backup, or use a more refined approanch setting the backupStaticAttributesExcludeList parameter below. Note that a test case that is explicitly setting the backupStaticAttributes property will override this configuration parameter.
    • backupStaticAttributesExcludeList - a list of classes to exclude from the static attributes backup. The list must be in the form of map from class names to the array of method names to exclude from the backup. See an example below.
    • skipInstall - a boolean value to indicate if the WordPress installation should be skipped between runs, when already installed. Defaults to false. During boot, the WPLoader module will re-install WordPress and activate, on top of the fresh installation, any plugin and theme specified in the plugins and theme configuration parameters: this can be a time-consuming operation. Set this parameter to true to run the WordPress installation once and just load it on the following runs. To force the installation to run again, rerun the suite using the WPLoader module using the --debug flag or delete the _wploader-state.sql file in the suite directory. This configuration parameter is ignored when the loadOnly parameter is set to true.
    • beStrictAboutWpdbConnectionId - a boolean value to indicate if the WPTestCase class should throw an exception if the database connection is closed during any setUpBeforeClass method; default is true.

    This is an example of an integration suite configured to use the module:

    actor: IntegrationTester\nbootstrap: _bootstrap.php\nmodules:\n  enabled:\n    - \\Helper\\Integration\n    - lucatume\\WPBrowser\\Module\\WPLoader:\n        wpRootFolder: /var/wordpress\n        dbUrl: mysql://root:root@mysql:3306/wordpress\n        tablePrefix: test_\n        domain: wordpress.test\n        adminEmail: admin@wordpress.test\n        title: 'Integration Tests'\n        plugins:\n          # This plugin will be loaded from the WordPress installation plugins directory.\n          - hello.php\n          # This plugin will be loaded from an arbitrary absolute path.\n          - /home/plugins/woocommerce/woocommerce.php\n          # This plugin will be loaded from an arbitrary relative path inside the project root folder.\n          - vendor/acme/project/plugin.php\n          # This plugin will be loaded from the project root folder.\n          - my-plugin.php\n        theme: twentytwentythree # Load the theme from the WordPress installation themes directory.\n

    The following configuration uses dynamic configuration parameters to set the module configuration:

    actor: IntegrationTester\nbootstrap: _bootstrap.php\nmodules:\n  enabled:\n    - \\Helper\\Integration\n    - lucatume\\WPBrowser\\Module\\WPLoader:\n        wpRootFolder: '%WP_ROOT_FOLDER%'\n        dbUrl: '%WP_DB_URL%'\n        tablePrefix: '%WP_TABLE_PREFIX%'\n        domain: '%WP_DOMAIN%'\n        adminEmail: '%WP_ADMIN_EMAIL%'\n        title: '%WP_TITLE%'\n        plugins:\n          - hello.php\n          - /home/plugins/woocommerce/woocommerce.php\n          - my-plugin.php\n          - vendor/acme/project/plugin.php\n        # Parent theme from the WordPress installation themes directory, child theme from absolute path.\n        theme: [ twentytwentythree, /home/themes/my-theme ]\n

    The following example configuration uses a SQLite database and loads a database fixture before the tests run:

    actor: IntegrationTester\nbootstrap: _bootstrap.php\nmodules:\n  enabled:\n    - \\Helper\\Integration\n    - lucatume\\WPBrowser\\Module\\WPLoader:\n        wpRootFolder: /var/wordpress\n        dbUrl: sqlite:///var/wordpress/wp-tests.sqlite\n        dump:\n          - tests/_data/products.sql\n          - tests/_data/users.sql\n          - tests/_data/orders.sql\n        tablePrefix: test_\n        domain: wordpress.test\n        adminEmail: admin@wordpress.test\n        title: 'Integration Tests'\n        plugins:\n          - hello.php\n          - woocommerce/woocommerce.php\n          - my-plugin/my-plugin.php\n        theme:\n          # Parent theme from relative path.\n          - vendor/acme/parent-theme\n          # Child theme from the current working directory.\n          - .\n

    The follow example configuration prevents the backup of globals and static attributes in all the tests of the suite that are not explicitly overriding the backupGlobals and backupStaticAttributes properties:

    actor: IntegrationTester\nbootstrap: _bootstrap.php\nmodules:\n  enabled:\n    - \\Helper\\Integration\n    - lucatume\\WPBrowser\\Module\\WPLoader:\n        wpRootFolder: /var/wordpress\n        dbUrl: sqlite:///var/wordpress/wp-tests.sqlite\n        dump:\n          - tests/_data/products.sql\n          - tests/_data/users.sql\n          - tests/_data/orders.sql\n        tablePrefix: test_\n        domain: wordpress.test\n        adminEmail: admin@wordpress.test\n        title: 'Integration Tests'\n        plugins:\n          - hello.php\n          - woocommerce/woocommerce.php\n          - my-plugin/my-plugin.php\n        theme: twentytwentythree\n        backupGlobals: false\n        backupStaticAttributes: false \n

    The following configuration prevents the backup of some globals and static attributes:

    actor: IntegrationTester\nbootstrap: _bootstrap.php\nmodules:\n  enabled:\n    - \\Helper\\Integration\n    - lucatume\\WPBrowser\\Module\\WPLoader:\n        wpRootFolder: /var/wordpress\n        dbUrl: sqlite:///var/wordpress/wp-tests.sqlite\n        dump:\n          - tests/_data/products.sql\n          - tests/_data/users.sql\n          - tests/_data/orders.sql\n        tablePrefix: test_\n        domain: wordpress.test\n        adminEmail: admin@wordpress.test\n        title: 'Integration Tests'\n        plugins:\n          - hello.php\n          - woocommerce/woocommerce.php\n          - my-plugin/my-plugin.php\n        theme: twentytwentythree\n        backupGlobalsExcludeList:\n          - my_plugin_will_explode_on_wakeup\n          - another_problematic_global\n        backupStaticAttributesExcludeList:\n          - MyPlugin\\MyClass:\n              - instance\n              - anotherStaticAttributeThatWillExplodeOnWakeup\n          - AnotherPlugin\\AnotherClass:\n              - instance\n              - yetAnotherStaticAttributeThatWillExplodeOnWakeup\n
    "},{"location":"modules/WPLoader/#handling-a-custom-site-structure","title":"Handling a custom site structure","text":"

    The setup process should just work for standard and non-standard WordPress installations alike.

    Even if you're working on a site project using a custom file structure, e.g. Bedrock, you will be able to set up your site to run tests using the default configuration based on PHP built-in server, Chromedriver and SQLite database.

    "},{"location":"modules/WPLoader/#configuration-with-loadonly-true","title":"Configuration with loadOnly: true","text":"

    The module will load WordPress from the location specified by the wpRootFolder parameter, relying on the WPDb module to manage the database state.

    Note

    The module will set the environment variable WPBROWSER_LOAD_ONLY=1 when running in this mode. This environment variable can be used to detect whether WordPress is being loaded by WPBrowser and in which mode.

    When used in this mode, the module supports the following configuration parameters:

    • loadOnly - true to load WordPress and make it available in the context of tests.
    • wpRootFolder - required; the path to the WordPress installation root folder. This can be a relative path to the codeception root directory, or an absolute path to the WordPress installation directory. The WordPress installation directory is the directory that contains the wp-load.php file.
    • dbUrl - required; the URL to the database to use to run tests. The URL must be in the form mysql://username:password@host:port/database to use a MySQL database, or in the form sqlite://path/to/database to use a SQLite database. Alternatively, you can use the dbName, dbUser, dbPassword, dbHost configuration parameters to specify the database connection details.
    • domain - the domain to use when loading WordPress. Equivalent to defining the WP_TESTS_DOMAIN constant.
    • configFile - a configuration file, or a set of configuration files, to load before the tests to further customize and control the WordPress testing environment. This file(s) will be loaded before the WordPress installation is loaded.

    Warning

    The module will define the DB_NAME, DB_USER, DB_PASSWORD and DB_HOST constants in the context of loading WordPress. This is done to allow the WordPress database connection to be configured using the dbUrl configuration parameter. The module will silence the warnings about the redeclaration of these constants, but in some cases with stricter error checking (e.g. Bedrock) this may not be enough. In those cases, you can use the WPBROWSER_LOAD_ONLY environment variable to detect whether WordPress is being loaded by WPBrowser and in which mode and configured your installation accordingly.

    The following is an example of the module configuration to run end-to-end tests on the site served at http://localhost:8080 URL and served from the /var/wordpress directory:

    actor: EndToEndTester\nbootstrap: _bootstrap.php\nmodules:\n  enabled:\n    - \\Helper\\Integration\n    - lucatume\\WPBrowser\\Module\\WPWebDriver:\n        url: 'http://localhost:8080'\n        adminUsername: 'admin'\n        adminPassword: 'password'\n        adminPath: '/wp-admin'\n        browser: chrome\n        host: 'localhost'\n        port: '4444'\n        path: '/'\n        window_size: false\n        capabilities:\n          \"goog:chromeOptions\":\n            args:\n              - \"--headless\"\n              - \"--disable-gpu\"\n              - \"--disable-dev-shm-usage\"\n              - \"--proxy-server='direct://'\"\n              - \"--proxy-bypass-list=*\"\n              - \"--no-sandbox\"\n    - lucatume\\WPBrowser\\Module\\WPDb:\n        dbUrl: 'mysql://root:password@localhost:3306/wordpress'\n        url: 'http://localhost:8080'\n        tablePrefix: 'wp_'\n        dump: 'tests/_data/dump.sql'\n        populate: true\n        cleanup: true\n        reconnect: false\n        urlReplacement: true\n        originalUrl: http://wordpress.test\n        waitlock: 10\n        createIfNotExists: true\n    - lucatume\\WPBrowser\\Module\\WPLoader:\n        loadOnly: true\n        wpRootFolder: /var/wordpress\n        dbUrl: 'mysql://root:password@localhost:3306/wordpress'\n        domain: wordpress.test\n
    "},{"location":"modules/WPLoader/#methods","title":"Methods","text":"

    The module provides the following methods:

    "},{"location":"modules/WPLoader/#factory","title":"factory","text":"

    Signature: factory() : lucatume\\WPBrowser\\Module\\WPLoader\\FactoryStore

    Accessor method to get the object storing the factories for things. This method gives access to the same factories provided by the Core test suite.

    "},{"location":"modules/WPLoader/#getcontentfolder","title":"getContentFolder","text":"

    Signature: getContentFolder([string $path]) : string

    Returns the absolute path to the WordPress content directory.

    "},{"location":"modules/WPLoader/#getinstallation","title":"getInstallation","text":"

    Signature: getInstallation() : lucatume\\WPBrowser\\WordPress\\Installation

    "},{"location":"modules/WPLoader/#getpluginsfolder","title":"getPluginsFolder","text":"

    Signature: getPluginsFolder([string $path]) : string

    Returns the absolute path to the plugins directory.

    The value will first look at the WP_PLUGIN_DIR constant, then the pluginsFolder configuration parameter and will, finally, look in the default path from the WordPress root directory.

    "},{"location":"modules/WPLoader/#getthemesfolder","title":"getThemesFolder","text":"

    Signature: getThemesFolder([string $path]) : string

    Returns the absolute path to the themes directory.

    "},{"location":"modules/WPLoader/#getwprootfolder","title":"getWpRootFolder","text":"

    Signature: getWpRootFolder([?string $path]) : string

    Returns the absolute path to the WordPress root folder or a path within it..

    "},{"location":"modules/WPQueries/","title":"WPQueries","text":""},{"location":"modules/WPQueries/#wpqueries-module","title":"WPQueries module","text":"

    This module provides assertions for WordPress queries.

    This module can be used in any test context where the global $wpdb variable is defined, this usually means in any suite where the WPLoader module is used.

    "},{"location":"modules/WPQueries/#configuration","title":"Configuration","text":"

    The method does not require configuration.

    "},{"location":"modules/WPQueries/#methods","title":"Methods","text":"

    The module provides the following methods:

    "},{"location":"modules/WPQueries/#assertcountqueries","title":"assertCountQueries","text":"

    Signature: assertCountQueries(int $n, [string $message]) : void

    Asserts that n queries have been made.

    <?php\n$posts = $this->factory()->post->create_many(3);\n$cachedUsers = $this->factory()->user->create_many(2);\n$nonCachedUsers = $this->factory()->user->create_many(2);\nforeach($cachedUsers as $userId){\n     wp_cache_set('page-posts-for-user-' . $userId, $posts, 'acme');\n}\n// Run the same query as different users\nforeach(array_merge($cachedUsers, $nonCachedUsers) as $userId){\n     $pagePosts = $plugin->getPagePostsForUser($userId);\n}\n$I->assertCountQueries(2, 'A query should be made for each user missing cached posts.')\n
    "},{"location":"modules/WPQueries/#assertnotqueries","title":"assertNotQueries","text":"

    Signature: assertNotQueries([string $message]) : void

    Asserts that no queries were made.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$posts = $this->factory()->post->create_many(3);\nwp_cache_set('page-posts', $posts, 'acme');\n$pagePosts = $plugin->getPagePosts();\n$I->assertNotQueries('Queries should not be made if the cache is set.')\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbyaction","title":"assertNotQueriesByAction","text":"

    Signature: assertNotQueriesByAction(string $action, [string $message]) : void

    Asserts that no queries were made as a consequence of the specified action.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_action( 'edit_post', function($postId){\n        $count = get_option('acme_title_updates_count');\n        update_option('acme_title_updates_count', ++$count);\n} );\nwp_delete_post($bookId);\n$this->assertNotQueriesByAction('edit_post');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbyfilter","title":"assertNotQueriesByFilter","text":"

    Signature: assertNotQueriesByFilter(string $filter, [string $message]) : void

    Asserts that no queries were made as a consequence of the specified filter.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_filter('the_title', function($title, $postId){\n     $post = get_post($postId);\n     if($post->post_type !== 'book'){\n         return $title;\n     }\n     $new = get_option('acme_new_prefix');\n     return \"{$new} - \" . $title;\n});\n$title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);\n$this->assertNotQueriesByFilter('the_title');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbyfunction","title":"assertNotQueriesByFunction","text":"

    Signature: assertNotQueriesByFunction(string $function, [string $message]) : void

    Asserts that no queries were made by the specified function.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$this->assertEmpty(Acme\\get_orphaned_posts());\nAcme\\delete_orphaned_posts();\n$this->assertNotQueriesByFunction('Acme\\delete_orphaned_posts');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbymethod","title":"assertNotQueriesByMethod","text":"

    Signature: assertNotQueriesByMethod(string $class, string $method, [string $message]) : void

    Asserts that no queries have been made by the specified class method.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$options = new Acme\\Options();\n$options->update('adsSource', 'not-a-real-url.org');\n$I->assertNotQueriesByMethod('Acme\\Options', 'update');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbystatement","title":"assertNotQueriesByStatement","text":"

    Signature: assertNotQueriesByStatement(string $statement, [string $message]) : void

    Asserts that no queries have been made by the specified class method.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$bookRepository = new Acme\\BookRepository();\n$repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);\n$this->assertNotQueriesByStatement('INSERT', 'Deferred write should happen on __destruct');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbystatementandaction","title":"assertNotQueriesByStatementAndAction","text":"

    Signature: assertNotQueriesByStatementAndAction(string $statement, string $action, [string $message]) : void

    Asserts that no queries were made as a consequence of the specified action containing the SQL query.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_action( 'edit_post', function($postId){\n        $count = get_option('acme_title_updates_count');\n        update_option('acme_title_updates_count', ++$count);\n} );\nwp_delete_post($bookId);\n$this->assertNotQueriesByStatementAndAction('DELETE', 'delete_post');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbystatementandfilter","title":"assertNotQueriesByStatementAndFilter","text":"

    Signature: assertNotQueriesByStatementAndFilter(string $statement, string $filter, [string $message]) : void

    Asserts that no queries were made as a consequence of the specified filter containing the specified SQL query.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_filter('the_title', function($title, $postId){\n     $post = get_post($postId);\n     if($post->post_type !== 'book'){\n         return $title;\n     }\n     $new = get_option('acme_new_prefix');\n     return \"{$new} - \" . $title;\n});\n$title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);\n$this->assertNotQueriesByStatementAndFilter('SELECT', 'the_title');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbystatementandfunction","title":"assertNotQueriesByStatementAndFunction","text":"

    Signature: assertNotQueriesByStatementAndFunction(string $statement, string $function, [string $message]) : void

    Asserts that no queries were made by the specified function starting with the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nwp_insert_post(['ID' => $bookId, 'post_title' => 'The Call of the Wild']);\n$this->assertNotQueriesByStatementAndFunction('INSERT', 'wp_insert_post');\n$this->assertQueriesByStatementAndFunction('UPDATE', 'wp_insert_post');\n
    "},{"location":"modules/WPQueries/#assertnotqueriesbystatementandmethod","title":"assertNotQueriesByStatementAndMethod","text":"

    Signature: assertNotQueriesByStatementAndMethod(string $statement, string $class, string $method, [string $message]) : void

    Asserts that no queries were made by the specified class method starting with the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nAcme\\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();\n$this->assertQueriesByStatementAndMethod('INSERT', Acme\\BookRepository::class, 'commit');\n
    "},{"location":"modules/WPQueries/#assertqueries","title":"assertQueries","text":"

    Signature: assertQueries([string $message]) : void

    Asserts that at least one query was made during the test.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nwp_cache_delete('page-posts', 'acme');\n$pagePosts = $plugin->getPagePosts();\n$I->assertQueries('Queries should be made to set the cache.')\n
    "},{"location":"modules/WPQueries/#assertqueriesbyaction","title":"assertQueriesByAction","text":"

    Signature: assertQueriesByAction(string $action, [string $message]) : void

    Asserts that at least one query was made as a consequence of the specified action.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_action( 'edit_post', function($postId){\n        $count = get_option('acme_title_updates_count');\n        update_option('acme_title_updates_count', ++$count);\n} );\nwp_update_post(['ID' => $bookId, 'post_title' => 'New Title']);\n$this->assertQueriesByAction('edit_post');\n
    "},{"location":"modules/WPQueries/#assertqueriesbyfilter","title":"assertQueriesByFilter","text":"

    Signature: assertQueriesByFilter(string $filter, [string $message]) : void

    Asserts that at least one query was made as a consequence of the specified filter.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_filter('the_title', function($title, $postId){\n     $post = get_post($postId);\n     if($post->post_type !== 'book'){\n         return $title;\n     }\n     $new = get_option('acme_new_prefix');\n     return \"{$new} - \" . $title;\n});\n$title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);\n$this->assertQueriesByFilter('the_title');\n
    "},{"location":"modules/WPQueries/#assertqueriesbyfunction","title":"assertQueriesByFunction","text":"

    Signature: assertQueriesByFunction(string $function, [string $message]) : void

    Asserts that queries were made by the specified function.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nacme_clean_queue();\n$this->assertQueriesByFunction('acme_clean_queue');\n
    "},{"location":"modules/WPQueries/#assertqueriesbymethod","title":"assertQueriesByMethod","text":"

    Signature: assertQueriesByMethod(string $class, string $method, [string $message]) : void

    Asserts that at least one query has been made by the specified class method.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$options = new Acme\\Options();\n$options->update('showAds', false);\n$I->assertQueriesByMethod('Acme\\Options', 'update');\n
    "},{"location":"modules/WPQueries/#assertqueriesbystatement","title":"assertQueriesByStatement","text":"

    Signature: assertQueriesByStatement(string $statement, [string $message]) : void

    Asserts that at least a query starting with the specified statement was made.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nwp_cache_flush();\ncached_get_posts($args);\n$I->assertQueriesByStatement('SELECT');\n
    "},{"location":"modules/WPQueries/#assertqueriesbystatementandaction","title":"assertQueriesByStatementAndAction","text":"

    Signature: assertQueriesByStatementAndAction(string $statement, string $action, [string $message]) : void

    Asserts that at least one query was made as a consequence of the specified action containing the SQL query.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_action( 'edit_post', function($postId){\n        $count = get_option('acme_title_updates_count');\n        update_option('acme_title_updates_count', ++$count);\n} );\nwp_update_post(['ID' => $bookId, 'post_title' => 'New']);\n$this->assertQueriesByStatementAndAction('UPDATE', 'edit_post');\n
    "},{"location":"modules/WPQueries/#assertqueriesbystatementandfilter","title":"assertQueriesByStatementAndFilter","text":"

    Signature: assertQueriesByStatementAndFilter(string $statement, string $filter, [string $message]) : void

    Asserts that at least one query was made as a consequence of the specified filter containing the SQL query.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_filter('the_title', function($title, $postId){\n     $post = get_post($postId);\n     if($post->post_type !== 'book'){\n         return $title;\n     }\n     $new = get_option('acme_new_prefix');\n     return \"{$new} - \" . $title;\n});\n$title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);\n$this->assertQueriesByStatementAndFilter('SELECT', 'the_title');\n
    "},{"location":"modules/WPQueries/#assertqueriesbystatementandfunction","title":"assertQueriesByStatementAndFunction","text":"

    Signature: assertQueriesByStatementAndFunction(string $statement, string $function, [string $message]) : void

    Asserts that queries were made by the specified function starting with the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nwp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);\n$this->assertQueriesByStatementAndFunction('INSERT', 'wp_insert_post');\n
    "},{"location":"modules/WPQueries/#assertqueriesbystatementandmethod","title":"assertQueriesByStatementAndMethod","text":"

    Signature: assertQueriesByStatementAndMethod(string $statement, string $class, string $method, [string $message]) : void

    Asserts that queries were made by the specified class method starting with the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nAcme\\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();\n$this->assertQueriesByStatementAndMethod('UPDATE', Acme\\BookRepository::class, 'commit');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbyaction","title":"assertQueriesCountByAction","text":"

    Signature: assertQueriesCountByAction(int $n, string $action, [string $message]) : void

    Asserts that n queries were made as a consequence of the specified action.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_action( 'edit_post', function($postId){\n        $count = get_option('acme_title_updates_count');\n        update_option('acme_title_updates_count', ++$count);\n} );\nwp_update_post(['ID' => $bookOneId, 'post_title' => 'One']);\nwp_update_post(['ID' => $bookTwoId, 'post_title' => 'Two']);\nwp_update_post(['ID' => $bookThreeId, 'post_title' => 'Three']);\n$this->assertQueriesCountByAction(3, 'edit_post');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbyfilter","title":"assertQueriesCountByFilter","text":"

    Signature: assertQueriesCountByFilter(int $n, string $filter, [string $message]) : void

    Asserts that n queries were made as a consequence of the specified filter.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_filter('the_title', function($title, $postId){\n     $post = get_post($postId);\n     if($post->post_type !== 'book'){\n         return $title;\n     }\n     $new = get_option('acme_new_prefix');\n     return \"{$new} - \" . $title;\n});\n$title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);\n$title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);\n$title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);\n$this->assertQueriesCountByFilter(2, 'the_title');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbyfunction","title":"assertQueriesCountByFunction","text":"

    Signature: assertQueriesCountByFunction(int $n, string $function, [string $message]) : void

    Asserts that n queries were made by the specified function.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$this->assertCount(3, Acme\\get_orphaned_posts());\nAcme\\delete_orphaned_posts();\n$this->assertQueriesCountByFunction(3, 'Acme\\delete_orphaned_posts');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbymethod","title":"assertQueriesCountByMethod","text":"

    Signature: assertQueriesCountByMethod(int $n, string $class, string $method, [string $message]) : void

    Asserts that n queries have been made by the specified class method.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$bookRepository = new Acme\\BookRepository();\n$repository->where('ID', 23)->commit('title', 'Peter Pan');\n$repository->where('ID', 89)->commit('title', 'Moby-dick');\n$repository->where('ID', 2389)->commit('title', 'The call of the wild');\n$this->assertQueriesCountByMethod(3, 'Acme\\BookRepository', 'commit');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbystatement","title":"assertQueriesCountByStatement","text":"

    Signature: assertQueriesCountByStatement(int $n, string $statement, [string $message]) : void

    Asserts that n queries starting with the specified statement were made.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\n$bookRepository = new Acme\\BookRepository();\n$repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);\n$repository->where('ID', 89)->set('title', 'Moby-dick', $deferred = true);\n$repository->where('ID', 2389)->set('title', 'The call of the wild', $deferred = false);\n$this->assertQueriesCountByStatement(1, 'INSERT', 'Deferred write should happen on __destruct');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbystatementandaction","title":"assertQueriesCountByStatementAndAction","text":"

    Signature: assertQueriesCountByStatementAndAction(int $n, string $statement, string $action, [string $message]) : void

    Asserts that n queries were made as a consequence of the specified action containing the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_action( 'edit_post', function($postId){\n        $count = get_option('acme_title_updates_count');\n        update_option('acme_title_updates_count', ++$count);\n} );\nwp_delete_post($bookOneId);\nwp_delete_post($bookTwoId);\nwp_update_post(['ID' => $bookThreeId, 'post_title' => 'New']);\n$this->assertQueriesCountByStatementAndAction(2, 'DELETE', 'delete_post');\n$this->assertQueriesCountByStatementAndAction(1, 'INSERT', 'edit_post');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbystatementandfilter","title":"assertQueriesCountByStatementAndFilter","text":"

    Signature: assertQueriesCountByStatementAndFilter(int $n, string $statement, string $filter, [string $message]) : void

    Asserts that n queries were made as a consequence of the specified filter containing the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nadd_filter('the_title', function($title, $postId){\n     $post = get_post($postId);\n     if($post->post_type !== 'book'){\n         return $title;\n     }\n     $new = get_option('acme_new_prefix');\n     return \"{$new} - \" . $title;\n});\n// Warm up the cache.\n$title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);\n// Cache is warmed up now.\n$title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);\n$title = apply_filters('the_title', get_post($bookThreeId)->post_title, $bookThreeId);\n$this->assertQueriesCountByStatementAndFilter(1, 'SELECT', 'the_title');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbystatementandfunction","title":"assertQueriesCountByStatementAndFunction","text":"

    Signature: assertQueriesCountByStatementAndFunction(int $n, string $statement, string $function, [string $message]) : void

    Asserts that n queries were made by the specified function starting with the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nwp_insert_post(['post_type' => 'book', 'post_title' => 'The Call of the Wild']);\nwp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);\nwp_insert_post(['post_type' => 'book', 'post_title' => 'The Chocolate Factory']);\n$this->assertQueriesCountByStatementAndFunction(3, 'INSERT', 'wp_insert_post');\n
    "},{"location":"modules/WPQueries/#assertqueriescountbystatementandmethod","title":"assertQueriesCountByStatementAndMethod","text":"

    Signature: assertQueriesCountByStatementAndMethod(int $n, string $statement, string $class, string $method, [string $message]) : void

    Asserts that n queries were made by the specified class method starting with the specified SQL statement.

    Queries generated by setUp, tearDown and factory methods are excluded by default.

    <?php\nAcme\\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();\nAcme\\BookRepository::new(['title' => 'Moby-Dick'])->commit();\nAcme\\BookRepository::new(['title' => 'The Call of the Wild'])->commit();\n$this->assertQueriesCountByStatementAndMethod(3, 'INSERT', Acme\\BookRepository::class, 'commit');\n
    "},{"location":"modules/WPQueries/#countqueries","title":"countQueries","text":"

    Signature: countQueries([?wpdb $wpdb]) : int

    Returns the current number of queries. Set-up and tear-down queries performed by the test case are filtered out.

    <?php\n// In a WPTestCase, using the global $wpdb object.\n$queriesCount = $this->queries()->countQueries();\n// In a WPTestCase, using a custom $wpdb object.\n$queriesCount = $this->queries()->countQueries($customWdbb);\n
    "},{"location":"modules/WPQueries/#getqueries","title":"getQueries","text":"

    Signature: getQueries([?wpdb $wpdb]) : array

    Returns the queries currently performed by the global database object or the specified one. Set-up and tear-down queries performed by the test case are filtered out.

    <?php\n// In a WPTestCase, using the global $wpdb object.\n$queries = $this->queries()->getQueries();\n// In a WPTestCase, using a custom $wpdb object.\n$queries = $this->queries()->getQueries($customWdbb);\n
    "},{"location":"modules/WPWebDriver/","title":"WPWebDriver","text":""},{"location":"modules/WPWebDriver/#wpwebdriver-module","title":"WPWebDriver module","text":"

    This module drives a browser using a solution like Selenium or Chromedriver to simulate user interactions with the WordPress project.

    The module has full Javascript support, differently from the WPBrowser module, and can be used to test sites that use Javascript to render the page or to make assertions that require Javascript support.

    The method extends the Codeception WebDriver module and is used in the context of Cest and Cept test cases.

    "},{"location":"modules/WPWebDriver/#configuration","title":"Configuration","text":"
    • browser - the browser to use; e.g. 'chrome'
    • host - the host to use; e.g. 'localhost'. This is the host of the Selenium server or the Chromedriver server.
    • port - the port to use; e.g. '4444'. This is the port of the Selenium server or the Chromedriver server.
    • path - the path to use; e.g. '/wd/hub' or '/'. Use '/' for Chrome.
    • url - required; the start URL of your WordPress project.
    • adminUsername - required; the site administrator username to use in actions like loginAsAdmin.
    • adminPassword - required; the site administrator password to use in actions like loginAsAdmin.
    • adminPath - the path to the WordPress admin directory; defaults to /wp-admin.

    More configuration options, and their explanation, are available in the Codeception WebDriver module documentation.

    The following is an example of the module configuration to run tests on thehttp://localhost:8080 site:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPBrowser:\n      url: 'http://localhost:8080'\n      adminUsername: 'admin'\n      adminPassword: 'password'\n      adminPath: '/wp-admin'\n      browser: chrome\n      host: 'localhost'\n      port: '4444'\n      path: '/'\n      window_size: false\n      capabilities:\n        \"goog:chromeOptions\":\n          args:\n            - \"--headless\"\n            - \"--disable-gpu\"\n            - \"--disable-dev-shm-usage\"\n            - \"--proxy-server='direct://'\"\n            - \"--proxy-bypass-list=*\"\n            - \"--no-sandbox\"\n

    The following configuration uses dynamic configuration parameters to set the module configuration:

    modules:\n  enabled:\n    lucatume\\WPBrowser\\Module\\WPBrowser:\n      url: 'http://localhost:8080'\n      adminUsername: 'admin'\n      adminPassword: 'password'\n      adminPath: '/wp-admin'\n      browser: chrome\n      host: '%CHROME_HOST%'\n      port: '%CHROME_PORT%'\n      path: '/'\n      window_size: `1920,1080`\n      capabilities:\n        \"goog:chromeOptions\":\n          args:\n            - \"--headless\"\n            - \"--disable-gpu\"\n            - \"--disable-dev-shm-usage\"\n            - \"--proxy-server='direct://'\"\n            - \"--proxy-bypass-list=*\"\n            - \"--no-sandbox\"\n

    Furthermore, the above configuration will not run Chrome in headless mode: the browser window will be visible.

    "},{"location":"modules/WPWebDriver/#methods","title":"Methods","text":"

    The module provides the following methods:

    "},{"location":"modules/WPWebDriver/#acceptpopup","title":"acceptPopup","text":"

    Signature: acceptPopup() : void

    Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt. Don't confuse popups with modal windows, as created by various libraries.

    "},{"location":"modules/WPWebDriver/#activateplugin","title":"activatePlugin","text":"

    Signature: activatePlugin(array|string $pluginSlug) : void

    In the plugin administration screen activates one or more plugins clicking the \"Activate\" link.

    The method will not handle authentication and navigation to the plugins administration page.

    <?php\n// Activate a plugin.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->activatePlugin('hello-dolly');\n// Activate a list of plugins.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->activatePlugin(['hello-dolly','another-plugin']);\n
    "},{"location":"modules/WPWebDriver/#activatetheme","title":"activateTheme","text":"

    Signature: activateTheme(string $slug) : void

    Activates a theme.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPWebDriver/#ameditingpostwithid","title":"amEditingPostWithId","text":"

    Signature: amEditingPostWithId(int $id) : void

    Go to the admin page to edit the post with the specified ID.

    The method will not handle authentication the admin area.

    <?php\n$I->loginAsAdmin();\n$postId = $I->havePostInDatabase();\n$I->amEditingPostWithId($postId);\n$I->fillField('post_title', 'Post title');\n
    "},{"location":"modules/WPWebDriver/#ameditinguserwithid","title":"amEditingUserWithId","text":"

    Signature: amEditingUserWithId(int $id) : void

    Go to the admin page to edit the user with the specified ID.

    The method will not handle authentication the admin area.

    <?php\n$I->loginAsAdmin();\n$userId = $I->haveUserInDatabase('luca', 'editor');\n$I->amEditingUserWithId($userId);\n$I->fillField('email', 'new@example.net');\n
    "},{"location":"modules/WPWebDriver/#amonadminajaxpage","title":"amOnAdminAjaxPage","text":"

    Signature: amOnAdminAjaxPage([array|string|null $queryVars]) : void

    Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

    The method will not handle authentication, nonces or authorization.

    <?php\n$I->amOnAdminAjaxPage(['action' => 'my-action', 'data' => ['id' => 23], 'nonce' => $nonce]);\n
    "},{"location":"modules/WPWebDriver/#amonadminpage","title":"amOnAdminPage","text":"

    Signature: amOnAdminPage(string $page) : void

    Go to a page in the admininstration area of the site.

    This method will not handle authentication to the administration area.

    <?php\n$I->loginAs('user', 'password');\n// Go to the plugins management screen.\n$I->amOnAdminPage('/plugins.php');\n
    "},{"location":"modules/WPWebDriver/#amoncronpage","title":"amOnCronPage","text":"

    Signature: amOnCronPage([array|string|null $queryVars]) : void

    Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

    <?php\n// Triggers the cron job with an optional query argument.\n$I->amOnCronPage('/?some-query-var=some-value');\n
    "},{"location":"modules/WPWebDriver/#amonpage","title":"amOnPage","text":"

    Signature: amOnPage($page) : void

    "},{"location":"modules/WPWebDriver/#amonpagespage","title":"amOnPagesPage","text":"

    Signature: amOnPagesPage() : void

    Go the \"Pages\" administration screen.

    The method will not handle authentication.

    <?php\n$I->loginAsAdmin();\n$I->amOnPagesPage();\n$I->see('Add New');\n
    "},{"location":"modules/WPWebDriver/#amonpluginspage","title":"amOnPluginsPage","text":"

    Signature: amOnPluginsPage() : void

    Go to the plugins administration screen.

    The method will not handle authentication.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->activatePlugin('hello-dolly');\n
    "},{"location":"modules/WPWebDriver/#amonsubdomain","title":"amOnSubdomain","text":"

    Signature: amOnSubdomain(string $subdomain) : void

    "},{"location":"modules/WPWebDriver/#amonthemespage","title":"amOnThemesPage","text":"

    Signature: amOnThemesPage() : void

    Moves to the themes administration page.

    "},{"location":"modules/WPWebDriver/#amonurl","title":"amOnUrl","text":"

    Signature: amOnUrl($url) : void

    "},{"location":"modules/WPWebDriver/#appendfield","title":"appendField","text":"

    Signature: appendField($field, string $value) : void

    Append the given text to the given element. Can also add a selection to a select box.

    <?php\n$I->appendField('#mySelectbox', 'SelectValue');\n$I->appendField('#myTextField', 'appended');\n
    "},{"location":"modules/WPWebDriver/#attachfile","title":"attachFile","text":"

    Signature: attachFile($field, string $filename) : void

    "},{"location":"modules/WPWebDriver/#cancelpopup","title":"cancelPopup","text":"

    Signature: cancelPopup() : void

    Dismisses the active JavaScript popup, as created by window.alert, window.confirm, or window.prompt.

    "},{"location":"modules/WPWebDriver/#checkoption","title":"checkOption","text":"

    Signature: checkOption($option) : void

    "},{"location":"modules/WPWebDriver/#clearfield","title":"clearField","text":"

    Signature: clearField($field) : void

    Clears given field which isn't empty.

    <?php\n$I->clearField('#username');\n
    "},{"location":"modules/WPWebDriver/#click","title":"click","text":"

    Signature: click($link, [$context]) : void

    "},{"location":"modules/WPWebDriver/#clickwithleftbutton","title":"clickWithLeftButton","text":"

    Signature: clickWithLeftButton([$cssOrXPath], [?int $offsetX], [?int $offsetY]) : void

    Performs click with the left mouse button on an element. If the first parameter null then the offset is relative to the actual mouse position. If the second and third parameters are given, then the mouse is moved to an offset of the element's top-left corner. Otherwise, the mouse is moved to the center of the element.

    <?php\n$I->clickWithLeftButton(['css' => '.checkout']);\n$I->clickWithLeftButton(null, 20, 50);\n$I->clickWithLeftButton(['css' => '.checkout'], 20, 50);\n
    "},{"location":"modules/WPWebDriver/#clickwithrightbutton","title":"clickWithRightButton","text":"

    Signature: clickWithRightButton([$cssOrXPath], [?int $offsetX], [?int $offsetY]) : void

    Performs contextual click with the right mouse button on an element. If the first parameter null then the offset is relative to the actual mouse position. If the second and third parameters are given, then the mouse is moved to an offset of the element's top-left corner. Otherwise, the mouse is moved to the center of the element.

    <?php\n$I->clickWithRightButton(['css' => '.checkout']);\n$I->clickWithRightButton(null, 20, 50);\n$I->clickWithRightButton(['css' => '.checkout'], 20, 50);\n
    "},{"location":"modules/WPWebDriver/#closetab","title":"closeTab","text":"

    Signature: closeTab() : void

    Closes current browser tab and switches to previous active tab.

    <?php\n$I->closeTab();\n
    "},{"location":"modules/WPWebDriver/#deactivateplugin","title":"deactivatePlugin","text":"

    Signature: deactivatePlugin(array|string $pluginSlug) : void

    In the plugin administration screen deactivate a plugin clicking the \"Deactivate\" link.

    The method will not handle authentication and navigation to the plugins administration page.

    <?php\n// Deactivate one plugin.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->deactivatePlugin('hello-dolly');\n// Deactivate a list of plugins.\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->deactivatePlugin(['hello-dolly', 'my-plugin']);\n
    "},{"location":"modules/WPWebDriver/#debugwebdriverlogs","title":"debugWebDriverLogs","text":"

    Signature: debugWebDriverLogs([?Codeception\\TestInterface $test]) : void

    Print out latest Selenium Logs in debug mode

    "},{"location":"modules/WPWebDriver/#deletesessionsnapshot","title":"deleteSessionSnapshot","text":"

    Signature: deleteSessionSnapshot($name) : void

    "},{"location":"modules/WPWebDriver/#dontsee","title":"dontSee","text":"

    Signature: dontSee($text, [$selector]) : void

    "},{"location":"modules/WPWebDriver/#dontseecheckboxischecked","title":"dontSeeCheckboxIsChecked","text":"

    Signature: dontSeeCheckboxIsChecked($checkbox) : void

    "},{"location":"modules/WPWebDriver/#dontseecookie","title":"dontSeeCookie","text":"

    Signature: dontSeeCookie($cookie, [array $params], [bool $showDebug]) : void

    "},{"location":"modules/WPWebDriver/#dontseecurrenturlequals","title":"dontSeeCurrentUrlEquals","text":"

    Signature: dontSeeCurrentUrlEquals(string $uri) : void

    "},{"location":"modules/WPWebDriver/#dontseecurrenturlmatches","title":"dontSeeCurrentUrlMatches","text":"

    Signature: dontSeeCurrentUrlMatches(string $uri) : void

    "},{"location":"modules/WPWebDriver/#dontseeelement","title":"dontSeeElement","text":"

    Signature: dontSeeElement($selector, [array $attributes]) : void

    "},{"location":"modules/WPWebDriver/#dontseeelementindom","title":"dontSeeElementInDOM","text":"

    Signature: dontSeeElementInDOM($selector, [array $attributes]) : void

    Opposite of seeElementInDOM.

    "},{"location":"modules/WPWebDriver/#dontseeincurrenturl","title":"dontSeeInCurrentUrl","text":"

    Signature: dontSeeInCurrentUrl(string $uri) : void

    "},{"location":"modules/WPWebDriver/#dontseeinfield","title":"dontSeeInField","text":"

    Signature: dontSeeInField($field, $value) : void

    "},{"location":"modules/WPWebDriver/#dontseeinformfields","title":"dontSeeInFormFields","text":"

    Signature: dontSeeInFormFields($formSelector, array $params) : void

    "},{"location":"modules/WPWebDriver/#dontseeinpagesource","title":"dontSeeInPageSource","text":"

    Signature: dontSeeInPageSource(string $text) : void

    Checks that the page source doesn't contain the given string.

    "},{"location":"modules/WPWebDriver/#dontseeinpopup","title":"dontSeeInPopup","text":"

    Signature: dontSeeInPopup(string $text) : void

    Checks that the active JavaScript popup, as created by window.alert|window.confirm|window.prompt, does NOT contain the given string.

    "},{"location":"modules/WPWebDriver/#dontseeinsource","title":"dontSeeInSource","text":"

    Signature: dontSeeInSource($raw) : void

    "},{"location":"modules/WPWebDriver/#dontseeintitle","title":"dontSeeInTitle","text":"

    Signature: dontSeeInTitle($title) : void

    "},{"location":"modules/WPWebDriver/#dontseelink","title":"dontSeeLink","text":"

    Signature: dontSeeLink(string $text, [string $url]) : void

    "},{"location":"modules/WPWebDriver/#dontseeoptionisselected","title":"dontSeeOptionIsSelected","text":"

    Signature: dontSeeOptionIsSelected($selector, $optionText) : void

    "},{"location":"modules/WPWebDriver/#dontseeplugininstalled","title":"dontSeePluginInstalled","text":"

    Signature: dontSeePluginInstalled(string $pluginSlug) : void

    Assert a plugin is not installed in the plugins administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->dontSeePluginInstalled('my-plugin');\n
    "},{"location":"modules/WPWebDriver/#doubleclick","title":"doubleClick","text":"

    Signature: doubleClick($cssOrXPath) : void

    Performs a double click on an element matched by CSS or XPath.

    "},{"location":"modules/WPWebDriver/#draganddrop","title":"dragAndDrop","text":"

    Signature: dragAndDrop($source, $target) : void

    Performs a simple mouse drag-and-drop operation.

    <?php\n$I->dragAndDrop('#drag', '#drop');\n
    "},{"location":"modules/WPWebDriver/#executeasyncjs","title":"executeAsyncJS","text":"

    Signature: executeAsyncJS(string $script, [array $arguments]) : void

    Executes asynchronous JavaScript. A callback should be executed by JavaScript to exit from a script. Callback is passed as a last element in arguments array. Additional arguments can be passed as array in second parameter.

    // wait for 1200 milliseconds my running `setTimeout`\n* $I->executeAsyncJS('setTimeout(arguments[0], 1200)');\n\n$seconds = 1200; // or seconds are passed as argument\n$I->executeAsyncJS('setTimeout(arguments[1], arguments[0])', [$seconds]);\n
    "},{"location":"modules/WPWebDriver/#executeinselenium","title":"executeInSelenium","text":"

    Signature: executeInSelenium(Closure $function) : void

    Low-level API method. If Codeception commands are not enough, this allows you to use Selenium WebDriver methods directly:

    $I->executeInSelenium(function(\\Facebook\\WebDriver\\Remote\\RemoteWebDriver $webdriver) {\n  $webdriver->get('https://google.com');\n});\n

    This runs in the context of the RemoteWebDriver class. Try not to use this command on a regular basis. If Codeception lacks a feature you need, please implement it and submit a patch.

    "},{"location":"modules/WPWebDriver/#executejs","title":"executeJS","text":"

    Signature: executeJS(string $script, [array $arguments]) : void

    Executes custom JavaScript.

    This example uses jQuery to get a value and assigns that value to a PHP variable:

    <?php\n$myVar = $I->executeJS('return $(\"#myField\").val()');\n\n// additional arguments can be passed as array\n// Example shows `Hello World` alert:\n$I->executeJS(\"window.alert(arguments[0])\", ['Hello world']);\n
    "},{"location":"modules/WPWebDriver/#fillfield","title":"fillField","text":"

    Signature: fillField($field, $value) : void

    "},{"location":"modules/WPWebDriver/#grabactivetheme","title":"grabActiveTheme","text":"

    Signature: grabActiveTheme() : ?string

    Returns the slug of the currently active themes.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPWebDriver/#grabattributefrom","title":"grabAttributeFrom","text":"

    Signature: grabAttributeFrom($cssOrXpath, $attribute) : ?string

    "},{"location":"modules/WPWebDriver/#grabavailablethemes","title":"grabAvailableThemes","text":"

    Signature: grabAvailableThemes([string $classes]) : array

    Returns the list of available themes.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPWebDriver/#grabcookie","title":"grabCookie","text":"

    Signature: grabCookie($cookie, [array $params]) : mixed

    "},{"location":"modules/WPWebDriver/#grabcookieswithpattern","title":"grabCookiesWithPattern","text":"

    Signature: grabCookiesWithPattern(string $cookiePattern) : ?array

    Returns all the cookies whose name matches a regex pattern.

    <?php\n$I->loginAs('customer','password');\n$I->amOnPage('/shop');\n$cartCookies = $I->grabCookiesWithPattern(\"#^shop_cart\\\\.*#\");\n
    "},{"location":"modules/WPWebDriver/#grabfromcurrenturl","title":"grabFromCurrentUrl","text":"

    Signature: grabFromCurrentUrl([$uri]) : mixed

    "},{"location":"modules/WPWebDriver/#grabfullurl","title":"grabFullUrl","text":"

    Signature: grabFullUrl() : string

    Grabs the current page full URL including the query vars.

    <?php\n$today = date('Y-m-d');\n$I->amOnPage('/concerts?date=' . $today);\n$I->assertRegExp('#\\\\/concerts$#', $I->grabFullUrl());\n
    "},{"location":"modules/WPWebDriver/#grabmultiple","title":"grabMultiple","text":"

    Signature: grabMultiple($cssOrXpath, [$attribute]) : array

    "},{"location":"modules/WPWebDriver/#grabpagesource","title":"grabPageSource","text":"

    Signature: grabPageSource() : string

    Grabs current page source code.

    "},{"location":"modules/WPWebDriver/#grabtextfrom","title":"grabTextFrom","text":"

    Signature: grabTextFrom($cssOrXPathOrRegex) : mixed

    "},{"location":"modules/WPWebDriver/#grabvaluefrom","title":"grabValueFrom","text":"

    Signature: grabValueFrom($field) : ?string

    "},{"location":"modules/WPWebDriver/#grabwordpresstestcookie","title":"grabWordPressTestCookie","text":"

    Signature: grabWordPressTestCookie([?string $name]) : ?Symfony\\Component\\BrowserKit\\Cookie

    Returns WordPress default test cookie object if present.

    <?php\n// Grab the default WordPress test cookie.\n$wpTestCookie = $I->grabWordPressTestCookie();\n// Grab a customized version of the test cookie.\n$myTestCookie = $I->grabWordPressTestCookie('my_test_cookie');\n
    "},{"location":"modules/WPWebDriver/#loadsessionsnapshot","title":"loadSessionSnapshot","text":"

    Signature: loadSessionSnapshot($name, [bool $showDebug]) : bool

    "},{"location":"modules/WPWebDriver/#logout","title":"logOut","text":"

    Signature: logOut([string|bool $redirectTo]) : void

    Navigate to the default WordPress logout page and click the logout link.

    <?php\n// Log out using the `wp-login.php` form and return to the current page.\n$I->logOut(true);\n// Log out using the `wp-login.php` form and remain there.\n$I->logOut(false);\n// Log out using the `wp-login.php` form and move to another page.\n$I->logOut('/some-other-page');\n
    "},{"location":"modules/WPWebDriver/#loginas","title":"loginAs","text":"

    Signature: loginAs(string $username, string $password, [int $timeout], [int $maxAttempts]) : void

    Login as the specified user.

    The method will not follow redirection, after the login, to any page. Depending on the driven browser the login might be \"too fast\" and the server might have not replied with valid cookies yet; in that case the method will re-attempt the login to obtain the cookies.

    <?php\n$I->loginAs('user', 'password');\n$I->amOnAdminPage('/');\n$I->see('Dashboard');\n
    "},{"location":"modules/WPWebDriver/#loginasadmin","title":"loginAsAdmin","text":"

    Signature: loginAsAdmin([int $timeout], [int $maxAttempts]) : void

    Login as the administrator user using the credentials specified in the module configuration.

    The method will not follow redirection, after the login, to any page.

    <?php\n$I->loginAsAdmin();\n$I->amOnAdminPage('/');\n$I->see('Dashboard');\n
    "},{"location":"modules/WPWebDriver/#makeelementscreenshot","title":"makeElementScreenshot","text":"

    Signature: makeElementScreenshot($selector, [?string $name]) : void

    Takes a screenshot of an element of the current window and saves it to tests/_output/debug.

    <?php\n$I->amOnPage('/user/edit');\n$I->makeElementScreenshot('#dialog', 'edit_page');\n// saved to: tests/_output/debug/edit_page.png\n$I->makeElementScreenshot('#dialog');\n// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png\n
    "},{"location":"modules/WPWebDriver/#makehtmlsnapshot","title":"makeHtmlSnapshot","text":"

    Signature: makeHtmlSnapshot([?string $name]) : void

    "},{"location":"modules/WPWebDriver/#makescreenshot","title":"makeScreenshot","text":"

    Signature: makeScreenshot([?string $name]) : void

    Takes a screenshot of the current window and saves it to tests/_output/debug.

    <?php\n$I->amOnPage('/user/edit');\n$I->makeScreenshot('edit_page');\n// saved to: tests/_output/debug/edit_page.png\n$I->makeScreenshot();\n// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png\n
    "},{"location":"modules/WPWebDriver/#maximizewindow","title":"maximizeWindow","text":"

    Signature: maximizeWindow() : void

    Maximizes the current window.

    "},{"location":"modules/WPWebDriver/#moveback","title":"moveBack","text":"

    Signature: moveBack() : void

    Moves back in history.

    "},{"location":"modules/WPWebDriver/#moveforward","title":"moveForward","text":"

    Signature: moveForward() : void

    Moves forward in history.

    "},{"location":"modules/WPWebDriver/#movemouseover","title":"moveMouseOver","text":"

    Signature: moveMouseOver([$cssOrXPath], [?int $offsetX], [?int $offsetY]) : void

    Move mouse over the first element matched by the given locator. If the first parameter null then the page is used. If the second and third parameters are given, then the mouse is moved to an offset of the element's top-left corner. Otherwise, the mouse is moved to the center of the element.

    <?php\n$I->moveMouseOver(['css' => '.checkout']);\n$I->moveMouseOver(null, 20, 50);\n$I->moveMouseOver(['css' => '.checkout'], 20, 50);\n
    "},{"location":"modules/WPWebDriver/#opennewtab","title":"openNewTab","text":"

    Signature: openNewTab() : void

    Opens a new browser tab and switches to it.

    <?php\n$I->openNewTab();\n
    The tab is opened with JavaScript's window.open(), which means: * Some ad-blockers might restrict it. * The sessionStorage is copied to the new tab (contrary to a tab that was manually opened by the user)

    "},{"location":"modules/WPWebDriver/#performon","title":"performOn","text":"

    Signature: performOn($element, $actions, [int $timeout]) : void

    Waits for element and runs a sequence of actions inside its context. Actions can be defined with array, callback, or Codeception\\Util\\ActionSequence instance.

    Actions as array are recommended for simple to combine \"waitForElement\" with assertions; waitForElement($el) and see('text', $el) can be simplified to:

    <?php\n$I->performOn($el, ['see' => 'text']);\n

    List of actions can be pragmatically build using Codeception\\Util\\ActionSequence:

    <?php\n$I->performOn('.model', ActionSequence::build()\n    ->see('Warning')\n    ->see('Are you sure you want to delete this?')\n    ->click('Yes')\n);\n

    Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to exception on failure.

    Whenever you need to define more actions a callback can be used. A WebDriver module is passed for argument:

    <?php\n$I->performOn('.rememberMe', function (WebDriver $I) {\n     $I->see('Remember me next time');\n     $I->seeElement('#LoginForm_rememberMe');\n     $I->dontSee('Login');\n});\n

    In 3rd argument you can set number a seconds to wait for element to appear

    "},{"location":"modules/WPWebDriver/#presskey","title":"pressKey","text":"

    Signature: pressKey($element, [...$chars]) : void

    Presses the given key on the given element. To specify a character and modifier (e.g. Ctrl, Alt, Shift, Meta), pass an array for $char with the modifier as the first element and the character as the second. For special keys, use the constants from Facebook\\WebDriver\\WebDriverKeys.

    <?php\n// <input id=\"page\" value=\"old\" />\n$I->pressKey('#page','a'); // => olda\n$I->pressKey('#page',array('ctrl','a'),'new'); //=> new\n$I->pressKey('#page',array('shift','111'),'1','x'); //=> old!!!1x\n$I->pressKey('descendant-or-self::*[@id='page']','u'); //=> oldu\n$I->pressKey('#name', array('ctrl', 'a'), \\Facebook\\WebDriver\\WebDriverKeys::DELETE); //=>''\n
    "},{"location":"modules/WPWebDriver/#reloadpage","title":"reloadPage","text":"

    Signature: reloadPage() : void

    Reloads the current page.

    "},{"location":"modules/WPWebDriver/#resetcookie","title":"resetCookie","text":"

    Signature: resetCookie($cookie, [array $params], [bool $showDebug]) : void

    "},{"location":"modules/WPWebDriver/#resizewindow","title":"resizeWindow","text":"

    Signature: resizeWindow(int $width, int $height) : void

    Resize the current window.

    <?php\n$I->resizeWindow(800, 600);\n
    "},{"location":"modules/WPWebDriver/#savesessionsnapshot","title":"saveSessionSnapshot","text":"

    Signature: saveSessionSnapshot($name) : void

    "},{"location":"modules/WPWebDriver/#scrollto","title":"scrollTo","text":"

    Signature: scrollTo($selector, [?int $offsetX], [?int $offsetY]) : void

    Move to the middle of the given element matched by the given locator. Extra shift, calculated from the top-left corner of the element, can be set by passing $offsetX and $offsetY parameters.

    <?php\n$I->scrollTo(['css' => '.checkout'], 20, 50);\n
    "},{"location":"modules/WPWebDriver/#see","title":"see","text":"

    Signature: see($text, [$selector]) : void

    "},{"location":"modules/WPWebDriver/#seecheckboxischecked","title":"seeCheckboxIsChecked","text":"

    Signature: seeCheckboxIsChecked($checkbox) : void

    "},{"location":"modules/WPWebDriver/#seecookie","title":"seeCookie","text":"

    Signature: seeCookie($cookie, [array $params], [bool $showDebug]) : void

    "},{"location":"modules/WPWebDriver/#seecurrenturlequals","title":"seeCurrentUrlEquals","text":"

    Signature: seeCurrentUrlEquals(string $uri) : void

    "},{"location":"modules/WPWebDriver/#seecurrenturlmatches","title":"seeCurrentUrlMatches","text":"

    Signature: seeCurrentUrlMatches(string $uri) : void

    "},{"location":"modules/WPWebDriver/#seeelement","title":"seeElement","text":"

    Signature: seeElement($selector, [array $attributes]) : void

    "},{"location":"modules/WPWebDriver/#seeelementindom","title":"seeElementInDOM","text":"

    Signature: seeElementInDOM($selector, [array $attributes]) : void

    Checks that the given element exists on the page, even it is invisible.

    <?php\n$I->seeElementInDOM('//form/input[type=hidden]');\n
    "},{"location":"modules/WPWebDriver/#seeerrormessage","title":"seeErrorMessage","text":"

    Signature: seeErrorMessage([array|string $classes]) : void

    In an administration screen look for an error admin notice.

    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

    <?php\n$I->loginAsAdmin()\n$I->amOnAdminPage('/');\n$I->seeErrorMessage('.my-plugin');\n
    "},{"location":"modules/WPWebDriver/#seeincurrenturl","title":"seeInCurrentUrl","text":"

    Signature: seeInCurrentUrl(string $uri) : void

    "},{"location":"modules/WPWebDriver/#seeinfield","title":"seeInField","text":"

    Signature: seeInField($field, $value) : void

    "},{"location":"modules/WPWebDriver/#seeinformfields","title":"seeInFormFields","text":"

    Signature: seeInFormFields($formSelector, array $params) : void

    "},{"location":"modules/WPWebDriver/#seeinpagesource","title":"seeInPageSource","text":"

    Signature: seeInPageSource(string $text) : void

    Checks that the page source contains the given string.

    <?php\n$I->seeInPageSource('<link rel=\"apple-touch-icon\"');\n
    "},{"location":"modules/WPWebDriver/#seeinpopup","title":"seeInPopup","text":"

    Signature: seeInPopup(string $text) : void

    Checks that the active JavaScript popup, as created by window.alert|window.confirm|window.prompt, contains the given string.

    "},{"location":"modules/WPWebDriver/#seeinsource","title":"seeInSource","text":"

    Signature: seeInSource($raw) : void

    "},{"location":"modules/WPWebDriver/#seeintitle","title":"seeInTitle","text":"

    Signature: seeInTitle($title) : void

    "},{"location":"modules/WPWebDriver/#seelink","title":"seeLink","text":"

    Signature: seeLink(string $text, [?string $url]) : void

    "},{"location":"modules/WPWebDriver/#seemessage","title":"seeMessage","text":"

    Signature: seeMessage([array|string $classes]) : void

    In an administration screen look for an admin notice.

    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

    <?php\n$I->loginAsAdmin()\n$I->amOnAdminPage('/');\n$I->seeMessage('.missing-api-token.my-plugin');\n
    "},{"location":"modules/WPWebDriver/#seenumberofelements","title":"seeNumberOfElements","text":"

    Signature: seeNumberOfElements($selector, $expected) : void

    "},{"location":"modules/WPWebDriver/#seenumberofelementsindom","title":"seeNumberOfElementsInDOM","text":"

    Signature: seeNumberOfElementsInDOM($selector, $expected) : void

    "},{"location":"modules/WPWebDriver/#seenumberoftabs","title":"seeNumberOfTabs","text":"

    Signature: seeNumberOfTabs(int $number) : void

    Checks current number of opened tabs

    <?php\n$I->seeNumberOfTabs(2);\n
    "},{"location":"modules/WPWebDriver/#seeoptionisselected","title":"seeOptionIsSelected","text":"

    Signature: seeOptionIsSelected($selector, $optionText) : void

    "},{"location":"modules/WPWebDriver/#seepluginactivated","title":"seePluginActivated","text":"

    Signature: seePluginActivated(string $pluginSlug) : void

    Assert a plugin is activated in the plugin administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->seePluginActivated('my-plugin');\n
    "},{"location":"modules/WPWebDriver/#seeplugindeactivated","title":"seePluginDeactivated","text":"

    Signature: seePluginDeactivated(string $pluginSlug) : void

    Assert a plugin is not activated in the plugins administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->seePluginDeactivated('my-plugin');\n
    "},{"location":"modules/WPWebDriver/#seeplugininstalled","title":"seePluginInstalled","text":"

    Signature: seePluginInstalled(string $pluginSlug) : void

    Assert a plugin is installed, no matter its activation status, in the plugin administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    <?php\n$I->loginAsAdmin();\n$I->amOnPluginsPage();\n$I->seePluginInstalled('my-plugin');\n
    "},{"location":"modules/WPWebDriver/#seethemeactivated","title":"seeThemeActivated","text":"

    Signature: seeThemeActivated(string $slug) : void

    Verifies that a theme is active.

    The method will not handle authentication and navigation to the themes administration page.

    "},{"location":"modules/WPWebDriver/#seewpdiepage","title":"seeWpDiePage","text":"

    Signature: seeWpDiePage() : void

    Checks that the current page is one generated by the wp_die function.

    The method will try to identify the page based on the default WordPress die page HTML attributes.

    <?php\n$I->loginAs('user', 'password');\n$I->amOnAdminPage('/forbidden');\n$I->seeWpDiePage();\n
    "},{"location":"modules/WPWebDriver/#selectoption","title":"selectOption","text":"

    Signature: selectOption($select, $option) : void

    "},{"location":"modules/WPWebDriver/#setcookie","title":"setCookie","text":"

    Signature: setCookie($name, $value, [array $params], [$showDebug]) : void

    "},{"location":"modules/WPWebDriver/#submitform","title":"submitForm","text":"

    Signature: submitForm($selector, array $params, [$button]) : void

    Submits the given form on the page, optionally with the given form values. Give the form fields values as an array. Note that hidden fields can't be accessed.

    Skipped fields will be filled by their values from the page. You don't need to click the 'Submit' button afterwards. This command itself triggers the request to form's action.

    You can optionally specify what button's value to include in the request with the last parameter as an alternative to explicitly setting its value in the second parameter, as button values are not otherwise included in the request.

    Examples:

    <?php\n$I->submitForm('#login', [\n    'login' => 'davert',\n    'password' => '123456'\n]);\n// or\n$I->submitForm('#login', [\n    'login' => 'davert',\n    'password' => '123456'\n], 'submitButtonName');\n

    For example, given this sample \"Sign Up\" form:

    <form action=\"/sign_up\">\n    Login:\n    <input type=\"text\" name=\"user[login]\" /><br/>\n    Password:\n    <input type=\"password\" name=\"user[password]\" /><br/>\n    Do you agree to our terms?\n    <input type=\"checkbox\" name=\"user[agree]\" /><br/>\n    Select pricing plan:\n    <select name=\"plan\">\n        <option value=\"1\">Free</option>\n        <option value=\"2\" selected=\"selected\">Paid</option>\n    </select>\n    <input type=\"submit\" name=\"submitButton\" value=\"Submit\" />\n</form>\n

    You could write the following to submit it:

    <?php\n$I->submitForm(\n    '#userForm',\n    [\n        'user[login]' => 'Davert',\n        'user[password]' => '123456',\n        'user[agree]' => true\n    ],\n    'submitButton'\n);\n
    Note that \"2\" will be the submitted value for the \"plan\" field, as it is the selected option.

    Also note that this differs from PhpBrowser, in that 'user' => [ 'login' => 'Davert' ] is not supported at the moment. Named array keys must be included in the name as above.

    Pair this with seeInFormFields for quick testing magic.

    <?php\n$form = [\n     'field1' => 'value',\n     'field2' => 'another value',\n     'checkbox1' => true,\n     // ...\n];\n$I->submitForm('//form[@id=my-form]', $form, 'submitButton');\n// $I->amOnPage('/path/to/form-page') may be needed\n$I->seeInFormFields('//form[@id=my-form]', $form);\n

    Parameter values must be set to arrays for multiple input fields of the same name, or multi-select combo boxes. For checkboxes, either the string value can be used, or boolean values which will be replaced by the checkbox's value in the DOM.

    <?php\n$I->submitForm('#my-form', [\n     'field1' => 'value',\n     'checkbox' => [\n         'value of first checkbox',\n         'value of second checkbox',\n     ],\n     'otherCheckboxes' => [\n         true,\n         false,\n         false,\n     ],\n     'multiselect' => [\n         'first option value',\n         'second option value',\n     ]\n]);\n

    Mixing string and boolean values for a checkbox's value is not supported and may produce unexpected results.

    Field names ending in \"[]\" must be passed without the trailing square bracket characters, and must contain an array for its value. This allows submitting multiple values with the same name, consider:

    <?php\n$I->submitForm('#my-form', [\n    'field[]' => 'value',\n    'field[]' => 'another value', // 'field[]' is already a defined key\n]);\n

    The solution is to pass an array value:

    <?php\n// this way both values are submitted\n$I->submitForm('#my-form', [\n    'field' => [\n        'value',\n        'another value',\n    ]\n]);\n

    The $button parameter can be either a string, an array or an instance of Facebook\\WebDriver\\WebDriverBy. When it is a string, the button will be found by its \"name\" attribute. If $button is an array then it will be treated as a strict selector and a WebDriverBy will be used verbatim.

    For example, given the following HTML:

    <input type=\"submit\" name=\"submitButton\" value=\"Submit\" />\n

    $button could be any one of the following: - 'submitButton' - ['name' => 'submitButton'] - WebDriverBy::name('submitButton')

    "},{"location":"modules/WPWebDriver/#switchtoframe","title":"switchToFrame","text":"

    Signature: switchToFrame([?string $locator]) : void

    Switch to another frame on the page.

    Example:

    <frame name=\"another_frame\" id=\"fr1\" src=\"https://example.com\">\n

    <?php\n# switch to frame by name\n$I->switchToFrame(\"another_frame\");\n# switch to frame by CSS or XPath\n$I->switchToFrame(\"#fr1\");\n# switch to parent page\n$I->switchToFrame();\n
    "},{"location":"modules/WPWebDriver/#switchtoiframe","title":"switchToIFrame","text":"

    Signature: switchToIFrame([?string $locator]) : void

    Switch to another iframe on the page.

    Example:

    <iframe name=\"another_frame\" id=\"fr1\" src=\"https://example.com\">\n

    <?php\n# switch to iframe by name\n$I->switchToIFrame(\"another_frame\");\n# switch to iframe by CSS or XPath\n$I->switchToIFrame(\"#fr1\");\n# switch to parent page\n$I->switchToIFrame();\n
    "},{"location":"modules/WPWebDriver/#switchtonexttab","title":"switchToNextTab","text":"

    Signature: switchToNextTab([int $offset]) : void

    Switches to next browser tab. An offset can be specified.

    <?php\n// switch to next tab\n$I->switchToNextTab();\n// switch to 2nd next tab\n$I->switchToNextTab(2);\n
    "},{"location":"modules/WPWebDriver/#switchtoprevioustab","title":"switchToPreviousTab","text":"

    Signature: switchToPreviousTab([int $offset]) : void

    Switches to previous browser tab. An offset can be specified.

    <?php\n// switch to previous tab\n$I->switchToPreviousTab();\n// switch to 2nd previous tab\n$I->switchToPreviousTab(2);\n
    "},{"location":"modules/WPWebDriver/#switchtowindow","title":"switchToWindow","text":"

    Signature: switchToWindow([?string $name]) : void

    Switch to another window identified by name.

    The window can only be identified by name. If the $name parameter is blank, the parent window will be used.

    Example:

    <input type=\"button\" value=\"Open window\" onclick=\"window.open('https://example.com', 'another_window')\">\n

    <?php\n$I->click(\"Open window\");\n# switch to another window\n$I->switchToWindow(\"another_window\");\n# switch to parent window\n$I->switchToWindow();\n

    If the window has no name, match it by switching to next active tab using switchToNextTab method.

    Or use native Selenium functions to get access to all opened windows:

    <?php\n$I->executeInSelenium(function (\\Facebook\\WebDriver\\Remote\\RemoteWebDriver $webdriver) {\n     $handles=$webdriver->getWindowHandles();\n     $last_window = end($handles);\n     $webdriver->switchTo()->window($last_window);\n});\n
    "},{"location":"modules/WPWebDriver/#type","title":"type","text":"

    Signature: type(string $text, [int $delay]) : void

    Type in characters on active element. With a second parameter you can specify delay between key presses.

    <?php\n// activate input element\n$I->click('#input');\n\n// type text in active element\n$I->type('Hello world');\n\n// type text with a 1sec delay between chars\n$I->type('Hello World', 1);\n

    This might be useful when you an input reacts to typing and you need to slow it down to emulate human behavior. For instance, this is how Credit Card fields can be filled in.

    "},{"location":"modules/WPWebDriver/#typeinpopup","title":"typeInPopup","text":"

    Signature: typeInPopup(string $keys) : void

    Enters text into a native JavaScript prompt popup, as created by window.prompt.

    "},{"location":"modules/WPWebDriver/#uncheckoption","title":"uncheckOption","text":"

    Signature: uncheckOption($option) : void

    "},{"location":"modules/WPWebDriver/#unselectoption","title":"unselectOption","text":"

    Signature: unselectOption($select, $option) : void

    Unselect an option in the given select box.

    "},{"location":"modules/WPWebDriver/#wait","title":"wait","text":"

    Signature: wait($timeout) : void

    Wait for $timeout seconds.

    "},{"location":"modules/WPWebDriver/#waitforelement","title":"waitForElement","text":"

    Signature: waitForElement($element, [int $timeout]) : void

    Waits up to $timeout seconds for an element to appear on the page. If the element doesn't appear, a timeout exception is thrown.

    <?php\n$I->waitForElement('#agree_button', 30); // secs\n$I->click('#agree_button');\n
    "},{"location":"modules/WPWebDriver/#waitforelementchange","title":"waitForElementChange","text":"

    Signature: waitForElementChange($element, Closure $callback, [int $timeout]) : void

    Waits up to $timeout seconds for the given element to change. Element \"change\" is determined by a callback function which is called repeatedly until the return value evaluates to true.

    <?php\nuse \\Facebook\\WebDriver\\WebDriverElement\n$I->waitForElementChange('#menu', function(WebDriverElement $el) {\n    return $el->isDisplayed();\n}, 100);\n
    "},{"location":"modules/WPWebDriver/#waitforelementclickable","title":"waitForElementClickable","text":"

    Signature: waitForElementClickable($element, [int $timeout]) : void

    Waits up to $timeout seconds for the given element to be clickable. If element doesn't become clickable, a timeout exception is thrown.

    <?php\n$I->waitForElementClickable('#agree_button', 30); // secs\n$I->click('#agree_button');\n
    "},{"location":"modules/WPWebDriver/#waitforelementnotvisible","title":"waitForElementNotVisible","text":"

    Signature: waitForElementNotVisible($element, [int $timeout]) : void

    Waits up to $timeout seconds for the given element to become invisible. If element stays visible, a timeout exception is thrown.

    <?php\n$I->waitForElementNotVisible('#agree_button', 30); // secs\n
    "},{"location":"modules/WPWebDriver/#waitforelementvisible","title":"waitForElementVisible","text":"

    Signature: waitForElementVisible($element, [int $timeout]) : void

    Waits up to $timeout seconds for the given element to be visible on the page. If element doesn't appear, a timeout exception is thrown.

    <?php\n$I->waitForElementVisible('#agree_button', 30); // secs\n$I->click('#agree_button');\n
    "},{"location":"modules/WPWebDriver/#waitforjs","title":"waitForJS","text":"

    Signature: waitForJS(string $script, [int $timeout]) : void

    Executes JavaScript and waits up to $timeout seconds for it to return true.

    In this example we will wait up to 60 seconds for all jQuery AJAX requests to finish.

    <?php\n$I->waitForJS(\"return $.active == 0;\", 60);\n
    "},{"location":"modules/WPWebDriver/#waitforjqueryajax","title":"waitForJqueryAjax","text":"

    Signature: waitForJqueryAjax([int $time]) : void

    Waits for any jQuery triggered AJAX request to be resolved.

    <?php\n$I->amOnPage('/triggering-ajax-requests');\n$I->waitForJqueryAjax();\n$I->see('From AJAX');\n
    "},{"location":"modules/WPWebDriver/#waitfortext","title":"waitForText","text":"

    Signature: waitForText(string $text, [int $timeout], [$selector]) : void

    Waits up to $timeout seconds for the given string to appear on the page.

    Can also be passed a selector to search in, be as specific as possible when using selectors. waitForText() will only watch the first instance of the matching selector / text provided. If the given text doesn't appear, a timeout exception is thrown.

    <?php\n$I->waitForText('foo', 30); // secs\n$I->waitForText('foo', 30, '.title'); // secs\n

    Read more in Codeception documentation.

    "},{"location":"traits/UopzFunctions/","title":"UopzFunctions trait","text":"

    This trait provides a set of methods to manipulate functions, methods and class attributes using the uopz PHP extension.

    Warning

    This test trait requires the uopz PHP extension.

    See the Installing the extension locally section of this page for more information about how to do that. If you need to install the extension in a CI environment, see the Installing the extension in CI section of this page.

    If the uopz extension is not installed, test methods using methods from the UopzFunctions trait will be marked as skipped.

    "},{"location":"traits/UopzFunctions/#why-require-an-extension","title":"Why require an extension?","text":"

    Why use a PHP extension instead of a user-land solution, i.e. a PHP library that does not require installing an extension?

    I've written such a solution myself, function-mocker, but have grown frustrated with its limitations, and the limitation of other similar solutions.

    All user-land, monkey-patching, pure PHP solutions rely on stream-wrapping. This is a very powerful feature that this project uses for some of its functionality, but it has a drawbacks when used extensively for monkey-patching functions and methods:

    • the files patch must be included after the library loaded
    • the files have to patched, or patched and cached, on each run
    • there are some random and difficult to track issues introduced by how function and method patching works; e.g. functions manipulating values by reference will not work as expected
    • some constants like __METHOD__ and __FUNCTION__ will not work as expected in the patched files
    • monkey-patching code will be \"inserted\" in the function stack, lengthening the stack trace and making it very difficult to debug
    • all this processing together with XDebug spells doom for the performance of the test suite

    The uopz extension is a solid and fast solution that has been created and maintained by people that know PHP internals and the PHP language very well that has none of the drawbacks of the above-mentioned solutions.

    It is just a better tool for the job.

    "},{"location":"traits/UopzFunctions/#installing-the-extension-locally","title":"Installing the extension locally","text":"WindowsLinuxMacOS
    • Locate your php.ini file:
      php --ini\n
    • Download the latest DLL stable version of the extension from the releases page. You'll likely need the NTS x64 version.
    • Unzip the file and copy the php_uopz.dll file to the ext folder of your PHP installation. If your php.ini file is located at C:\\tools\\php81\\php.ini, the extensions directory will be located at C:\\tools\\php81\\ext.
    • Edit your php.ini file and add the following line to enable and configure the extension:
      extension=uopz\nuopz.exit=1\n
    • Make sure the extension is correctly installed by running php -m and making sure the uopz extension appears in the list of extensions.

    You can find more information about installing PHP extensions on Windows in the PHP manual and in the uopz extension install guide.

    • Use the pecl command to install the extension:
      pecl install uopz\n
    • Configure the extension to ensure it will allow exit and die calls to terminate the script execution. Add the following line to either the main PHP configuration file (php.ini), or a dedicated configuration file:
      uopz.exit=1\n
    • Make sure the extension is correctly installed by running php -m and making sure the uopz extension appears in the list of extensions.

    Alternatively, you can build the extension from source as detailed in the uopz extension install guide.

    • Use the pecl command to install the extension:
      pecl install uopz\n
    • Configure the extension to ensure it will allow exit and die calls to terminate the script execution. Add the following line to either the main PHP configuration file (php.ini), or a dedicated configuration file:
      uopz.exit=1\n
    • Make sure the extension is correctly installed by running php -m and making sure the uopz extension appears in the list of extensions.

    Alternatively, you can build the extension from source as detailed in the uopz extension install guide.

    "},{"location":"traits/UopzFunctions/#installing-the-extension-in-ci","title":"Installing the extension in CI","text":"

    Depending on your Continuous Integration (CI) solution of choice, the configuration required to install and set up the uopz extensions will be different.

    As an example, here is how you can set up the uopz extension in a GitHub Actions job:

    - name: Setup PHP 8.1 with uopz\nuses: shivammathur/setup-php@v2\nwith:\n  php-version: 8.1\n  extensions: uopz\n  ini-values: uopz.exit=1\n

    This project uses the very same setup.

    Most CI systems are based on Linux OSes: if you're not using GitHub Actions, you can reference to the Linux local installation instructions to set up and install the extension for your CI solution of choice.

    "},{"location":"traits/UopzFunctions/#usage","title":"Usage","text":"

    Include the UopzFunctions trait in your test class and use the methods provided by the trait to manipulate functions, methods and class attributes.

    <?php\n\nuse lucatume\\WPBrowser\\WPTestCase;\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_mock_wp_create_nonce()\n    {\n        $this->setFunctionReturn('wp_create_nonce', 'super-secret-nonce');\n\n        $this->assertEquals('super-secret-nonce', wp_create_nonce('some-action'));\n    }\n}\n

    The trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    You can use the UopzFunctions trait in test cases extending the PHUnit\\Framework\\TestCase class as well:

    <?php\n\nuse PHPUnit\\Framework\\TestCase;\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\n\nclass MyTest extends TestCase\n{\n    use UopzFunctions;\n\n    public function test_can_mock_my_function()\n    {\n        $this->setFunctionReturn('someFunction', 'mocked-value');\n\n        $this->assertEquals('mocked-value', someFunction());\n    }\n}\n

    If you need to reset a function return or mock during a test, you can use the unset Closure returned by each method setting up a mock or return value:

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\n\nfunction someFunction()\n{\n    return 'original-value';\n}\n\nclass MyTestWithUopzFunctions extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_mock_my_function()\n    {\n        $unsetSomeFunctionReturn = $this->setFunctionReturn('someFunction', 'mocked-value');\n\n        $this->assertEquals('mocked-value', someFunction());\n\n        $unsetSomeFunctionReturn();\n\n        $this->assertEquals('original-value', someFunction());\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#methods","title":"Methods","text":"

    The UopzFunctions trait provides the following methods:

    "},{"location":"traits/UopzFunctions/#setfunctionreturn","title":"setFunctionReturn","text":"

    setFunctionReturn(string $function, mixed $value, bool $execute = false): Closure

    Set the return value for the function $function to $value. The Closure returned by this method can be used to unset the return value.

    If $value is a closure and $execute is true, then the return value will be the return value of the closure.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_function_return()\n    {\n        $this->setFunctionReturn('wp_generate_nonce', 'super-secret-nonce');\n\n        $this->assertEquals('super-secret-nonce', wp_create_nonce('some-action'));\n    }\n}\n

    If $value is a closure, the original function can be called within the closure to relay the original return value:

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_function_return_with_closure()\n    {\n        $this->setFunctionReturn(\n            'wp_generate_nonce',\n            fn(string $action) => $action === 'test' ? 'test-nonce' : wp_create_nonce($action),\n            true\n        );\n\n        $this->assertEquals('test-nonce', wp_create_nonce('test'));\n        $this->assertNotEquals('test-nonce', wp_create_nonce('some-other-action'));\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetfunctionreturn","title":"unsetFunctionReturn","text":"

    unsetFunctionReturn(string $function): void

    Unset the return value for the function $function previously set with setFunctionReturn.

    You do not need to unset the return value for a function that was set with setFunctionReturn using unsetFunctionReturn explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setmethodreturn","title":"setMethodReturn","text":"

    setMethodReturn(string $class, string $method, mixed $value, bool $execute = false): Closure

    Sets the return value for the static or instance method $method of the class $class to $value. The Closure returned by this method can be used to unset the return value.

    If $value is a closure and $execute is true, then the return value will be the return value of the closure.

    Magic methods like __construct, __destruct, __call and so on cannot be mocked using this method. See the setClassMock method for more information about how to mock magic class methods.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass SomeLegacyClass {\n    public static function staticMethod(){\n        return 'some-static-value';\n    }\n\n    public function instanceMethod(){\n        return 'some-instance-value';\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_method_return()\n    {\n        $this->setMethodReturn(SomeLegacyClass::class, 'staticMethod', 'STATIC');\n        $this->setMethodReturn(SomeLegacyClass::class, 'instanceMethod', 'TEST');\n\n        $legacyClass = new SomeLegacyClass();\n\n        $this->assertEquals('STATIC', SomeLegacyClass::staticMethod());\n        $this->assertEquals('TEST', $legacyClass->instanceMethod());\n    }\n}\n

    If $value is a closure, the original static or instance method can be called within the closure, with correctly bound self and $this context, to relay the original return value:

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass SomeLegacyClass {\n    public static function raiseStaticFlag(bool $flag = false){\n        return $flag ? 'static-flag-raised' : 'static-flag-lowered';\n    }\n\n    public function raiseFlag(bool $flag = false){\n        return $flag ? 'flag-raised' : 'flag-lowered';\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_method_return_with_closure()\n    {\n        $this->setMethodReturn(\n            SomeLegacyClass::class,\n            'raiseStaticFlag',\n            fn(bool $flag) => $flag ? 'STATIC' : self::raiseStaticFlag($flag),\n            true\n        );\n        $this->setMethodReturn(\n            SomeLegacyClass::class,\n            'raiseFlag',\n            fn(bool $flag) => $flag ? 'TEST' : $this->raiseFlag($flag),\n            true\n        );\n\n        $legacyClass = new SomeLegacyClass();\n\n        $this->assertEquals('STATIC', SomeLegacyClass::raiseStaticFlag(true));\n        $this->assertEquals('static-flag-lowered', SomeLegacyClass::raiseStaticFlag(false));\n        $this->assertEquals('TEST', $legacyClass->raiseFlag(true));\n        $this->assertEquals('flag-lowered', $legacyClass->raiseFlag(false));\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetmethodreturn","title":"unsetMethodReturn","text":"

    unsetmethodreturn(string $class, string $method): void

    Unset the return value for the static or instance method $method of the class $class previously set with setMethodReturn.

    You do not need to unset the return value for a method that was set with setMethodReturn using unsetMethodReturn explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setfunctionhook","title":"setFunctionHook","text":"

    setFunctionHook(string $function, Closure $hook): Closure

    Execute $hook when entering the function $function. The Closure returned by this method can be used to unset the hook.

    Hooks can be set on both internal and user-defined functions.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_hook()\n    {\n        $log = [];\n        $this->setFunctionHook(\n            'header', \n            function($header, bool $replace = true, int $response_code = 0) use (&$log): void {\n                $log[] = $header;\n            }\n        );\n\n        header('X-Plugin-Version: 1.0.0');\n        header('X-Plugin-REST-Enabled: 1');\n        header('X-Plugin-GraphQL-Enabled: 0');\n\n        $this->assertEquals([\n            [\n                'X-Plugin-Version' => '1.0.0',\n                'X-Plugin-REST-Enabled' => '1',\n                'X-Plugin-GraphQL-Enabled' => '0'\n        ], $log);\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetfunctionhook","title":"unsetFunctionHook","text":"

    unsetFunctionHook(string $function): void

    Unset the hook for the function $function previously set with setFunctionHook.

    You do not need to unset the hook for a function that was set with setFunctionHook using unsetFunctionHook explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setmethodhook","title":"setMethodHook","text":"

    setMethodHook(string $class, string $method, Closure $hook): Closure

    Execute $hook when entering the static or instance method $method of the class $class. The Closure returned by this method can be used to unset the hook.

    The keywords self and $this will be correctly bound to the class and the class instance respectively.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass LegacyApiController {\n    private static array $connections = [];\n    private ?array $cachedItems = null;\n\n    public static function connect(): self {\n        $connected = new self;\n        self::$connections[] = $connected;\n        return $connected;\n    }\n\n    public function getItems(int $count, int $from = 0): array {\n        if($this->cachedItems === null){\n            $this->cachedItems = wp_remote_get('https://example.com/items');\n        }\n\n        return array_slice($this->cachedItems, $from, $count);\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_method_hook()\n    {\n        $connections = 0;\n        $this->setMethodHook(\n            LegacyApiController::class, \n            'connect', \n            function() use (&$connections): void {\n                $connections  = count(self::$connections) + 1;\n            }\n        );\n        $itemsCacheHits = 0;\n        $this->setMethodHook(\n            LegacyApiController::class, \n            'getItems', \n            function(int $count, int $from = 0) use (&$itemsCacheHit): bool {\n                if($this->cachedItems !== null){\n                    $itemsCacheHits++;\n                }\n            }\n        );\n\n        $connectedController1 = LegacyApiController::connect();\n        $connectedController2 = LegacyApiController::connect();\n        $connectedController1->getItems(10, 0);\n        $connectedController1->getItems(10, 10);\n        $connectedController2->getItems(10, 0);\n        $connectedController2->getItems(10, 10);\n\n        $this->assertEquals(2, $connections);\n        $this->assertEquals(4, $itemsCacheHits);\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetmethodhook","title":"unsetMethodHook","text":"

    unsetMethodHook(string $class, string $method): void

    Unset the hook for the static or instance method $method of the class $class previously set with setMethodHook.

    You do not need to unset the hook for a method that was set with seMethodHook using unsetClassMethodHook explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setconstant","title":"setConstant","text":"

    setConstant(string $constant, mixed $value): Closure

    Set the constant $constant to the value $value. The Closure returned by this method can be used to unset the constant or reset it to its original value.

    If the constant is not already defined, it will be defined and set to the value $value.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_constant()\n    {\n        $this->setconstant('WP_ADMIN', true);\n        $this->setconstant('TEST_CONST', 23);\n\n        $this->assertTrue(wp_is_admin());\n        $this->assertEquals(23, TEST_CONST);\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetconstant","title":"unsetConstant","text":"

    unsetConstant(string $constant): void

    Unset an existing constant or restores the original value of the constant if set with setConstant.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_unset_constant()\n    {\n        // The test is starting in Admin context.\n        $this->assertTrue(is_admin());\n\n        $this->unsetConstant('WP_ADMIN');\n\n        $this->assertFalse(is_admin());\n    }\n}\n

    You do not need to undefine a constant defined with setConstant using unsetConstant explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setclassconstant","title":"setClassConstant","text":"

    setClassConstant(string $class, string $constant, mixed $value): Closure

    Set the constant $constant of the class $class to the value $value. The Closure returned by this method can be used to unset the constant or reset it to its original value.

    If the class constant is not already defined, it will be defined and set to the value $value.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyPlugin {\n    const VERSION = '89.0.0';\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_class_constant()\n    {\n        $this->setClassConstant(MyPlugin::class, 'VERSION', '23.89.0');\n        $this->setClassConstant(MyPlugin::class, 'NOT_EXISTING', 'TEST');\n\n        $this->assertEquals('23.89.0', MyPlugin::VERSION);\n        $this->assertEquals('TEST', MyPlugin::NOT_EXISTING);\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetclassconstant","title":"unsetClassConstant","text":"

    unsetClassConstant(string $class, string $constant): void

    Restore the constant $constant of the class $class to its original value or removes it if it was not defined.

    You do not need to undefine a constant defined with setClassConstant using undefineClassConstant explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setclassmock","title":"setClassMock","text":"

    setClassMock(string $class, string|object $mock): Closure

    Use $mock instead of $class when creating new instances of the class $class. The Closure returned by this method can be used to unset the mock.

    This method allows you to override magic methods as well as you would do with a normal class extension.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MockPaymentApi extends PaymentApi {\n    public static function version($name, $arguments){\n        return '23.89.0';\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_class_mock()\n    {\n        $this->setClassMock(PaymentApi::class, MockPaymentApi::class);\n\n        $paymentApi = new PaymentApi();\n        $this->assertInstanceOf(MyPluginMock::class, $paymentApi);\n        $this->assertSame('23.89.0', $paymentApi::version());\n    }\n}\n

    If you set the $mock to an object, then the same mock object will be used for all the new instances of the class $class:

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MockPaymentApi extends PaymentApi {\n    public function getIds($name, $arguments){\n        return [1, 23, 89];\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_class_mock()\n    {\n        $mockPaymentApi = new MockPaymentApi();\n\n        $this->setClassMock(PaymentApi::class, $mockPaymentApi);\n\n        $api1 = new PaymentApi();\n        $this->assertSame($mockPaymentApi, $api1);\n        $this->assertSame([1, 23, 89], $api1->getIds());\n        $api2 = new PaymentApi();\n        $this->assertSame($mockPaymentApi, $api2);\n        $this->assertSame([1, 23, 89], $api2->getIds());\n    }\n}\n

    The $mock class, or instance, is not required to be a subclass of the class $class by the trait; although it might be required from the code you're testing by means of type hinting.

    If the class or method you would like to set a mock for is final, then you can combine this method with the unsetClassFinalAttribute and unsetMethodFinalAttribute methods to avoid the final attribute being set on the class:

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nfinal class LegacyPaymentApi {\n    public function getIds(){\n        // ... fetch ids from a real external API ...\n    }\n}\n\nclass LegacyCacheController {\n    protected final function get(string $key){\n        // ... fetch data from a real cache ...\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_class_mock()\n    {\n        $this->unsetClassFinalAttribute(LegacyPaymentApi::class);\n        $mockPaymentApi = new class extends LegacyPaymentApi {\n            public function getIds(){\n                return [1, 23, 89];\n            }\n        };\n        $this->setClassMock(LegacyPaymentApi::class, $mockPaymentApi);\n        $this->unsetMethodFinalAttribute(LegacyCacheController::class, 'get');\n        $mockCacheController = new class extends LegacyCacheController {\n            public function get(string $key){\n                return 'some-value';\n            }\n        };\n\n        $paymentApi = new LegacyPaymentApi();\n\n        $this->assertSame($mockPaymentApi, $paymentApi);\n        $this->assertSame([1, 23, 89], $paymentApi->getIds());\n\n        $cacheController = new LegacyCacheController();\n\n        $this->assertSame($mockCacheController, $cacheController);\n        $this->assertSame('some-value', $cacheController->get('some-key'));\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#unsetclassmock","title":"unsetClassMock","text":"

    unsetClassMock(string $class): void

    Remove the mock for the class $class previously set with setMock.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_unset_class_mock()\n    {\n        $this->setClassMock(MyPlugin::class, new MyPluginMock());\n\n        $this->assertInstanceOf(MyPluginMock::class, new MyPlugin());\n\n        $this->unsetClassMock(MyPlugin::class);\n\n        $this->assertInstanceOf(MyPlugin::class, new MyPlugin());\n    }\n}\n

    You do not need to unset the mock for a class that was set with setClassMock using unsetClassMock explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#unsetclassfinalattribute","title":"unsetClassFinalAttribute","text":"

    unsetClassFinalAttribute(string $class): Closure

    Remove the final attribute from the class $class. The Closure returned by this method can be used to reset the final attribute.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nfinal class LegacyPaymentApi {}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_remove_class_final_attribute()\n    {\n        $post = static::factory()->post->createAndGet();\n\n        $this->unsetClassFinalAttribute(LegacyPaymentApi::class);\n\n        // The class is not final anymore; it can be extended for testing purposes.\n        $mockPaymentApi = new class extends LegacyPaymentApi {\n            public function getIds(){\n                return [1, 23, 89];\n            }\n        };\n\n        $this->assertSame([1, 23, 89], $mockPaymentApi->getIds());\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#resetclassfinalattribute","title":"resetClassFinalAttribute","text":"

    resetClassFinalAttribute(string $class): void

    Reset the final attribute of the class $class previously removed with the unsetClassFinalAttribute method.

    You do not need to restore the class final attribute for a class that was set with unsetClassFinalAttribute using setClassFinalAttribute explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#unsetmethodfinalattribute","title":"unsetMethodFinalAttribute","text":"

    unsetMethodFinalAttribute(string $class, string $method): Closure

    Remove the final attribute from the static or instance method $method of the class $class. The Closure returned by this method can be used to reset the final attribute.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_remove_method_final_attribute()\n    {\n        $this->unsetMethodFinalAttribute(LegacyAjaxController::class, 'printResponseAndExit');\n\n        // Build a class to avoid the `printResponseAndExit` method from exiting.\n        $testLegacyAdminController = new class extends LegacyAjaxController {\n            public string $response = '';\n\n            public function printResponseAndExit(){\n                $this->response = $this->template->render('list', return: true);\n                return;\n            }\n        };\n\n        // Set up things for the test ...\n\n        $testLegacyAjaxController->printResponseAndExit();\n\n        $this->assertEquals('<ul><li>Item One</li><li>Item Two</li></ul>', $testLegacyAjaxController->response);\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#restoremethodfinalattribute","title":"restoreMethodFinalAttribute","text":"

    restoreMethodFinalAttribute(string $class, string $method): void

    Restore the final attribute of the method static or instance $method of the class $class previously removed with the unsetMethodFinalAttribute method.

    You do not need to restore the method final attribute for a method that was set with unsetMethodFinalAttribute using restoreMethodFinalAttribute explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#addclassmethod","title":"addClassMethod","text":"

    addClassMethod(string $class, string $method, Closure $closure, bool $static = false): Closure

    Add a public static ($static = true) or instance ($static = false) method to the class $class with the name $method and the code provided by the closure $closure. The Closure returned by this method can be used to remove the method.

    Differently from the setClassMock method, this method will work on already existing instances of the class $class, not just new instances.

    The closure $this will be bound to the class instance.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass LegacySingletonController {\n    private static $instance;\n    private array $cache = null;\n    private int $cacheCount = 0;\n\n    public static function getInstance(){\n        if(!self::$instance){\n            self::$instance = new self();\n        }\n        return self::$instance;\n    }\n\n    public function getItems(int $count, int $from = 0){\n        if($this->cache === null){\n            $this->cache = wp_remote_get('https://example.com/items');\n            $this->cacheCount = count($cache);\n        }\n\n        return array_slice($this->cache, $from, $count);\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_add_class_method()\n    {\n        $controller = LegacySingletonController::getInstance();\n\n        $this->addClassMethod(\n            LegacySingletonController::class, \n            'setCache',\n            function(array $cache): void {\n                $this->cache = $cache;\n                $this->cacheCount = count($cache);\n            }\n        );\n\n        // Set the singletong instance cache for testing purposes.\n        $controller->setCache(range(1,100));\n\n        $this->assertEquals([1,2,3], $controller->getItems(3, 0));\n    }\n
    "},{"location":"traits/UopzFunctions/#removeclassmethod","title":"removeClassMethod","text":"

    removeClassMethod(string $class, string $method): void

    Remove the static or instance method $method added with addClassMethod from the class $class.

    You do not need to remove a method added with addClassMethod, or addClassStaticMethod, using removeClassMethod explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#setobjectproperty","title":"setObjectProperty","text":"

    setObjectProperty(string|object $classOrObject, string $property, mixed $value): Closure

    If $classOrInstance is a string, set the property $property of the class $classOrObject to the value $value. If $classOrInstance is an object, set the property $property of the object $classOrObject to the value $value. The Closure returned by this method can be used to unset the property.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass Payment {\n    private string $uuid;\n    private string $from;\n    private string $to;\n\n    public function __construct(string $from, $string $to){\n        $this->uuid = UUID::generate();\n    }\n\n    public function getHash(): string {\n        return wp_hash(serialize([\n            'uuid' => $this->uuid\n            'from' => $this->from,\n            'to' => $this->to\n        ]));\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_object_property()\n    {\n        $payment = new Payment('Bob', 'Alice');\n\n        $this->setObjectProperty($payment, 'uuid', '550e8400-e29b-41d4-a716-446655440000');\n\n        $this->assertEquals(wp_hash(serialize([\n            'uuid' => '550e8400-e29b-41d4-a716-446655440000',\n            'from' => 'Bob',\n            'to' => 'Alice'\n        ])), $payment->getHash());\n    }\n}\n

    You do not need to reset the property of an object that was set with setObjectProperty explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#getobjectproperty","title":"getObjectProperty","text":"

    getObjectProperty(object $object, string $property): mixed

    Get the value of the static or instance property $property of the object $object.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass LegacyController {\n    private Template $template;\n\n    public function __construct(){\n        $this->template = new Template();\n    }\n\n    // ...\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_get_object_property()\n    {\n        $controller = new LegacyController();\n\n        $templateEngine $this->getObjectProperty($controller, 'template'));\n\n        // ... do something with the template ...\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#resetobjectproperty","title":"resetObjectProperty","text":"

    resetObjectProperty(string|object $classOrObject, string $property): void

    Reset the property $property of the class $class or object $object to its original value.

    You do not need to reset the property of an object that was set with setObjectProperty explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#getmethodstaticvariables","title":"getMethodStaticVariables","text":"

    getMethodStaticVariables(string $class, string $method): array

    Get the value of the static variables of the class $class and method $method.

    The method will work for both static and instance methods of the class $class.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass RequestLogger {\n    public function log(int $code, string $response):void {\n        static $requestId;\n\n        if($requestId === null){\n            $requestId = md5(microtime());\n        }\n\n        printf(\"Request %s: %d %s\\n\", $requestId, $code, $response);\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_get_class_method_static_variables()\n    {\n        $requestLogger = new RequestLogger();\n\n        ob_start();\n        $requestLogger->log(200, 'OK');\n        $requestLogger->log(403, 'Forbidden');\n        $requestLogger->log(200, 'OK');\n        $buffer = ob_get_clean();\n\n        $requestId = $this->getClassMethodStaticVariables(RequestLogger::class, 'log')['requestId'];\n\n        $this->assertEquals(\"Request $requestId: 200 OK\\nRequest $requestId: 403 Forbidden\\nRequest $requestId: 200 OK\\n\", $buffer);\n}\n
    "},{"location":"traits/UopzFunctions/#setmethodstaticvariables","title":"setMethodStaticVariables","text":"

    setMethodStaticVariables(string $class, string $method, array $values): Closure

    Set the static variablesof the class $class and method $method to the values $values. The Closure returned by this method can be used to unset the static variables.

    This will work on both static and instance methods.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass ListComponent {\n    public function render(){\n        static $hash;\n\n        if(!$hash){\n            $hash = md5(microtime());\n        }\n\n        return '<ul screen=' . $hash . '><li>Item One</li><li>Item Two</li></ul>';\n    }\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_class_method_static_variables()\n    {\n        $newValues = array_merge(\n            $this->getMethodStaticVariables(ListComponent::class, 'render'),\n            ['hash' => 'some-hash']\n        );\n        $this->setClassMethodStaticVariables( ListComponent::class, 'render', [\n          'hash' => 'some-hash'\n        ]);\n\n        $component = new ListComponent();\n\n        $this->assertEquals(\n            '<ul data-screen=\"some-hash\"><li>Item One</li><li>Item Two</li></ul>', \n            $component->render()\n        );\n    }\n}\n

    You do not need to reset the static variable of a class method that was set with setMethodStaticVariables explicitly using resetMethodStaticVariables explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#resetmethodstaticvariables","title":"resetMethodStaticVariables","text":"

    resetMethodStaticVariables(string $class, string $method): void

    Resets the static variables of the class $class method $method to their original values.

    "},{"location":"traits/UopzFunctions/#setfunctionstaticvariable","title":"setFunctionStaticVariable","text":"

    setFunctionStaticVariables(string $function, string $variable, mixed $value): Closure

    Set the static variable $variable of the function $function to the value $value. The Closure returned by this method can be used to unset the static variable.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nfunction renderScreen(): string{\n    static $rendered;\n\n    if($rendered){\n        return;\n    }\n\n    $html = '<p>Some HTML</p>';\n\n    $rendered = true;\n\n    return $html;\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_function_static_variables()\n    {\n        $this->setFunctionStaticVariables('renderScreen', ['rendered' => false]);\n\n        $this->assertEquals('<p>Some HTML</p>', renderScreen());\n    }\n}\n

    You do not need to reset the value of a function static variable set using the resetFunctionStaticVariables method explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#getfunctionstaticvariables","title":"getFunctionStaticVariables","text":"

    getFunctionStaticVariables(string $function, ): array

    Get the value of the static variable $variable of the function $function.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nfunction renderScreen(): string {\n    static $screenHash;\n\n    if(!$screenHash){\n        $screenHash = md5(microtime());\n    }\n\n    return '<p data-screen=\"' . $screenHash . '\">Some HTML</p>';\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_set_function_static_variables()\n    {\n        $screenHash = $this->getFunctionStaticVariables('renderScreen')['screenHash'];\n\n        $this->assertEquals('<p data-screen=\"' . $screenHash . '\">Some HTML</p>', renderScreen());\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#resetfunctionstaticvariables","title":"resetFunctionStaticVariables","text":"

    resetFunctionStaticVariables(string $function): void

    Resets the static variables of the function $function set with the setFunctionStaticVariables method.

    "},{"location":"traits/UopzFunctions/#addfunction","title":"addFunction","text":"

    addFunction(string $function, Closure $closure): void

    Add a global or namespaced function to the current scope.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_add_function()\n    {\n        $this->addFunction('myGlobalFunction', fn() => 23);\n        $this->addFunction('Acme\\Project\\namespacedFunction', fn() => 89);\n\n        $this->assertEquals(23, myGlobalFunction());\n        $this->assertEquals(89, Acme\\Project\\namespacedFunction());\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#removefunction","title":"removeFunction","text":"

    removeFunction(string $function): void

    Removes the global or namespaced function $function from the current scope. This will work for functions defined using the addFunction method or defined elsewhere.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_add_function()\n    {\n        $this->addFunction('myGlobalFunction', fn() => 23);\n        $this->addFunction('Acme\\Project\\namespacedFunction', fn() => 89);\n\n        $this->removeFunction('some_plugin_function');\n        $this->removeFunction('Acme\\Project\\namespacedFunction');\n\n        // Added with addFunction.\n        $this->assertFalse(function_exists('myGlobalFunction');\n        $this->assertFalse(function_exists('Acme\\Project\\namespacedFunction');\n\n        $this->assertFalse(function_exists('some_plugin_function');\n        $this->assertFalse(function_exists('Another\\Plugin\\some_function');\n    }\n}\n

    You do not need to remove a function added with addFunction using removeFunction explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"traits/UopzFunctions/#preventexit","title":"preventExit","text":"

    preventExit(): void

    Prevents exit or die calls executed after the method from terminating the PHP process calling exit or die.

    <?php\n\nuse lucatume\\WPBrowser\\Traits\\UopzFunctions;\nuse lucatume\\WPBrowser\\TestCase\\WPTestCase;\n\nfunction printAndDie(): void{\n    print 'Some HTML';\n    die();\n}\n\nclass MyTest extends WPTestCase\n{\n    use UopzFunctions;\n\n    public function test_can_prevent_exit()\n    {\n        $this->preventExit();\n\n        ob_start();\n        printAndDie();\n        $buffer = ob_get_clean();\n\n        $this->assertEquals('Some HTML', $buffer);\n    }\n}\n
    "},{"location":"traits/UopzFunctions/#restoreexit","title":"restoreExit","text":"

    allowExit(): void

    Restores the original behavior of the exit and die functions.

    You do not need to restore the exit behavior for a exit that was prevented using preventExit using allowExit explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

    "},{"location":"v3/","title":"Welcome","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    The wp-browser project provides a Codeception based solution to test WordPress plugins, themes and whole sites at all levels of testing.

    The purpose of this documentation is to help you set up, run and iterate over your project and test code using the powerful APIs provided by Codeception while trying to alleviate the pains of setting it up for WordPress projects.

    Throughout the documentation you will find references to test terminology: I've tried to condense those into small, digestable chunks to provide a rough idea without and a limited context; where required I tried to provide links to dive deeper into the subjects.

    Happy testing!

    "},{"location":"v3/codeception-4-support/","title":"Using wp-browser with Codeception 4.0","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/codeception-4-support/#using-wp-browser-with-codeception-40","title":"Using wp-browser with Codeception 4.0","text":"

    Codeception version 4.0 introduced a number of new features to the framework and it's the version of wp-browser that will be maintained from now on.

    I've made an effort to keep wp-browser compatible with PHP 5.6 and Codeception versions from 2.5 up.

    One the biggest changes of Codeception version 4.0 is that modules have been broken out into separate packages. To use wp-browser with Codeception 4.0 all you need to do is to add this to your project composer.json file:

    {\n  \"require-dev\": {\n    \"lucatume/wp-browser\": \"^2.4\",\n    \"codeception/module-asserts\": \"^1.0\",\n    \"codeception/module-phpbrowser\": \"^1.0\",\n    \"codeception/module-webdriver\": \"^1.0\",\n    \"codeception/module-db\": \"^1.0\",\n    \"codeception/module-filesystem\": \"^1.0\",\n    \"codeception/module-cli\": \"^1.0\",\n    \"codeception/util-universalframework\": \"^1.0\"\n  }\n}\n

    You might not need all the modules listed here, depending on the wp-browser modules you use in your test suites. This is a scheme of what Codeception modules you will need for which wp-browser module to help you choose only the required modules:

    • \"codeception/module-asserts\" - Required for Codeception 4.0 compatibility.
    • \"codeception/module-phpbrowser\" - Required by the WPBrowser module.
    • \"codeception/module-webdriver\" - Required by the WPWebDriver module.
    • \"codeception/module-db\" - Required by the WPDb module.
    • \"codeception/module-filesystem\" - Required by the WPFilesystem module.
    • \"codeception/module-cli\" - Required by the WPCLI module.
    • \"codeception/util-universalframework\" - Required by the WordPress framework module.
    "},{"location":"v3/codeception-phpunit-and-wpbrowser/","title":"Codeception, PHPUnit and wp-browser","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/codeception-phpunit-and-wpbrowser/#the-wp-browser-stack","title":"The wp-browser stack","text":"

    The wp-browser project is built leveraging the power of a number of open-source projects.

    While I'm not listing all of them here it's worth mentioning those that will come up, again and again, in the documentation.

    "},{"location":"v3/codeception-phpunit-and-wpbrowser/#wordpress","title":"WordPress","text":"

    WordPress is open source software you can use to create a beautiful website, blog, or app.

    The line is taken directly from WordPress.org site.

    In the context of this documentation WordPress is the PHP and JavaScript framework websites and web applications can be built on, the one anyone can download from here.

    "},{"location":"v3/codeception-phpunit-and-wpbrowser/#codeception","title":"Codeception","text":"

    Codeception (home) is a modern, powerful PHP testing framework written in PHP.

    It comes with a number of modules and extensions that are comparable to WordPress plugins and themes.

    Modules and extensions are combined in suites to be able to run a specific type of test. Each suite will handle a specific type of test for a specific set of code.

    wp-browser is none other than a collection of modules and extensions for Codeception made specifically to test WordPress applications.

    "},{"location":"v3/codeception-phpunit-and-wpbrowser/#phpunit","title":"PHPUnit","text":"

    PHPUnit is the most widely known PHP testing framework. As the name implies it was born to make unit testing of PHP code easier but its scope and power has grown well below that.

    Codeception is based, and uses, PhpUnit to wrap some of its functionalities into an easy-to-use API. The two are so compatible one with the other that Codeception can run PHPUnit tests with little to no changes.

    This documentation will not cover this subject and will only deal with Codeception-native test methods but you can find more information here.

    "},{"location":"v3/commands/","title":"Commands","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/commands/#custom-commands-provided-by-wp-browser","title":"Custom commands provided by wp-browser","text":"

    The project comes with its own set of custom Codeception commands.

    The commands provide functionalities to quickly scaffold different types of tests. Any other codecept command remains intact and available.

    "},{"location":"v3/commands/#adding-the-commands-to-an-existing-project","title":"Adding the commands to an existing project","text":"

    The commands are added to the main Codeception configuration file, codeception.yml, when scaffolding a project via the codecept init wp-browser command.

    They can be added to any existing project adding, or editing, the commands section of the configuration file:

    extensions:\n    commands:\n        - \"Codeception\\\\Command\\\\GenerateWPUnit\"\n        - \"Codeception\\\\Command\\\\GenerateWPRestApi\"\n        - \"Codeception\\\\Command\\\\GenerateWPRestController\"\n        - \"Codeception\\\\Command\\\\GenerateWPRestPostTypeController\"\n        - \"Codeception\\\\Command\\\\GenerateWPAjax\"\n        - \"Codeception\\\\Command\\\\GenerateWPCanonical\"\n        - \"Codeception\\\\Command\\\\GenerateWPXMLRPC\"\n
    "},{"location":"v3/commands/#generation-commands","title":"Generation commands","text":"

    The library provides commands to quickly scaffold integration test cases for specific types of WordPress components, see levels of testing for more information.

    The tests are almost identical to the ones you could write in a PHPUnit based Core suite with the exception of extending the Codeception\\TestCase\\WPTestCase test case.

    "},{"location":"v3/commands/#generatewpunit","title":"generate:wpunit","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPTestCase class using the

      codecept generate:wpunit suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/commands/#generatewprest","title":"generate:wprest","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPRestApiTestCase class using the

      codecept generate:wprest suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPRestApiTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/commands/#generatewprestcontroller","title":"generate:wprestcontroller","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPRestControllerTestCase class using the

      codecept generate:wprest suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPRestControllerTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/commands/#generatewprestposttypecontroller","title":"generate:wprestposttypecontroller","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPRestPostTypeControllerTestCase class using the

      codecept generate:wprest suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPRestPostTypeControllerTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/commands/#generatewpajax","title":"generate:wpajax","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPAjaxTestCase class using the

      codecept generate:wpajax suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPAjaxTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/commands/#generatewpxmlrpc","title":"generate:wpxmlrpc","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPXMLRPCTestCase class using the

      codecept generate:wpxmlrpc suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPXMLRPCTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/commands/#generatewpcanonical","title":"generate:wpcanonical","text":"

    Generates a test case extending the \\Codeception\\TestCase\\WPCanonicalTestCase class using the

      codecept generate:wpcanonical suite SomeClass\n

    The command will generate a skeleton test case like

    <?php\n\nclass SomeClassTest extends \\Codeception\\TestCase\\WPCanonicalTestCase\n{\n    public function setUp()\n    {\n      parent::setUp();\n    }\n\n    public function tearDown()\n    {\n      parent::tearDown();\n    }\n\n    // tests\n    public function testMe()\n    {\n    }\n\n}\n
    "},{"location":"v3/configuration/","title":"Configuration","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/configuration/#initializing-wp-browser","title":"Initializing wp-browser","text":"

    While wp-browser can be configured manually creating each file the fastest way to bootstrap its configuration is by using its initialization template.

    Throughout the steps below I will use the WordPress setup I've prepared before From the root folder of the project, /Users/luca/Sites/wordpress/wp-content/plugins/acme-plugin in the example, run the command:

    vendor/bin/codecept init wpbrowser\n

    Composer installed Codeception binary (codecept) in the vendor folder of my project.

    With the command above I'm telling Codeception to initialize a wp-browser project in the current folder. When I click enter I'm presented with a list of questions, each answer will be used to configure the wp-browser project for me; one by one.

    In the screenshot the answers I've provided to each question, with reference to the setup above:

    wp-browser will try to provide a brief explanation of what each question is but below is the long version.

    "},{"location":"v3/configuration/#long-question-explanation","title":"Long question explanation","text":"

    I've tried to condense as much clarity as possible in the questions the codecept init wpbrowser command will ask but, for sake of brevity and space, there's no way I could provide inline a deeper explanation of each.

    Below is a longer explanation of each question:

    • How would you like the acceptance suite to be called?
    • How would you like the functional suite to be called?
    • How would you like the WordPress unit and integration suite to be called?
    • How would you like to call the env configuration file?
    • Where is WordPress installed?
    • What is the path, relative to WordPress root URL, of the admin area of the test site?
    • What is the name of the test database used by the test site?
    • What is the host of the test database used by the test site?
    • What is the user of the test database WPLoader should use?
    • What is the password of the test database WPLoader should use?
    • What is the table prefix of the test database WPLoader should use?
    • What is the URL the test site?
    • What is the email of the test site WordPress administrator?
    • What is the title of the test site?
    • What is the login of the administrator user of the test site?
    • What is the password of the administrator user of the test site?
    • Are you testing a plugin, a theme or a combination of both?
    • What is the folder/plugin.php name of the plugin?
    • Are you developing a child theme?
    • Are you using a child theme?
    • What is the slug of the parent theme?
    • What is the slug of the theme?
    • What is the slug of the theme you are using?
    • Does your project needs additional plugins to be activated to work?
    "},{"location":"v3/configuration/#how-would-you-like-the-acceptance-suite-to-be-called","title":"How would you like the acceptance suite to be called?","text":"

    With reference to the testing levels definition this question provides you with the possibility to change the name of the acceptance-like test suite.

    Common, alternative, names are ui, rest and user.

    "},{"location":"v3/configuration/#how-would-you-like-the-functional-suite-to-be-called","title":"How would you like the functional suite to be called?","text":"

    With reference to the testing levels definition this question provides you with the possibility to change the name of the functional-like test suite.

    A common alternative name is service.

    "},{"location":"v3/configuration/#how-would-you-like-the-wordpress-unit-and-integration-suite-to-be-called","title":"How would you like the WordPress unit and integration suite to be called?","text":"

    With reference to the testing levels definition this question provides you with the possibility to change the name of the suite dedicated to integration and \"WordPress unit\" tests.

    A common alternative name is integration.

    "},{"location":"v3/configuration/#how-would-you-like-to-call-the-env-configuration-file","title":"How would you like to call the env configuration file?","text":"

    Instead of configuring each module in each suite with the same parameters over and over Codeception supports dynamic configuration via environment files.

    wp-browser will scaffold such a configuration for you and will use, by default, a file called .env to store the configuration parameters.

    The file name might not suit all setups especially and this question allows changing that file name; common, alternative, file names are .env.tests, .env.codeception and similar.

    "},{"location":"v3/configuration/#where-is-wordpress-installed","title":"Where is WordPress installed?","text":"

    During tests the test code will need to access WordPress code, precisely wp-browser requires being pointed to the folder that contains the wp-load.php file.

    The answer can be an absolute path, like /Users/luca/Sites/wordrpress, or a path relative to the folder where Codeception is installed like vendor/wordpress.

    This path should be accessible by the machine that is running the tests; if you're running the tests from your machine (e.g. your laptop) that's just the path to the folder where WordPress is installed, /Users/luca/Sites/wordpress in the example configuration above.

    If you are, instead, running the tests from within a virtualized machine (e.g. Vagrant or Docker) then the path should be the one used by the virtualized machine.

    To make an example:

    • on my machine WordPress is installed at /Users/luca/Sites/wordpress
    • I've created a Docker container using the official WordPress image and bound the above folder into the container
    • internally the container will put WordPress in the /var/www/html folder

    If I run the tests from my host machine then WordPress root directory will be /Users/luca/Sites/wordpress, if I run the tests from within the Docker container then WordPress root folder will be /var/www/html.

    Another example is Local by Flywheel:

    • in the host machine the path to the WordPress root folder will be /Users/luca/Local\\ Sites/wordpress/app/public
    • from within the Docker container managed by Local the path will be /app/public

    If you need a solution that will work in both instances use a relative path: wp-browser will accept paths like ./../../../wordpress and will attempt to resolve them.

    "},{"location":"v3/configuration/#what-is-the-path-relative-to-wordpress-root-url-of-the-admin-area-of-the-test-site","title":"What is the path, relative to WordPress root URL, of the admin area of the test site?","text":"

    This is usually /wp-admin but you might have the web-server, or a plugin, redirect or hide requests for the administration area to another path.

    Some examples are /admin, /login and the like.

    Mind that this is not the path to the login page but the path to the administrationo area; this will be used by wp-browser to find to the administration area in acceptance and functional tests.

    "},{"location":"v3/configuration/#what-is-the-name-of-the-test-database-used-by-the-test-site","title":"What is the name of the test database used by the test site?","text":"

    In my example setup it's wordpress.

    This is the name of the database that is storing the information used by the site I can reach at http://localhost:8080.

    I want to underline the word \"test\". Any site and any database you use and expose to wp-browser should be intended for tests; this means that it does not contain any data you care about as it will be lost.

    "},{"location":"v3/configuration/#what-is-the-host-of-the-test-database-used-by-the-test-site","title":"What is the host of the test database used by the test site?","text":"

    In my example setup it's 127.0.0.1:3306.

    Here the same principle valid for Where is WordPress installed? applies: the database host is relative to the machine that is running the tests.

    In my example I'm hosting the database locally, on my laptop, and my machine can reach it at the localhost address (127.0.0.1) on MySQL default port (3306).

    If I am using the database of a Local by Flywheel site from my host machine then it might be something like 192.168.92.100:4050 (from the site \"Database\" tab); the same principle applies if I am using a Vagrant-based or Docker-based solution.

    If I am running the tests from within a virtualized machine (a Docker container, a Vagrant box et cetera) then it would probably be localhost or 1270.0.0.1.

    This detail will be used in the context of acceptance and functional tests by the WPDb module.

    "},{"location":"v3/configuration/#what-is-the-user-of-the-test-database-used-by-the-test-site","title":"What is the user of the test database used by the test site?","text":"

    In my example setup it's root as I'm using MySQL server root user to access the database during tests.

    Depending on your setup it might be different; since wp-browser will need to not only read but write too to the database make sure to use a user that has full access to the database specified in the answer to the What is the host of the test database used by the test site? question.

    This detail will be used in the context of acceptance and functional tests by the WPDb module.

    "},{"location":"v3/configuration/#what-is-the-password-of-the-test-database-used-by-the-test-site","title":"What is the password of the test database used by the test site?","text":"

    In my example setup it's empty as I've not set any password for the root account.

    In your case it might be different and it should be the password associated with the user specified in the answer to the What is the user of the test database used by the test site? question.

    This detail will be used in the context of acceptance and functional tests by the WPDb module.

    "},{"location":"v3/configuration/#what-is-the-table-prefix-of-the-test-database-used-by-the-test-site","title":"What is the table prefix of the test database used by the test site?","text":"

    In my example setup it's wp_; that value is taken from the WordPress installation configuration file.

    To have any influence on the site wp-browser will need to modify the same database tables WordPress is using; as I did you can take this value from the wp-config.php file directly: it's the value of the $table_prefix variable.

    This detail will be used in the context of acceptance and functional tests by the WPDb module.

    "},{"location":"v3/configuration/#what-is-the-name-of-the-test-database-wploader-should-use","title":"What is the name of the test database WPLoader should use?","text":"

    In my example setup it's tests.

    During integration, or WordPress \"unit\" tests, wp-loader will need to load WordPress code.

    Since WordPress code is not meant to be \"modular\" it does not support auto-loading or loading just parts of it; it's either almost all or nothing.

    One of the first things WordPress does, when loading, is trying to connect to a database: if that database is not available then WordPress will not load.

    In the answer to the question Where is WordPress installed? I've told wp-browser where to find WordPress code, in this answer I'm telling wp-browser what database it should use to bootstrap WordPress.

    This detail will be used by the WPLoader module to bootstrap WordPress. It's highly recommended to use a different database from the one used for functional and acceptance tests.

    "},{"location":"v3/configuration/#what-is-the-host-of-the-test-database-wploader-should-use","title":"What is the host of the test database WPLoader should use?","text":"

    In my example setup it's 127.0.0.1:3306.

    As in the answer to the question What is the name of the test database WPLoader should use? we're providing connection details about the database that should be used to bootstrap WordPress during integration and WordPress \"unit\" tests.

    Again the database host is in relation to the machine running the tests, all the considerations done for What is the host of the test database used by the test site? apply.

    This detail will be used by the WPLoader module to bootstrap WordPress.

    "},{"location":"v3/configuration/#what-is-the-user-of-the-test-database-wploader-should-use","title":"What is the user of the test database WPLoader should use?","text":"

    In my example it's root.

    Similar to the question What is the user of the test database used by the test site? but in relation to the database specified in the question What is the name of the test database WPLoader should use?.

    This detail will be used by the WPLoader module to bootstrap WordPress.

    "},{"location":"v3/configuration/#what-is-the-password-of-the-test-database-wploader-should-use","title":"What is the password of the test database WPLoader should use?","text":"

    In my example setup it's empty as I've not set any password for the root account.

    Similar to the question What is the password of the test database used by the test site? but in relation to the database specified in the question What is the name of the test database WPLoader should use?.

    This detail will be used by the WPLoader module to bootstrap WordPress.

    "},{"location":"v3/configuration/#what-is-the-table-prefix-of-the-test-database-wploader-should-use","title":"What is the table prefix of the test database WPLoader should use?","text":"

    In my example setup it's wp_.

    Similar to the question What is the table prefix of the test database used by the test site? but in relation to the database specified in the question What is the name of the test database WPLoader should use?.

    This detail will be used by the WPLoader module to bootstrap WordPress.

    "},{"location":"v3/configuration/#what-is-the-url-the-test-site","title":"What is the URL the test site?","text":"

    In my example setup it's http://localhost:8080.

    This is the full URL you would have to enter in the browser, on the machine that is running the tests, to reach the test WordPress site homepage.

    "},{"location":"v3/configuration/#what-is-the-email-of-the-test-site-wordpress-administrator","title":"What is the email of the test site WordPress administrator?","text":"

    In my example setup it's admin@wp.localhost.

    This detail will be used by the WPLoader module to bootstrap WordPress and, while required, it's usually not relevant unless you're testing email communications.

    "},{"location":"v3/configuration/#what-is-the-title-of-the-test-site","title":"What is the title of the test site?","text":"

    In my example setup it's Acme Plugin Test Site.

    This detail will be used by the WPLoader module to bootstrap WordPress and, while required, it's usually not relevant unless you're testing around the site title.

    "},{"location":"v3/configuration/#what-is-the-login-of-the-administrator-user-of-the-test-site","title":"What is the login of the administrator user of the test site?","text":"

    In my example setup it's admin.

    This detail will be used by the WPBrowser or WPWebDriver modules to fill in the login details for the administrator user.

    It should be the same as the one that allows you to access the site administration area in the WordPress test site, http://localhost:8080/wp-admin in my example.

    "},{"location":"v3/configuration/#what-is-the-password-of-the-administrator-user-of-the-test-site","title":"What is the password of the administrator user of the test site?","text":"

    In my example setup it's password.

    This detail will be used by the WPBrowser or WPWebDriver modules to fill in the login details for the administrator user.

    It should be the same as the one that allows you to access the site administration area in the WordPress test site, http://localhost:8080/wp-admin in my example.

    "},{"location":"v3/configuration/#are-you-testing-a-plugin-a-theme-or-a-combination-of-both","title":"Are you testing a plugin, a theme or a combination of both?","text":"

    Depending on the answer the WPLoader module will load, during integration or WordPress \"unit\" tests, your WordPress plugin or theme.

    If you replied with both (for \"a combination of both\") then you'll be able to choose the plugins and theme to load in integration and WordPress \"unit\" tests in the following questions.

    "},{"location":"v3/configuration/#what-is-the-folderpluginphp-name-of-the-plugin","title":"What is the folder/plugin.php name of the plugin?","text":"

    This question will be asked only if you replied plugin to the question Are you testing a plugin, a theme or a combination of both?. In my example setup it's acme-plugin/plugin.php.

    This is the <folder>/<main-plugin-file>.php path, relative to the WordPress installation plugins folder, to the plugin you are testing.

    The main plugin file is the one that contains the plugin header.

    This detail will be used by the WPLoader module to bootstrap WordPress and load your plugin or theme in integration and WordPress \"unit\" tests.

    "},{"location":"v3/configuration/#are-you-developing-a-child-theme","title":"Are you developing a child theme?","text":"

    This question will be asked only if you replied theme to the question Are you testing a plugin, a theme or a combination of both?. Enter yes if you are developing a child theme.

    This detail will be used by the WPLoader module to bootstrap WordPress and load a parent theme along with your theme in integration and WordPress \"unit\" tests.

    Please note that wp-browser will not download and install the parent theme in the WordPress installation for you.

    "},{"location":"v3/configuration/#are-you-using-a-child-theme","title":"Are you using a child theme?","text":"

    This question will be asked only if you replied both to the question Are you testing a plugin, a theme or a combination of both?. Enter yes if you are using a child theme.

    This detail will be used by the WPLoader module to bootstrap WordPress and load a parent theme along with your theme in integration and WordPress \"unit\" tests.

    Please note that wp-browser will not download and install the parent theme in the WordPress installation for you.

    "},{"location":"v3/configuration/#what-is-the-slug-of-the-parent-theme","title":"What is the slug of the parent theme?","text":"

    This question will be asked only if you replied yes to the question Are you developing a child theme?.

    Reply with the slug of the parent theme, that's usually the name of the folder the parent theme lives in, e.g. twentyseventeen.

    This detail will be used by the WPLoader module to bootstrap WordPress and load a parent theme along with your theme in integration and WordPress \"unit\" tests.

    Please note that wp-browser will not download and install the parent theme in the WordPress installation for you.

    "},{"location":"v3/configuration/#what-is-the-slug-of-the-theme","title":"What is the slug of the theme?","text":"

    This question will be asked only if you replied theme to the question Are you testing a plugin, a theme or a combination of both?. Reply with the slug of the theme, that's usually the name of the folder the theme lives in, e.g. twentyseventeen.

    This detail will be used by the WPLoader module to bootstrap WordPress and load your theme in integration and WordPress \"unit\" tests.

    "},{"location":"v3/configuration/#what-is-the-slug-of-the-theme-you-are-using","title":"What is the slug of the theme you are using?","text":"

    This question will be asked only if you replied both to the question Are you testing a plugin, a theme or a combination of both?. Reply with the slug of the theme you are using, that's usually the name of the folder the theme lives in, e.g. twentyseventeen.

    This detail will be used by the WPLoader module to bootstrap WordPress and load the theme integration and WordPress \"unit\" tests.

    "},{"location":"v3/configuration/#does-your-project-needs-additional-plugins-to-be-activated-to-work","title":"Does your project needs additional plugins to be activated to work?","text":"

    Whether you're testing a plugin, a theme or a combination of both you might need some additional plugins to run your tests.

    As an example if I'm testing a WooCommerce extension I need the WooCommerce plugin to test it; this is the place where I can define it.

    The required plugins follow the same format as the one used in the question What is the folder/plugin.php name of the plugin?: <plugin-folder>/<plugin-main-file>.php; in the case of WooCommerce it would be woocommerce/woocommerce.php.

    This detail will be used by the WPLoader module to bootstrap WordPress and load the required plugins in integration and WordPress \"unit\" tests.

    Please note that wp-browser will not download and install the required plugins in the WordPress installation for you.

    "},{"location":"v3/configuration/#if-you-entered-a-wrong-value","title":"If you entered a wrong value","text":"

    No worries, just correct the value in the environment file or in the suites configuration files.

    The environment file will have the name you specified in the answer the question How would you like to call the env configuration file?.

    The suites configuration files can be found in tests/<suite>.suite.yml; e.g. the wpunit suite configuration file will be tests/wpunit.suite.yml file.

    "},{"location":"v3/configuration/#final-steps","title":"Final steps","text":"

    To complete the setup I have removed any demo content from the site and activated my plugin in the plugins administration page.

    In the tests/acceptance.suite.yml file and in the tests/functional.suite.yml file, the configuration file for the acceptance and functional suites respectively, the WPDb module configuration contains a dump configuration parameter:

    class_name: AcceptanceTester\nmodules:\n    enabled:\n        - WPDb\n    config:\n        WPDb:\n            dump: 'tests/_data/dump.sql'\n

    The dump parameter is inherited by the WPDb module from the Codeception Db module and defines the SQL dump file that should be loaded before, and between, tests to reset the testing environment to a base known state.

    As for any other database-related operation wp-browser will not create the dump for me. I use MySQL binary to export the database state (a dump) with the command:

    mysqldump -u root -h 127.0.0.1 -P 3306 wordpress > /Users/luca/Sites/wordpress/wp-content/plugins/acme-plugin/tests/_data/dump.sql\n

    I could use any other combination of tools to produce the dump; using mysql binary is not a requirement.

    Graphic interfaces like SequelPro, Adminer and the like would be perfectly fine.

    "},{"location":"v3/configuration/#pre-flight-check","title":"Pre-flight check","text":"

    There is one last check I need to make before jumping into the creation of tests: making sure all the paths and credentials I've configured wp-browser with are correct.

    The bootstrap process generated four suites for me: acceptance, functional, integration and unit. If you have modified the default suite names during the setup your suites names might differ though.

    To test the setup I will run each suite and make sure it can run correctly empty of any test. To run a suite of tests I will use the codecept run command:

    codecept run acceptance\ncodecept run functional\ncodecept run integration\ncodecept run unit\n

    How comes I'm not using the command codecept run (without specifying the suite names)? See the FAQ entry.

    If you cannot run all the suites without issues then check your configuration settings again, read the errors and see If you entered a wrong value

    "},{"location":"v3/events-api/","title":"Events API","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/events-api/#events-api","title":"Events API","text":"

    Codeception comes with a set of events modules and extensions can subscribe to.

    Codeception Events API is, but, only available to Modules and Extensions, and while that might be good for most cases, it might not cover a number of edge cases.

    Similarly to WordPress add_action function, wp-browser provides the tad\\WPBrowser\\addListener function:

    function addListener($eventName, callable $listener, $priority = 0);\n

    The priority works the reverse way as it does in WordPress: highest number will be processed first!

    Again similarly to WordPress do_action function, the tad\\WPBrowser\\dispatch function:

    function dispatch($eventName, $origin = null, array $context = []);\n

    This is the kind of API that is better shown with an example, though.

    "},{"location":"v3/events-api/#example","title":"Example","text":"

    In this example I'm writing acceptance tests and would like to avoid the performance hit that the cleanup configuration parameter of the Db, or WPDb, module implies. The cleanup parameter will trigger the drop of all tables in the test database and the re-import of the SQL dump file, or files, between each test. This will ensure a clean starting fixture between tests, but for larger setup fixtures this might be a long operation that wastes precious seconds when, say, the only change is the addition of 3 posts, as in this example.

    The Events API allows implementing a tailored clean-up procedure that can avoid costly clean ups between tests.

    In the suite bootstrap file, e.g. tests/acceptance/_bootstrap.php, I add a listener on the my-plugin-test/setup-posts event. The event will contain information about what post IDs I've set up in the tests and will provide an instance of the tester object to handle database manipulation. With that information, the costly cleanup procedure can be avoided.

    <?php\n\n$registerPostsCleanup = static function (tad\\WPBrowser\\Events\\WpbrowserEvent $event) {\n    $ids = $event->get('ids', []);\n    /** @var \\EventsTester $db */\n    $db = $event->get('db');\n\n    // When tests are done, then remove all the posts we've created at the start of the test, if any.\n    tad\\WPBrowser\\addListener(\n        Codeception\\Events::TEST_AFTER,\n        static function () use ($ids, $db) {\n            foreach ($ids as $id) {\n                $db->dontHavePostInDatabase([ 'ID' => $id ], true);\n                // Ensure the clean up did happen correctly.\n                $db->dontSeePostInDatabase([ 'ID' => $id ]);\n                $db->dontSeePostMetaInDatabase([ 'post_id' => $id ]);\n            }\n        }\n    );\n};\n\n// Listen for this event to register the posts to remove, along with their custom fields, after the test.\ntad\\WPBrowser\\addListener('test-event-1/setup-posts', $registerPostsCleanup);\n

    In this simple test I'm adding 3 posts [using the factory provided by the WPLoader module in loadOnly mode][2] and want to make sure those, and the relative meta, are removed at the end of the tests. The WPDb module, extending the Db module from Codeception, will remove the inserted rows, but will not take care of modified rows, or rows not inserted by the WPDb module.

    Mirroring the requirement of the clean up function I've defined above, I'm passing the post IDs of the posts I've created and the current tester to provide the clean up function with database handling capabilities.

    <?php\n/** @var Codeception\\Scenario $scenario */\n$I = new AcceptanceTester($scenario);\n$I->wantTo('add posts and clean them up using the Events API');\n\n/*\n * Use WordPress methods, thanks to the `WPLoader` module, to use WordPress, or our own, API to insert posts.\n * This will prevent, but, `WPDb` from removing the inserted rows and clean up, so we remove the posts and meta\n * with an event and our custom clean-up function.\n */\n$ids = $I->factory()->post->create_many(3, [ 'post_type' => 'some_post_type' ]);\n\ntad\\WPBrowser\\dispatch('test-event-1/setup-posts', __FILE__, [\n    'ids' => $ids,\n    'db'  => $I\n]);\n
    "},{"location":"v3/extensions/","title":"Extensions","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/extensions/#extensions","title":"Extensions","text":"

    The Codeception testing framework can be extended in a number of ways.

    The one this project leverages the most are modules but [extensions are another way].

    Modules extend the functionality of Codeception in the context of the tests, while extensions extend its interaction capacities; this is by no means a strict rule but that's usually the case.

    The package contains two additional extensions to facilitate testers' life.

    "},{"location":"v3/extensions/#symlinker","title":"Symlinker","text":"

    The tad\\WPBrowser\\Extension\\Symlinker extension provides an automation to have the Codeception root directory symbolically linked in a WordPress local installation.

    Since version 3.9 WordPress supports this feature (with some precautions) and the extension takes charge of:

    • symbolically linking a plugin or theme folder in the specified destination before any suite boots up
    • unlinking that symbolic link after all of the suites did run

    It's the equivalent of doing something like this from the command line (on a Mac):

    ln -s /my/central/plugin/folder/my-plugin /my/local/wordpress/installation/wp-content/plugins/my-plugin\n/my/central/plugin/folder/my-plugin/vendor/bin/codecept run\nrm -rf /my/local/wordpress/installation/wp-content/plugins/my-plugin\n

    The extension needs small configuration in the codeception.yml file:

    extensions:\n    enabled:\n        - tad\\WPBrowser\\Extension\\Symlinker\n    config:\n        tad\\WPBrowser\\Extension\\Symlinker:\n            mode: plugin\n            destination: /my/local/wordpress/installation/wp-content/plugins\n            rootFolder: /some/plugin/folder\n

    The arguments are:

    • mode - can be plugin or theme and indicates whether the current Codeception root folder being symlinked is a plugin or a theme one
    • destination - the absolute path to the WordPress local installation plugins or themes folder; to take the never ending variety of possible setups into account the extension will make no checks on the nature of the destination: could be any folder.
    • rootFolder - optional absolute path to the WordPress plugin or theme to be symlinked root folder; will default to the Codeception root folder
    "},{"location":"v3/extensions/#copier","title":"Copier","text":"

    The tad\\WPBrowser\\Extension\\Copier extension provides an automation to have specific files and folders copied to specified destination files and folders before the suites run.

    While WordPress handles symbolic linking pretty well there are some cases, like themes and drop-ins, where there is a need for \"real\" files to be put in place.

    One of such cases is, currently, one where Docker is used to to host and serve the code under test: symbolically linked files cannot be bound inside a container and Docker containers will fail to start in this case.

    The extension follows the standard Codeception extension activation and has one configuration parameter only:

    extensions:\n    enabled:\n        - tad\\WPBrowser\\Extension\\Copier\n    config:\n        tad\\WPBrowser\\Extension\\Copier:\n            files:\n                tests/_data/required-drop-in.php: /var/www/wordpress/wp-content/drop-in.php\n                tests/_data/themes/dummy: /var/www/wordpress/wp-content/themes/dummy\n                /Users/Me/Repos/required-plugin: /var/www/wordpress/wp-content/plugins/required-plugin.php\n                /Users/Me/Repos/mu-plugin.php: ../../../../wp-content/mu-plugins/mu-plugin.php\n

    The extension will handle absolute and relative paths for sources and destinations and will resolve relative paths from the project root folder.

    When copying directories the extension will only create the destination folder and not the folder tree required; in the example configuration above the last entry specifies that a mu-plugin.php file should be copied to the mu-plugins folder: that mu-plugins folder must be there already.

    "},{"location":"v3/extensions/#environments-support","title":"Environments support","text":"

    Being able to symlink a plugin or theme folder into a WordPress installation for testing purposes could make sense when trying to test, as an example, a plugin in a single site and in multi site environment.

    Codeception supports environments and the extension does as well specifying a destination for each.

    As an example the acceptance.suite.yml file might be configured to support single and multisite environments:

    env:\n    single:\n        modules:\n            config:\n                WPBrowser:\n                    url: 'http://wp.dev'\n                WPDb:\n                    dsn: 'mysql:host=127.0.0.1;dbname=wp'\n    multisite:\n        modules:\n            config:\n                WPBrowser:\n                    url: 'http://mu.dev'\n                WPDb:\n                    dsn: 'mysql:host=127.0.0.1;dbname=mu'\n

    In the codeception.yml file specifying a destination for each supported environment will tell the extension to symbolically link the plugin or theme file to different locations according to the current environment:

    extensions:\n    enabled:\n        - tad\\WPBrowser\\Extension\\Symlinker\n    config:\n        tad\\WPBrowser\\Extension\\Symlinker:\n            mode: plugin\n            destination:\n                single: /var/www/wp/wp-content/plugins\n                multisite: /var/www/mu/wp-content/plugins\n

    If no destination is specified for the current environment the extension will fallback to the first specified one.

    A default destination can be specified to override this behaviour.

    extensions:\n    enabled:\n        - tad\\WPBrowser\\Extension\\Symlinker\n    config:\n        tad\\WPBrowser\\Extension\\Symlinker:\n            mode: plugin\n            destination:\n                default: /var/www/default/wp-content/plugins\n                single: /var/www/wp/wp-content/plugins\n                multisite: /var/www/mu/wp-content/plugins\n

    When running a suite specifying more than one environment like

    codecept run acceptance --env foo,baz,multisite\n

    Then the extension will use the first matched one, in the case above the multisite destination will be used.

    The rootFolder parameter too can be set to be environment-aware and it will follow the same logic as the destination:

    extensions:\n    enabled:\n        - tad\\WPBrowser\\Extension\\Symlinker\n    config:\n        tad\\WPBrowser\\Extension\\Symlinker:\n            mode: plugin\n            rootFolder:\n                dev: /\n                dist: /dist\n                default: /\n            destination:\n                default: /var/www/dev/wp-content/plugins\n                dev: /var/www/dev/wp-content/plugins\n                dist: /var/www/dist/wp-content/plugins\n

    When running a suite specifying more than one environment like

    codecept run acceptance --env dist\n

    Then the extension will symlink the files from /dist into the /var/www/dist/wp-content/plugins folder.

    "},{"location":"v3/extensions/#events","title":"Events","text":"

    Due to some internal changes in Codeception 4.0, the internal API (really a collection of low-level hacks on my part) that allowed wp-browser to dispatch, and listen for, events in the modules has been removed.

    If you want to leverage [the event system wp-browser provides] with Codeception default events (e.g. suite.init or test.before), then you will need to use this extension.

    You will not need this extension if you're not using Codeception version 4.0.

    You will need to enable it in your Codeception main configuration file (e.g. codeception.dist.yml).

    extensions:\n    enabled:\n        - tad\\WPBrowser\\Extension\\Events\n    config:\n      tad\\WPBrowser\\Extension\\Events:\n        suites: ['acceptance']\n

    The extension only configuration is the suites parameter that allows specifying the suites the extension should apply to. If the suites parameter is not specified, then the extension will apply to all suites.

    "},{"location":"v3/faq/","title":"Frequently asked questions","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/faq/#some-common-questions","title":"Some common questions","text":"

    There are questions I keep receiving via email, GitHub or in person at conferences.

    I tried to address some of them here.

    "},{"location":"v3/faq/#is-codeceptionwp-browser-php-52-compatible","title":"Is Codeception/wp-browser PHP 5.2 compatible?","text":"

    No, Codeception, and wp-browser by extension, will require PHP 5.6 minimum.

    This does not mean your code cannot be PHP 5.2 compatible: you can test your code using all the possibilities of newer PHP versions and still keep it PHP 5.2 compatible.

    Just because you can doesn't mean you should though: this documentation will assume a minimum PHP version, for the example and test code, of PHP 5.6.

    "},{"location":"v3/faq/#can-i-run-unit-tests-with-wp-browsercodeception","title":"Can I run unit tests with wp-browser/Codeception?","text":"

    Yes, with some distinctions.

    In the WordPress ecosystem there's a tendency to call any kind of test a \"unit test\". Under that definition will fall tests that are not \"unit\" tests at all.

    Without drowning into a long and painful battle for definitions this guide will use the following definitions for different levels of testing.

    The next section will detail the conventions this documentation uses to define different levels of testing in more detail.

    "},{"location":"v3/faq/#isnt-wordpress-untestable","title":"Isn't WordPress untestable?","text":"

    No; it's sometimes difficult to test and not as straightforward as other PHP frameworks but it's definitely not untestable.

    You are writing code that runs on WordPress, not the Core code for WordPress so the question should really be: will you write testable code?

    It's up to you to decide at what level you want to make your code testable and how much you want to test it.

    "},{"location":"v3/faq/#do-i-need-to-use-a-specific-local-development-environment-to-use-wp-browser","title":"Do I need to use a specific local development environment to use wp-browser?","text":"

    No. I've started using wp-browser on a vanilla PHP built-in server to, then, move to MAMP (or XAMP) and, from there, to other solutions.

    I've configured and used wp-browser on Docker, Vagrant, VVV, Valet and various CI solutions.

    To this day I keep using different setups on different machines and personally prefer Docker for its portability.

    "},{"location":"v3/faq/#can-i-only-test-plugins-with-wp-browser","title":"Can I only test plugins with wp-browser?","text":"

    No, you can test any kind of WordPress application.

    With \"application\" I mean any PHP software built on top of WordPress: plugins, themes, whole sites.

    "},{"location":"v3/faq/#if-im-testing-a-site-do-i-have-to-use-the-default-wordpress-file-structure","title":"If I'm testing a site do I have to use the default WordPress file structure?","text":"

    No, you can use any file structure you want.

    Some wp-browser modules will need a little help to find your code but, so far, I've never been unable to set it up.

    "},{"location":"v3/faq/#can-i-use-wp-browser-even-if-my-wordpress-application-doesnt-use-composer","title":"Can I use wp-browser even if my WordPress application doesn't use Composer?","text":"

    Yes, although wp-browser, as a development tool, cannot be installed without Composer.

    "},{"location":"v3/faq/#should-i-use-wp-browser-to-test-my-production-servers","title":"Should I use wp-browser to test my production servers?","text":"

    No. Unless you know very well what you're doing that's a dangerous idea that might leave you with a broken site and an empty database.

    As almost any testing tool, wp-browser should be used locally on local installations of WordPress that do not contain any valuable information.

    "},{"location":"v3/faq/#how-can-i-avoid-the-wpdb-module-from-replacing-the-contents-of-my-database","title":"How can I avoid the WPDb module from replacing the contents of my database?","text":"

    You should always backup any database that contains any information you care about before running any test.

    You can read the answer to this question in the WPDb module documentation.

    "},{"location":"v3/faq/#can-i-run-all-my-tests-with-one-command","title":"Can I run all my tests with one command?","text":"

    Theoretically: yes, in practice: no.

    When you use codecept run Codeception will run all the tests from all the suites.

    This, done in the context of other frameworks, will generally not create any problem but, in the context of WordPress it will.

    While handling a single HTTP request WordPress will set, and use, a number of constants and globals and, likewise, will do plugins and themes that follow WordPress standards.

    This means that the global context (variable scope) will be left \"dirty\" and contain \"left-over\" constants and globals from the previous tests.

    An example is one where a test for the handling of Ajax requests sets the DOING_AJAX constant: this will be now set for any test after the one that set it thus breaking, or worse altering, all the following ones.

    So, in short, run each suite separately.

    "},{"location":"v3/faq/#can-i-have-more-than-one-suite-of-one-kind","title":"Can I have more than one suite of one kind?","text":"

    Yes, you should.

    As an example you might have a frontend suite running acceptance tests on the site frontend and a backend suite running acceptance tests on the site backend.

    Think of suites as a tool to organize your tests: there's a good measure between too organized and not organized at all.

    "},{"location":"v3/faq/#ive-used-phpunit-before-for-my-unit-tests-can-i-reuse-that-knowledge-and-code-with-wp-browser","title":"I've used PHPUnit before for my unit tests, can I reuse that knowledge and code with wp-browser?","text":"

    Yes.

    Codeception uses PHPUnit as one of its main components and can run PHPUnit tests with little or no modification.

    As such you can just move your existing PHPUnit tests in a dedicated suite and be ready to run in minutes.

    "},{"location":"v3/faq/#ive-already-set-up-my-tests-to-run-using-the-core-phpunit-based-test-suite-can-i-keep-using-my-tests","title":"I've already set up my tests to run using the Core PHPUnit-based test suite, can I keep using my tests?","text":"

    Yes.

    Codeception uses PHPUnit as one of its main components and can run PHPUnit tests with little or no modification.

    One of the goals of wp-browser was to make it easier to test WordPress application at an integration level (or \"WordPress unit\" level).

    As such migrating those tests could be a matter of minutes requiring no modification to the tests if not for moving some files and creating a dedicated suite.

    "},{"location":"v3/faq/#why-is-the-project-called-wp-browser","title":"Why is the project called wp-browser?","text":"

    When I started working with Codeception to run my acceptance tests I kept creating steps that I would reuse over and over in my projects.

    I packed them in a module extending the PHPBrowser module.

    Being a natural talent in naming things I've called the module WPBrowser and published it. As I started relying on Codeception more and more I kept adding modules but the name remained.

    "},{"location":"v3/installation/","title":"Installation","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/installation/#installation","title":"Installation","text":""},{"location":"v3/installation/#where-should-i-install-wp-browser","title":"Where should I install wp-browser?","text":"

    As a rule-of-thumb wp-browser should be installed in the root folder of your project.

    If your project is a plugin then it should be installed in the root folder of your plugin; if your project is a theme it should be installed in the root folder of your theme.

    If your project is a site I'd, personally install it in the site root folder.

    The purpose of installing wp-browser in the root folder of a project is to keep the code and its tests under version control together.

    Exceptions apply but, for most projects, that's what I would do.

    "},{"location":"v3/installation/#initializing-the-composer-project","title":"Initializing the Composer project","text":"

    Since Composer is a requirement of wp-browser and the only way to install it you should, first thing, initialize the Composer project.

    If you've already initialized the Composer project you can skip this section.

    Once you've decided where to install wp-browser navigate to that folder using the terminal and type:

    composer init\n

    Composer will take you through a number of questions to setup some meta information about your project.

    Do not install any dependency yet when asked (unless you know what you're doing) and, as a suggestion, set wordpress-plugin as \"Package Type\".

    Also, since WordPress is licensed under the GPL-2.0+ you might want to set the \"License\" of your project to GPL-2.0-or-later.

    "},{"location":"v3/installation/#installing-wp-browser-as-a-development-dependency","title":"Installing wp-browser as a development dependency","text":"

    Once you've initialized the Composer project it's time to require wp-browser ; you can read more about the usage of the require command on the Composer documentation.

    wp-browser is a testing tool and, as such, should be installed as a project development dependency, not as a normal (production) one.

    From the terminal type:

    composer require --dev lucatume/wp-browser\n

    This will install the latest stable version of wp-browser and, along with it, Codeception and PHPUnit in the vendor folder of your project.

    Once that's done it's time to move to the setup and configuration of wp-browser.

    "},{"location":"v3/levels-of-testing/","title":"Levels of testing","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/levels-of-testing/#what-is-a-unit-test-an-acceptance-test","title":"What is a unit test? An acceptance test?","text":"

    This page has no pretense to be THE source of truth about what is called how in the context of tests; the purpose of this page is to lay out the terminology that I'll use in the documentation to define the levels and component of testing. Wikipedia, forums and other documents online will offer alternate, and equally valid, definitions.

    "},{"location":"v3/levels-of-testing/#the-signup-page-example","title":"The signup page example","text":"

    Let's assume I'm testing a WordPress plugin that adds mailing list management and subscription functionalities to a site.

    The plugin provides a number of functions and, among them, it will add a sign-up page to receive users applications.

    "},{"location":"v3/levels-of-testing/#acceptance-tests","title":"Acceptance tests","text":"

    In brief: make assertions as a user would.

    The user might be tech-savvy as much as I want her to be but still make assertions only on what feedback the site provides.

    The code below tests a user can subscribe to the mailing list:

    <?php\n// UserSuccessfulSignupTest.php\n\n// Add a page that contains the shortcode that will render the signup form.\n$I->havePageInDatabase( [\n    'post_name' => 'signup',\n    'post_content'=> 'Sign-up for our awesome thing! [signup]',\n] );\n\n// Go to the page.\n$I->amOnPage( '/signup' );\n\n// Submit the form as a user would submit it. \n$I->submitForm( '#signup-form', [\n  'name' => 'Luca',\n  'email' => 'luca@theAverageDev.com',\n] );\n\n// Make sure I see a confirmation message. \n$I->waitForElement( '#signup-confirmation' );\n
    "},{"location":"v3/levels-of-testing/#functional-tests","title":"Functional tests","text":"

    In brief: make assertions as a developer would.

    The test code below asserts front-end submissions are correctly processed from the developer perspective:

    <?php\n// file tests/functional/SignupSubmissionCest.php\n\nclass SignupSubmissionCest {\n\n    public function _before( FunctionalTester $I ) {\n        // Add a page that contains the shortcode that will render the signup form.\n        $I->havePageInDatabase( [\n            'post_name' => 'signup',\n            'post_content'=> 'Sign-up for our awesome thing! [signup]',\n        ] );\n\n        $I->amOnPage( '/signup' );\n    }\n\n    public function test_good_signup( FunctionalTester $I ) {\n        $I->sendAjaxPostRequest( '/wp-json/acme/v1/signup', [\n          '_wpnonce' => $I->grabAttributeFrom( '#signup-nonce', 'value' ),\n          'name' => 'Luca',\n          'email' => 'luca@theAverageDev.com',\n        ] );\n\n        $I->seeResponseCodeIsSuccessful();\n        $I->seeUserInDatabase( [ 'user_login' => 'luca', 'user_email' => 'luca@theaveragedev.com' ] );\n    }\n\n    public function test_bad_email_signup( FunctionalTester $I ) {\n        $I->sendAjaxPostRequest( '/wp-json/acme/v1/signup', [\n          '_wpnonce' => $I->grabAttributeFrom( '#signup-nonce', 'value' ),\n          'name' => 'Luca',\n          'email' => 'not-really-an-email',\n        ] );\n\n        $I->seeResponseCodeIs( 400 );\n        $I->dontSeeUserInDatabase( [ 'user_login' => 'luca', 'user_email' => 'not-really-an-email' ] );\n    }\n}\n

    The code looks, initially, like an acceptance test, but differs in its action and assertion phase: in place of filling a form and clicking \"Submit\" it sends a POST request to a REST API endpoint and checks the effect of the submission in the database.

    All of these actions fall squarely into what a developer would do, not into what a user could/should be able to do.

    Furthermore, the format of the test is not the same as the one used in the acceptance test.

    The acceptance test is written in the most eloquent testing format supported by Codeception, the Cept format, this test uses a more PHPUnit-like format, the Cest format.

    While the first is easier to skim for non-developers the second harnesses the power of a re-using pieces of code, the page creation and navigation in the example, to optimize the test code.

    "},{"location":"v3/levels-of-testing/#integration-tests","title":"Integration tests","text":"

    In brief: test code modules in the context of a WordPress website.

    In this type of test the WordPress, and additional plugins code, is loaded in the same variable scope as the tests; this is why in the example below I'm using classes (WP_REST_Request, WP_REST_Response) and methods (register_rest_route) defined by WordPress, not the plugin code.

    The REST API request sent by the application form will be handled by a class, Acme\\Signup\\SubmissionHandler, that's been attached to the /wp-json/acme/v1/signup path:

    <?php\n// file src/rest.php\n\nadd_action( 'rest_api_init', function () {\n    register_rest_route( 'acme/v1', '/signup', array(\n        'methods' => 'POST',\n        'callback' => function( WP_Rest_Request $request ) {\n            $email_validator = new Acme\\Signup\\EmailValidator();\n            $handler = new Acme\\Signup\\SubmissionHandler( $email_validator );\n\n            return $handler->handle( $request );\n        },\n    ) );\n} );\n

    I want to test the chain of classes and methods that's handling such a request in the context of a WordPress installation.

    Integration is usually about testing \"modules\" of code: groups of classes and functions working together to provide a service or complete a task.

    In the context of integration testing the class dependencies and/or the context are not mocked.

    <?php\n// file tests/integration/SubmissionHandlingTest.php\n\nclass SubmissionHandlingTest extends \\Codeception\\TestCase\\WPTestCase {\n    public function test_good_request() {\n        $request = new WP_Rest_Request();\n        $request->set_body_params( [ 'name' => 'luca', 'email' => 'luca@theaveragedev.com' ] );\n        $handler = new  Acme\\Signup\\SubmissionHandler();\n\n        $response = $handler->handle( $request );\n\n        $this->assertIntsanceOf( WP_REST_Response::class, $response );\n        $this->assertEquals( 200, $response->get_status() );\n        $this->assertInstanceOf( Acme\\Signup\\Submission_Good::class, $handler->last_submission() );\n        $this->assertEquals( 'luca', $handler->last_submission()->name() );\n        $this->assertEquals( 'luca@theaveragedev.com', $handler->last_submission()->email() );\n    }\n\n    public function test_bad_email_request() {\n        $request = new WP_Rest_Request();\n        $request->set_body_params( [ 'name' => 'luca', 'email' => 'not-a-valid-email' ] );\n        $handler = new  Acme\\Signup\\SubmissionHandler();\n\n        $response = $handler->handle( $request );\n\n        $this->assertIntsanceOf( WP_REST_Response::class, $response );\n        $this->assertEquals( 400, $response->get_status() );\n        $this->assertInstanceOf( Acme\\Signup\\Submission_Bad::class, $handler->last_submission() );\n        $this->assertEquals( 'luca', $handler->last_submission()->name() );\n        $this->assertEquals( 'not-a-valid-email', $handler->last_submission()->email() );\n    }\n}\n

    The test format used is the familiar PhpUnit one; the only difference is the base test class that's being extended (\\Codeception\\TestCase\\WPTestCase) is one provided by wp-browser.

    In the context of WordPress \"integration\" might also mean testing that filters used by the code have the expected effect.

    "},{"location":"v3/levels-of-testing/#unit-tests","title":"Unit tests","text":"

    In brief: test single classes or functions in isolation.

    The email address is validated by the Acme\\Signup\\EmailValidator class.

    In the test code below I want to make sure the validation works as intended.

    <?php\n// file tests/unit/EmailValidatorTest.php\n\nclass EmailValidatorTest extends Codeception\\Test\\Test {\n    public function test_good_email_validation() {\n        $validator = new Acme\\Signup\\EmailValidator();\n\n        $this->assertTrue( $validator->validate( 'luca@theaveragedev.com' ) ); \n    }\n\n    public function test_bad_email_validation(){\n        $validator = new Acme\\Signup\\EmailValidator();\n\n        $this->assertTrue( $validator->validate( 'not-an-email' ) );\n    }\n\n    public function test_tricky_email_validation() {\n        $validator = new Acme\\Signup\\EmailValidator();\n\n        $this->assertTrue( $validator->validate( 'luca+signup@theaveragedev.com' ) ); \n    }\n\n    public function test_validation_with_service(){\n        // Stub the validation service.\n        $validation_service = $this->prophesize( Acme\\Signup\\ValidationService::class );\n        $validation_service->validate( 'luca@theaveragedev.com' )->willReturn( true );\n        $validation_service->validate( 'lucas@theaveragedev.com' )->willReturn( false );\n        // Build the validator and set it to use the mock validation service.\n        $validator = new Acme\\Signup\\EmailValidator();\n        $validator->use_service( $validation_service->reveal() );\n\n        $this->assertTrue( $validator->validate( 'luca@theaveragedev.com' ) );\n        $this->assertFalse( $validator->validate( 'lucas@theaveragedev.com' ) );\n    }\n}\n

    Unit tests is where stubbing/mocking/spying of dependencies is used to gain total control over the input and context the class is using.

    In the last test method I'm doing exactly that testing the email validator with an external validation service.

    In the example I'm using the Prophecy mock engine that comes with PHPUnit along with its own mocking/stubbing/spying solutions.

    There are other mocking engines (e.g Mockery) that could be used.

    "},{"location":"v3/levels-of-testing/#wordpress-unit-tests","title":"WordPress \"unit\" tests","text":"

    In brief: test single classes or functions that require WordPress code in as much isolation as possible.

    This is what most people referring to \"unit tests\" in the context of WordPress is talking about.

    The purpose of this kind of tests is to test one class of a WordPress application, or one function, that requires a WordPress-defined function or class with a unit testing approach.

    In the example below I'm testing the Acme\\Signup\\SubmissionHandler class on a \"unit\" level making sure it will mark a request as bad if the email is not a valid one.

    <?php\n// file tests/unit/SubmissionHandlerTest.php\nclass SubmissionHandlerTest extends Codeception\\Test\\Test {\n    protected  $request;\n    protected $validator;\n\n    public function setUp() {\n        // Mock the request.\n        $this->request = $this->prophesize( WP_REST_Request::class );\n        // Spy on the validator.\n        $this->validator = $this->prophesize( Acme\\Signup\\EmailValidator::class );\n    }\n\n    public function test_email_is_validated_by_default() {\n        $this->request->get_param( 'name' )->willReturn( 'luca' );\n        $this->request->get_param( 'email' )->willReturn( 'luca@theaveragedev.com' );\n\n        $handler = new Acme\\Signup\\SubmissionHandler( $this->validator->reveal() );\n        $handler->set_validator( $this->validator );\n        $response = $handler->handle( $this->request->reveal() );\n\n        $this->assertInstanceOf( WP_REST_Response::class, $response );\n        // Verify on the validator spy.\n        $this->validator->validate( 'luca@theaveragedev.com' )->shouldHaveBeenCalled();\n    }\n\n    public function test_will_not_validate_email_if_missing() {\n        $this->request->get_param( 'name' )->willReturn( 'luca' );\n        $this->request->get_param( 'email' )->willReturn( '' );\n\n        $handler = new Acme\\Signup\\SubmissionHandler( $this->validator->reveal() );\n        $handler->set_validator( $this->validator );\n        $response = $handler->handle( $this->request->reveal() );\n\n        $this->assertInstanceOf( WP_REST_Response::class, $response );\n        // Verify on the validator spy.\n        $this->validator->validate( Argument::any() )->shouldNotHaveBeenCalled();\n    }\n}\n

    The class uses the WP_REST_Request and WP_Rest_Response classes as input and output and will probably, internally, use more functions defined by WordPress.

    One solution to avoid loading WordPress, could be to rewrite test versions of each and all the WordPress functions and classes needed by all the classes I want to unit test; this would require updating each time the classes requirements change.

    Furthermore internationalization (e.g. __()) and filtering (e.g apply_filters) functions would not need to be mocked if not in specific cases and would pretty much be copy and paste versions of the WordPres ones.

    Loading single pieces of WordPress is a dangerous and brittle endeavour and it's not supported by the framework.

    To avoid all this WordPress \"unit tests\" pay the price of having to bootstrap WordPress, thus requiring a database connection.

    This kind of test setup and level is the one you can see in the PHPUnit Core suite of WordPress itself.

    "},{"location":"v3/requirements/","title":"Requirements","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/requirements/#requirements","title":"Requirements","text":"

    wp-browser has some requirements your development environment will need to fulfill for it to work correctly.

    "},{"location":"v3/requirements/#php","title":"PHP","text":"

    The minimum supported version of PHP supported by wp-browser is 5.6.

    This requirement does not reflect on the minimum PHP version your plugin might require; see the FAQs for more information.

    "},{"location":"v3/requirements/#composer","title":"Composer","text":"

    There is no phar version of wp-browser and it can only be installed using Composer.

    See Composer installation guide for more information.

    "},{"location":"v3/requirements/#wordpress-mysql-apachenginx","title":"WordPress, MySQL, Apache/Nginx","text":"

    wp-browser will not download, install and configure WordPress for you.

    It will also not download, install and setup MySQL, Apache, Nginx or any other technology required by a fully functional WordPress installation for you.

    You need to set up a local WordPress installation on your own; you can use your preferred solution to do it.

    In the documentation I will show automated ways to do this but, for most projects, that's not the best solution.

    "},{"location":"v3/setting-up-minimum-wordpress-installation/","title":"Setting up a minimum WordPress installation","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/setting-up-minimum-wordpress-installation/#setting-up-a-minimum-wordpress-installation","title":"Setting up a minimum WordPress installation","text":"

    As mentioned in Installation section wp-browser will not download, configure and install WordPress for you.

    On a high level, once WordPress is installed and configured, whatever local development environment solution you've used, there are some information you'll need to gather before moving into wp-browser configuration.

    While there will be a section dedicated to different environments and setups I will outline below the example setup I will use, in the next section, to configure wp-browser:

    • WordPress is installed, on my machine, at /Users/luca/Sites/wordpress.
    • I'm running MySQL server locally; I can connect to the MySQL server with the command mysql -u root -h 127.0.0.1 -P 3306; there is no password.
    • I've created two databases, wordpress and tests, with the command:
      mysql -u root -h 127.0.0.1 -P 3306 -e \"create database if not exists wordpress; create database if not exists tests\"\n
    • I've configured the /Users/luca/Sites/wordpress/wp-config.php file like below (redacted for brevity):
      <?php\ndefine( 'DB_NAME', 'wordpress' );\ndefine( 'DB_USER', 'root' );\ndefine( 'DB_PASSWORD', '' );\ndefine( 'DB_HOST', '127.0.0.1' );\ndefine( 'DB_CHARSET', 'utf8' );\ndefine( 'DB_COLLATE', '' );\n\n$table_prefix = 'wp_';\n\nif ( ! defined( 'ABSPATH' ) )\n    define( 'ABSPATH', dirname( __FILE__ ) . '/' );\n\nrequire_once ABSPATH . 'wp-settings.php';\n
    • To serve the site I'm using PHP built-in server with the command:
      (cd /Users/luca/Sites/wordpress; php -S localhost:8080)\n
    • I can access the WordPress homepage at http://localhost:8080 and the administration area at http://localhost:8080/wp-admin.
    • I've installed WordPress via its UI (http://localhost:8080/wp-admin), the administrator username is admin, the administrator password is password.
    • I'm testing a plugin and that plugin is in the folder, relative to the WordPress root folder, wp-content/plugins/acme-plugin.

    With all the steps above done I can now move into the actual wp-browser configuration phase.

    "},{"location":"v3/advanced/run-in-separate-process/","title":"Running tests in separate processes","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/advanced/run-in-separate-process/#running-tests-in-separate-processes","title":"Running tests in separate processes","text":"

    PHPUnit offers the possibility to run tests in a separate PHP process; Codeception does not officially support the option as of version 4.0.

    The wp-browser project tries to fill that gap by supporting the @runInSeparateProcess annotation. This support comes with some caveats, though:

    1. The support is only for test cases extending the Codeception\\TestCase\\WPTestCase class (the base test case for integration or \"WordPress unit\" tests)
    2. The support wp-browser provides only supports the @preserveGlobalState annotation with the disabled value; this means there is no support for preserving global state between tests.

    Read more about what this means in PHPUnit documentation.

    "},{"location":"v3/advanced/run-in-separate-process/#why-run-tests-in-a-separate-php-process","title":"Why run tests in a separate PHP process?","text":"

    One main reason: isolation.

    What does \"isolation\" means?

    Before answering that question, it's essential to understand, via an example, why a lack of isolation might be an issue.

    I want to test the get_api function. The function will return the correct singleton instance of an API handling class: an instance of Api when the function is called in non-admin context, and an instance of AdminApi when the function is called in admin context. The get_api function is acting as a service locator.

    <?php\nfunction get_api(){\n    static $api;\n\n    if(null !== $api){\n        return $api;\n    }\n\n    if( is_admin() ) {\n        $api = new Admin_Api();\n    } else {\n        $api = new Api();\n    }\n\n    return $api;\n}\n

    There are two challenges to testing this function:

    1. The is_admin function, defined by WordPress, looks up a WP_ADMIN constant to know if the context of the current request is an administration UI one or not.
    2. The get_api function will check for the context and resolve and build the correct instance only once, the first time it's called in the context of a request.

    There are some possible solutions to this problem:

    a. Refactor the get_api function into a method of an Api_Factory object taking the context as a dependency, thus allowing injection of the \"context\" (which implies the creation of a Context adapter that will proxy its is_admin method to the is_admin function). You can find the code for such refactoring in the OOP refactoring of get_api section. b. Refactor the get_api function to accept the current is_admin value as an input argument, get_api( $is_admin ), this refactoring moves part of the complexity of getting hold of the correct instance of the API handler on the client code. Adding more build condition and checks, e.g., if the current request is a REST request or not or some tests on the user authorizations, then, requires adding more input arguments to the get_api function: the knowledge of the implementation of the get_api method will \"leak\" to the client code having to replicate complexity throughout the system.

    I want to layout possible solutions to the problem to show there is always a design alternative to make code testable that might or might not fit the current time or scope constraint.

    In this example, I've inherited the get_api function from the existing code, and it cannot be changed, yet I want to test it dealing with the two problems outlined above.

    "},{"location":"v3/advanced/run-in-separate-process/#running-tests-in-separate-php-processes","title":"Running tests in separate PHP processes","text":"

    To test the get_api function shown above I've created a new wpunit type of test:

    vendor/bin/codecept g:wpunit integration \"api\"\n

    The command scaffolds a test/integration/apiTest.php file that I've modified to ensure full coverage of the get_api function:

    <?php\n\nclass apiTest extends \\Codeception\\TestCase\\WPTestCase\n{\n    public function test_get_api_exists()\n    {\n        $this->assertTrue(function_exists('get_api'));\n    }\n\n    public function test_get_api_will_cache()\n    {\n        $this->assertSame(get_api(), get_api());\n    }\n\n    /**\n     * @runInSeparateProcess\n     * @preserveGlobalState disabled\n     */\n    public function test_get_api_will_return_api_if_not_admin()\n    {\n        // Let's make sure we're NOT in admin context.\n        define('WP_ADMIN', false);\n\n        $api = get_api();\n\n        $this->assertInstanceOf(Api::class, $api);\n    }\n\n    /**\n     * @runInSeparateProcess\n     * @preserveGlobalState disabled\n     */\n    public function test_get_api_will_cache_api_if_not_admin()\n    {\n        // Let's make sure we're NOT in admin context.\n        define('WP_ADMIN', false);\n\n        $api = get_api();\n\n        $this->assertSame(get_api(), $api);\n    }\n\n    /**\n     * @runInSeparateProcess\n     * @preserveGlobalState disabled\n     */\n    public function test_get_api_will_return_api_if_is_admin()\n    {\n        // Let's make sure we're NOT in admin context.\n        define('WP_ADMIN', true);\n\n        $api = get_api();\n\n        $this->assertInstanceOf(AdminApi::class, $api);\n    }\n\n    /**\n     * @runInSeparateProcess\n     * @preserveGlobalState disabled\n     */\n    public function test_get_api_will_cache_api_if_is_admin()\n    {\n        // Let's make sure we're NOT in admin context.\n        define('WP_ADMIN', true);\n\n        $api = get_api();\n\n        $this->assertSame(get_api(), $api);\n    }\n}\n

    Some pieces of this code are worth pointing out:

    1. There are two test methods, test_get_api_exists and test_get_api_will_cache that are not running in a separate process. Running tests in a separate process provide isolation at the cost of speed, only tests that require isolation should run in a separate PHP process.
    2. I instruct the Codeception and PHPUnit test runner to run a test method in a different process by adding two annotations that are both required ** precisely as shown**:
      /**\n * @runInSeparateProcess\n * @preserveGlobalState disabled\n */\n
    3. The isolation part of this testing approach shines through when I define, in the last four tests, the WP_ADMIN constant multiple times. If I try to do that in test code running in the same PHP process, then the second define call would cause a fatal error.
    4. The isolation has also taken care of the second issue where the get_api function caches the $api instance after its first resolution in a static variable: since each test happens in a self-contained, dedicated PHP process, the static $api variable will be null at the start of each test.
    "},{"location":"v3/advanced/run-in-separate-process/#can-i-run-some-tests-in-the-same-process-and-some-in-a-separate-process","title":"Can I run some tests in the same process and some in a separate process?","text":"

    Yes. In the example test code in the previous section, the test_get_api_exists and test_get_api_will_cache test methods are not running in separate processes.

    In your test cases extending the Codeception\\TestCase\\WPTestCase, you can mix test methods running in the primary PHP process and those running in a separate PHP process without issues.

    "},{"location":"v3/advanced/run-in-separate-process/#oop-refactoring-of-get_api","title":"OOP refactoring of get_api","text":"

    In the Why run tests in a separate PHP process? section I've outlined a possible refactoring of the get_api function to make it testable without requiring the use of separate PHP processes.

    I'm providing this refactoring code below for the sake of completeness, the judgment of which approach is \"better\" is up to the reader.

    <?php\n\nclass Context_Adapter{\n\n    public function is_admin(){\n        return \\is_admin();\n    }\n\n}\n\nclass Api_Factory{\n\n    private $api;\n    private $context;\n\n    public function __construct(Context_Adapter $context){\n        $this->context = $context;\n    }\n\n    public function getApi(){\n        if(null !== $this->api){\n            return $this->api;    \n        }\n\n        if($this->context->is_admin()){\n            $api = new Admin_Api;\n        } else {\n            $api = new Api;\n        }\n\n        return $api;\n    }\n}\n

    Now the Api_Factory class can be injected by injecting a mocked Context_Adapter class, modifying the return value of the Context_Adapter::is_admin method.

    Due to the supposed requirement of the API instance being a singleton, this solution will also require some container or service-locator to ensure at most only one instance of the Api_Factory exists at any given time in the context of a request.

    "},{"location":"v3/migration/from-version-2-to-version-3/","title":"Version 2 to version 3","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/migration/from-version-2-to-version-3/#migrating-projects-from-version-2-of-wp-browser-to-version-3","title":"Migrating projects from version 2 of wp-browser to version 3","text":"

    Version 3 of wp-browser removed, to allow for broader compatibility with PHP and Composer versions, some of its dependencies and modified some of its methods. Here is a list of changes and the suggested courses of action:

    • Removed symfony/process to launch and manage external processes; re-add it your project development requirements using composer require --dev symfony/process.
    • Removed the wp-cli/wp-cli-bundle dependency; if you were relying on non-core packages, then re-add it to your project development requirements using composer require --dev wp-cli/wp-cli-bundle.
    • Removed the WithWpCli::executeBackgroundWpCliCommand trait method, and, as a consequence, the WPCLI::executeBackgroundWpCliCommand module method; you could have used the latter, if this was the case, then require the symfony/process as explained above and launch processes in background using its API; find out more.
    • Refactored the WPCLI module to build and escape string command lines differently; the handling of command-line arguments for the WPCLI module has been modified to make it a bit more consistent and robust; as a consequence, you might experience some breakages in string commands that used to work correctly before; should this be the case then either modify your code to provide the command in array format (taking care of the correct escaping in your code), or make sure to pass a correctly structured command string to the WPCLI module.
    "},{"location":"v3/modules/WPBrowser/","title":"WPBrowser","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/modules/WPBrowser/#wpbrowser-module","title":"WPBrowser module","text":"

    This module should be used in acceptance and functional tests, see levels of testing for more information.

    This module extends the PHPBrowser module adding WordPress-specific configuration parameters and methods.

    The module simulates a user interaction with the site without Javascript support; if you need to test your project with Javascript support use the WPWebDriver module.

    "},{"location":"v3/modules/WPBrowser/#module-requirements-for-codeception-40","title":"Module requirements for Codeception 4.0+","text":"

    This module requires the codeception/module-phpbrowser Composer package to work when wp-browser is used with Codeception 4.0.

    To install the package run:

    composer require --dev codeception/module-phpbrowser:^1.0\n
    "},{"location":"v3/modules/WPBrowser/#configuration","title":"Configuration","text":"

    Since this module extends the PHPBrowser module provided by Codeception, please refer to the PHPBrowser configuration section for more information about the base configuration parameters.

    • url required - Start URL of your WordPress project, e.g. http://wp.test.
    • headers - Default headers are set before each test; this might be useful to simulate a specific user agent during the tests or to identify the request source. Note that the headers defined in the config should be prefaced with HTTP_ in your wp-config.php file. This can be used to select which database to use.
    • handler (default: curl) - The Guzzle handler to use. By default curl is used, also possible to pass stream, or any valid class name as Handler.
    • middleware - The Guzzle middlewares to add. An array of valid callables is required; see here for more information.
    • curl - curl options; only applied if using the curl handler; more options are available.
    • adminUsername required - This is the login name, not the \"nice\" name, of the administrator user of the WordPress test site. This will be used to fill the username field in WordPress login page.
    • adminPassword required - This is the the password of the administrator use of the WordPress test site. This will be used to fill the password in WordPress login page.
    • adminPath required - The path, relative to the WordPress test site home URL, to the administration area, usually /wp-admin.
    "},{"location":"v3/modules/WPBrowser/#example-configuration","title":"Example configuration","text":"
      modules:\n      enabled:\n          - WPBrowser\n      config:\n          WPBrowser:\n              url: 'http://wordpress.localhost'\n              adminUsername: 'admin'\n              adminPassword: 'password'\n              adminPath: '/wp-admin'\n              headers:\n                X_TEST_REQUEST: 1\n                X_WPBROWSER_REQUEST: 1\n

    Read here how to use the headers information to automatically change the database during acceptance and functional tests.

    "},{"location":"v3/modules/WPBrowser/#public-api","title":"Public API","text":"
    • activatePlugin($pluginSlug) : void In the plugin administration screen activates a plugin clicking the \"Activate\" link.

    The method will not handle authentication to the admin area.

    • activateTheme($slug) : void Activates a theme.

    The method will not handle authentication and navigation to the themes administration page.

    • amEditingPostWithId($id) : void Go to the admin page to edit the post with the specified ID.

    The method will not handle authentication the admin area.

    • amEditingUserWithId($id) : void Go to the admin page to edit the user with the specified ID.

    The method will not handle authentication the admin area.

    • amHttpAuthenticated($username, $password) : void

    • amOnAdminAjaxPage([$queryVars]) : void Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

    The method will not handle authentication, nonces or authorization.

    • amOnAdminPage($page) : void Go to a page in the admininstration area of the site.

    This method will not handle authentication to the administration area.

    • amOnCronPage([$queryVars]) : void Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

    • amOnPage($page) : void

    • amOnPagesPage() : void Go the \"Pages\" administration screen.

    The method will not handle authentication.

    • amOnPluginsPage() : void Go to the plugins administration screen.

    The method will not handle authentication.

    • amOnSubdomain($subdomain) : void

    • amOnThemesPage() : void Moves to the themes administration page.

    • amOnUrl($url) : void

    • attachFile($field, $filename) : void

    • checkOption($option) : void

    • click($link, [$context]) : void

    • deactivatePlugin($pluginSlug) : void In the plugin administration screen deactivate a plugin clicking the \"Deactivate\" link.

    The method will not handle authentication and navigation to the plugins administration page.

    • deleteHeader($name) : void Deletes the header with the passed name. Subsequent requests will not have the deleted header in its request.

    Example:

    <?php\n$I->haveHttpHeader('X-Requested-With', 'Codeception');\n$I->amOnPage('test-headers.php');\n// ...\n$I->deleteHeader('X-Requested-With');\n$I->amOnPage('some-other-page.php');\n

    • dontSee($text, [$selector]) : void

    • dontSeeCheckboxIsChecked($checkbox) : void

    • dontSeeCookie($cookie, [array $params]) : void

    • dontSeeCurrentUrlEquals($uri) : void

    • dontSeeCurrentUrlMatches($uri) : void

    • dontSeeElement($selector, [$attributes]) : void

    • dontSeeInCurrentUrl($uri) : void

    • dontSeeInField($field, $value) : void

    • dontSeeInFormFields($formSelector, array $params) : void

    • dontSeeInSource($raw) : void

    • dontSeeInTitle($title) : void

    • dontSeeLink($text, [$url]) : void

    • dontSeeOptionIsSelected($selector, $optionText) : void

    • dontSeePluginInstalled($pluginSlug) : void Assert a plugin is not installed in the plugins administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    • dontSeeResponseCodeIs($code) : void Checks that response code is equal to value provided.
    <?php\n$I->dontSeeResponseCodeIs(200);\n\n// recommended \\Codeception\\Util\\HttpCode\n$I->dontSeeResponseCodeIs(\\Codeception\\Util\\HttpCode::OK);\n
    • executeInGuzzle(Closure $function) : void Low-level API method. If Codeception commands are not enough, use Guzzle HTTP Client methods directly

    Example:

    <?php\n$I->executeInGuzzle(function (\\GuzzleHttp\\Client $client) {\n     $client->get('/get', ['query' => ['foo' => 'bar']]);\n});\n?>\n

    It is not recommended to use this command on a regular basis. If Codeception lacks important Guzzle Client methods, implement them and submit patches.

    • fillField($field, $value) : void

    • followRedirect() : void Follow pending redirect if there is one.

    <?php\n$I->followRedirect();\n
    • grabActiveTheme() : void Returns the slug of the currently active themes.

    The method will not handle authentication and navigation to the themes administration page.

    • grabAttributeFrom($cssOrXpath, $attribute) : void

    • grabAvailableThemes([$classes]) : void Returns the list of available themes.

    The method will not handle authentication and navigation to the themes administration page.

    • grabCookie($cookie, [array $params]) : void

    • grabCookiesWithPattern($cookiePattern) : void Returns all the cookies whose name matches a regex pattern.

    • grabFromCurrentUrl([$uri]) : void

    • grabMultiple($cssOrXpath, [$attribute]) : void

    • grabPageSource() : void Grabs current page source code.

    • grabTextFrom($cssOrXPathOrRegex) : void

    • grabValueFrom($field) : void

    • grabWordPressTestCookie([$name]) : void Returns WordPress default test cookie object if present.

    • haveHttpHeader($name, $value) : void Sets the HTTP header to the passed value - which is used on subsequent HTTP requests through PhpBrowser.

    Example:

    <?php\n$I->haveHttpHeader('X-Requested-With', 'Codeception');\n$I->amOnPage('test-headers.php');\n

    To use special chars in Header Key use HTML Character Entities: Example: Header with underscore - 'Client_Id' should be represented as - 'Client_Id' or 'Client_Id'

    <?php\n$I->haveHttpHeader('Client&#95;Id', 'Codeception');\n
    • haveServerParameter($name, $value) : void Sets SERVER parameter valid for all next requests.
    $I->haveServerParameter('name', 'value');\n
    • logOut([$redirectTo]) : void Navigate to the default WordPress logout page and click the logout link.

    • loginAs($username, $password) : void Login as the specified user.

    The method will not follow redirection, after the login, to any page.

    • loginAsAdmin() : void Login as the administrator user using the credentials specified in the module configuration.

    The method will not follow redirection, after the login, to any page.

    • makeHtmlSnapshot([$name]) : void

    • moveBack([$numberOfSteps]) : void Moves back in history.

    • resetCookie($cookie, [array $params]) : void

    • see($text, [$selector]) : void

    • seeCheckboxIsChecked($checkbox) : void

    • seeCookie($cookie, [array $params]) : void

    • seeCurrentUrlEquals($uri) : void

    • seeCurrentUrlMatches($uri) : void

    • seeElement($selector, [$attributes]) : void

    • seeErrorMessage([$classes]) : void In an administration screen look for an error admin notice.

    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

    • seeInCurrentUrl($uri) : void

    • seeInField($field, $value) : void

    • seeInFormFields($formSelector, array $params) : void

    • seeInSource($raw) : void

    • seeInTitle($title) : void

    • seeLink($text, [$url]) : void

    • seeMessage([$classes]) : void In an administration screen look for an admin notice.

    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

    • seeNumberOfElements($selector, $expected) : void

    • seeOptionIsSelected($selector, $optionText) : void

    • seePageNotFound() : void Asserts that current page has 404 response status code.

    • seePluginActivated($pluginSlug) : void Assert a plugin is activated in the plugin administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    • seePluginDeactivated($pluginSlug) : void Assert a plugin is not activated in the plugins administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    • seePluginInstalled($pluginSlug) : void Assert a plugin is installed, no matter its activation status, in the plugin administration screen.

    The method will not handle authentication and navigation to the plugin administration screen.

    • seeResponseCodeIs($code) : void Checks that response code is equal to value provided.
    <?php\n$I->seeResponseCodeIs(200);\n\n// recommended \\Codeception\\Util\\HttpCode\n$I->seeResponseCodeIs(\\Codeception\\Util\\HttpCode::OK);\n
    • seeResponseCodeIsBetween($from, $to) : void Checks that response code is between a certain range. Between actually means [from <= CODE <= to]

    • seeResponseCodeIsClientError() : void Checks that the response code is 4xx

    • seeResponseCodeIsRedirection() : void Checks that the response code 3xx

    • seeResponseCodeIsServerError() : void Checks that the response code is 5xx

    • seeResponseCodeIsSuccessful() : void Checks that the response code 2xx

    • seeThemeActivated($slug) : void Verifies that a theme is active.

    The method will not handle authentication and navigation to the themes administration page.

    • seeWpDiePage() : void Checks that the current page is one generated by the wp_die function.

    The method will try to identify the page based on the default WordPress die page HTML attributes.

    • selectOption($select, $option) : void

    • sendAjaxGetRequest($uri, [$params]) : void Sends an ajax GET request with the passed parameters. See sendAjaxPostRequest()

    • sendAjaxPostRequest($uri, [$params]) : void Sends an ajax POST request with the passed parameters. The appropriate HTTP header is added automatically: X-Requested-With: XMLHttpRequest Example:

      <?php\n$I->sendAjaxPostRequest('/add-task', ['task' => 'lorem ipsum']);\n
      Some frameworks (e.g. Symfony) create field names in the form of an \"array\": <input type=\"text\" name=\"form[task]\"> In this case you need to pass the fields like this:
      <?php\n$I->sendAjaxPostRequest('/add-task', ['form' => [\n    'task' => 'lorem ipsum',\n    'category' => 'miscellaneous',\n]]);\n

    • sendAjaxRequest($method, $uri, [$params]) : void Sends an ajax request, using the passed HTTP method. See sendAjaxPostRequest() Example:

      <?php\n$I->sendAjaxRequest('PUT', '/posts/7', ['title' => 'new title']);\n

    • setCookie($name, $val, [array $params]) : void

    • setHeader($name, $value) : void Alias to haveHttpHeader

    • setMaxRedirects($maxRedirects) : void Sets the maximum number of redirects that the Client can follow.

    <?php\n$I->setMaxRedirects(2);\n
    • setServerParameters(array $params) : void Sets SERVER parameters valid for all next requests. this will remove old ones.
    $I->setServerParameters([]);\n
    • startFollowingRedirects() : void Enables automatic redirects to be followed by the client.
    <?php\n$I->startFollowingRedirects();\n
    • stopFollowingRedirects() : void Prevents automatic redirects to be followed by the client.
    <?php\n$I->stopFollowingRedirects();\n
    • submitForm($selector, array $params, [$button]) : void

    • switchToIframe($name) : void Switch to iframe or frame on the page.

    Example:

    <iframe name=\"another_frame\" src=\"http://example.com\">\n

    <?php\n# switch to iframe\n$I->switchToIframe(\"another_frame\");\n
    • uncheckOption($option) : void

    This class extends \\Codeception\\Module\\PhpBrowser

    This class implements \\Codeception\\Lib\\Interfaces\\MultiSession, \\Codeception\\Lib\\Interfaces\\Remote, \\Codeception\\Lib\\Interfaces\\Web, \\Codeception\\Lib\\Interfaces\\PageSourceSaver, \\Codeception\\Lib\\Interfaces\\ElementLocator, \\Codeception\\Lib\\Interfaces\\ConflictsWithModule

    "},{"location":"v3/modules/WPCLI/","title":"WPCLI","text":"

    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

    "},{"location":"v3/modules/WPCLI/#wpcli-module","title":"WPCLI module","text":"

    This module should be used in acceptance and functional tests to setup, or verify, tests pre and post conditions using WP-CLI commands. This module allows invoking WP-CLI commands, refer to the official site for more information.

    The module will use its own version of WP-CLI, not the one installed in the machine running the tests!

    By default, wp-browser will only include the wp-cli/wp-cli package; this package contains the basic files to run WP-CLI and does not contain all the commands that come with a typical wp-cli installation. If, in your tests, you require all the commands that usually come installed with WP-CLI, then you should require the wp-cli/wp-cli-bundle package as a development dependency of your project, see below.

    "},{"location":"v3/modules/WPCLI/#fixing-not-a-registered-command-issue","title":"Fixing \"not a registered command\" issue","text":"

    To keep the conflicts at a manageable level, the wp-browser project does not include all the commands WP-CLI usually comes bundled with. Running, in the context of an automated test, a WP-CLI command that would work on your machine, e.g. wp plugin list --status=active, will not work on a default installation of wp-browser and you will get the following error message:

    [ModuleException] WPCLI: wp-cli terminated with status [1] and output [Error: 'plugin' is not a registered wp command. See 'wp help' for available commands.]\n

    To resolve the message just add the package you require as a development dependency or add the whole WP-CLI bundle:

    composer require --dev wp-cli/wp-cli-bundle\n

    The package will make all the default WP-CLI commands available to the WP-CLI version used in tests.

    "},{"location":"v3/modules/WPCLI/#module-requirements-for-codeception-40","title":"Module requirements for Codeception 4.0+","text":"

    This module requires the codeception/module-cli Composer package to work when wp-browser is used with Codeception 4.0.

    To install the package run:

    composer require --dev codeception/module-cli:^1.0\n
    "},{"location":"v3/modules/WPCLI/#detecting-requests-coming-from-this-module","title":"Detecting requests coming from this module","text":"

    When it runs this module will set the WPBROWSER_HOST_REQUEST environment variable. You can detect and use that information to, as an example, use the correct database in your test site wp-config.php file:

    <?php\nif ( \n    // Custom header.\n    isset( $_SERVER['HTTP_X_TESTING'] )\n    // Custom user agent.\n    || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )\n    // The env var set by the WPClIr or WordPress modules.\n    || getenv( 'WPBROWSER_HOST_REQUEST' )\n) {\n    // Use the test database if the request comes from a test.\n    define( 'DB_NAME', 'wordpress_test' );\n} else {\n    // Else use the default one.\n    define( 'DB_NAME', 'wordpress' );\n}\n

    "},{"location":"v3/modules/WPCLI/#configuration","title":"Configuration","text":"
    • path required - the absolute, or relative, path to the WordPress root folder. This will be mapped to the --path argument of the wp-cli binary.
    • throw - defaults to true to throw an exception when a wp-cli command does not return an exit status of 0; if set to false then the exit status of the commands will be returned as is.
    • timeout - defaults to 60 (seconds) to set each process execution timeout to a certain value; set to null, false or 0 to disable timeout completely.

    Additionally the module configuration will forward any configuration parameter to wp-cli as a flag or option. In the example configuration below the allow-root flag and the some-option option will be passed to wp-cli directly and prepended to the command as global options.

    Note: these extract configuration flags and options will be prepended to all commands executed by wp-cli!

    "},{"location":"v3/modules/WPCLI/#environment-configuration","title":"Environment configuration","text":"

    The wp-cli binary supports a set of environment variables to modify its behavior.

    These environment variables can be set on the commands ran by the WPCLI module using the optional env array in the module configuration. The example configuration below shows all of them with some example values. Most of the times you won't need any of these, but they are there for more fine-grained control over the module operations.

    The module is not validating the environment variables in any way! Those values will be evaluated by wp-cli at runtime and might generate errors if not correctly configured.

    "},{"location":"v3/modules/WPCLI/#example-configuration","title":"Example configuration","text":"
    modules:\n    enabled:\n        - WPCLI\n    config:\n        WPCLI:\n            path: /Users/Luca/Sites/wp\n            throw: true\n            timeout: 60\n            # This will be prepended to the command, `wp --allow-root <command>`.\n            allow-root: true\n            # This will be prepended to the command, `wp --some-option=some-value <command>`.\n            some-option: some-value\n            env:\n                # Any one of these, if provided, will be set as environment variable for the the cli command process. \n                # See https://make.wordpress.org/cli/handbook/config/#environment-variables for information.\n                # Equivalent to `WP_CLI_STRICT_ARGS_MODE=1 wp <command>'.\n                strict-args: true\n                # Equivalent to `WP_CLI_CACHE_DIR=/tmp/wp-cli-cache wp <command>'.\n                cache-dir: '/tmp/wp-cli-cache'\n                # Equivalent to `WP_CLI_CONFIG_PATH=/app/public wp <command>'.\n                config-path: '/app/public'\n                # Equivalent to `WP_CLI_CUSTOM_SHELL=/bin/zsh wp <command>'.\n                custom-shell: '/bin/zsh'\n                # Equivalent to `WP_CLI_DISABLE_AUTO_CHECK_UPDATE=1 wp <command>'.\n                disable-auto-update: true\n                # Equivalent to `WP_CLI_PACKAGES_DIR=/wp-cli/packages wp <command>'.\n                packages-dir: '/wp-cli/packages'\n                # Equivalent to `WP_CLI_PHP=/usr/local/bin/php/7.2/php wp <command>'.\n                php: '/usr/local/bin/php/7.2/php'\n                # Equivalent to `WP_CLI_PHP_ARGS='foo=bar some=23' wp <command>'.\n                php-args: 'foo=bar some=23'\n
    "},{"location":"v3/modules/WPCLI/#public-api","title":"Public API","text":"
    • buildFullCommand
    • cli
    • cliToArray
    • cliToString
    • dontSeeInShellOutput
    • seeInShellOutput
    • seeResultCodeIs
    • seeResultCodeIsNot
    • seeShellOutputMatches
    buildFullCommand

    Builds the full command to run including the PHP binary and the wp-cli boot file path.

    // This method is defined in the WithWpCli trait.\n  // Set the wp-cli path, `$this` is a test case.\n  $this->setUpWpCli( '/var/www/html' );\n  // Builds the full wp-cli command, including the `path` variable.\n  $fullCommand =  $this->buildFullCommand(['core', 'version']);\n  // The full command can then be used to run it with another process handler.\n  $wpCliProcess = new Process($fullCommand);\n  $wpCliProcess->run();\n
    Parameters
    • \\Codeception\\Module\\array/string $command - The command to run. cli

      Executes a wp-cli command targeting the test WordPress installation. minus wp. For back-compatibility purposes you can still pass the commandline as a string, but the array format is the preferred and supported method.

      // Activate a plugin via wp-cli in the test WordPress site.\n  $I->cli(['plugin', 'activate', 'my-plugin']);\n  // Change a user password.\n  $I->cli(['user', 'update', 'luca', '--user_pass=newpassword']);\n
      Parameters
      • string/string/\\Codeception\\Module\\array $userCommand - The string of command and parameters as it would be passed to wp-cli cliToArray

        Returns the output of a wp-cli command as an array optionally allowing a callback to process the output. minus wp. For back-compatibility purposes you can still pass the commandline as a string, but the array format is the preferred and supported method.

        // Return a list of inactive themes, like ['twentyfourteen', 'twentyfifteen'].\n  $inactiveThemes = $I->cliToArray(['theme', 'list', '--status=inactive', '--field=name']);\n  // Get the list of installed plugins and only keep the ones starting with \"foo\".\n  $fooPlugins = $I->cliToArray(['plugin', 'list', '--field=name'], function($output){\n  return array_filter(explode(PHP_EOL, $output), function($name){\n  return strpos(trim($name), 'foo') === 0;\n  });\n  });\n
        Parameters
        • string/string/\\Codeception\\Module\\array $userCommand - The string of command and parameters as it would be passed to wp-cli
        • \\callable $splitCallback - An optional callback function to split the results array.
        • cliToString

          Returns the output of a wp-cli command as a string. minus wp. For back-compatibility purposes you can still pass the commandline as a string, but the array format is the preferred and supported method.

          // Return the current site administrator email, using string command format.\n  $adminEmail = $I->cliToString('option get admin_email');\n  // Get the list of active plugins in JSON format, two ways.\n  $activePlugins = $I->cliToString(['plugin', 'list','--status=active', '--format=json']);\n  $activePlugins = $I->cliToString(['option', 'get', 'active_plugins' ,'--format=json']);\n
          Parameters
          • string/\\Codeception\\Module\\array $userCommand - The string of command and parameters as it would be passed to wp-cli dontSeeInShellOutput

            Checks that output from last command doesn't contain text.

            // Return the current site administrator email, using string command format.\n  $I->cli('plugin list --status=active');\n  $I->dontSeeInShellOutput('my-inactive/plugin.php');\n
            Parameters
            • string $text - The text to assert is not in the output.
            seeInShellOutput

            Checks that output from last command contains text.

            // Return the current site administrator email, using string command format.\n  $I->cli('option get admin_email');\n
            Parameters
            • string $text - The text to assert is in the output.
            seeResultCodeIs

            Checks the result code from the last command.

            // Return the current site administrator email, using string command format.\n  $I->cli('option get admin_email');\n  $I->seeResultCodeIs(0);\n
            Parameters
            • int $code - The desired result code.
            seeResultCodeIsNot

            Checks the result code from the last command.

            // Return the current site administrator email, using string command format.\n  $I->cli('invalid command');\n  $I->seeResultCodeIsNot(0);\n
            Parameters
            • int $code - The result code the command should not have exited with.
            seeShellOutputMatches

            Checks that output from the last command matches a given regular expression.

            // Return the current site administrator email, using string command format.\n  $I->cli('option get admin_email');\n
            Parameters
            • string $regex - The regex pattern, including delimiters, to assert the output matches against.

            This class extends \\Codeception\\Module

            "},{"location":"v3/modules/WPDb/","title":"WPDb","text":"

            This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

            "},{"location":"v3/modules/WPDb/#wpdb-module","title":"WPDb module","text":"

            This module should be used in acceptance and functional tests, see levels of testing for more information. This module extends the Db module adding WordPress-specific configuration parameters and methods. The module provides methods to read, write and update the WordPress database directly, without relying on WordPress methods, using WordPress functions or triggering WordPress filters.

            "},{"location":"v3/modules/WPDb/#module-requirements-for-codeception-40","title":"Module requirements for Codeception 4.0+","text":"

            This module requires the codeception/module-db Composer package to work when wp-browser is used with Codeception 4.0.

            To install the package run:

            composer require --dev codeception/module-db:^1.0\n
            "},{"location":"v3/modules/WPDb/#backup-your-content","title":"Backup your content","text":"

            This module, like the Codeception Db one it extends, by default will load a database dump in the database it's using. This means that the database contents will be replaced by the dump contents on each run of a suite using the module. You can set the populate and cleanup parameters to false to prevent this default behavior but it's usually not what you need in an automated test. Make a backup of any database you're using in tests that contains any information you care about before you run any test!

            "},{"location":"v3/modules/WPDb/#change-the-database-used-depending-on-whether-youre-running-tests-or-not","title":"Change the database used depending on whether you're running tests or not","text":"

            The chore of having to plug different databases, or backup them, depending on whether you're manually testing the site or automatically testing can be mitigated switching them automatically depending on the browser user agent or request headers. This module was born to be used in acceptance and functional tests (see levels of testing for more information) and will often be coupled with modules like the WPBrowser one or the WPWebDriver one. Depending on which of the two modules is being used in the suite there are different ways to automate the \"database switching\".

            "},{"location":"v3/modules/WPDb/#automatically-changing-database-based-on-the-browser-user-agent","title":"Automatically changing database based on the browser user agent","text":"

            If you would like to automate the \"switching above\" below you will find an example setup. Update the test site wp-config.php file from this:

            define( 'DB_NAME', 'wordpress' );\n
            to this:
            <?php\nif ( \n    // Custom header.\n    isset( $_SERVER['HTTP_X_TESTING'] )\n    // Custom user agent.\n    || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )\n    // The env var set by the WPClIr or WordPress modules.\n    || getenv( 'WPBROWSER_HOST_REQUEST' )\n) {\n    // Use the test database if the request comes from a test.\n    define( 'DB_NAME', 'wordpress_test' );\n} else {\n    // Else use the default one.\n    define( 'DB_NAME', 'wordpress' );\n}\n

            If you're using the WPWebDriver module set the user agent in the browser, in this example I'm setting the user agent in Chromedriver:

            class_name: AcceptanceTester\nmodules:\n    enabled:\n        - \\Helper\\Acceptance\n        - WPDb\n        - WPWebDriver\n    config:\n        WPDb:\n            dsn: 'mysql:host=%WP_DB_HOST%;dbname=%WP_DB_NAME%'\n            user: %WP_DB_USER%\n            password: %WP_DB_PASSWORD%\n            dump: tests/_data/dump.sql\n            populate: true\n            cleanup: false\n            url: '%WP_URL%'\n            tablePrefix: %WP_TABLE_PREFIX%\n            urlReplacement: true\n        WPWebDriver:\n            url: '%WP_URL%'\n            adminUsername: '%WP_ADMIN_USERNAME%'\n            adminPassword: '%WP_ADMIN_PASSWORD%'\n            adminPath: '%WP_ADMIN_PATH%'\n            browser: chrome\n            host: localhost\n            port: 4444\n            window_size: false\n            wait: 5\n            capabilities:\n              \"goog:chromeOptions\":\n                args:\n                  - \"--headless\"\n                  - \"--disable-gpu\"\n                  - \"--disable-dev-shm-usage\"\n                  - \"--proxy-server='direct://'\"\n                  - \"--proxy-bypass-list=*\"\n                  - \"--no-sandbox\"\n

            If you're using the WPBrowser module send a specific header in the context of test requests:

            class_name: AcceptanceTester\nmodules:\n    enabled:\n        - \\Helper\\Acceptance\n        - WPDb\n        - WPBrowser\n    config:\n        WPDb:\n              dsn: 'mysql:host=%DB_HOST%;dbname=%WP_DB_NAME%'\n              user: %WP_DB_USER%\n              password: %WP_DB_PASSWORD%\n              dump: 'tests/_data/dump.sql'\n              populate: true\n              cleanup: true\n              reconnect: false\n              url: '%WP_URL%'\n              tablePrefix: 'wp_'\n        WPBrowser:\n              url: '%WP_URL%'\n              adminUsername: 'admin'\n              adminPassword: 'admin'\n              adminPath: '/wp-admin'\n              headers: \n                X-Testing: 'wp-browser'\n

            "},{"location":"v3/modules/WPDb/#configuration","title":"Configuration","text":"
            • dsn required - the database POD DSN connection details; read more on PHP PDO documentation. If the database is accessible (as is the case on the latest version of [Local by Flywheel][http://localwp.com]) via unix socket, then the string to insert here should look like this mysql:unix_socket=/path/to/the/mysql.sock;dbname=wordpress.
            • user required - the database user.
            • password required - the database password.
            • url required - the full URL, including the HTTP scheme, of the website whose database is being accessed. WordPress uses hard-codece URLs in the database, that URL will be set by this module when applying the SQL dump file during population or cleanup.
            • dump required - defaults to null; sets the path, relative to the project root folder, or absolute to the SQL dump file that will be used to set the tests initial database fixture. If set to null then the populate, cleanup and populator parameters will be ignored.
            • populate - defaults to true to empty the target database and import the SQL dump(s) specified in the dump argument before the test suite is started.
            • cleanup - defaults to true empty the target database and import the SQL dump(s) specified in the dump argument before each test.
            • urlReplacement - defaults to true to replace, while using the built-in, PHP-based, dump import solution the hard-coded WordPress URL in the database with the specified one.
            • originalUrl - specifies the original URL hard-coded into the version controlled SQL dump files. This can help prevent some URL replacement issues when the urlReplacement configuration parameter is set to true.
            • populator - defaults to null, if set to an executable shell command then that command will be used to populate the database in place of the built-in PHP solution; URL replacement will not apply in this case. Read more about this on Codeception documentation.
            • reconnect - defaults to true to force the module to reconnect to the database before each test in place of only connecting at the start of the tests.
            • waitlock - defaults to 10; wait lock (in seconds) that the database session should use for DDL statements.
            • tablePrefix - defaults to wp_; sets the prefix of the tables that the module will manipulate.
            • letAdminEmailVerification - defaults to an empty value to remove the Administrator Email Verification screen introduced in WordPress 5.3. Set to true to not remove the screen and show it when an administrator user first logs in.
            • letCron - defaults to an empty value to avoid wp-cron from being spawned during tests. Setting this to true will let wp-cron requests to fire during tests.
            "},{"location":"v3/modules/WPDb/#example-configuration","title":"Example configuration","text":"
            modules:\n  enabled:\n      - WPDb\n  config:\n      WPDb:\n          dsn: 'mysql:host=localhost;dbname=wordpress'\n          user: 'root'\n          password: 'password'\n          dump: 'tests/_data/dump.sql'\n          populate: true\n          cleanup: true\n          waitlock: 10\n          url: 'http://wordpress.localhost'\n          urlReplacement: true\n          tablePrefix: 'wp_'\n
            "},{"location":"v3/modules/WPDb/#using-the-module-with-the-wploader-one","title":"Using the module with the WPLoader one","text":"

            This module is often used in conjunction with the WPLoader one to use WordPress-defined functions, classes and methods in acceptance or functional tests. The WPLoader module should be set to only load WordPress and this module should be listed, in the modules.enabled section of the suite configuration file before the WPLoader one:

            modules:\n  enabled:\n      - WPDb # this before...\n      - WPLoader # ...this one.\n  config:\n      WPDb:\n        # ...\n      WPLoader:\n        loadOnly: true\n        # ... \n
            This will avoid issues where the WPLoader module could exit, terminating the test run, due to an inconsistent database state.

            "},{"location":"v3/modules/WPDb/#public-api","title":"Public API","text":"
            • countRowsInDatabase
            • dontHaveAttachmentFilesInDatabase
            • dontHaveAttachmentInDatabase
            • dontHaveBlogInDatabase
            • dontHaveCommentInDatabase
            • dontHaveCommentMetaInDatabase
            • dontHaveInDatabase
            • dontHaveLinkInDatabase
            • dontHaveOptionInDatabase
            • dontHavePostInDatabase
            • dontHavePostMetaInDatabase
            • dontHavePostThumbnailInDatabase
            • dontHaveSiteOptionInDatabase
            • dontHaveSiteTransientInDatabase
            • dontHaveTableInDatabase
            • dontHaveTermInDatabase
            • dontHaveTermMetaInDatabase
            • dontHaveTermRelationshipInDatabase
            • dontHaveTermTaxonomyInDatabase
            • dontHaveTransientInDatabase
            • dontHaveUserInDatabase
            • dontHaveUserInDatabaseWithEmail
            • dontHaveUserMetaInDatabase
            • dontSeeAttachmentInDatabase
            • dontSeeBlogInDatabase
            • dontSeeCommentInDatabase
            • dontSeeCommentMetaInDatabase
            • dontSeeLinkInDatabase
            • dontSeeOptionInDatabase
            • dontSeePageInDatabase
            • dontSeePostInDatabase
            • dontSeePostMetaInDatabase
            • dontSeePostWithTermInDatabase
            • dontSeeSiteOptionInDatabase
            • dontSeeTableInDatabase
            • dontSeeTermInDatabase
            • dontSeeTermMetaInDatabase
            • dontSeeTermTaxonomyInDatabase
            • dontSeeUserInDatabase
            • dontSeeUserMetaInDatabase
            • getSiteDomain
            • getUsersTableName
            • grabAllFromDatabase
            • grabAttachmentAttachedFile
            • grabAttachmentMetadata
            • grabBlogDomain
            • grabBlogPath
            • grabBlogTableName
            • grabBlogTableNames
            • grabBlogTablePrefix
            • grabBlogVersionsTableName
            • grabBlogsTableName
            • grabCommentmetaTableName
            • grabCommentsTableName
            • grabLatestEntryByFromDatabase
            • grabLinksTableName
            • grabOptionFromDatabase
            • grabPostMetaFromDatabase
            • grabPostmetaTableName
            • grabPostsTableName
            • grabPrefixedTableNameFor
            • grabRegistrationLogTableName
            • grabSignupsTableName
            • grabSiteMetaTableName
            • grabSiteOptionFromDatabase
            • grabSiteTableName
            • grabSiteTransientFromDatabase
            • grabSiteUrl
            • grabTablePrefix
            • grabTermIdFromDatabase
            • grabTermMetaTableName
            • grabTermRelationshipsTableName
            • grabTermTaxonomyIdFromDatabase
            • grabTermTaxonomyTableName
            • grabTermsTableName
            • grabUserIdFromDatabase
            • grabUserMetaFromDatabase
            • grabUsermetaTableName
            • grabUsersTableName
            • haveAttachmentInDatabase
            • haveBlogInDatabase
            • haveCommentInDatabase
            • haveCommentMetaInDatabase
            • haveLinkInDatabase
            • haveManyBlogsInDatabase
            • haveManyCommentsInDatabase
            • haveManyLinksInDatabase
            • haveManyPostsInDatabase
            • haveManyTermsInDatabase
            • haveManyUsersInDatabase
            • haveMenuInDatabase
            • haveMenuItemInDatabase
            • haveOptionInDatabase
            • havePageInDatabase
            • havePostInDatabase
            • havePostThumbnailInDatabase
            • havePostmetaInDatabase
            • haveSiteOptionInDatabase
            • haveSiteTransientInDatabase
            • haveTermInDatabase
            • haveTermMetaInDatabase
            • haveTermRelationshipInDatabase
            • haveTransientInDatabase
            • haveUserCapabilitiesInDatabase
            • haveUserInDatabase
            • haveUserLevelsInDatabase
            • haveUserMetaInDatabase
            • importSql
            • importSqlDumpFile
            • seeAttachmentInDatabase
            • seeBlogInDatabase
            • seeCommentInDatabase
            • seeCommentMetaInDatabase
            • seeLinkInDatabase
            • seeOptionInDatabase
            • seePageInDatabase
            • seePostInDatabase
            • seePostMetaInDatabase
            • seePostWithTermInDatabase
            • seeSiteOptionInDatabase
            • seeSiteSiteTransientInDatabase
            • seeTableInDatabase
            • seeTermInDatabase
            • seeTermMetaInDatabase
            • seeTermRelationshipInDatabase
            • seeTermTaxonomyInDatabase
            • seeUserInDatabase
            • seeUserMetaInDatabase
            • useBlog
            • useMainBlog
            • useTheme
            countRowsInDatabase

            Returns the number of table rows matching a criteria.

            $I->haveManyPostsInDatabase(3, ['post_status' => 'draft' ]);\n  $I->haveManyPostsInDatabase(3, ['post_status' => 'private' ]);\n  // Make sure there are now the expected number of draft posts.\n  $postsTable = $I->grabPostsTableName();\n  $draftsCount = $I->countRowsInDatabase($postsTable, ['post_status' => 'draft']);\n
            Parameters
            • string $table - The table to count the rows in.
            • array/\\Codeception\\Module\\array/array $criteria - Search criteria, if empty all table rows will be counted. dontHaveAttachmentFilesInDatabase

              Removes all the files attached with an attachment post, it will not remove the database entries. Requires the WPFilesystem module to be loaded in the suite.

              $posts = $I->grabPostsTableName();\n  $attachmentIds = $I->grabColumnFromDatabase($posts, 'ID', ['post_type' => 'attachment']);\n  // This will only remove the files, not the database entries.\n  $I->dontHaveAttachmentFilesInDatabase($attachmentIds);\n
              Parameters
              • \\Codeception\\Module\\array/int $attachmentIds - An attachment post ID or an array of attachment post IDs. dontHaveAttachmentInDatabase

                Removes an attachment from the posts table. table. the suite.

                $postmeta = $I->grabpostmetatablename();\n  $thumbnailId = $I->grabFromDatabase($postmeta, 'meta_value', [\n  'post_id' => $id,\n  'meta_key'=>'thumbnail_id'\n  ]);\n  // Remove only the database entry (including postmeta) but not the files.\n  $I->dontHaveAttachmentInDatabase($thumbnailId);\n  // Remove the database entry (including postmeta) and the files.\n  $I->dontHaveAttachmentInDatabase($thumbnailId, true, true);\n
                Parameters
                • \\Codeception\\Module\\array/array $criteria - An array of search criteria to find the attachment post in the posts
                • bool $purgeMeta - If set to true then the meta for the attachment will be purged too.
                • bool $removeFiles - Remove all files too, requires the WPFilesystem module to be loaded in
                • dontHaveBlogInDatabase

                  Removes one ore more blogs from the database.

                  // Remove the blog, all its tables and files.\n  $I->dontHaveBlogInDatabase(['path' => 'test/one']);\n  // Remove the blog entry, not the tables though.\n  $I->dontHaveBlogInDatabase(['blog_id' => $blogId]);\n  // Remove multiple blogs.\n  $I->dontHaveBlogInDatabase(['domain' => 'test']);\n
                  Parameters
                  • \\Codeception\\Module\\array/array $criteria - An array of search criteria to find the blog rows in the blogs table.
                  • bool $removeTables - Remove the blog tables.
                  • bool $removeUploads - Remove the blog uploads; requires the WPFilesystem module.
                  • dontHaveCommentInDatabase

                    Removes an entry from the comments table.

                    $I->dontHaveCommentInDatabase(['comment_post_ID' => 23, 'comment_url' => 'http://example.copm']);\n
                    Parameters
                    • \\Codeception\\Module\\array/array $criteria - An array of search criteria.
                    • bool $purgeMeta - If set to true then the meta for the comment will be purged too.
                    • dontHaveCommentMetaInDatabase

                      Removes a post comment meta from the database

                      // Remove all meta for the comment with an ID of 23.\n  $I->dontHaveCommentMetaInDatabase(['comment_id' => 23]);\n  // Remove the `count` comment meta for the comment with an ID of 23.\n  $I->dontHaveCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'count']);\n
                      Parameters
                      • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontHaveInDatabase

                        Deletes a database entry. criteria.

                        $I->dontHaveInDatabase('custom_table', ['book_ID' => 23, 'book_genre' => 'fiction']);\n
                        Parameters
                        • string $table - The table name.
                        • \\Codeception\\Module\\array/array $criteria - An associative array of the column names and values to use as deletion dontHaveLinkInDatabase

                          Removes a link from the database.

                          $I->dontHaveLinkInDatabase(['link_url' => 'http://example.com']);\n
                          Parameters
                          • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontHaveOptionInDatabase

                            Removes an entry from the options table.

                            // Remove the `foo` option.\n  $I->dontHaveOptionInDatabase('foo');\n  // Remove the 'bar' option only if it has the `baz` value.\n  $I->dontHaveOptionInDatabase('bar', 'baz');\n
                            Parameters
                            • string $key - The option name.
                            • mixed/null $value - If set the option will only be removed if its value matches the passed one.
                            dontHavePostInDatabase

                            Removes an entry from the posts table.

                            $posts = $I->haveManyPostsInDatabase(3, ['post_title' => 'Test {{n}}']);\n  $I->dontHavePostInDatabase(['post_title' => 'Test 2']);\n
                            Parameters
                            • \\Codeception\\Module\\array/array $criteria - An array of search criteria.
                            • bool $purgeMeta - If set to true then the meta for the post will be purged too.
                            • dontHavePostMetaInDatabase

                              Removes an entry from the postmeta table.

                              $postId = $I->havePostInDatabase(['meta_input' => ['rating' => 23]]);\n  $I->dontHavePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'rating']);\n
                              Parameters
                              • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontHavePostThumbnailInDatabase

                                Remove the thumbnail (featured image) from a post, if any. Please note: the method will NOT remove the attachment post, post meta and file.

                                $attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));\n  $postId = $I->havePostInDatabase();\n  // Attach the thumbnail to the post.\n  $I->havePostThumbnailInDatabase($postId, $attachmentId);\n  // Remove the thumbnail from the post.\n  $I->dontHavePostThumbnailInDatabase($postId);\n
                                Parameters
                                • int $postId - The post ID to remove the thumbnail (featured image) from.
                                dontHaveSiteOptionInDatabase

                                Removes a site option from the database.

                                // Remove the `foo_count` option.\n  $I->dontHaveSiteOptionInDatabase('foo_count');\n  // Remove the `foo_count` option only if its value is `23`.\n  $I->dontHaveSiteOptionInDatabase('foo_count', 23);\n
                                Parameters
                                • string $key - The option name.
                                • mixed/null $value - If set the option will only be removed it its value matches the specified one.
                                dontHaveSiteTransientInDatabase

                                Removes a site transient from the database.

                                $I->dontHaveSiteTransientInDatabase(['my_plugin_site_buffer']);\n
                                Parameters
                                • string $key - The name of the transient to delete.
                                dontHaveTableInDatabase

                                Removes a table from the database. The case where a table does not exist is handled without raising an error.

                                $ordersTable = $I->grabPrefixedTableNameFor('orders');\n  $I->dontHaveTableInDatabase($ordersTable);\n
                                Parameters
                                • string $fullTableName - The full table name, including the table prefix.
                                dontHaveTermInDatabase

                                Removes a term from the database.

                                $I->dontHaveTermInDatabase(['name' => 'romance']);\n  $I->dontHaveTermInDatabase(['slug' => 'genre--romance']);\n
                                Parameters
                                • \\Codeception\\Module\\array/array $criteria - An array of search criteria.
                                • bool $purgeMeta - Whether the terms meta should be purged along side with the meta or not.
                                • dontHaveTermMetaInDatabase

                                  Removes a term meta from the database.

                                  // Remove the \"karma\" key.\n  $I->dontHaveTermMetaInDatabase(['term_id' => $termId, 'meta_key' => 'karma']);\n  // Remove all meta for the term.\n  $I->dontHaveTermMetaInDatabase(['term_id' => $termId]);\n
                                  Parameters
                                  • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontHaveTermRelationshipInDatabase

                                    Removes an entry from the term_relationships table.

                                    // Remove the relation between a post and a category.\n  $I->dontHaveTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $ttaxId]);\n  // Remove all terms for a post.\n  $I->dontHaveTermMetaInDatabase(['object_id' => $postId]);\n
                                    Parameters
                                    • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontHaveTermTaxonomyInDatabase

                                      Removes an entry from the term_taxonomy table.

                                      // Remove a specific term from the genre taxonomy.\n  $I->dontHaveTermTaxonomyInDatabase(['term_id' => $postId, 'taxonomy' => 'genre']);\n  // Remove all terms for a taxonomy.\n  $I->dontHaveTermTaxonomyInDatabase(['taxonomy' => 'genre']);\n
                                      Parameters
                                      • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontHaveTransientInDatabase

                                        Removes a transient from the database.

                                        // Removes the `tweets` transient from the database, if set.\n  $I->dontHaveTransientInDatabase('tweets');\n
                                        Parameters
                                        • string $transient - The name of the transient to delete.
                                        dontHaveUserInDatabase

                                        Removes a user from the database.

                                        $bob = $I->haveUserInDatabase('bob');\n  $alice = $I->haveUserInDatabase('alice');\n  // Remove Bob's user and meta.\n  $I->dontHaveUserInDatabase('bob');\n  // Remove Alice's user but not meta.\n  $I->dontHaveUserInDatabase($alice);\n
                                        Parameters
                                        • int/string $userIdOrLogin - The user ID or login name.
                                        • bool $purgeMeta - Whether the user meta should be purged alongside the user or not.
                                        dontHaveUserInDatabaseWithEmail

                                        Removes a user(s) from the database using the user email address.

                                        $luca = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);\n
                                        Parameters
                                        • string $userEmail - The email of the user to remove.
                                        • bool $purgeMeta - Whether the user meta should be purged alongside the user or not.
                                        dontHaveUserMetaInDatabase

                                        Removes an entry from the usermeta table.

                                        // Remove the `karma` user meta for a user.\n  $I->dontHaveUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);\n  // Remove all the user meta for a user.\n  $I->dontHaveUserMetaInDatabase(['user_id' => 23]);\n
                                        Parameters
                                        • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeAttachmentInDatabase

                                          Checks that an attachment is not in the database.

                                          $url = 'https://example.org/images/foo.png';\n  $I->dontSeeAttachmentInDatabase(['guid' => $url]);\n
                                          Parameters
                                          • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeBlogInDatabase

                                            Checks that a row is not present in the blogs table.

                                            $I->haveManyBlogsInDatabase(2, ['path' => 'test-{{n}}'], false)\n  $I->dontSeeBlogInDatabase(['path' => '/test-3/'])\n
                                            Parameters
                                            • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeCommentInDatabase

                                              Checks that a comment is not in the database. Will look up the \"comments\" table.

                                              // Checks for one comment.\n  $I->dontSeeCommentInDatabase(['comment_ID' => 23]);\n  // Checks for comments from a user.\n  $I->dontSeeCommentInDatabase(['user_id' => 89]);\n
                                              Parameters
                                              • \\Codeception\\Module\\array/array $criteria - The search criteria. dontSeeCommentMetaInDatabase

                                                Checks that a comment meta value is not in the database. Will look up the \"commentmeta\" table.

                                                // Delete a comment `karma` meta.\n  $I->dontSeeCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'karma']);\n  // Delete all meta for a comment.\n  $I->dontSeeCommentMetaInDatabase(['comment_id' => 23]);\n
                                                Parameters
                                                • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeLinkInDatabase

                                                  Checks that a link is not in the links database table.

                                                  $I->dontSeeLinkInDatabase(['link_url' => 'http://example.com']);\n  $I->dontSeeLinkInDatabase(['link_url' => 'http://example.com', 'link_name' => 'example']);\n
                                                  Parameters
                                                  • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeOptionInDatabase

                                                    Checks that an option is not in the database for the current blog. If the value is an object or an array then the serialized option will be checked.

                                                    $I->dontHaveOptionInDatabase('posts_per_page');\n  $I->dontSeeOptionInDatabase('posts_per_page');\n  $I->dontSeeOptionInDatabase('posts_per_page', 23);\n  $I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page']);\n  $I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page', 'option_value' => 23]);\n
                                                    Parameters
                                                    • \\Codeception\\Module\\array/string $criteriaOrName - An array of search criteria or the option name.
                                                    • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                    • dontSeePageInDatabase

                                                      Checks that a page is not in the database.

                                                      // Assert a page with an ID does not exist.\n  $I->dontSeePageInDatabase(['ID' => 23]);\n  // Assert a page with a slug and ID.\n  $I->dontSeePageInDatabase(['post_name' => 'test', 'ID' => 23]);\n
                                                      Parameters
                                                      • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeePostInDatabase

                                                        Checks that a post is not in the database.

                                                        // Asserts a post with title 'Test' is not in the database.\n  $I->dontSeePostInDatabase(['post_title' => 'Test']);\n  // Asserts a post with title 'Test' and content 'Test content' is not in the database.\n  $I->dontSeePostInDatabase(['post_title' => 'Test', 'post_content' => 'Test content']);\n
                                                        Parameters
                                                        • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeePostMetaInDatabase

                                                          Checks that a post meta value does not exist. If the meta value is an object or an array then the check will be made on its serialized version.

                                                          $postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']]);\n  $I->dontSeePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'woot']);\n
                                                          Parameters
                                                          • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeePostWithTermInDatabase

                                                            Checks that a post to term relation does not exist in the database. The method will check the \"term_relationships\" table.

                                                            $fiction = $I->haveTermInDatabase('fiction', 'genre');\n  $nonFiction = $I->haveTermInDatabase('non-fiction', 'genre');\n  $postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);\n  $I->dontSeePostWithTermInDatabase($postId, $nonFiction['term_taxonomy_id], );\n  passed this parameter will be interpreted as a `term_id`, else as a\n  the\n  term order.\n  to build a `taxonomy_term_id` from the `term_id`.\n
                                                            Parameters
                                                            • int $post_id - The post ID.
                                                            • int $term_taxonomy_id - The term term_id or term_taxonomy_id; if the $taxonomy argument is
                                                            • int/null $term_order - The order the term applies to the post, defaults to null to not use
                                                            • string/null $taxonomy - The taxonomy the term_id is for; if passed this parameter will be used
                                                            dontSeeSiteOptionInDatabase

                                                            Checks that a site option is not in the database.

                                                            // Check that the option is not set in the database.\n  $I->dontSeeSiteOptionInDatabase('foo_count');\n  // Check that the option is not set with a specific value.\n  $I->dontSeeSiteOptionInDatabase('foo_count', 23);\n  $I->dontSeeSiteOptionInDatabase(['option_name => 'foo_count', 'option_value' => 23]);\n
                                                            Parameters
                                                            • \\Codeception\\Module\\array/string $criteriaOrName - An array of search criteria or the option name.
                                                            • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                            • dontSeeTableInDatabase

                                                              Checks that a table is not in the database.

                                                              $options = $I->grabPrefixedTableNameFor('options');\n  $I->dontHaveTableInDatabase($options)\n  $I->dontSeeTableInDatabase($options);\n
                                                              Parameters
                                                              • string $table - The full table name, including the table prefix.
                                                              dontSeeTermInDatabase

                                                              Makes sure a term is not in the database. Looks up both the terms table and the term_taxonomy tables. and the term_taxonomy tables.

                                                              // Asserts a 'fiction' term is not in the database.\n  $I->dontSeeTermInDatabase(['name' => 'fiction']);\n  // Asserts a 'fiction' term with slug 'genre--fiction' is not in the database.\n  $I->dontSeeTermInDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);\n
                                                              Parameters
                                                              • \\Codeception\\Module\\array/array $criteria - An array of criteria to search for the term, can be columns from the terms dontSeeTermMetaInDatabase

                                                                Checks that a term meta is not in the database.

                                                                list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n  $I->haveTermMetaInDatabase($termId, 'rating', 4);\n  $I->dontSeeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'average_review']);\n
                                                                Parameters
                                                                • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeTermTaxonomyInDatabase

                                                                  Checks that a term taxonomy is not in the database.

                                                                  list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n  $I->dontSeeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'country']);\n
                                                                  Parameters
                                                                  • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeUserInDatabase

                                                                    Checks that a user is not in the database.

                                                                    // Asserts a user does not exist in the database.\n  $I->dontSeeUserInDatabase(['user_login' => 'luca']);\n  // Asserts a user with email and login is not in the database.\n  $I->dontSeeUserInDatabase(['user_login' => 'luca', 'user_email' => 'luca@theaveragedev.com']);\n
                                                                    Parameters
                                                                    • \\Codeception\\Module\\array/array $criteria - An array of search criteria. dontSeeUserMetaInDatabase

                                                                      Check that a user meta value is not in the database.

                                                                      // Asserts a user does not have a 'karma' meta assigned.\n  $I->dontSeeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);\n  // Asserts no user has any 'karma' meta assigned.\n  $I->dontSeeUserMetaInDatabase(['meta_key' => 'karma']);\n
                                                                      Parameters
                                                                      • \\Codeception\\Module\\array/array $criteria - An array of search criteria. getSiteDomain

                                                                        Returns the site domain inferred from the url set in the config.

                                                                        $domain = $I->getSiteDomain();\n  // We should be redirected to the HTTPS version when visiting the HTTP version.\n  $I->amOnPage('http://' . $domain);\n  $I->seeCurrentUrlEquals('https://' . $domain);\n
                                                                        getUsersTableName

                                                                        Returns the prefixed users table name.

                                                                        // Given a `wp_` table prefix returns `wp_users`.\n  $usersTable = $I->getUsersTableName();\n  // Given a `wp_` table prefix returns `wp_users`.\n  $I->useBlog(23);\n  $usersTable = $I->getUsersTableName();\n
                                                                        grabAllFromDatabase

                                                                        Returns all entries matching a criteria from the database.

                                                                        $books = $I->grabPrefixedTableNameFor('books');\n  $I->grabAllFromDatabase($books, 'title', ['genre' => 'fiction']);\n
                                                                        Parameters
                                                                        • string $table - The table to grab the values from.
                                                                        • string $column - The column to fetch.
                                                                        • \\Codeception\\Module\\array $criteria - The search criteria. grabAttachmentAttachedFile

                                                                          Returns the path, as stored in the database, of an attachment _wp_attached_file meta. The attached file is, usually, an attachment origal file.

                                                                          $file = $I->grabAttachmentAttachedFile($attachmentId);\n  $fileInfo = new SplFileInfo($file);\n  $I->assertEquals('jpg', $fileInfo->getExtension());\n
                                                                          Parameters
                                                                          • int $attachmentPostId - The attachment post ID.
                                                                          grabAttachmentMetadata

                                                                          Returns the metadata array for an attachment post. This is the value of the _wp_attachment_metadata meta.

                                                                          $metadata = $I->grabAttachmentMetadata($attachmentId);\n  $I->assertEquals(['thumbnail', 'medium', 'medium_large'], array_keys($metadata['sizes']);\n
                                                                          Parameters
                                                                          • int $attachmentPostId - The attachment post ID.
                                                                          grabBlogDomain

                                                                          Returns a blog domain given its ID.

                                                                          $blogIds = $I->haveManyBlogsInDatabase(3);\n  $domains = array_map(function($blogId){\n  return $I->grabBlogDomain($blogId);\n  }, $blogIds);\n
                                                                          Parameters
                                                                          • int $blogId - The blog ID.
                                                                          grabBlogPath

                                                                          Grabs a blog domain from the blogs table.

                                                                          $blogId = $I->haveBlogInDatabase('test');\n  $path = $I->grabBlogDomain($blogId);\n  $I->amOnSubdomain($path);\n  $I->amOnPage('/');\n
                                                                          Parameters
                                                                          • int $blogId - The blog ID.
                                                                          grabBlogTableName

                                                                          Returns the full name of a table for a blog from a multisite installation database.

                                                                          $blogOptionTable = $I->grabBlogTableName($blogId, 'option');\n
                                                                          Parameters
                                                                          • int $blogId - The blog ID.
                                                                          • string $table - The table name, without table prefix.
                                                                          grabBlogTableNames

                                                                          Returns a list of tables for a blog ID.

                                                                          $blogId = $I->haveBlogInDatabase('test');\n  $tables = $I->grabBlogTableNames($blogId);\n  $options = array_filter($tables, function($tableName){\n  return str_pos($tableName, 'options') !== false;\n  });\n
                                                                          Parameters
                                                                          • int $blogId - The ID of the blog to fetch the tables for.
                                                                          grabBlogTablePrefix

                                                                          Returns the table prefix for a blog.

                                                                          $blogId = $I->haveBlogInDatabase('test');\n  $blogTablePrefix = $I->getBlogTablePrefix($blogId);\n  $blogOrders = $I->blogTablePrefix . 'orders';\n
                                                                          Parameters
                                                                          • int $blogId - The blog ID.
                                                                          grabBlogVersionsTableName

                                                                          Gets the prefixed blog_versions table name.

                                                                          // Assuming a `wp_` table prefix it will return `wp_blog_versions`.\n  $blogVersionsTable = $I->grabBlogVersionsTableName();\n  $I->useBlog(23);\n  // Assuming a `wp_` table prefix it will return `wp_blog_versions`.\n  $blogVersionsTable = $I->grabBlogVersionsTableName();\n
                                                                          grabBlogsTableName

                                                                          Gets the prefixed blogs table name.

                                                                          // Assuming a `wp_` table prefix it will return `wp_blogs`.\n  $blogVersionsTable = $I->grabBlogsTableName();\n  $I->useBlog(23);\n  // Assuming a `wp_` table prefix it will return `wp_blogs`.\n  $blogVersionsTable = $I->grabBlogsTableName();\n
                                                                          grabCommentmetaTableName

                                                                          Returns the prefixed comment meta table name.

                                                                          // Get all the values of 'karma' for all comments.\n  $commentMeta = $I->grabCommentmetaTableName();\n  $I->grabAllFromDatabase($commentMeta, 'meta_value', ['meta_key' => 'karma']);\n
                                                                          grabCommentsTableName

                                                                          Gets the comments table name.

                                                                          // Will be `wp_comments`.\n  $comments = $I->grabCommentsTableName();\n  // Will be `wp_23_comments`.\n  $I->useBlog(23);\n  $comments = $I->grabCommentsTableName();\n
                                                                          grabLatestEntryByFromDatabase

                                                                          Returns the id value of the last table entry.

                                                                          $I->haveManyPostsInDatabase();\n  $postsTable = $I->grabPostsTableName();\n  $last = $I->grabLatestEntryByFromDatabase($postsTable, 'ID');\n  items.\n
                                                                          Parameters
                                                                          • string $tableName - The table to fetch the last insertion for.
                                                                          • string $idColumn - The column that is used, in the table, to uniquely identify
                                                                          grabLinksTableName

                                                                          Returns the prefixed links table name.

                                                                          // Given a `wp_` table prefix returns `wp_links`.\n  $linksTable = $I->grabLinksTableName();\n  // Given a `wp_` table prefix returns `wp_23_links`.\n  $I->useBlog(23);\n  $linksTable = $I->grabLinksTableName();\n
                                                                          grabOptionFromDatabase

                                                                          Gets an option value from the database.

                                                                          $count = $I->grabOptionFromDatabase('foo_count');\n
                                                                          Parameters
                                                                          • string $option_name - The name of the option to grab from the database.
                                                                          grabPostMetaFromDatabase

                                                                          Gets the value of one or more post meta values from the database.

                                                                          $thumbnail_id = $I->grabPostMetaFromDatabase($postId, '_thumbnail_id', true);\n
                                                                          Parameters
                                                                          • int $postId - The post ID.
                                                                          • string $metaKey - The key of the meta to retrieve.
                                                                          • bool $single - Whether to return a single meta value or an array of all available meta values.
                                                                          grabPostmetaTableName

                                                                          Returns the prefixed post meta table name.

                                                                          // Returns 'wp_postmeta'.\n  $I->grabPostmetaTableName();\n  // Returns 'wp_23_postmeta'.\n  $I->useBlog(23);\n  $I->grabPostmetaTableName();\n
                                                                          grabPostsTableName

                                                                          Gets the posts prefixed table name.

                                                                          // Given a `wp_` table prefix returns `wp_posts`.\n  $postsTable = $I->grabPostsTableName();\n  // Given a `wp_` table prefix returns `wp_23_posts`.\n  $I->useBlog(23);\n  $postsTable = $I->grabPostsTableName();\n
                                                                          grabPrefixedTableNameFor

                                                                          Returns a prefixed table name for the current blog. If the table is not one to be prefixed (e.g. users) then the proper table name will be returned.

                                                                          // Will return wp_users.\n  $usersTable = $I->grabPrefixedTableNameFor('users');\n  // Will return wp_options.\n  $optionsTable = $I->grabPrefixedTableNameFor('options');\n  // Use a different blog and get its options table.\n  $I->useBlog(2);\n  $blogOptionsTable = $I->grabPrefixedTableNameFor('options');\n
                                                                          Parameters
                                                                          • string $tableName - The table name, e.g. options.
                                                                          grabRegistrationLogTableName

                                                                          Gets the prefixed registration_log table name.

                                                                          // Assuming a `wp_` table prefix it will return `wp_registration_log`.\n  $blogVersionsTable = $I->grabRegistrationLogTableName();\n  $I->useBlog(23);\n  // Assuming a `wp_` table prefix it will return `wp_registration_log`.\n  $blogVersionsTable = $I->grabRegistrationLogTableName();\n
                                                                          grabSignupsTableName

                                                                          Gets the prefixed signups table name.

                                                                          // Assuming a `wp_` table prefix it will return `wp_signups`.\n  $blogVersionsTable = $I->grabSignupsTableName();\n  $I->useBlog(23);\n  // Assuming a `wp_` table prefix it will return `wp_signups`.\n  $blogVersionsTable = $I->grabSignupsTableName();\n
                                                                          grabSiteMetaTableName

                                                                          Gets the prefixed sitemeta table name.

                                                                          // Assuming a `wp_` table prefix it will return `wp_sitemeta`.\n  $blogVersionsTable = $I->grabSiteMetaTableName();\n  $I->useBlog(23);\n  // Assuming a `wp_` table prefix it will return `wp_sitemeta`.\n  $blogVersionsTable = $I->grabSiteMetaTableName();\n
                                                                          grabSiteOptionFromDatabase

                                                                          Gets a site option from the database.

                                                                          $fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');\n
                                                                          Parameters
                                                                          • string $key - The name of the option to read from the database.
                                                                          grabSiteTableName

                                                                          Gets the prefixed site table name.

                                                                          // Assuming a `wp_` table prefix it will return `wp_site`.\n  $blogVersionsTable = $I->grabSiteTableName();\n  $I->useBlog(23);\n  // Assuming a `wp_` table prefix it will return `wp_site`.\n  $blogVersionsTable = $I->grabSiteTableName();\n
                                                                          grabSiteTransientFromDatabase

                                                                          Gets a site transient from the database.

                                                                          $I->grabSiteTransientFromDatabase('total_comments');\n  $I->grabSiteTransientFromDatabase('api_data');\n
                                                                          Parameters
                                                                          • string $key - The site transient to fetch the value for, w/o the _site_transient_ prefix.
                                                                          grabSiteUrl

                                                                          Returns the current site URL as specified in the module configuration.

                                                                          $shopPath = $I->grabSiteUrl('/shop');\n
                                                                          Parameters
                                                                          • string $path - A path that should be appended to the site URL.
                                                                          grabTablePrefix

                                                                          Returns the table prefix, namespaced for secondary blogs if selected.

                                                                          // Assuming a table prefix of `wp_` it will return `wp_`;\n  $tablePrefix = $I->grabTablePrefix();\n  $I->useBlog(23);\n  // Assuming a table prefix of `wp_` it will return `wp_23_`;\n  $tablePrefix = $I->grabTablePrefix();\n
                                                                          grabTermIdFromDatabase

                                                                          Gets a term ID from the database. Looks up the prefixed terms table, e.g. wp_terms.

                                                                          // Return the 'fiction' term 'term_id'.\n  $termId = $I->grabTermIdFromDatabase(['name' => 'fiction']);\n  // Get a term ID by more stringent criteria.\n  $termId = $I->grabTermIdFromDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);\n  // Return the 'term_id' of the first term for a group.\n  $termId = $I->grabTermIdFromDatabase(['term_group' => 23]);\n
                                                                          Parameters
                                                                          • \\Codeception\\Module\\array/array $criteria - An array of search criteria. grabTermMetaTableName

                                                                            Gets the terms meta table prefixed name.

                                                                            // Returns 'wp_termmeta'.\n  $I->grabTermMetaTableName();\n  // Returns 'wp_23_termmeta'.\n  $I->useBlog(23);\n  $I->grabTermMetaTableName();\n
                                                                            grabTermRelationshipsTableName

                                                                            Gets the prefixed term relationships table name, e.g. wp_term_relationships.

                                                                            $I->grabTermRelationshipsTableName();\n
                                                                            grabTermTaxonomyIdFromDatabase

                                                                            Gets a term_taxonomy_id from the database. Looks up the prefixed terms_relationships table, e.g. wp_term_relationships.

                                                                            // Get the `term_taxonomy_id` for a term and a taxonomy.\n  $I->grabTermTaxonomyIdFromDatabase(['term_id' => $fictionId, 'taxonomy' => 'genre']);\n  // Get the `term_taxonomy_id` for the first term with a count of 23.\n  $I->grabTermTaxonomyIdFromDatabase(['count' => 23]);\n
                                                                            Parameters
                                                                            • \\Codeception\\Module\\array/array $criteria - An array of search criteria. grabTermTaxonomyTableName

                                                                              Gets the prefixed term and taxonomy table name, e.g. wp_term_taxonomy.

                                                                              // Returns 'wp_term_taxonomy'.\n  $I->grabTermTaxonomyTableName();\n  // Returns 'wp_23_term_taxonomy'.\n  $I->useBlog(23);\n  $I->grabTermTaxonomyTableName();\n
                                                                              grabTermsTableName

                                                                              Gets the prefixed terms table name, e.g. wp_terms.

                                                                              // Returns 'wp_terms'.\n  $I->grabTermsTableName();\n  // Returns 'wp_23_terms'.\n  $I->useBlog(23);\n  $I->grabTermsTableName();\n
                                                                              grabUserIdFromDatabase

                                                                              Gets the a user ID from the database using the user login.

                                                                              $userId = $I->grabUserIdFromDatabase('luca');\n
                                                                              Parameters
                                                                              • string $userLogin - The user login name.
                                                                              grabUserMetaFromDatabase

                                                                              Gets a user meta from the database.

                                                                              // Returns a user 'karma' value.\n  $I->grabUserMetaFromDatabase($userId, 'karma');\n  // Returns an array, the unserialized version of the value stored in the database.\n  $I->grabUserMetaFromDatabase($userId, 'api_data');\n
                                                                              Parameters
                                                                              • int $userId - The ID of th user to get the meta for.
                                                                              • string $meta_key - The meta key to fetch the value for.
                                                                              grabUsermetaTableName

                                                                              Returns the prefixed users meta table name.

                                                                              // Given a `wp_` table prefix returns `wp_usermeta`.\n  $usermetaTable = $I->grabUsermetaTableName();\n  // Given a `wp_` table prefix returns `wp_usermeta`.\n  $I->useBlog(23);\n  $usermetaTable = $I->grabUsermetaTableName();\n
                                                                              grabUsersTableName

                                                                              Returns the prefixed users table name.

                                                                              // Given a `wp_` table prefix returns `wp_users`.\n  $usersTable = $I->grabUsersTableName();\n  // Given a `wp_` table prefix returns `wp_users`.\n  $I->useBlog(23);\n  $usersTable = $I->grabUsersTableName();\n
                                                                              haveAttachmentInDatabase

                                                                              Creates the database entries representing an attachment and moves the attachment file to the right location. timestamp that should be used to build the \"year/time\" uploads sub-folder structure. override the image sizes created by default.

                                                                              $file = codecept_data_dir('images/test.png');\n  $attachmentId = $I->haveAttachmentInDatabase($file);\n  $image = codecept_data_dir('images/test-2.png');\n  $lastWeekAttachment = $I->haveAttachmentInDatabase($image, '-1 week');\n  Requires the WPFilesystem module.\n
                                                                              Parameters
                                                                              • string $file - The absolute path to the attachment file.
                                                                              • string/string/int $date - Either a string supported by the strtotime function or a UNIX
                                                                              • array/\\Codeception\\Module\\array/array $overrides - An associative array of values overriding the default ones.
                                                                              • \\Codeception\\Module\\array> $imageSizes - An associative array in the format [ => [,]] to haveBlogInDatabase

                                                                                Inserts a blog in the blogs table.

                                                                                // Create the `test` subdomain blog.\n  $blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId]);\n  // Create the `/test` subfolder blog.\n  $blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId], false);\n  or subfolder (`true`)\n
                                                                                Parameters
                                                                                • string $domainOrPath - The subdomain or the path to the be used for the blog.
                                                                                • array/\\Codeception\\Module\\array/array $overrides - An array of values to override the defaults.
                                                                                • bool $subdomain - Whether the new blog should be created as a subdomain (true)
                                                                                • haveCommentInDatabase

                                                                                  Inserts a comment in the database.

                                                                                  $I->haveCommentInDatabase($postId, ['comment_content' => 'Test Comment', 'comment_karma' => 23]);\n
                                                                                  Parameters
                                                                                  • int $comment_post_ID - The id of the post the comment refers to.
                                                                                  • array/\\Codeception\\Module\\array/array $data - The comment data overriding default and random generated values. haveCommentMetaInDatabase

                                                                                    Inserts a comment meta field in the database. Array and object meta values will be serialized.

                                                                                    $I->haveCommentMetaInDatabase($commentId, 'api_ID', 23);\n  // The value will be serialized.\n  $apiData = ['ID' => 23, 'user' => 89, 'origin' => 'twitter'];\n  $I->haveCommentMetaInDatabase($commentId, 'api_data', $apiData);\n
                                                                                    Parameters
                                                                                    • int $comment_id - The ID of the comment to insert the meta for.
                                                                                    • string $meta_key - The key of the comment meta to insert.
                                                                                    • mixed $meta_value - The value of the meta to insert, if serializable it will be serialized.
                                                                                    haveLinkInDatabase

                                                                                    Inserts a link in the database.

                                                                                    $linkId = $I->haveLinkInDatabase(['link_url' => 'http://example.org']);\n
                                                                                    Parameters
                                                                                    • array/\\Codeception\\Module\\array/array $overrides - The data to insert. haveManyBlogsInDatabase

                                                                                      Inserts many blogs in the database. by the count.

                                                                                      $blogIds = $I->haveManyBlogsInDatabase(3, ['domain' =>'test-{{n}}']);\n  foreach($blogIds as $blogId){\n  $I->useBlog($blogId);\n  $I->haveManuPostsInDatabase(3);\n  }\n
                                                                                      Parameters
                                                                                      • int $count - The number of blogs to create.
                                                                                      • array/\\Codeception\\Module\\array/array $overrides - An array of values to override the default ones; {{n}} will be replaced
                                                                                      • bool $subdomain - Whether the new blogs should be created as a subdomain or subfolder.
                                                                                      • haveManyCommentsInDatabase

                                                                                        Inserts many comments in the database.

                                                                                        // Insert 3 random comments for a post.\n  $I->haveManyCommentsInDatabase(3, $postId);\n  // Insert 3 random comments for a post.\n  $I->haveManyCommentsInDatabase(3, $postId, ['comment_content' => 'Comment {{n}}']);\n
                                                                                        Parameters
                                                                                        • int $count - The number of comments to insert.
                                                                                        • int $comment_post_ID - The comment parent post ID.
                                                                                        • array/\\Codeception\\Module\\array/array $overrides - An associative array to override the defaults. haveManyLinksInDatabase

                                                                                          Inserts many links in the database links table.

                                                                                          // Insert 3 randomly generated links in the database.\n  $linkIds = $I->haveManyLinksInDatabase(3);\n  // Inserts links in the database replacing the `n` placeholder.\n  $linkIds = $I->haveManyLinksInDatabase(3, ['link_url' => 'http://example.org/test-{{n}}']);\n
                                                                                          Parameters
                                                                                          • int $count - The number of links to insert.
                                                                                          • array/\\Codeception\\Module\\array/array $overrides - Overrides for the default arguments. haveManyPostsInDatabase

                                                                                            Inserts many posts in the database returning their IDs. An array of values to override the defaults. The {{n}} placeholder can be used to have the post count inserted in its place; e.g. Post Title - {{n}} will be set to Post Title - 0 for the first post, Post Title - 1 for the second one and so on. The same applies to meta values as well.

                                                                                            // Insert 3 random posts.\n  $I->haveManyPostsInDatabase(3);\n  // Insert 3 posts with generated titles.\n  $I->haveManyPostsInDatabase(3, ['post_title' => 'Test post {{n}}']);\n
                                                                                            Parameters
                                                                                            • int $count - The number of posts to insert.
                                                                                            • array/\\Codeception\\Module\\array/array $overrides haveManyTermsInDatabase

                                                                                              Inserts many terms in the database.

                                                                                              $terms = $I->haveManyTermsInDatabase(3, 'genre-{{n}}', 'genre');\n  $termIds = array_column($terms, 0);\n  $termTaxonomyIds = array_column($terms, 1);\n
                                                                                              Parameters
                                                                                              • int $count - The number of terms to insert.
                                                                                              • string $name - The term name template, can include the {{n}} placeholder.
                                                                                              • string $taxonomy - The taxonomy to insert the terms for.
                                                                                              • array/\\Codeception\\Module\\array/array $overrides - An associative array of default overrides. haveManyUsersInDatabase

                                                                                                Inserts many users in the database.

                                                                                                $subscribers = $I->haveManyUsersInDatabase(5, 'user-{{n}}');\n  $editors = $I->haveManyUsersInDatabase(\n  5,\n  'user-{{n}}',\n  'editor',\n  ['user_email' => 'user-{{n}}@example.org']\n  );\n
                                                                                                Parameters
                                                                                                • int $count - The number of users to insert.
                                                                                                • string $user_login - The user login name.
                                                                                                • string $role - The user role.
                                                                                                • array/\\Codeception\\Module\\array/array $overrides - An array of values to override the default ones. haveMenuInDatabase

                                                                                                  Creates and adds a menu to a theme location in the database.

                                                                                                  list($termId, $termTaxId) = $I->haveMenuInDatabase('test', 'sidebar');\n
                                                                                                  Parameters
                                                                                                  • string $slug - The menu slug.
                                                                                                  • string $location - The theme menu location the menu will be assigned to.
                                                                                                  • array/\\Codeception\\Module\\array/array $overrides - An array of values to override the defaults. haveMenuItemInDatabase

                                                                                                    Adds a menu element to a menu for the current theme. post meta.

                                                                                                    $I->haveMenuInDatabase('test', 'sidebar');\n  $I->haveMenuItemInDatabase('test', 'Test one', 0);\n  $I->haveMenuItemInDatabase('test', 'Test two', 1);\n
                                                                                                    Parameters
                                                                                                    • string $menuSlug - The menu slug the item should be added to.
                                                                                                    • string $title - The menu item title.
                                                                                                    • int/null $menuOrder - An optional menu order, 1 based.
                                                                                                    • array/\\Codeception\\Module\\array/array $meta - An associative array that will be prefixed with _menu_item_ for the item haveOptionInDatabase

                                                                                                      Inserts an option in the database.

                                                                                                      $I->haveOptionInDatabase('posts_per_page', 23);\n  $I->haveOptionInDatabase('my_plugin_options', ['key_one' => 'value_one', 'key_two' => 89]);\n  If the option value is an object or an array then the value will be serialized.\n
                                                                                                      Parameters
                                                                                                      • string $option_name - The option name.
                                                                                                      • mixed $option_value - The option value; if an array or object it will be serialized.
                                                                                                      • string $autoload - Weather the option should be autoloaded by WordPress or not.
                                                                                                      havePageInDatabase

                                                                                                      Inserts a page in the database.

                                                                                                      // Creates a test page in the database with random values.\n  $randomPageId = $I->havePageInDatabase();\n  // Creates a test page in the database defining its title.\n  $testPageId = $I->havePageInDatabase(['post_title' => 'Test page']);\n
                                                                                                      Parameters
                                                                                                      • array/\\Codeception\\Module\\array/array $overrides - An array of values to override the default ones. havePostInDatabase

                                                                                                        Inserts a post in the database. values.

                                                                                                        // Insert a post with random values in the database.\n  $randomPostId = $I->havePostInDatabase();\n  // Insert a post with specific values in the database.\n  $I->havePostInDatabase([\n  'post_type' => 'book',\n  'post_title' => 'Alice in Wonderland',\n  'meta_input' => [\n  'readers_count' => 23\n  ],\n  'tax_input' => [\n  ['genre' => 'fiction']\n  ]\n  ]);\n
                                                                                                        Parameters
                                                                                                        • array/\\Codeception\\Module\\array/array $data - An associative array of post data to override default and random generated havePostThumbnailInDatabase

                                                                                                          Assigns the specified attachment ID as thumbnail (featured image) to a post.

                                                                                                          $attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));\n  $postId = $I->havePostInDatabase();\n  $I->havePostThumbnailInDatabase($postId, $attachmentId);\n
                                                                                                          Parameters
                                                                                                          • int $postId - The post ID to assign the thumbnail (featured image) to.
                                                                                                          • int $thumbnailId - The post ID of the attachment.
                                                                                                          havePostmetaInDatabase

                                                                                                          Adds one or more meta key and value couples in the database for a post.

                                                                                                          // Set the post-meta for a post.\n  $I->havePostmetaInDatabase($postId, 'karma', 23);\n  // Set an array post-meta for a post, it will be serialized in the db.\n  $I->havePostmetaInDatabase($postId, 'data', ['one', 'two']);\n  // Use a loop to insert one meta per row.\n  foreach( ['one', 'two'] as $value){\n  $I->havePostmetaInDatabase($postId, 'data', $value);\n  }\n
                                                                                                          Parameters
                                                                                                          • int $postId - The post ID.
                                                                                                          • string $meta_key - The meta key.
                                                                                                          • mixed $meta_value - The value to insert in the database, objects and arrays will be serialized.
                                                                                                          haveSiteOptionInDatabase

                                                                                                          Inserts a site option in the database. If the value is an array or an object then the value will be serialized.

                                                                                                          $fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');\n
                                                                                                          Parameters
                                                                                                          • string $key - The name of the option to insert.
                                                                                                          • mixed $value - The value to insert for the option.
                                                                                                          haveSiteTransientInDatabase

                                                                                                          Inserts a site transient in the database. If the value is an array or an object then the value will be serialized.

                                                                                                          $I->haveSiteTransientInDatabase('total_comments_count', 23);\n  // This value will be serialized.\n  $I->haveSiteTransientInDatabase('api_data', ['user' => 'luca', 'token' => '11ae3ijns-j83']);\n
                                                                                                          Parameters
                                                                                                          • string $key - The key of the site transient to insert, w/o the _site_transient_ prefix.
                                                                                                          • mixed $value - The value to insert; if serializable the value will be serialized.
                                                                                                          haveTermInDatabase

                                                                                                          Inserts a term in the database.

                                                                                                          // Insert a random 'genre' term in the database.\n  $I->haveTermInDatabase('non-fiction', 'genre');\n  // Insert a term in the database with term meta.\n  $I->haveTermInDatabase('fiction', 'genre', [\n  'slug' => 'genre--fiction',\n  'meta' => [\n  'readers_count' => 23\n  ]\n  ]);\n
                                                                                                          Parameters
                                                                                                          • string $name - The term name, e.g. \"Fuzzy\".
                                                                                                          • string $taxonomy - The term taxonomy
                                                                                                          • array/\\Codeception\\Module\\array/array $overrides - An array of values to override the default ones. haveTermMetaInDatabase

                                                                                                            Inserts a term meta row in the database. Objects and array meta values will be serialized.

                                                                                                            $I->haveTermMetaInDatabase($fictionId, 'readers_count', 23);\n  // Insert some meta that will be serialized.\n  $I->haveTermMetaInDatabase($fictionId, 'flags', [3, 4, 89]);\n  // Use a loop to insert one meta per row.\n  foreach([3, 4, 89] as $value) {\n  $I->haveTermMetaInDatabase($fictionId, 'flag', $value);\n  }\n
                                                                                                            Parameters
                                                                                                            • int $term_id - The ID of the term to insert the meta for.
                                                                                                            • string $meta_key - The key of the meta to insert.
                                                                                                            • mixed $meta_value - The value of the meta to insert, if serializable it will be serialized.
                                                                                                            haveTermRelationshipInDatabase

                                                                                                            Creates a term relationship in the database. No check about the consistency of the insertion is made. E.g. a post could be assigned a term from a taxonomy that's not registered for that post type.

                                                                                                            // Assign the `fiction` term to a book.\n  $I->haveTermRelationshipInDatabase($bookId, $fictionId);\n
                                                                                                            Parameters
                                                                                                            • int $object_id - A post ID, a user ID or anything that can be assigned a taxonomy term.
                                                                                                            • int $term_taxonomy_id - The term_taxonomy_id of the term and taxonomy to create a relation with.
                                                                                                            • int $term_order - Defaults to 0.
                                                                                                            haveTransientInDatabase

                                                                                                            Inserts a transient in the database. If the value is an array or an object then the value will be serialized. Since the transients are set in the context of tests it's not possible to set an expiration directly.

                                                                                                            // Store an array in the `tweets` transient.\n  $I->haveTransientInDatabase('tweets', $tweets);\n
                                                                                                            Parameters
                                                                                                            • string $transient - The transient name.
                                                                                                            • mixed $value - The transient value.
                                                                                                            haveUserCapabilitiesInDatabase

                                                                                                            Sets a user capabilities in the database.

                                                                                                            // Assign one user a role in a blog.\n  $blogId = $I->haveBlogInDatabase('test');\n  $editor = $I->haveUserInDatabase('luca', 'editor');\n  $capsIds = $I->haveUserCapabilitiesInDatabase($editor, [$blogId => 'editor']);\n  // Assign a user two roles in blog 1.\n  $capsIds = $I->haveUserCapabilitiesInDatabase($userId, ['editor', 'subscriber']);\n  // Assign one user different roles in different blogs.\n  $capsIds = $I->haveUserCapabilitiesInDatabase($userId, [$blogId1 => 'editor', $blogId2 => 'author']);\n  // Assign a user a role and an additional capability in blog 1.\n  $I->haveUserCapabilitiesInDatabase($userId, ['editor' => true, 'edit_themes' => true]);\n  // Assign a user a mix of roles and capabilities in different blogs.\n  $capsIds = $I->haveUserCapabilitiesInDatabase(\n  $userId,\n  [\n  $blogId1 => ['editor' => true, 'edit_themes' => true],\n  $blogId2 => ['administrator' => true, 'edit_themes' => false]\n  ]\n  );\n  associative array of blog IDs/roles for a multisite\n  installation (e.g. `[1 => 'administrator`, 2 =>\n  'subscriber']`).\n
                                                                                                            Parameters
                                                                                                            • int $userId - The ID of the user to set the capabilities of.
                                                                                                            • string/\\Codeception\\Module\\array/\\Codeception\\Module\\array $role - Either a role string (e.g. administrator),an haveUserInDatabase

                                                                                                              Inserts a user and its meta in the database. defaults to subscriber. If more than one role is specified, then the first role in the list will be the user primary role and the wp_user_level will be set to that role. in the users and usermeta table.

                                                                                                              // Create an editor user in blog 1 w/ specific email.\n  $userId = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);\n  // Create a subscriber user in blog 1.\n  $subscriberId = $I->haveUserInDatabase('subscriber');\n  // Create a user editor in blog 1, author in blog 2, administrator in blog 3.\n  $userWithMeta = $I->haveUserInDatabase('luca',\n  [\n  1 => 'editor',\n  2 => 'author',\n  3 => 'administrator'\n  ], [\n  'user_email' => 'luca@example.org'\n  'meta' => ['a meta_key' => 'a_meta_value']\n  ]\n  );\n  // Create editor in blog 1 w/ `edit_themes` cap, author in blog 2, admin in blog 3 w/o `manage_options` cap.\n  $userWithMeta = $I->haveUserInDatabase('luca',\n  [\n  1 => ['editor', 'edit_themes'],\n  2 => 'author',\n  3 => ['administrator' => true, 'manage_options' => false]\n  ]\n  );\n  // Create a user w/o role.\n  $userId = $I->haveUserInDatabase('luca', '');\n
                                                                                                              Parameters
                                                                                                              • string $user_login - The user login name.
                                                                                                              • string/string/\\Codeception\\Module\\array $role - The user role slug(s), e.g. administrator or ['author', 'editor'];
                                                                                                              • array/\\Codeception\\Module\\array/array $overrides - An associative array of column names and values overriding defaults haveUserLevelsInDatabase

                                                                                                                Sets the user access level meta in the database for a user. IDs/roles for a multisite installation (e.g. [1 => 'administrator, 2 => 'subscriber']`).

                                                                                                                $userId = $I->haveUserInDatabase('luca', 'editor');\n  $moreThanAnEditorLessThanAnAdmin = 8;\n  $I->haveUserLevelsInDatabase($userId, $moreThanAnEditorLessThanAnAdmin);\n
                                                                                                                Parameters
                                                                                                                • int $userId - The ID of the user to set the level for.
                                                                                                                • \\Codeception\\Module\\array/string $role - Either a role string (e.g. administrator) or an array of blog haveUserMetaInDatabase

                                                                                                                  Sets a user meta in the database.

                                                                                                                  $userId = $I->haveUserInDatabase('luca', 'editor');\n  $I->haveUserMetaInDatabase($userId, 'karma', 23);\n  values will trigger the insertion of multiple rows.\n
                                                                                                                  Parameters
                                                                                                                  • int $userId - The user ID.
                                                                                                                  • string $meta_key - The meta key to set the value for.
                                                                                                                  • mixed $meta_value - Either a single value or an array of values; objects will be serialized while array of
                                                                                                                  importSql

                                                                                                                  Loads a set SQL code lines in the current database.

                                                                                                                  // Import a SQL string.\n  $I->importSql([$sqlString]);\n  // Import a set of SQL strings.\n  $I->importSql($sqlStrings);\n  // Import a prepared set of SQL strings.\n  $preparedSqlStrings = array_map(function($line){\n  return str_replace('{{date}}', date('Y-m-d H:i:s'), $line);\n  }, $sqlTemplate);\n  $I->importSql($preparedSqlStrings);\n
                                                                                                                  Parameters
                                                                                                                  • \\Codeception\\Module\\array/array $sql - The SQL strings to load. importSqlDumpFile

                                                                                                                    Import the SQL dump file if populate is enabled.

                                                                                                                    // Import a dump file passing the absolute path.\n  $I->importSqlDumpFile(codecept_data_dir('dumps/start.sql'));\n  Specifying a dump file that file will be imported.\n
                                                                                                                    Parameters
                                                                                                                    • string/null $dumpFile - The dump file that should be imported in place of the default one.
                                                                                                                    seeAttachmentInDatabase

                                                                                                                    Checks for an attachment in the database.

                                                                                                                    $url = 'https://example.org/images/foo.png';\n  $I->seeAttachmentInDatabase(['guid' => $url]);\n
                                                                                                                    Parameters
                                                                                                                    • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeBlogInDatabase

                                                                                                                      Checks for a blog in the blogs table.

                                                                                                                      // Search for a blog by `blog_id`.\n  $I->seeBlogInDatabase(['blog_id' => 23]);\n  // Search for all blogs on a path.\n  $I->seeBlogInDatabase(['path' => '/sub-path/']);\n
                                                                                                                      Parameters
                                                                                                                      • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeCommentInDatabase

                                                                                                                        Checks for a comment in the database. Will look up the \"comments\" table.

                                                                                                                        $I->seeCommentInDatabase(['comment_ID' => 23]);\n
                                                                                                                        Parameters
                                                                                                                        • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeCommentMetaInDatabase

                                                                                                                          Checks that a comment meta value is in the database. Will look up the \"commentmeta\" table.

                                                                                                                          // Assert a specified meta for a comment exists.\n  $I->seeCommentMetaInDatabase(['comment_ID' => $commentId, 'meta_key' => 'karma', 'meta_value' => 23]);\n  // Assert the comment has at least one meta set.\n  $I->seeCommentMetaInDatabase(['comment_ID' => $commentId]);\n
                                                                                                                          Parameters
                                                                                                                          • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeLinkInDatabase

                                                                                                                            Checks for a link in the links table of the database.

                                                                                                                            // Asserts a link exists by name.\n  $I->seeLinkInDatabase(['link_name' => 'my-link']);\n  // Asserts at least one link exists for the user.\n  $I->seeLinkInDatabase(['link_owner' => $userId]);\n
                                                                                                                            Parameters
                                                                                                                            • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeOptionInDatabase

                                                                                                                              Checks if an option is in the database for the current blog, either by criteria or by name and value. If checking for an array or an object then the serialized version will be checked for.

                                                                                                                              // Checks an option is in the database.\n  $I->seeOptionInDatabase('tables_version');\n  // Checks an option is in the database and has a specific value.\n  $I->seeOptionInDatabase('tables_version', '1.0');\n  $I->seeOptionInDatabase(['option_name' => 'tables_version', 'option_value' => 1.0']);\n
                                                                                                                              Parameters
                                                                                                                              • \\Codeception\\Module\\array/string $criteriaOrName - An array of search criteria or the option name.
                                                                                                                              • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                                                                                              • seePageInDatabase

                                                                                                                                Checks for a page in the database.

                                                                                                                                // Asserts a page with an exists in the database.\n  $I->seePageInDatabase(['ID' => 23]);\n  // Asserts a page with a slug and ID exists in the database.\n  $I->seePageInDatabase(['post_title' => 'Test Page', 'ID' => 23]);\n
                                                                                                                                Parameters
                                                                                                                                • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seePostInDatabase

                                                                                                                                  Checks for a post in the database.

                                                                                                                                  // Assert a post exists in the database.\n  $I->seePostInDatabase(['ID' => 23]);\n  // Assert a post with a slug and ID exists in the database.\n  $I->seePostInDatabase(['post_content' => 'test content', 'ID' => 23]);\n
                                                                                                                                  Parameters
                                                                                                                                  • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seePostMetaInDatabase

                                                                                                                                    Checks for a post meta value in the database for the current blog. If the meta_value is an object or an array then the check will be made for serialized values.

                                                                                                                                    $postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']];\n  $I->seePostMetaInDatabase(['post_id' => '$postId', 'meta_key' => 'foo']);\n
                                                                                                                                    Parameters
                                                                                                                                    • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seePostWithTermInDatabase

                                                                                                                                      Checks that a post to term relation exists in the database. The method will check the \"term_relationships\" table.

                                                                                                                                      $fiction = $I->haveTermInDatabase('fiction', 'genre');\n  $postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);\n  $I->seePostWithTermInDatabase($postId, $fiction['term_taxonomy_id']);\n  passed this parameter will be interpreted as a `term_id`, else as a\n  the\n  term order.\n  to build a `taxonomy_term_id` from the `term_id`.\n
                                                                                                                                      Parameters
                                                                                                                                      • int $post_id - The post ID.
                                                                                                                                      • int $term_taxonomy_id - The term term_id or term_taxonomy_id; if the $taxonomy argument is
                                                                                                                                      • int/null $term_order - The order the term applies to the post, defaults to null to not use
                                                                                                                                      • string/null $taxonomy - The taxonomy the term_id is for; if passed this parameter will be used
                                                                                                                                      seeSiteOptionInDatabase

                                                                                                                                      Checks that a site option is in the database.

                                                                                                                                      // Check that the option is set in the database.\n  $I->seeSiteOptionInDatabase('foo_count');\n  // Check that the option is set and has a specific value.\n  $I->seeSiteOptionInDatabase('foo_count', 23);\n
                                                                                                                                      Parameters
                                                                                                                                      • \\Codeception\\Module\\array/string $criteriaOrName - An array of search criteria or the option name.
                                                                                                                                      • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                                                                                                      • seeSiteSiteTransientInDatabase

                                                                                                                                        Checks that a site option is in the database.

                                                                                                                                        // Check a transient exists.\n  $I->seeSiteSiteTransientInDatabase('total_counts');\n  // Check a transient exists and has a specific value.\n  $I->seeSiteSiteTransientInDatabase('total_counts', 23);\n
                                                                                                                                        Parameters
                                                                                                                                        • string $key - The name of the transient to check for, w/o the _site_transient_ prefix.
                                                                                                                                        • mixed/null $value - If provided then the assertion will include the value.
                                                                                                                                        seeTableInDatabase

                                                                                                                                        Checks that a table is in the database.

                                                                                                                                        $options = $I->grabPrefixedTableNameFor('options');\n  $I->seeTableInDatabase($options);\n
                                                                                                                                        Parameters
                                                                                                                                        • string $table - The full table name, including the table prefix.
                                                                                                                                        seeTermInDatabase

                                                                                                                                        Checks for a term in the database. Looks up the terms and term_taxonomy prefixed tables. and the term_taxonomy tables.

                                                                                                                                        $I->seeTermInDatabase(['slug' => 'genre--fiction']);\n  $I->seeTermInDatabase(['name' => 'Fiction', 'slug' => 'genre--fiction']);\n
                                                                                                                                        Parameters
                                                                                                                                        • \\Codeception\\Module\\array/array $criteria - An array of criteria to search for the term, can be columns from the terms seeTermMetaInDatabase

                                                                                                                                          Checks for a term meta in the database.

                                                                                                                                          list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n  $I->haveTermMetaInDatabase($termId, 'rating', 4);\n  $I->seeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'rating', 'meta_value' => 4]);\n
                                                                                                                                          Parameters
                                                                                                                                          • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeTermRelationshipInDatabase

                                                                                                                                            Checks for a term relationship in the database.

                                                                                                                                            $postId = $I->havePostInDatabase(['tax_input' => ['category' => 'one']]);\n  $I->seeTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $oneTermTaxId]);\n
                                                                                                                                            Parameters
                                                                                                                                            • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeTermTaxonomyInDatabase

                                                                                                                                              Checks for a taxonomy taxonomy in the database.

                                                                                                                                              list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');\n  $I->seeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'genre']);\n
                                                                                                                                              Parameters
                                                                                                                                              • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeUserInDatabase

                                                                                                                                                Checks that a user is in the database. The method will check the \"users\" table.

                                                                                                                                                $I->seeUserInDatabase([\n  \"user_email\" => \"test@example.org\",\n  \"user_login\" => \"login name\"\n  ])\n
                                                                                                                                                Parameters
                                                                                                                                                • \\Codeception\\Module\\array/array $criteria - An array of search criteria. seeUserMetaInDatabase

                                                                                                                                                  Checks for a user meta value in the database.

                                                                                                                                                  $I->seeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);\n
                                                                                                                                                  Parameters
                                                                                                                                                  • \\Codeception\\Module\\array/array $criteria - An array of search criteria. useBlog

                                                                                                                                                    Sets the blog to be used. This has nothing to do with WordPress switch_to_blog function, this code will affect the table prefixes used.

                                                                                                                                                    // Switch to the blog with ID 23.\n  $I->useBlog(23);\n  // Switch back to the main blog.\n  $I->useMainBlog();\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $blogId - The ID of the blog to use.
                                                                                                                                                    useMainBlog

                                                                                                                                                    Sets the current blog to the main one (blog_id 1).

                                                                                                                                                    // Switch to the blog with ID 23.\n  $I->useBlog(23);\n  // Switch back to the main blog.\n  $I->useMainBlog();\n
                                                                                                                                                    useTheme

                                                                                                                                                    Sets the current theme options.

                                                                                                                                                    $I->useTheme('twentyseventeen');\n  $I->useTheme('child-of-twentyseventeen', 'twentyseventeen');\n  $I->useTheme('acme', 'acme', 'Acme Theme');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $stylesheet - The theme stylesheet slug, e.g. twentysixteen.
                                                                                                                                                    • string $template - The theme template slug, e.g. twentysixteen, defaults to $stylesheet.
                                                                                                                                                    • string $themeName - The theme name, e.g. Acme, defaults to the \"title\" version of

                                                                                                                                                    This class extends \\Codeception\\Module\\Db

                                                                                                                                                    This class implements \\Codeception\\Lib\\Interfaces\\Db

                                                                                                                                                    "},{"location":"v3/modules/WPFilesystem/","title":"WPFilesystem","text":"

                                                                                                                                                    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                    "},{"location":"v3/modules/WPFilesystem/#wpfilesystem-module","title":"WPFilesystem module","text":"

                                                                                                                                                    This module should be used in acceptance and functional tests, see levels of testing for more information. This module extends the Filesystem module adding WordPress-specific configuration parameters and methods. The module provides methods to read, write and update the WordPress filesystem directly, without relying on WordPress methods, using WordPress functions or triggering WordPress filters. This module also provides methods to scaffold plugins and themes on the fly in the context of tests and auto-remove them after each test.

                                                                                                                                                    "},{"location":"v3/modules/WPFilesystem/#module-requirements-for-codeception-40","title":"Module requirements for Codeception 4.0+","text":"

                                                                                                                                                    This module requires the codeception/module-filesystem Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                    To install the package run:

                                                                                                                                                    composer require --dev codeception/module-filesystem:^1.0\n
                                                                                                                                                    "},{"location":"v3/modules/WPFilesystem/#configuration","title":"Configuration","text":"
                                                                                                                                                    • wpRootFolder required The absolute, or relative to the project root folder, path to the root WordPress installation folder. The WordPress installation root folder is the one that contains the wp-load.php file.
                                                                                                                                                    • themes - defaults to /wp-content/themes; the path, relative to the the WordPress installation root folder, to the themes folder.
                                                                                                                                                    • plugins - defaults to /wp-content/plugins; the path, relative to the WordPress installation root folder, to the plugins folder.
                                                                                                                                                    • mu-plugins - defaults to wp-content/mu-plugins; the path, relative to the WordPress installation root folder, to the must-use plugins folder.
                                                                                                                                                    • uploads - defaults to /wp-content/uploads; the path, relative to the WordPress installation root folder, to the uploads folder.
                                                                                                                                                    "},{"location":"v3/modules/WPFilesystem/#example-configuration","title":"Example configuration","text":"
                                                                                                                                                    modules:\n    enabled:\n        - WPFilesystem\n    config:\n        WPFilesystem:\n            wpRootFolder: \"/var/www/wordpress\"\n
                                                                                                                                                    "},{"location":"v3/modules/WPFilesystem/#public-api","title":"Public API","text":"
                                                                                                                                                    • amInMuPluginPath
                                                                                                                                                    • amInPluginPath
                                                                                                                                                    • amInThemePath
                                                                                                                                                    • amInUploadsPath
                                                                                                                                                    • cleanMuPluginDir
                                                                                                                                                    • cleanPluginDir
                                                                                                                                                    • cleanThemeDir
                                                                                                                                                    • cleanUploadsDir
                                                                                                                                                    • copyDirToMuPlugin
                                                                                                                                                    • copyDirToPlugin
                                                                                                                                                    • copyDirToTheme
                                                                                                                                                    • copyDirToUploads
                                                                                                                                                    • deleteMuPluginFile
                                                                                                                                                    • deletePluginFile
                                                                                                                                                    • deleteThemeFile
                                                                                                                                                    • deleteUploadedDir
                                                                                                                                                    • deleteUploadedFile
                                                                                                                                                    • dontSeeInMuPluginFile
                                                                                                                                                    • dontSeeInPluginFile
                                                                                                                                                    • dontSeeInThemeFile
                                                                                                                                                    • dontSeeInUploadedFile
                                                                                                                                                    • dontSeeMuPluginFileFound
                                                                                                                                                    • dontSeePluginFileFound
                                                                                                                                                    • dontSeeThemeFileFound
                                                                                                                                                    • dontSeeUploadedFileFound
                                                                                                                                                    • getBlogUploadsPath
                                                                                                                                                    • getUploadsPath
                                                                                                                                                    • getWpRootFolder
                                                                                                                                                    • haveMuPlugin
                                                                                                                                                    • havePlugin
                                                                                                                                                    • haveTheme
                                                                                                                                                    • makeUploadsDir
                                                                                                                                                    • openUploadedFile
                                                                                                                                                    • seeInMuPluginFile
                                                                                                                                                    • seeInPluginFile
                                                                                                                                                    • seeInThemeFile
                                                                                                                                                    • seeInUploadedFile
                                                                                                                                                    • seeMuPluginFileFound
                                                                                                                                                    • seePluginFileFound
                                                                                                                                                    • seeThemeFileFound
                                                                                                                                                    • seeUploadedFileFound
                                                                                                                                                    • writeToMuPluginFile
                                                                                                                                                    • writeToPluginFile
                                                                                                                                                    • writeToThemeFile
                                                                                                                                                    • writeToUploadedFile
                                                                                                                                                    amInMuPluginPath

                                                                                                                                                    Sets the current working folder to a folder in a mu-plugin.

                                                                                                                                                    $I->amInMuPluginPath('mu-plugin');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - The path to the folder, relative to the mu-plugins root folder.
                                                                                                                                                    amInPluginPath

                                                                                                                                                    Sets the current working folder to a folder in a plugin.

                                                                                                                                                    $I->amInPluginPath('my-plugin');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - The folder path, relative to the root uploads folder, to change to.
                                                                                                                                                    amInThemePath

                                                                                                                                                    Sets the current working folder to a folder in a theme.

                                                                                                                                                    $I->amInThemePath('my-theme');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - The path to the theme folder, relative to themes root folder.
                                                                                                                                                    amInUploadsPath

                                                                                                                                                    Enters, changing directory, to the uploads folder in the local filesystem.

                                                                                                                                                    $I->amInUploadsPath('/logs');\n  $I->seeFileFound('shop.log');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - The path, relative to the site uploads folder.
                                                                                                                                                    cleanMuPluginDir

                                                                                                                                                    Cleans, emptying it, a folder in a mu-plugin folder.

                                                                                                                                                    $I->cleanMuPluginDir('mu-plugin1/foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $dir - The path to the directory, relative to the mu-plugins root folder.
                                                                                                                                                    cleanPluginDir

                                                                                                                                                    Cleans, emptying it, a folder in a plugin folder.

                                                                                                                                                    $I->cleanPluginDir('my-plugin/foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $dir - The path to the folder, relative to the plugins root folder.
                                                                                                                                                    cleanThemeDir

                                                                                                                                                    Clears, emptying it, a folder in a theme folder.

                                                                                                                                                    $I->cleanThemeDir('my-theme/foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $dir - The path to the folder, relative to the themese root folder.
                                                                                                                                                    cleanUploadsDir

                                                                                                                                                    Clears a folder in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->cleanUploadsDir('some/folder');\n  $I->cleanUploadsDir('some/folder', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $dir - The path to the directory to delete, relative to the uploads folder.
                                                                                                                                                    • string/int/[\\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                    copyDirToMuPlugin

                                                                                                                                                    Copies a folder to a folder in a mu-plugin.

                                                                                                                                                    $I->copyDirToMuPlugin(codecept_data_dir('foo'), 'mu-plugin/foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $src - The path to the source file to copy.
                                                                                                                                                    • string $pluginDst - The path to the destination folder, relative to the mu-plugins root folder.
                                                                                                                                                    copyDirToPlugin

                                                                                                                                                    Copies a folder to a folder in a plugin.

                                                                                                                                                    // Copy the 'foo' folder to the 'foo' folder in the plugin.\n  $I->copyDirToPlugin(codecept_data_dir('foo'), 'my-plugin/foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $src - The path to the source directory to copy.
                                                                                                                                                    • string $pluginDst - The destination path, relative to the plugins root folder.
                                                                                                                                                    copyDirToTheme

                                                                                                                                                    Copies a folder in a theme folder.

                                                                                                                                                    $I->copyDirToTheme(codecept_data_dir('foo'), 'my-theme');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $src - The path to the source file.
                                                                                                                                                    • string $themeDst - The path to the destination folder, relative to the themes root folder.
                                                                                                                                                    copyDirToUploads

                                                                                                                                                    Copies a folder to the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo');\n  $I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $src - The path to the source file, relative to the current uploads folder.
                                                                                                                                                    • string $dst - The path to the destination file, relative to the current uploads folder.
                                                                                                                                                    • string/int/[\\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                    deleteMuPluginFile

                                                                                                                                                    Deletes a file in a mu-plugin folder.

                                                                                                                                                    $I->deleteMuPluginFile('mu-plugin1/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the mu-plugins root folder.
                                                                                                                                                    deletePluginFile

                                                                                                                                                    Deletes a file in a plugin folder.

                                                                                                                                                    $I->deletePluginFile('my-plugin/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The folder path, relative to the plugins root folder.
                                                                                                                                                    deleteThemeFile

                                                                                                                                                    Deletes a file in a theme folder.

                                                                                                                                                    $I->deleteThemeFile('my-theme/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file to delete, relative to the themes root folder.
                                                                                                                                                    deleteUploadedDir

                                                                                                                                                    Deletes a dir in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->deleteUploadedDir('folder');\n  $I->deleteUploadedDir('folder', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $dir - The path to the directory to delete, relative to the uploads folder.
                                                                                                                                                    • string/int/[\\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                    deleteUploadedFile

                                                                                                                                                    Deletes a file in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->deleteUploadedFile('some-file.txt');\n  $I->deleteUploadedFile('some-file.txt', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                    • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                    dontSeeInMuPluginFile

                                                                                                                                                    Checks that a file in a mu-plugin folder does not contain a string.

                                                                                                                                                    $I->dontSeeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the mu-plugins root folder.
                                                                                                                                                    • string $contents - The contents to check the file for.
                                                                                                                                                    dontSeeInPluginFile

                                                                                                                                                    Checks that a file in a plugin folder does not contain a string.

                                                                                                                                                    $I->dontSeeInPluginFile('my-plugin/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                    • string $contents - The contents to check the file for.
                                                                                                                                                    dontSeeInThemeFile

                                                                                                                                                    Checks that a file in a theme folder does not contain a string.

                                                                                                                                                    $I->dontSeeInThemeFile('my-theme/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                    • string $contents - The contents to check the file for.
                                                                                                                                                    dontSeeInUploadedFile

                                                                                                                                                    Checks that a file in the uploads folder does contain a string. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->dontSeeInUploadedFile('some-file.txt', 'foo');\n  $I->dontSeeInUploadedFile('some-file.txt','foo', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                    • string $contents - The not expected file contents or part of them.
                                                                                                                                                    • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                    dontSeeMuPluginFileFound

                                                                                                                                                    Checks that a file is not found in a mu-plugin folder.

                                                                                                                                                    $I->dontSeeMuPluginFileFound('mu-plugin1/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the mu-plugins folder.
                                                                                                                                                    dontSeePluginFileFound

                                                                                                                                                    Checks that a file is not found in a plugin folder.

                                                                                                                                                    $I->dontSeePluginFileFound('my-plugin/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                    dontSeeThemeFileFound

                                                                                                                                                    Checks that a file is not found in a theme folder.

                                                                                                                                                    $I->dontSeeThemeFileFound('my-theme/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                    dontSeeUploadedFileFound

                                                                                                                                                    Checks thata a file does not exist in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->dontSeeUploadedFileFound('some-file.txt');\n  $I->dontSeeUploadedFileFound('some-file.txt','today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                    • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                    getBlogUploadsPath

                                                                                                                                                    Returns the absolute path to a blog uploads folder or file.

                                                                                                                                                    $blogId = $I->haveBlogInDatabase('test');\n  $testTodayUploads = $I->getBlogUploadsPath($blogId);\n  $testLastMonthLogs = $I->getBlogUploadsPath($blogId, '/logs', '-1 month');\n  file or folder.\n  sub-folders in the year/month format; a UNIX timestamp or\n  a string supported by the `strtotime` function; defaults\n  to `now`.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $blogId - The blog ID to get the path for.
                                                                                                                                                    • string $file - The path, relatitve to the blog uploads folder, to the
                                                                                                                                                    • null/string/[\\DateTime](http://php.net/manual/en/class.datetime.php)/[\\DateTime](http://php.net/manual/en/class.datetime.php)Immutable $date - The date that should be used to build the uploads
                                                                                                                                                    getUploadsPath

                                                                                                                                                    Returns the path to the specified uploads file of folder. Not providing a value for $file and $date will return the uploads folder path.

                                                                                                                                                    $todaysPath = $I->getUploadsPath();\n  $lastWeek = $I->getUploadsPath('', '-1 week');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The file path, relative to the uploads folder.
                                                                                                                                                    • mixed $date - A string compatible with strtotime, a Unix timestamp or a Date object.
                                                                                                                                                    getWpRootFolder

                                                                                                                                                    Returns the absolute path to WordPress root folder without trailing slash.

                                                                                                                                                    $rootFolder = $I->getWpRootFolder();\n  $I->assertFileExists($rootFolder . 'wp-load.php');\n
                                                                                                                                                    haveMuPlugin

                                                                                                                                                    Creates a mu-plugin file, including plugin header, in the mu-plugins folder. The code can not contain the opening '<?php' tag.

                                                                                                                                                    $code = 'echo \"Hello world!\"';\n  $I->haveMuPlugin('foo-mu-plugin.php', $code);\n  // Load the code from a file.\n  $code = file_get_contents(codecept_data_dir('code/mu-plugin.php'));\n  $I->haveMuPlugin('foo-mu-plugin.php', $code);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $filename - The path to the file to create, relative to the plugins root folder.
                                                                                                                                                    • string $code - The content of the plugin file with or without the opening PHP tag.
                                                                                                                                                    havePlugin

                                                                                                                                                    Creates a plugin file, including plugin header, in the plugins folder. The plugin is just created and not activated; the code can not contain the opening '<?php' tag.

                                                                                                                                                    $code = 'echo \"Hello world!\"';\n  $I->havePlugin('foo/plugin.php', $code);\n  // Load the code from a file.\n  $code = file_get_contents(codecept_data_dir('code/plugin.php'));\n  $I->havePlugin('foo/plugin.php', $code);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - The path to the file to create, relative to the plugins folder.
                                                                                                                                                    • string $code - The content of the plugin file with or without the opening PHP tag.
                                                                                                                                                    haveTheme

                                                                                                                                                    Creates a theme file structure, including theme style file and index, in the themes folder. The theme is just created and not activated; the code can not contain the opening '<?php' tag.

                                                                                                                                                    $code = 'sayHi();';\n  $functionsCode  = 'function sayHi(){echo \"Hello world\";};';\n  $I->haveTheme('foo', $indexCode, $functionsCode);\n  // Load the code from a file.\n  $indexCode = file_get_contents(codecept_data_dir('code/index.php'));\n  $functionsCode = file_get_contents(codecept_data_dir('code/functions.php'));\n  $I->haveTheme('foo', $indexCode, $functionsCode);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $folder - The path to the theme to create, relative to the themes root folder.
                                                                                                                                                    • string $indexFileCode - The content of the theme index.php file with or without the opening PHP tag.
                                                                                                                                                    • string $functionsFileCode - The content of the theme functions.php file with or without the opening PHP tag.
                                                                                                                                                    makeUploadsDir

                                                                                                                                                    Creates an empty folder in the WordPress installation uploads folder.

                                                                                                                                                    $logsDir = $I->makeUploadsDir('logs/acme');\n  to create.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - The path, relative to the WordPress installation uploads folder, of the folder
                                                                                                                                                    openUploadedFile

                                                                                                                                                    Opens a file in the the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->openUploadedFile('some-file.txt');\n  $I->openUploadedFile('some-file.txt', 'time');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $filename - The path to the file, relative to the current uploads folder.
                                                                                                                                                    • string/int/[\\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                    seeInMuPluginFile

                                                                                                                                                    Checks that a file in a mu-plugin folder contains a string.

                                                                                                                                                    $I->seeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path the file, relative to the mu-plugins root folder.
                                                                                                                                                    • string $contents - The contents to check the file for.
                                                                                                                                                    seeInPluginFile

                                                                                                                                                    Checks that a file in a plugin folder contains a string.

                                                                                                                                                    $I->seeInPluginFile('my-plugin/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                    • string $contents - The contents to check the file for.
                                                                                                                                                    seeInThemeFile

                                                                                                                                                    Checks that a file in a theme folder contains a string.

                                                                                                                                                    <?php\n  $I->seeInThemeFile('my-theme/some-file.txt', 'foo');\n  ?>\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                    • string $contents - The contents to check the file for.
                                                                                                                                                    seeInUploadedFile

                                                                                                                                                    Checks that a file in the uploads folder contains a string. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->seeInUploadedFile('some-file.txt', 'foo');\n  $I->seeInUploadedFile('some-file.txt','foo', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                    • string $contents - The expected file contents or part of them.
                                                                                                                                                    • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                    seeMuPluginFileFound

                                                                                                                                                    Checks that a file is found in a mu-plugin folder.

                                                                                                                                                    $I->seeMuPluginFileFound('mu-plugin1/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the mu-plugins folder.
                                                                                                                                                    seePluginFileFound

                                                                                                                                                    Checks that a file is found in a plugin folder.

                                                                                                                                                    $I->seePluginFileFound('my-plugin/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to thep plugins root folder.
                                                                                                                                                    seeThemeFileFound

                                                                                                                                                    Checks that a file is found in a theme folder.

                                                                                                                                                    $I->seeThemeFileFound('my-theme/some-file.txt');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                    seeUploadedFileFound

                                                                                                                                                    Checks if file exists in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->seeUploadedFileFound('some-file.txt');\n  $I->seeUploadedFileFound('some-file.txt','today');\n  ?>\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $filename - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                    • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                    writeToMuPluginFile

                                                                                                                                                    Writes a file in a mu-plugin folder.

                                                                                                                                                    $I->writeToMuPluginFile('mu-plugin1/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the destination file, relative to the mu-plugins root folder.
                                                                                                                                                    • string $data - The data to write to the file.
                                                                                                                                                    writeToPluginFile

                                                                                                                                                    Writes a file in a plugin folder.

                                                                                                                                                    $I->writeToPluginFile('my-plugin/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                    • string $data - The data to write in the file.
                                                                                                                                                    writeToThemeFile

                                                                                                                                                    Writes a string to a file in a theme folder.

                                                                                                                                                    $I->writeToThemeFile('my-theme/some-file.txt', 'foo');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $file - The path to the file, relative to the themese root folder.
                                                                                                                                                    • string $data - The data to write to the file.
                                                                                                                                                    writeToUploadedFile

                                                                                                                                                    Writes a string to a file in the the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                    $I->writeToUploadedFile('some-file.txt', 'foo bar');\n  $I->writeToUploadedFile('some-file.txt', 'foo bar', 'today');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $filename - The path to the destination file, relative to the current uploads folder.
                                                                                                                                                    • string $data - The data to write to the file.
                                                                                                                                                    • string/int/[\\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.

                                                                                                                                                    This class extends \\Codeception\\Module\\Filesystem

                                                                                                                                                    "},{"location":"v3/modules/WPLoader/","title":"WPLoader","text":"

                                                                                                                                                    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#wploader-module","title":"WPLoader module","text":"

                                                                                                                                                    This module should be used in integration tests, see levels of testing for more information, to bootstrap WordPress code in the context of the tests. Setting the loadOnly parameter to true the module can be additionally used in acceptance and functional tests to access WordPress code in the tests context. This module is a wrapper around the functionalities provided by the WordPress PHPUnit Core test suite, as such it provides the same method and facilities. The parameters provided to the module duplicate the ones used in the WordPress configuration file: the WPLoader module will not bootstrap WordPress using the wp-config.php file, it will define and use its own WordPress configuration built from the module parameters.

                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#everything-happens-in-a-transaction","title":"Everything happens in a transaction","text":"

                                                                                                                                                    When used to bootstrap and install WordPress (loadOnly: false) exactly as the the WordPress PHPUnit Core test suite it is based on, this module will operate any change to the database in a transaction. This means that, in the context of integration tests, the result of any write or delete operation done during the tests will be rolled back at the end of each test method; this is done for a number of reasons like performance and tests independence. Inspection of the database during tests, e.g. stopping execution using XDebug, will not show any change in the database. Keep this in mind while trying to debug integration tests using the WPLoader module. When configured to only load WordPress (loadOnly: true) then any database operation will be committed and written to the database.

                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#configuration","title":"Configuration","text":"
                                                                                                                                                    • wpRootFolder required The absolute, or relative to the project root folder, path to the root WordPress installation folder. The WordPress installation root folder is the one that contains the wp-load.php file.
                                                                                                                                                    • dbName required - The name of the database used by the WordPress installation, same as the DB_NAME constant.
                                                                                                                                                    • dbHost required - The host of the database used by the WordPress installation, same as the DB_HOST constant. If the database is accessible (as is the case on the latest version of [Local by Flywheel][http://localwp.com]) via unix socket, then the string to insert here should look like this localhost:/path/to/the/mysql.sock.
                                                                                                                                                    • dbUser required - The user of the database used by the WordPress installation, same as the DB_USER constant.
                                                                                                                                                    • dbPassword required - The password of the database used by the WordPress installation, same as DB_PASSWORD constant.
                                                                                                                                                    • loadOnly - defaults to false; whether to only load WordPress, without bootstrapping a fresh installation for tests or not. Read more in the \"Using WPLoader in acceptance and functional tests\" section. If this parameter is set to true the following parameters will not apply.
                                                                                                                                                    • isolatedInstall - defaults to true, whether to install and bootstrap the WordPress installation in a secondary PHP thread for thread safety or not. Maintained for back-compatibility purposes with wp-browser first versions: to get a replica of the bootstrap process used by WordPress Core PHPUnit tests leave this to true.
                                                                                                                                                    • installationTableHandling - defaults to empty; it controls how tables created by WordPress and plugins will be handled during the installation of WordPress during tests. By default tables will be emptied of any content, but some plugins might require tables to be dropped before WordPress is installed and after plugins are activated (this used to be the default behavior). Supported values are drop to drop the tables, empty to just empty the tables and let to do nothing about the tables. If you get errors from database queries while the WPLoader module installs the tests, then try changing this parameter value.
                                                                                                                                                    • wpDebug - defaults to true, the value the WP_DEBUG constant will be set to.
                                                                                                                                                    • multisite - defaults to false, the value the MULTISITE constant will be set to.
                                                                                                                                                    • skipPluggables - defaults to false, if set to true will skip the definition of pluggable functions.
                                                                                                                                                    • dbCharset - defaults to utf8, the value the DB_CHARSET constant will be set to.
                                                                                                                                                    • dbCollate - defaults to an empty string, the value the DB_COLLATE constant will be set to.
                                                                                                                                                    • tablePrefix - defaults to wptests_, the value the $table_prefix variable will be set to.
                                                                                                                                                    • domain - defaults to example.org, the domain of the WordPress site to scaffold for the tests.
                                                                                                                                                    • adminEmail - defaults to admin@example.org, the email of the WordPress site to scaffold for the tests.
                                                                                                                                                    • title - defaults to Test Blog, the title of the WordPress site to scaffolded for the tests.
                                                                                                                                                    • phpBinary - defaults to php, the PHP binary the host machine will have to use to bootstrap and load the test WordPress installation.
                                                                                                                                                    • language - defaults to an empty string, the language of the WordPress installation to scaffold.
                                                                                                                                                    • configFile - defaults to an empty string, an additional configuration file to include before loading WordPress. Any instruction in this fill will run before any WordPress file is included.
                                                                                                                                                    • contentFolder - defaults to an empty string; the path, relative to the wpRootFolder or absolute, to the content folder if different from the default one or the one defined by the WP_CONTENT_DIR constant; if the WP_CONTENT_DIR constant is defined in a config file (see the configFile parameter) this will be ignored.
                                                                                                                                                    • pluginsFolder - defaults to an empty string; the path, relative to the wpRootFolder or absolute, to the plugins folder from the wpRootFolder if different from the default one or the one defined by the WP_PLUGIN_DIR constant; if the WP_PLUGIN_DIR constant is defined in a config file (see the configFile parameter) this will be ignored.
                                                                                                                                                    • plugins - defaults to an empty array; a list of plugins that should be loaded before any test case runs and after mu-plugins have been loaded; these should be defined in the folder/plugin-file.php format.
                                                                                                                                                    • activateplugins - defaults to an empty array, a list of plugins that will be activated before any test case runs and after wordpress is fully loaded and set up; these should be defined in the folder/plugin-file.php format; when the multisite option is set to true the plugins will be network activated during the installation.
                                                                                                                                                    • activatePluginsSilently - defaults to an empty array, a list of plugins that will be silently activated, thus not firing the plugins' activation actions, before any test case runs and after wordpress is fully loaded and set up; these should be defined in the folder/plugin-file.php format; when the multisite option is set to true the plugins will be network activated during the installation.
                                                                                                                                                    • bootstrapActions - defaults to an empty string, a list of actions, static functions or functions that should be called after before any test case runs, after plugins have been loaded and activated; static functions should be defined in the YAML array format:
                                                                                                                                                      bootstrapActions:\n    - action_one\n    - action_two\n    - [MyClass, myStaticMethod]\n    - my_function\n
                                                                                                                                                    • theme - defaults to an empty string, the theme that should be activated for the tests; if a string is passed then both template and stylesheet options will be set to the passed value; if an array is passed then the template and stylesheet will be set in that order:

                                                                                                                                                      theme: my-theme\n

                                                                                                                                                      The theme will be set to my-theme.

                                                                                                                                                      theme: [ parent, child ]\n

                                                                                                                                                      The template will be set to parent, the stylesheet will be set to child.

                                                                                                                                                    A word of caution: right now the only way to write tests able to take advantage of the suite is to use the WP_UnitTestCase test case class; while the module will load fine and will raise no problems WP_UnitTestCase will take care of handling the database as intended and using another test case class will almost certainly result in an error if the test case defines more than one test method.

                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#example-configuration","title":"Example configuration","text":"
                                                                                                                                                      modules:\n      enabled:\n          - WPLoader\n      config:\n          WPLoader:\n              multisite: false\n              wpRootFolder: \"/Users/luca/www/wordpress\"\n              dbName: \"wordpress_tests\"\n              dbHost: \"localhost\"\n              dbUser: \"root\"\n              dbPassword: \"password\"\n              isolatedInstall: true\n              installationTableHandling: drop\n              tablePrefix: \"wptests_\"\n              domain: \"wordrpess.localhost\"\n              adminEmail: \"admin@wordpress.localhost\"\n              title: \"Test Blog\"\n              theme: my-theme\n              plugins: ['hello.php', 'my-plugin/my-plugin.php']\n              activatePlugins: ['hello.php', 'my-plugin/my-plugin.php']\n
                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#usage-in-integration-or-wordpress-unit-tests","title":"Usage in integration or \"WordPress unit\" tests","text":"

                                                                                                                                                    The most common use of this module is to run integration, or \"WordPress unit\" tests (see levels of testing for more information).

                                                                                                                                                    As a first step generate a WPTestCase using Codeception command-line utility (see the commands provided by wp-browser):

                                                                                                                                                    codecept generate:wpunit my_suite \"Acme\\User\"\n

                                                                                                                                                    Codeception will generate the tests/my_suite/Acme/UserTest.php class. The class extends the Codeception\\TestCase\\WPTestCase class provided by wp-browser; this looks like a normal PHPUnit test case but has some perks due to it's mixed breed nature. Understanding them might help you work with it:

                                                                                                                                                    • WordPress is installed and configured for the tests before the test case is loaded; WordPress defined functions and classes (and those of the plugins and themes loaded with it) will be available in the setUpBeforeClass method.
                                                                                                                                                    • WordPress is not loaded when PHPUnit will call the data provider methods; this means the post_provider method will generate a function not found exception when the test case runs as the WordPress defined methods are not loaded yet:
                                                                                                                                                      public function post_provider(){\n        // `wp_insert_post` is loaded with WordPress and WordPress has not been loaded yet!\n        return [\n                [wp_insert_post(['post_title' => 'Test', 'post_status' => 'publish'])]\n        ];\n}\n\npublic function test_posts($post_id){\n        $this->assertInstanceOf(WP_Post::class, get_post($post_id));\n}\n
                                                                                                                                                    • WordPress is reset to an initial known state before each test runs; the database transaction is rolled back to wipe any data and tables you might have manipulated in the tests, the global space is cleaned. See Everything happens in a transaction.
                                                                                                                                                    • This is a Codeception Unit test, as such it does provide access to the $this->tester property to access the methods defined in other modules loaded in the suite and to Codeception test doubles
                                                                                                                                                    • This is a PhpUnit test case too; there are way too many testing functions to cover to report them here but, to highlight a few: mocking with Prophecy and the wealth of PHPUnit assertion methods.
                                                                                                                                                    • This is kind of a WordPress Core suite test case; as such it provides access to its functions and to the often-overlooked static::factory() method; in this instance too there are too many methods to list them all but it's worth noting how easy it is to set up test fixtures with the factory:
                                                                                                                                                      public function test_post_creation(){\n        $random_post_id = static::factory()->post->create();\n\n        $this->assertInstanceOf(WP_Post::class, get_post($random_post_id));\n}\n
                                                                                                                                                    • The factory property can be accessed on the tester property too and will work the same way as if called using static::factory():
                                                                                                                                                      public function test_post_creation(){\n        $random_post_id = $this->tester->factory()->post->create();\n\n        $this->assertInstanceOf(WP_Post::class, get_post($random_post_id));\n}\n
                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#wploader-to-only-bootstrap-wordpress","title":"WPLoader to only bootstrap WordPress","text":"

                                                                                                                                                    If the need is to just bootstrap the WordPress installation in the context of the tests variable scope then the WPLoader module loadOnly parameter should be set to true; this could be the case for functional tests in need to access WordPress provided methods, functions and values. An example configuration for the module in this mode is this one:

                                                                                                                                                      modules:\n      enabled:\n          - WPDb # BEFORE the WPLoader one!\n          - WPLoader # AFTER the WPDb one!\n      config:\n          WPDb:\n              dsn: 'mysql:host=localhost;dbname=wordpress'\n              user: 'root'\n              password: 'password'\n              dump: 'tests/_data/dump.sql'\n              populate: true\n              cleanup: true\n              waitlock: 10\n              url: 'http://wordpress.localhost'\n              urlReplacement: true\n              tablePrefix: 'wp_'\n          WPLoader:\n              loadOnly: true \n              wpRootFolder: \"/Users/User/www/wordpress\"\n              dbName: \"wpress-tests\"\n              dbHost: \"localhost\"\n              dbUser: \"root\"\n              dbPassword: \"root\"\n              domain: \"wordpress.localhost\"\n

                                                                                                                                                    With reference to the table above the module will not take care of the test WordPress installation state before and after the tests, the installed and activated plugins, and theme. The module can be used in conjunction with a WPDb module to provide the tests with a WordPress installation suiting the tests at hand; when doing so please take care to list, in the suite configuration file modules section (see example above) the WPDb module before the WPLoader one. Codeception will initialize the modules in the same order they are listed in the modules section of the suite configuration file and the WPLoader module needs the database to be populated by the WPDb module before it runs! As an example this is a correct suite configuration:

                                                                                                                                                    modules:\n  enabled:\n      - WPDb # this before...\n      - WPLoader # ...this one.\n  config:\n      WPDb:\n        # ...\n      WPLoader:\n        loadOnly: true\n        # ... \n

                                                                                                                                                    "},{"location":"v3/modules/WPLoader/#public-api","title":"Public API","text":"
                                                                                                                                                    • debugWpActionFinal
                                                                                                                                                    • debugWpActionInitial
                                                                                                                                                    • debugWpFilterFinal
                                                                                                                                                    • debugWpFilterInitial
                                                                                                                                                    • factory
                                                                                                                                                    • getContentFolder
                                                                                                                                                    • getPluginsFolder
                                                                                                                                                    • startWpFiltersDebug
                                                                                                                                                    • stopWpFiltersDebug
                                                                                                                                                    debugWpActionFinal

                                                                                                                                                    Debugs a single WordPress action final call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                    // Start debugging all WordPress actions final value.\n  add_action('all', [$this,'debugWpActionFinal']);\n  // Run some code firing actions and debug them.\n  // Stop debugging all WordPress actions final value.\n  remove_action('all', [$this,'debugWpActionFinal']);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • mixed $args
                                                                                                                                                    debugWpActionInitial

                                                                                                                                                    Debugs a single WordPress action initial call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                    // Start debugging all WordPress actions initial value.\n  add_action('all', [$this,'debugWpActionInitial']);\n  // Run some code firing actions and debug them.\n  // Stop debugging all WordPress actions initial value.\n  remove_action('all', [$this,'debugWpActionInitial']);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • mixed $args
                                                                                                                                                    debugWpFilterFinal

                                                                                                                                                    Debugs a single WordPress filter final call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                    // Start debugging all WordPress filters final value.\n  add_filter('all', [$this,'debugWpFilterFinal']);\n  // Run some code firing filters and debug them.\n  // Stop debugging all WordPress filters final value.\n  remove_filter('all', [$this,'debugWpFilterFinal']);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • mixed $args
                                                                                                                                                    debugWpFilterInitial

                                                                                                                                                    Debugs a single WordPress filter initial call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                    // Start debugging all WordPress filters initial value.\n  add_filter('all', [$this,'debugWpFilterInitial']);\n  // Run some code firing filters and debug them.\n  // Stop debugging all WordPress filters initial value.\n  remove_filter('all', [$this,'debugWpFilterInitial']);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • mixed $args
                                                                                                                                                    factory

                                                                                                                                                    Accessor method to get the object storing the factories for things. This methods gives access to the same factories provided by the Core test suite.

                                                                                                                                                    $postId = $I->factory()->post->create();\n  $userId = $I->factory()->user->create(['role' => 'administrator']);\n
                                                                                                                                                    getContentFolder

                                                                                                                                                    Returns the absolute path to the WordPress content directory.

                                                                                                                                                    $content = $this->getContentFolder();\n  $themes = $this->getContentFolder('themes');\n  $twentytwenty = $this->getContentFolder('themes/twentytwenty');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - An optional path to append to the content directory absolute path.
                                                                                                                                                    getPluginsFolder

                                                                                                                                                    Returns the absolute path to the plugins directory. The value will first look at the WP_PLUGIN_DIR constant, then the pluginsFolder configuration parameter and will, finally, look in the default path from the WordPress root directory.

                                                                                                                                                    $plugins = $this->getPluginsFolder();\n  $hello = $this->getPluginsFolder('hello.php');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $path - A relative path to append to te plugins directory absolute path.
                                                                                                                                                    startWpFiltersDebug

                                                                                                                                                    Starts the debug of all WordPress filters and actions. The method hook on all filters and actions to debug their value.

                                                                                                                                                    // Start debugging all WordPress filters and action final and initial values.\n  $this->startWpFiltersDebug();\n  // Run some code firing filters and debug them.\n  // Stop debugging all WordPress filters and action final and initial values.\n  $this->stopWpFiltersDebug();\n  the array of arguments as input.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • \\callable $format - A callback function to format the arguments debug output; the callback will receive
                                                                                                                                                    stopWpFiltersDebug

                                                                                                                                                    Stops the debug of all WordPress filters and actions.

                                                                                                                                                    // Start debugging all WordPress filters and action final and initial values.\n  $this->startWpFiltersDebug();\n  // Run some code firing filters and debug them.\n  // Stop debugging all WordPress filters and action final and initial values.\n  $this->stopWpFiltersDebug();\n

                                                                                                                                                    This class extends \\Codeception\\Module

                                                                                                                                                    "},{"location":"v3/modules/WPQueries/","title":"WPQueries","text":"

                                                                                                                                                    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                    "},{"location":"v3/modules/WPQueries/#wpqueries-module","title":"WPQueries module","text":"

                                                                                                                                                    This module should be used in integration tests, see levels of testing for more information, to make assertions on the database queries made by the global $wpdb object. This module requires the WPLoader module to work. The module will set, if not set already, the SAVEQUERIES constant to true and will throw an exception if the constant is already set to a falsy value.

                                                                                                                                                    "},{"location":"v3/modules/WPQueries/#configuration","title":"Configuration","text":"

                                                                                                                                                    This module does not require any configuration, but requires the WPLoader module to work correctly.

                                                                                                                                                    "},{"location":"v3/modules/WPQueries/#usage","title":"Usage","text":"

                                                                                                                                                    This module must be used in a test case extending the \\Codeception\\TestCase\\WPTestCase class.

                                                                                                                                                    The module public API is accessible calling via the \\Codeception\\TestCase\\WPTestCase::queries() method:

                                                                                                                                                    <?php\n\nuse Codeception\\Module\\WPQueries;\n\nclass WPQueriesUsageTest extends \\Codeception\\TestCase\\WPTestCase\n{\n    public function test_queries_made_by_factory_are_not_tracked()\n    {\n        $currentQueriesCount = $this->queries()->countQueries();\n\n        $this->assertNotEmpty($currentQueriesCount);\n\n        static::factory()->post->create_many(3);\n\n        $this->assertNotEmpty($currentQueriesCount);\n        $this->assertEquals($currentQueriesCount, $this->queries()->countQueries());\n    }\n\n    public function test_count_queries()\n    {\n        $currentQueriesCount = $this->queries()->countQueries();\n\n        $this->assertNotEmpty($currentQueriesCount);\n\n        foreach (range(1, 3) as $i) {\n            wp_insert_post(['post_title' => 'Post ' . $i, 'post_content' => str_repeat('test', $i)]);\n        }\n\n        $this->assertNotEmpty($currentQueriesCount);\n        $this->assertGreaterThan($currentQueriesCount, $this->queries()->countQueries());\n    }\n}\n
                                                                                                                                                    "},{"location":"v3/modules/WPQueries/#public-api","title":"Public API","text":"
                                                                                                                                                    • assertCountQueries
                                                                                                                                                    • assertNotQueries
                                                                                                                                                    • assertNotQueriesByAction
                                                                                                                                                    • assertNotQueriesByFilter
                                                                                                                                                    • assertNotQueriesByFunction
                                                                                                                                                    • assertNotQueriesByMethod
                                                                                                                                                    • assertNotQueriesByStatement
                                                                                                                                                    • assertNotQueriesByStatementAndAction
                                                                                                                                                    • assertNotQueriesByStatementAndFilter
                                                                                                                                                    • assertNotQueriesByStatementAndFunction
                                                                                                                                                    • assertNotQueriesByStatementAndMethod
                                                                                                                                                    • assertQueries
                                                                                                                                                    • assertQueriesByAction
                                                                                                                                                    • assertQueriesByFilter
                                                                                                                                                    • assertQueriesByFunction
                                                                                                                                                    • assertQueriesByMethod
                                                                                                                                                    • assertQueriesByStatement
                                                                                                                                                    • assertQueriesByStatementAndAction
                                                                                                                                                    • assertQueriesByStatementAndFilter
                                                                                                                                                    • assertQueriesByStatementAndFunction
                                                                                                                                                    • assertQueriesByStatementAndMethod
                                                                                                                                                    • assertQueriesCountByAction
                                                                                                                                                    • assertQueriesCountByFilter
                                                                                                                                                    • assertQueriesCountByFunction
                                                                                                                                                    • assertQueriesCountByMethod
                                                                                                                                                    • assertQueriesCountByStatement
                                                                                                                                                    • assertQueriesCountByStatementAndAction
                                                                                                                                                    • assertQueriesCountByStatementAndFilter
                                                                                                                                                    • assertQueriesCountByStatementAndFunction
                                                                                                                                                    • assertQueriesCountByStatementAndMethod
                                                                                                                                                    • countQueries
                                                                                                                                                    • getQueries
                                                                                                                                                    assertCountQueries

                                                                                                                                                    Asserts that n queries have been made.

                                                                                                                                                    $posts = $this->factory()->post->create_many(3);\n  $cachedUsers = $this->factory()->user->create_many(2);\n  $nonCachedUsers = $this->factory()->user->create_many(2);\n  foreach($cachedUsers as $userId){\n  wp_cache_set('page-posts-for-user-' . $userId, $posts, 'acme');\n  }\n  // Run the same query as different users\n  foreach(array_merge($cachedUsers, $nonCachedUsers) as $userId){\n  $pagePosts = $plugin->getPagePostsForUser($userId);\n  }\n  $I->assertCountQueries(2, 'A query should be made for each user missing cached posts.')\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueries

                                                                                                                                                    Asserts that no queries were made. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $posts = $this->factory()->post->create_many(3);\n  wp_cache_set('page-posts', $posts, 'acme');\n  $pagePosts = $plugin->getPagePosts();\n  $I->assertNotQueries('Queries should not be made if the cache is set.')\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByAction

                                                                                                                                                    Asserts that no queries were made as a consequence of the specified action. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_action( 'edit_post', function($postId){\n  $count = get_option('acme_title_updates_count');\n  update_option('acme_title_updates_count', ++$count);\n  } );\n  wp_delete_post($bookId);\n  $this->assertNotQueriesByAction('edit_post');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $action - The action name, e.g. 'init'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByFilter

                                                                                                                                                    Asserts that no queries were made as a consequence of the specified filter. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_filter('the_title', function($title, $postId){\n  $post = get_post($postId);\n  if($post->post_type !== 'book'){\n  return $title;\n  }\n  $new = get_option('acme_new_prefix');\n  return \"{$new} - \" . $title;\n  });\n  $title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);\n  $this->assertNotQueriesByFilter('the_title');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByFunction

                                                                                                                                                    Asserts that no queries were made by the specified function. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $this->assertEmpty(Acme\\get_orphaned_posts());\n  Acme\\delete_orphaned_posts();\n  $this->assertNotQueriesByFunction('Acme\\delete_orphaned_posts');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $function - The fully qualified name of the function to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByMethod

                                                                                                                                                    Asserts that no queries have been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $options = new Acme\\Options();\n  $options->update('adsSource', 'not-a-real-url.org');\n  $I->assertNotQueriesByMethod('Acme\\Options', 'update');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $class - The fully qualified name of the class to check.
                                                                                                                                                    • string $method - The name of the method to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByStatement

                                                                                                                                                    Asserts that no queries have been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $bookRepository = new Acme\\BookRepository();\n  $repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);\n  $this->assertNotQueriesByStatement('INSERT', 'Deferred write should happen on __destruct');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByStatementAndAction

                                                                                                                                                    Asserts that no queries were made as a consequence of the specified action containing the SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_action( 'edit_post', function($postId){\n  $count = get_option('acme_title_updates_count');\n  update_option('acme_title_updates_count', ++$count);\n  } );\n  wp_delete_post($bookId);\n  $this->assertNotQueriesByStatementAndAction('DELETE', 'delete_post');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $action - The action name, e.g. 'init'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByStatementAndFilter

                                                                                                                                                    Asserts that no queries were made as a consequence of the specified filter containing the specified SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_filter('the_title', function($title, $postId){\n  $post = get_post($postId);\n  if($post->post_type !== 'book'){\n  return $title;\n  }\n  $new = get_option('acme_new_prefix');\n  return \"{$new} - \" . $title;\n  });\n  $title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);\n  $this->assertNotQueriesByStatementAndFilter('SELECT', 'the_title');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByStatementAndFunction

                                                                                                                                                    Asserts that no queries were made by the specified function starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    wp_insert_post(['ID' => $bookId, 'post_title' => 'The Call of the Wild']);\n  $this->assertNotQueriesByStatementAndFunction('INSERT', 'wp_insert_post');\n  $this->assertQueriesByStatementAndFunction('UPDATE', 'wp_insert_post');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $function - The name of the function to check the assertions for.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertNotQueriesByStatementAndMethod

                                                                                                                                                    Asserts that no queries were made by the specified class method starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    Acme\\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();\n  $this->assertQueriesByStatementAndMethod('INSERT', Acme\\BookRepository::class, 'commit');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $class - The fully qualified name of the class to check.
                                                                                                                                                    • string $method - The name of the method to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueries

                                                                                                                                                    Asserts that at least one query was made during the test. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    wp_cache_delete('page-posts', 'acme');\n  $pagePosts = $plugin->getPagePosts();\n  $I->assertQueries('Queries should be made to set the cache.')\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByAction

                                                                                                                                                    Asserts that at least one query was made as a consequence of the specified action. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_action( 'edit_post', function($postId){\n  $count = get_option('acme_title_updates_count');\n  update_option('acme_title_updates_count', ++$count);\n  } );\n  wp_update_post(['ID' => $bookId, 'post_title' => 'New Title']);\n  $this->assertQueriesByAction('edit_post');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $action - The action name, e.g. 'init'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByFilter

                                                                                                                                                    Asserts that at least one query was made as a consequence of the specified filter. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_filter('the_title', function($title, $postId){\n  $post = get_post($postId);\n  if($post->post_type !== 'book'){\n  return $title;\n  }\n  $new = get_option('acme_new_prefix');\n  return \"{$new} - \" . $title;\n  });\n  $title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);\n  $this->assertQueriesByFilter('the_title');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByFunction

                                                                                                                                                    Asserts that queries were made by the specified function. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    acme_clean_queue();\n  $this->assertQueriesByFunction('acme_clean_queue');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $function - The fully qualified name of the function to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByMethod

                                                                                                                                                    Asserts that at least one query has been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $options = new Acme\\Options();\n  $options->update('showAds', false);\n  $I->assertQueriesByMethod('Acme\\Options', 'update');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $class - The fully qualified name of the class to check.
                                                                                                                                                    • string $method - The name of the method to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByStatement

                                                                                                                                                    Asserts that at least a query starting with the specified statement was made. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    wp_cache_flush();\n  cached_get_posts($args);\n  $I->assertQueriesByStatement('SELECT');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByStatementAndAction

                                                                                                                                                    Asserts that at least one query was made as a consequence of the specified action containing the SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_action( 'edit_post', function($postId){\n  $count = get_option('acme_title_updates_count');\n  update_option('acme_title_updates_count', ++$count);\n  } );\n  wp_update_post(['ID' => $bookId, 'post_title' => 'New']);\n  $this->assertQueriesByStatementAndAction('UPDATE', 'edit_post');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $action - The action name, e.g. 'init'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByStatementAndFilter

                                                                                                                                                    Asserts that at least one query was made as a consequence of the specified filter containing the SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_filter('the_title', function($title, $postId){\n  $post = get_post($postId);\n  if($post->post_type !== 'book'){\n  return $title;\n  }\n  $new = get_option('acme_new_prefix');\n  return \"{$new} - \" . $title;\n  });\n  $title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);\n  $this->assertQueriesByStatementAndFilter('SELECT', 'the_title');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByStatementAndFunction

                                                                                                                                                    Asserts that queries were made by the specified function starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    wp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);\n  $this->assertQueriesByStatementAndFunction('INSERT', 'wp_insert_post');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $function - The fully qualified function name.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesByStatementAndMethod

                                                                                                                                                    Asserts that queries were made by the specified class method starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    Acme\\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();\n  $this->assertQueriesByStatementAndMethod('UPDATE', Acme\\BookRepository::class, 'commit');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $class - The fully qualified name of the class to check.
                                                                                                                                                    • string $method - The name of the method to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByAction

                                                                                                                                                    Asserts that n queries were made as a consequence of the specified action. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_action( 'edit_post', function($postId){\n  $count = get_option('acme_title_updates_count');\n  update_option('acme_title_updates_count', ++$count);\n  } );\n  wp_update_post(['ID' => $bookOneId, 'post_title' => 'One']);\n  wp_update_post(['ID' => $bookTwoId, 'post_title' => 'Two']);\n  wp_update_post(['ID' => $bookThreeId, 'post_title' => 'Three']);\n  $this->assertQueriesCountByAction(3, 'edit_post');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $action - The action name, e.g. 'init'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByFilter

                                                                                                                                                    Asserts that n queries were made as a consequence of the specified filter. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_filter('the_title', function($title, $postId){\n  $post = get_post($postId);\n  if($post->post_type !== 'book'){\n  return $title;\n  }\n  $new = get_option('acme_new_prefix');\n  return \"{$new} - \" . $title;\n  });\n  $title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);\n  $title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);\n  $title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);\n  $this->assertQueriesCountByFilter(2, 'the_title');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByFunction

                                                                                                                                                    Asserts that n queries were made by the specified function. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $this->assertCount(3, Acme\\get_orphaned_posts());\n  Acme\\delete_orphaned_posts();\n  $this->assertQueriesCountByFunction(3, 'Acme\\delete_orphaned_posts');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $function - The function to check the queries for.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByMethod

                                                                                                                                                    Asserts that n queries have been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $bookRepository = new Acme\\BookRepository();\n  $repository->where('ID', 23)->commit('title', 'Peter Pan');\n  $repository->where('ID', 89)->commit('title', 'Moby-dick');\n  $repository->where('ID', 2389)->commit('title', 'The call of the wild');\n  $this->assertQueriesCountByMethod(3, 'Acme\\BookRepository', 'commit');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $class - The fully qualified name of the class to check.
                                                                                                                                                    • string $method - The name of the method to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByStatement

                                                                                                                                                    Asserts that n queries starting with the specified statement were made. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    $bookRepository = new Acme\\BookRepository();\n  $repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);\n  $repository->where('ID', 89)->set('title', 'Moby-dick', $deferred = true);\n  $repository->where('ID', 2389)->set('title', 'The call of the wild', $deferred = false);\n  $this->assertQueriesCountByStatement(1, 'INSERT', 'Deferred write should happen on __destruct');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByStatementAndAction

                                                                                                                                                    Asserts that n queries were made as a consequence of the specified action containing the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_action( 'edit_post', function($postId){\n  $count = get_option('acme_title_updates_count');\n  update_option('acme_title_updates_count', ++$count);\n  } );\n  wp_delete_post($bookOneId);\n  wp_delete_post($bookTwoId);\n  wp_update_post(['ID' => $bookThreeId, 'post_title' => 'New']);\n  $this->assertQueriesCountByStatementAndAction(2, 'DELETE', 'delete_post');\n  $this->assertQueriesCountByStatementAndAction(1, 'INSERT', 'edit_post');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $action - The action name, e.g. 'init'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByStatementAndFilter

                                                                                                                                                    Asserts that n queries were made as a consequence of the specified filter containing the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    add_filter('the_title', function($title, $postId){\n  $post = get_post($postId);\n  if($post->post_type !== 'book'){\n  return $title;\n  }\n  $new = get_option('acme_new_prefix');\n  return \"{$new} - \" . $title;\n  });\n  // Warm up the cache.\n  $title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);\n  // Cache is warmed up now.\n  $title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);\n  $title = apply_filters('the_title', get_post($bookThreeId)->post_title, $bookThreeId);\n  $this->assertQueriesCountByStatementAndFilter(1, 'SELECT', 'the_title');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByStatementAndFunction

                                                                                                                                                    Asserts that n queries were made by the specified function starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    wp_insert_post(['post_type' => 'book', 'post_title' => 'The Call of the Wild']);\n  wp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);\n  wp_insert_post(['post_type' => 'book', 'post_title' => 'The Chocolate Factory']);\n  $this->assertQueriesCountByStatementAndFunction(3, 'INSERT', 'wp_insert_post');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $function - The fully-qualified function name.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    assertQueriesCountByStatementAndMethod

                                                                                                                                                    Asserts that n queries were made by the specified class method starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                    Acme\\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();\n  Acme\\BookRepository::new(['title' => 'Moby-Dick'])->commit();\n  Acme\\BookRepository::new(['title' => 'The Call of the Wild'])->commit();\n  $this->assertQueriesCountByStatementAndMethod(3, 'INSERT', Acme\\BookRepository::class, 'commit');\n  Regular expressions must contain delimiters.\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $n - The expected number of queries.
                                                                                                                                                    • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                    • string $class - The fully qualified name of the class to check.
                                                                                                                                                    • string $method - The name of the method to check.
                                                                                                                                                    • string $message - An optional message to override the default one.
                                                                                                                                                    countQueries

                                                                                                                                                    Returns the current number of queries. Set-up and tear-down queries performed by the test case are filtered out.

                                                                                                                                                    // In a WPTestCase, using the global $wpdb object.\n  $queriesCount = $this->queries()->countQueries();\n  // In a WPTestCase, using a custom $wpdb object.\n  $queriesCount = $this->queries()->countQueries($customWdbb);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • \\wpdb/null $wpdb - A specific instance of the wpdb class or null to use the global one.
                                                                                                                                                    getQueries

                                                                                                                                                    Returns the queries currently performed by the global database object or the specified one. Set-up and tear-down queries performed by the test case are filtered out.

                                                                                                                                                    // In a WPTestCase, using the global $wpdb object.\n  $queries = $this->queries()->getQueries();\n  // In a WPTestCase, using a custom $wpdb object.\n  $queries = $this->queries()->getQueries($customWdbb);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • null/\\wpdb $wpdb - A specific instance of the wpdb class or null to use the global one.

                                                                                                                                                    This class extends \\Codeception\\Module

                                                                                                                                                    "},{"location":"v3/modules/WPWebDriver/","title":"WPWebDriver","text":"

                                                                                                                                                    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                    "},{"location":"v3/modules/WPWebDriver/#wpwebdriver-module","title":"WpWebDriver module","text":"

                                                                                                                                                    This module should be used in acceptance tests, see levels of testing for more information.

                                                                                                                                                    This module extends the WebDriver module adding WordPress-specific configuration parameters and methods.

                                                                                                                                                    The module simulates a user interaction with the site with Javascript support; if you don't need to test your project with Javascript support use the WPBrowser module.

                                                                                                                                                    "},{"location":"v3/modules/WPWebDriver/#module-requirements-for-codeception-40","title":"Module requirements for Codeception 4.0+","text":"

                                                                                                                                                    This module requires the codeception/module-webdriver Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                    To install the package run:

                                                                                                                                                    composer require --dev codeception/module-webdriver:^1.0\n
                                                                                                                                                    "},{"location":"v3/modules/WPWebDriver/#configuration","title":"Configuration","text":"

                                                                                                                                                    Due to the combination of possible browsers, capabilities and configurations, it's not possible to provide an exhaustive coverage of all the possible configuration parameteters here.

                                                                                                                                                    Please refer to WebDriver documentation for more information.

                                                                                                                                                    • url required - Start URL of your WordPress project, e.g. http://wp.test.
                                                                                                                                                    • adminUsername required - This is the login name, not the \"nice\" name, of the administrator user of the WordPress test site. This will be used to fill the username field in WordPress login page.
                                                                                                                                                    • adminPassword required - This is the the password of the administrator use of the WordPress test site. This will be used to fill the password in WordPress login page.
                                                                                                                                                    • adminPath required - The path, relative to the WordPress test site home URL, to the administration area, usually /wp-admin.
                                                                                                                                                    • browser - The browser to use for the tests, e.g. chrome or firefox.
                                                                                                                                                    • capabilities - Depending on the browser set in browser this is a list of browser-specific capabilities.
                                                                                                                                                    "},{"location":"v3/modules/WPWebDriver/#example-configuration","title":"Example configuration","text":"
                                                                                                                                                    modules:\n  enabled:\n    - WPWebDriver\n  config:\n    WPWebDriver:\n      url: 'http://wp.test'\n      adminUsername: 'admin'\n      adminPassword: 'password'\n      adminPath: '/wp-admin'\n      browser: chrome\n      host: localhost\n      port: 4444\n      window_size: false #disabled for Chrome driver\n      capabilities:\n        \"goog:chromeOptions\":\n          args:\n            - \"--headless\"\n            - \"--disable-gpu\"\n            - \"--disable-dev-shm-usage\"\n            - \"--proxy-server='direct://'\"\n            - \"--proxy-bypass-list=*\"\n            - \"--no-sandbox\"\n
                                                                                                                                                    "},{"location":"v3/modules/WPWebDriver/#public-api","title":"Public API","text":"
                                                                                                                                                    • acceptPopup() : void Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt. Don't confuse popups with modal windows, as created by various libraries.

                                                                                                                                                    • activatePlugin($pluginSlug) : void In the plugin administration screen activates one or more plugins clicking the \"Activate\" link.

                                                                                                                                                    The method will not handle authentication and navigation to the plugins administration page.

                                                                                                                                                    • activateTheme($slug) : void Activates a theme.

                                                                                                                                                    The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                    • amEditingPostWithId($id) : void Go to the admin page to edit the post with the specified ID.

                                                                                                                                                    The method will not handle authentication the admin area.

                                                                                                                                                    • amEditingUserWithId($id) : void Go to the admin page to edit the user with the specified ID.

                                                                                                                                                    The method will not handle authentication the admin area.

                                                                                                                                                    • amOnAdminAjaxPage([$queryVars]) : void Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

                                                                                                                                                    The method will not handle authentication, nonces or authorization.

                                                                                                                                                    • amOnAdminPage($page) : void Go to a page in the admininstration area of the site.

                                                                                                                                                    This method will not handle authentication to the administration area.

                                                                                                                                                    • amOnCronPage([$queryVars]) : void Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

                                                                                                                                                    • amOnPage($page) : void

                                                                                                                                                    • amOnPagesPage() : void Go the \"Pages\" administration screen.

                                                                                                                                                    The method will not handle authentication.

                                                                                                                                                    • amOnPluginsPage() : void Go to the plugins administration screen.

                                                                                                                                                    The method will not handle authentication.

                                                                                                                                                    • amOnSubdomain($subdomain) : void

                                                                                                                                                    • amOnThemesPage() : void Moves to the themes administration page.

                                                                                                                                                    • amOnUrl($url) : void

                                                                                                                                                    • appendField($field, $value) : void Append the given text to the given element. Can also add a selection to a select box.

                                                                                                                                                    <?php\n$I->appendField('#mySelectbox', 'SelectValue');\n$I->appendField('#myTextField', 'appended');\n?>\n
                                                                                                                                                    • attachFile($field, $filename) : void

                                                                                                                                                    • cancelPopup() : void Dismisses the active JavaScript popup, as created by window.alert, window.confirm, or window.prompt.

                                                                                                                                                    • checkOption($option) : void

                                                                                                                                                    • clearField($field) : void Clears given field which isn't empty.

                                                                                                                                                    <?php\n$I->clearField('#username');\n
                                                                                                                                                    • click($link, [$context]) : void

                                                                                                                                                    • clickWithLeftButton([$cssOrXPath], [$offsetX], [$offsetY]) : void Performs click with the left mouse button on an element. If the first parameter null then the offset is relative to the actual mouse position. If the second and third parameters are given, then the mouse is moved to an offset of the element's top-left corner. Otherwise, the mouse is moved to the center of the element.

                                                                                                                                                    <?php\n$I->clickWithLeftButton(['css' => '.checkout']);\n$I->clickWithLeftButton(null, 20, 50);\n$I->clickWithLeftButton(['css' => '.checkout'], 20, 50);\n?>\n
                                                                                                                                                    • clickWithRightButton([$cssOrXPath], [$offsetX], [$offsetY]) : void Performs contextual click with the right mouse button on an element. If the first parameter null then the offset is relative to the actual mouse position. If the second and third parameters are given, then the mouse is moved to an offset of the element's top-left corner. Otherwise, the mouse is moved to the center of the element.
                                                                                                                                                    <?php\n$I->clickWithRightButton(['css' => '.checkout']);\n$I->clickWithRightButton(null, 20, 50);\n$I->clickWithRightButton(['css' => '.checkout'], 20, 50);\n?>\n
                                                                                                                                                    • closeTab() : void Closes current browser tab and switches to previous active tab.
                                                                                                                                                    <?php\n$I->closeTab();\n
                                                                                                                                                    • deactivatePlugin($pluginSlug) : void In the plugin administration screen deactivate a plugin clicking the \"Deactivate\" link.

                                                                                                                                                    The method will not handle authentication and navigation to the plugins administration page.

                                                                                                                                                    • debugWebDriverLogs([?Codeception\\TestInterface $test]) : void Print out latest Selenium Logs in debug mode

                                                                                                                                                    • deleteSessionSnapshot($name) : void

                                                                                                                                                    • dontSee($text, [$selector]) : void

                                                                                                                                                    • dontSeeCheckboxIsChecked($checkbox) : void

                                                                                                                                                    • dontSeeCookie($cookie, [array $params]) : void

                                                                                                                                                    • dontSeeCurrentUrlEquals($uri) : void

                                                                                                                                                    • dontSeeCurrentUrlMatches($uri) : void

                                                                                                                                                    • dontSeeElement($selector, [$attributes]) : void

                                                                                                                                                    • dontSeeElementInDOM($selector, [$attributes]) : void Opposite of seeElementInDOM.

                                                                                                                                                    • dontSeeInCurrentUrl($uri) : void

                                                                                                                                                    • dontSeeInField($field, $value) : void

                                                                                                                                                    • dontSeeInFormFields($formSelector, array $params) : void

                                                                                                                                                    • dontSeeInPageSource($text) : void Checks that the page source doesn't contain the given string.

                                                                                                                                                    • dontSeeInPopup($text) : void Checks that the active JavaScript popup, as created by window.alert|window.confirm|window.prompt, does NOT contain the given string.

                                                                                                                                                    • dontSeeInSource($raw) : void

                                                                                                                                                    • dontSeeInTitle($title) : void

                                                                                                                                                    • dontSeeLink($text, [$url]) : void

                                                                                                                                                    • dontSeeOptionIsSelected($selector, $optionText) : void

                                                                                                                                                    • dontSeePluginInstalled($pluginSlug) : void Assert a plugin is not installed in the plugins administration screen.

                                                                                                                                                    The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                    • doubleClick($cssOrXPath) : void Performs a double-click on an element matched by CSS or XPath.

                                                                                                                                                    • dragAndDrop($source, $target) : void Performs a simple mouse drag-and-drop operation.

                                                                                                                                                    <?php\n$I->dragAndDrop('#drag', '#drop');\n?>\n
                                                                                                                                                    • executeAsyncJS($script, [array $arguments]) : void Executes asynchronous JavaScript. A callback should be executed by JavaScript to exit from a script. Callback is passed as a last element in arguments array. Additional arguments can be passed as array in second parameter.
                                                                                                                                                    // wait for 1200 milliseconds my running `setTimeout`\n* $I->executeAsyncJS('setTimeout(arguments[0], 1200)');\n\n$seconds = 1200; // or seconds are passed as argument\n$I->executeAsyncJS('setTimeout(arguments[1], arguments[0])', [$seconds]);\n
                                                                                                                                                    • executeInSelenium(Closure $function) : void Low-level API method. If Codeception commands are not enough, this allows you to use Selenium WebDriver methods directly:
                                                                                                                                                    $I->executeInSelenium(function(\\Facebook\\WebDriver\\Remote\\RemoteWebDriver $webdriver) {\n  $webdriver->get('http://google.com');\n});\n

                                                                                                                                                    This runs in the context of the RemoteWebDriver class. Try not to use this command on a regular basis. If Codeception lacks a feature you need, please implement it and submit a patch.

                                                                                                                                                    • executeJS($script, [array $arguments]) : void Executes custom JavaScript.

                                                                                                                                                    This example uses jQuery to get a value and assigns that value to a PHP variable:

                                                                                                                                                    <?php\n$myVar = $I->executeJS('return $(\"#myField\").val()');\n\n// additional arguments can be passed as array\n// Example shows `Hello World` alert:\n$I->executeJS(\"window.alert(arguments[0])\", ['Hello world']);\n
                                                                                                                                                    • fillField($field, $value) : void

                                                                                                                                                    • grabActiveTheme() : void Returns the slug of the currently active themes.

                                                                                                                                                    The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                    • grabAttributeFrom($cssOrXpath, $attribute) : void

                                                                                                                                                    • grabAvailableThemes([$classes]) : void Returns the list of available themes.

                                                                                                                                                    The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                    • grabCookie($cookie, [array $params]) : void

                                                                                                                                                    • grabCookiesWithPattern($cookiePattern) : void Returns all the cookies whose name matches a regex pattern.

                                                                                                                                                    • grabFromCurrentUrl([$uri]) : void

                                                                                                                                                    • grabFullUrl() : void Grabs the current page full URL including the query vars.

                                                                                                                                                    • grabMultiple($cssOrXpath, [$attribute]) : void

                                                                                                                                                    • grabPageSource() : void Grabs current page source code.

                                                                                                                                                    • grabTextFrom($cssOrXPathOrRegex) : void

                                                                                                                                                    • grabValueFrom($field) : void

                                                                                                                                                    • grabWordPressTestCookie([$name]) : void Returns WordPress default test cookie object if present.

                                                                                                                                                    • loadSessionSnapshot($name) : void

                                                                                                                                                    • logOut([$redirectTo]) : void Navigate to the default WordPress logout page and click the logout link.

                                                                                                                                                    • loginAs($username, $password, [$timeout], [$maxAttempts]) : void Login as the specified user.

                                                                                                                                                    The method will not follow redirection, after the login, to any page. Depending on the driven browser the login might be \"too fast\" and the server might have not replied with valid cookies yet; in that case the method will re-attempt the login to obtain the cookies.

                                                                                                                                                    • loginAsAdmin([$timeout], [$maxAttempts]) : void Login as the administrator user using the credentials specified in the module configuration.

                                                                                                                                                    The method will not follow redirection, after the login, to any page.

                                                                                                                                                    • makeElementScreenshot($selector, [$name]) : void Takes a screenshot of an element of the current window and saves it to tests/_output/debug.
                                                                                                                                                    <?php\n$I->amOnPage('/user/edit');\n$I->makeElementScreenshot('#dialog', 'edit_page');\n// saved to: tests/_output/debug/edit_page.png\n$I->makeElementScreenshot('#dialog');\n// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png\n
                                                                                                                                                    • makeHtmlSnapshot([$name]) : void

                                                                                                                                                    • makeScreenshot([$name]) : void Takes a screenshot of the current window and saves it to tests/_output/debug.

                                                                                                                                                    <?php\n$I->amOnPage('/user/edit');\n$I->makeScreenshot('edit_page');\n// saved to: tests/_output/debug/edit_page.png\n$I->makeScreenshot();\n// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png\n
                                                                                                                                                    • maximizeWindow() : void Maximizes the current window.

                                                                                                                                                    • moveBack() : void Moves back in history.

                                                                                                                                                    • moveForward() : void Moves forward in history.

                                                                                                                                                    • moveMouseOver([$cssOrXPath], [$offsetX], [$offsetY]) : void Move mouse over the first element matched by the given locator. If the first parameter null then the page is used. If the second and third parameters are given, then the mouse is moved to an offset of the element's top-left corner. Otherwise, the mouse is moved to the center of the element.

                                                                                                                                                    <?php\n$I->moveMouseOver(['css' => '.checkout']);\n$I->moveMouseOver(null, 20, 50);\n$I->moveMouseOver(['css' => '.checkout'], 20, 50);\n?>\n
                                                                                                                                                    • openNewTab() : void Opens a new browser tab and switches to it.

                                                                                                                                                    <?php\n$I->openNewTab();\n
                                                                                                                                                    The tab is opened with JavaScript's window.open(), which means: * Some adblockers might restrict it. * The sessionStorage is copied to the new tab (contrary to a tab that was manually opened by the user)

                                                                                                                                                    • performOn($element, $actions, [$timeout]) : void Waits for element and runs a sequence of actions inside its context. Actions can be defined with array, callback, or Codeception\\Util\\ActionSequence instance.

                                                                                                                                                    Actions as array are recommended for simple to combine \"waitForElement\" with assertions; waitForElement($el) and see('text', $el) can be simplified to:

                                                                                                                                                    <?php\n$I->performOn($el, ['see' => 'text']);\n

                                                                                                                                                    List of actions can be pragmatically build using Codeception\\Util\\ActionSequence:

                                                                                                                                                    <?php\n$I->performOn('.model', ActionSequence::build()\n    ->see('Warning')\n    ->see('Are you sure you want to delete this?')\n    ->click('Yes')\n);\n

                                                                                                                                                    Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to exception on failure.

                                                                                                                                                    Whenever you need to define more actions a callback can be used. A WebDriver module is passed for argument:

                                                                                                                                                    <?php\n$I->performOn('.rememberMe', function (WebDriver $I) {\n     $I->see('Remember me next time');\n     $I->seeElement('#LoginForm_rememberMe');\n     $I->dontSee('Login');\n});\n

                                                                                                                                                    In 3rd argument you can set number a seconds to wait for element to appear

                                                                                                                                                    • pressKey($element, $char) : void Presses the given key on the given element. To specify a character and modifier (e.g. Ctrl, Alt, Shift, Meta), pass an array for $char with the modifier as the first element and the character as the second. For special keys, use the constants from Facebook\\WebDriver\\WebDriverKeys.
                                                                                                                                                    <?php\n// <input id=\"page\" value=\"old\" />\n$I->pressKey('#page','a'); // => olda\n$I->pressKey('#page',array('ctrl','a'),'new'); //=> new\n$I->pressKey('#page',array('shift','111'),'1','x'); //=> old!!!1x\n$I->pressKey('descendant-or-self::*[@id='page']','u'); //=> oldu\n$I->pressKey('#name', array('ctrl', 'a'), \\Facebook\\WebDriver\\WebDriverKeys::DELETE); //=>''\n?>\n
                                                                                                                                                    • reloadPage() : void Reloads the current page.

                                                                                                                                                    • resetCookie($cookie, [array $params]) : void

                                                                                                                                                    • resizeWindow($width, $height) : void Resize the current window.

                                                                                                                                                    <?php\n$I->resizeWindow(800, 600);\n
                                                                                                                                                    • saveSessionSnapshot($name) : void

                                                                                                                                                    • scrollTo($selector, [$offsetX], [$offsetY]) : void Move to the middle of the given element matched by the given locator. Extra shift, calculated from the top-left corner of the element, can be set by passing $offsetX and $offsetY parameters.

                                                                                                                                                    <?php\n$I->scrollTo(['css' => '.checkout'], 20, 50);\n?>\n
                                                                                                                                                    • see($text, [$selector]) : void

                                                                                                                                                    • seeCheckboxIsChecked($checkbox) : void

                                                                                                                                                    • seeCookie($cookie, [array $params]) : void

                                                                                                                                                    • seeCurrentUrlEquals($uri) : void

                                                                                                                                                    • seeCurrentUrlMatches($uri) : void

                                                                                                                                                    • seeElement($selector, [$attributes]) : void

                                                                                                                                                    • seeElementInDOM($selector, [$attributes]) : void Checks that the given element exists on the page, even it is invisible.

                                                                                                                                                    <?php\n$I->seeElementInDOM('//form/input[type=hidden]');\n?>\n
                                                                                                                                                    • seeErrorMessage([$classes]) : void In an administration screen look for an error admin notice.

                                                                                                                                                    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

                                                                                                                                                    • seeInCurrentUrl($uri) : void

                                                                                                                                                    • seeInField($field, $value) : void

                                                                                                                                                    • seeInFormFields($formSelector, array $params) : void

                                                                                                                                                    • seeInPageSource($text) : void Checks that the page source contains the given string.

                                                                                                                                                    <?php\n$I->seeInPageSource('<link rel=\"apple-touch-icon\"');\n
                                                                                                                                                    • seeInPopup($text) : void Checks that the active JavaScript popup, as created by window.alert|window.confirm|window.prompt, contains the given string.

                                                                                                                                                    • seeInSource($raw) : void

                                                                                                                                                    • seeInTitle($title) : void

                                                                                                                                                    • seeLink($text, [$url]) : void

                                                                                                                                                    • seeMessage([$classes]) : void In an administration screen look for an admin notice.

                                                                                                                                                    The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

                                                                                                                                                    • seeNumberOfElements($selector, $expected) : void

                                                                                                                                                    • seeNumberOfElementsInDOM($selector, $expected) : void

                                                                                                                                                    • seeNumberOfTabs($number) : void Checks current number of opened tabs

                                                                                                                                                    <?php\n$I->seeNumberOfTabs(2);\n
                                                                                                                                                    • seeOptionIsSelected($selector, $optionText) : void

                                                                                                                                                    • seePluginActivated($pluginSlug) : void Assert a plugin is activated in the plugin administration screen.

                                                                                                                                                    The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                    • seePluginDeactivated($pluginSlug) : void Assert a plugin is not activated in the plugins administration screen.

                                                                                                                                                    The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                    • seePluginInstalled($pluginSlug) : void Assert a plugin is installed, no matter its activation status, in the plugin administration screen.

                                                                                                                                                    The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                    • seeThemeActivated($slug) : void Verifies that a theme is active.

                                                                                                                                                    The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                    • seeWpDiePage() : void Checks that the current page is one generated by the wp_die function.

                                                                                                                                                    The method will try to identify the page based on the default WordPress die page HTML attributes.

                                                                                                                                                    • selectOption($select, $option) : void

                                                                                                                                                    • setCookie($cookie, $value, [array $params], [$showDebug]) : void

                                                                                                                                                    • submitForm($selector, array $params, [$button]) : void Submits the given form on the page, optionally with the given form values. Give the form fields values as an array. Note that hidden fields can't be accessed.

                                                                                                                                                    Skipped fields will be filled by their values from the page. You don't need to click the 'Submit' button afterwards. This command itself triggers the request to form's action.

                                                                                                                                                    You can optionally specify what button's value to include in the request with the last parameter as an alternative to explicitly setting its value in the second parameter, as button values are not otherwise included in the request.

                                                                                                                                                    Examples:

                                                                                                                                                    <?php\n$I->submitForm('#login', [\n    'login' => 'davert',\n    'password' => '123456'\n]);\n// or\n$I->submitForm('#login', [\n    'login' => 'davert',\n    'password' => '123456'\n], 'submitButtonName');\n

                                                                                                                                                    For example, given this sample \"Sign Up\" form:

                                                                                                                                                    <form action=\"/sign_up\">\n    Login:\n    <input type=\"text\" name=\"user[login]\" /><br/>\n    Password:\n    <input type=\"password\" name=\"user[password]\" /><br/>\n    Do you agree to our terms?\n    <input type=\"checkbox\" name=\"user[agree]\" /><br/>\n    Select pricing plan:\n    <select name=\"plan\">\n        <option value=\"1\">Free</option>\n        <option value=\"2\" selected=\"selected\">Paid</option>\n    </select>\n    <input type=\"submit\" name=\"submitButton\" value=\"Submit\" />\n</form>\n

                                                                                                                                                    You could write the following to submit it:

                                                                                                                                                    <?php\n$I->submitForm(\n    '#userForm',\n    [\n        'user[login]' => 'Davert',\n        'user[password]' => '123456',\n        'user[agree]' => true\n    ],\n    'submitButton'\n);\n
                                                                                                                                                    Note that \"2\" will be the submitted value for the \"plan\" field, as it is the selected option.

                                                                                                                                                    Also note that this differs from PhpBrowser, in that 'user' => [ 'login' => 'Davert' ] is not supported at the moment. Named array keys must be included in the name as above.

                                                                                                                                                    Pair this with seeInFormFields for quick testing magic.

                                                                                                                                                    <?php\n$form = [\n     'field1' => 'value',\n     'field2' => 'another value',\n     'checkbox1' => true,\n     // ...\n];\n$I->submitForm('//form[@id=my-form]', $form, 'submitButton');\n// $I->amOnPage('/path/to/form-page') may be needed\n$I->seeInFormFields('//form[@id=my-form]', $form);\n?>\n

                                                                                                                                                    Parameter values must be set to arrays for multiple input fields of the same name, or multi-select combo boxes. For checkboxes, either the string value can be used, or boolean values which will be replaced by the checkbox's value in the DOM.

                                                                                                                                                    <?php\n$I->submitForm('#my-form', [\n     'field1' => 'value',\n     'checkbox' => [\n         'value of first checkbox',\n         'value of second checkbox',\n     ],\n     'otherCheckboxes' => [\n         true,\n         false,\n         false,\n     ],\n     'multiselect' => [\n         'first option value',\n         'second option value',\n     ]\n]);\n?>\n

                                                                                                                                                    Mixing string and boolean values for a checkbox's value is not supported and may produce unexpected results.

                                                                                                                                                    Field names ending in \"[]\" must be passed without the trailing square bracket characters, and must contain an array for its value. This allows submitting multiple values with the same name, consider:

                                                                                                                                                    $I->submitForm('#my-form', [\n    'field[]' => 'value',\n    'field[]' => 'another value', // 'field[]' is already a defined key\n]);\n

                                                                                                                                                    The solution is to pass an array value:

                                                                                                                                                    // this way both values are submitted\n$I->submitForm('#my-form', [\n    'field' => [\n        'value',\n        'another value',\n    ]\n]);\n

                                                                                                                                                    The $button parameter can be either a string, an array or an instance of Facebook\\WebDriver\\WebDriverBy. When it is a string, the button will be found by its \"name\" attribute. If $button is an array then it will be treated as a strict selector and a WebDriverBy will be used verbatim.

                                                                                                                                                    For example, given the following HTML:

                                                                                                                                                    <input type=\"submit\" name=\"submitButton\" value=\"Submit\" />\n

                                                                                                                                                    $button could be any one of the following: - 'submitButton' - ['name' => 'submitButton'] - WebDriverBy::name('submitButton')

                                                                                                                                                    • switchToFrame([$locator]) : void Switch to another frame on the page.

                                                                                                                                                    Example:

                                                                                                                                                    <frame name=\"another_frame\" id=\"fr1\" src=\"http://example.com\">\n

                                                                                                                                                    <?php\n# switch to frame by name\n$I->switchToFrame(\"another_frame\");\n# switch to frame by CSS or XPath\n$I->switchToFrame(\"#fr1\");\n# switch to parent page\n$I->switchToFrame();\n
                                                                                                                                                    • switchToIFrame([$locator]) : void Switch to another iframe on the page.

                                                                                                                                                    Example:

                                                                                                                                                    <iframe name=\"another_frame\" id=\"fr1\" src=\"http://example.com\">\n

                                                                                                                                                    <?php\n# switch to iframe by name\n$I->switchToIFrame(\"another_frame\");\n# switch to iframe by CSS or XPath\n$I->switchToIFrame(\"#fr1\");\n# switch to parent page\n$I->switchToIFrame();\n
                                                                                                                                                    • switchToNextTab([$offset]) : void Switches to next browser tab. An offset can be specified.
                                                                                                                                                    <?php\n// switch to next tab\n$I->switchToNextTab();\n// switch to 2nd next tab\n$I->switchToNextTab(2);\n
                                                                                                                                                    • switchToPreviousTab([$offset]) : void Switches to previous browser tab. An offset can be specified.
                                                                                                                                                    <?php\n// switch to previous tab\n$I->switchToPreviousTab();\n// switch to 2nd previous tab\n$I->switchToPreviousTab(2);\n
                                                                                                                                                    • switchToWindow([$name]) : void Switch to another window identified by name.

                                                                                                                                                    The window can only be identified by name. If the $name parameter is blank, the parent window will be used.

                                                                                                                                                    Example:

                                                                                                                                                    <input type=\"button\" value=\"Open window\" onclick=\"window.open('http://example.com', 'another_window')\">\n

                                                                                                                                                    <?php\n$I->click(\"Open window\");\n# switch to another window\n$I->switchToWindow(\"another_window\");\n# switch to parent window\n$I->switchToWindow();\n?>\n

                                                                                                                                                    If the window has no name, match it by switching to next active tab using switchToNextTab method.

                                                                                                                                                    Or use native Selenium functions to get access to all opened windows:

                                                                                                                                                    <?php\n$I->executeInSelenium(function (\\Facebook\\WebDriver\\Remote\\RemoteWebDriver $webdriver) {\n     $handles=$webdriver->getWindowHandles();\n     $last_window = end($handles);\n     $webdriver->switchTo()->window($last_window);\n});\n?>\n
                                                                                                                                                    • type($text, [$delay]) : void Type in characters on active element. With a second parameter you can specify delay between key presses.
                                                                                                                                                    <?php\n// activate input element\n$I->click('#input');\n\n// type text in active element\n$I->type('Hello world');\n\n// type text with a 1sec delay between chars\n$I->type('Hello World', 1);\n

                                                                                                                                                    This might be useful when you an input reacts to typing and you need to slow it down to emulate human behavior. For instance, this is how Credit Card fields can be filled in.

                                                                                                                                                    • typeInPopup($keys) : void Enters text into a native JavaScript prompt popup, as created by window.prompt.

                                                                                                                                                    • uncheckOption($option) : void

                                                                                                                                                    • unselectOption($select, $option) : void Unselect an option in the given select box.

                                                                                                                                                    • wait($timeout) : void Wait for $timeout seconds.

                                                                                                                                                    • waitForElement($element, [$timeout]) : void Waits up to $timeout seconds for an element to appear on the page. If the element doesn't appear, a timeout exception is thrown.

                                                                                                                                                    <?php\n$I->waitForElement('#agree_button', 30); // secs\n$I->click('#agree_button');\n?>\n
                                                                                                                                                    • waitForElementChange($element, Closure $callback, [$timeout]) : void Waits up to $timeout seconds for the given element to change. Element \"change\" is determined by a callback function which is called repeatedly until the return value evaluates to true.
                                                                                                                                                    <?php\nuse \\Facebook\\WebDriver\\WebDriverElement\n$I->waitForElementChange('#menu', function(WebDriverElement $el) {\n    return $el->isDisplayed();\n}, 100);\n?>\n
                                                                                                                                                    • waitForElementClickable($element, [$timeout]) : void Waits up to $timeout seconds for the given element to be clickable. If element doesn't become clickable, a timeout exception is thrown.
                                                                                                                                                    <?php\n$I->waitForElementClickable('#agree_button', 30); // secs\n$I->click('#agree_button');\n?>\n
                                                                                                                                                    • waitForElementNotVisible($element, [$timeout]) : void Waits up to $timeout seconds for the given element to become invisible. If element stays visible, a timeout exception is thrown.
                                                                                                                                                    <?php\n$I->waitForElementNotVisible('#agree_button', 30); // secs\n?>\n
                                                                                                                                                    • waitForElementVisible($element, [$timeout]) : void Waits up to $timeout seconds for the given element to be visible on the page. If element doesn't appear, a timeout exception is thrown.
                                                                                                                                                    <?php\n$I->waitForElementVisible('#agree_button', 30); // secs\n$I->click('#agree_button');\n?>\n
                                                                                                                                                    • waitForJS($script, [$timeout]) : void Executes JavaScript and waits up to $timeout seconds for it to return true.

                                                                                                                                                    In this example we will wait up to 60 seconds for all jQuery AJAX requests to finish.

                                                                                                                                                    <?php\n$I->waitForJS(\"return $.active == 0;\", 60);\n?>\n
                                                                                                                                                    • waitForJqueryAjax([$time]) : void Waits for any jQuery triggered AJAX request to be resolved.

                                                                                                                                                    • waitForText($text, [$timeout], [$selector]) : void Waits up to $timeout seconds for the given string to appear on the page.

                                                                                                                                                    Can also be passed a selector to search in, be as specific as possible when using selectors. waitForText() will only watch the first instance of the matching selector / text provided. If the given text doesn't appear, a timeout exception is thrown.

                                                                                                                                                    <?php\n$I->waitForText('foo', 30); // secs\n$I->waitForText('foo', 30, '.title'); // secs\n?>\n

                                                                                                                                                    This class extends \\Codeception\\Module\\WebDriver

                                                                                                                                                    This class implements \\Codeception\\Lib\\Interfaces\\RequiresPackage, \\Codeception\\Lib\\Interfaces\\ConflictsWithModule, \\Codeception\\Lib\\Interfaces\\ElementLocator, \\Codeception\\Lib\\Interfaces\\PageSourceSaver, \\Codeception\\Lib\\Interfaces\\ScreenshotSaver, \\Codeception\\Lib\\Interfaces\\SessionSnapshot, \\Codeception\\Lib\\Interfaces\\MultiSession, \\Codeception\\Lib\\Interfaces\\Remote, \\Codeception\\Lib\\Interfaces\\Web

                                                                                                                                                    "},{"location":"v3/modules/WordPress/","title":"WordPress","text":"

                                                                                                                                                    This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                    "},{"location":"v3/modules/WordPress/#wordpress-module","title":"WordPress module","text":"

                                                                                                                                                    This module requires good knowledge and attention to be used effectively; you can replace it with a combination of the WPBrowser module together with the WPLoader module in loadOnly mode. This module should be used in functional tests, see levels of testing for more information. This module provides a middle-ground, in terms of testing and effects, between the fully isolated approach of the WPBrowser module and the fully integrated approach of the WPLoader module with loadOnly set to false. It allows to interact with WordPress on a very high level, using methods like $I->loginAs() or $I->amOnPage() as you could do with the WPBrowser module while also loading WordPress in the same variable scope as the tests as the WPLoader module would. Due to WordPress reliance on constants, globals and side-effects this module will make requests to WordPress in an insulated manner and reproduce WordPress environment (globals and super-globals) after each response in the tests variable scope. The module simulates a user interaction with the site without Javascript support, use the WPWebDriver module for any kind of testing that requires Javascript-based interaction with the site.

                                                                                                                                                    "},{"location":"v3/modules/WordPress/#module-requirements-for-codeception-40","title":"Module requirements for Codeception 4.0+","text":"

                                                                                                                                                    This module requires the codeception/lib-innerbrowser Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                    To install the package run:

                                                                                                                                                    composer require --dev codeception/lib-innerbrowser:^1.0\n
                                                                                                                                                    "},{"location":"v3/modules/WordPress/#detecting-requests-coming-from-this-module","title":"Detecting requests coming from this module","text":"

                                                                                                                                                    When it runs this module will set the WPBROWSER_HOST_REQUEST environment variable. You can detect and use that information to, as an example, use the correct database in your test site wp-config.php file:

                                                                                                                                                    <?php\nif ( \n    // Custom header.\n    isset( $_SERVER['HTTP_X_TESTING'] )\n    // Custom user agent.\n    || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )\n    // The env var set by the WPClIr or WordPress modules.\n    || getenv( 'WPBROWSER_HOST_REQUEST' )\n) {\n    // Use the test database if the request comes from a test.\n    define( 'DB_NAME', 'wordpress_test' );\n} else {\n    // Else use the default one.\n    define( 'DB_NAME', 'wordpress' );\n}\n

                                                                                                                                                    "},{"location":"v3/modules/WordPress/#configuration","title":"Configuration","text":"
                                                                                                                                                    • wpRootFolder required The absolute, or relative to the project root folder, path to the root WordPress installation folder. The WordPress installation root folder is the one that contains the wp-load.php file.
                                                                                                                                                    • adminUsername required - This is the login name, not the \"nice\" name, of the administrator user of the WordPress test site. This will be used to fill the username field in WordPress login page.
                                                                                                                                                    • adminPassword required - This is the the password of the administrator use of the WordPress test site. This will be used to fill the password in WordPress login page.
                                                                                                                                                    • adminPath required - The path, relative to the WordPress test site home URL, to the administration area, usually /wp-admin.
                                                                                                                                                    "},{"location":"v3/modules/WordPress/#example-configuration","title":"Example configuration","text":"
                                                                                                                                                      modules:\n      enabled:\n          - WordPress\n      config:\n          WordPress:\n              wpRootFolder: \"/var/www/wordpress\"\n              adminUsername: 'admin'\n              adminPassword: 'password'\n              adminPath: '/wp-admin'\n
                                                                                                                                                    "},{"location":"v3/modules/WordPress/#public-api","title":"Public API","text":"
                                                                                                                                                    • amEditingPostWithId
                                                                                                                                                    • amOnAdminAjaxPage
                                                                                                                                                    • amOnAdminPage
                                                                                                                                                    • amOnCronPage
                                                                                                                                                    • amOnPage
                                                                                                                                                    • amOnPagesPage
                                                                                                                                                    • amOnPluginsPage
                                                                                                                                                    • dontSeePluginInstalled
                                                                                                                                                    • extractCookie
                                                                                                                                                    • getResponseContent
                                                                                                                                                    • getWpRootFolder
                                                                                                                                                    • grabWordPressTestCookie
                                                                                                                                                    • logOut
                                                                                                                                                    • loginAs
                                                                                                                                                    • loginAsAdmin
                                                                                                                                                    • seeErrorMessage
                                                                                                                                                    • seeMessage
                                                                                                                                                    • seePluginActivated
                                                                                                                                                    • seePluginDeactivated
                                                                                                                                                    • seePluginInstalled
                                                                                                                                                    • seeWpDiePage
                                                                                                                                                    amEditingPostWithId

                                                                                                                                                    Go to the admin page to edit the post with the specified ID. The method will not handle authentication the admin area.

                                                                                                                                                    $I->loginAsAdmin();\n  $postId = $I->havePostInDatabase();\n  $I->amEditingPostWithId($postId);\n  $I->fillField('post_title', 'Post title');\n
                                                                                                                                                    Parameters
                                                                                                                                                    • int $id - The post ID.
                                                                                                                                                    amOnAdminAjaxPage

                                                                                                                                                    Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request. The method will not handle authentication, nonces or authorization.

                                                                                                                                                    $I->amOnAdminAjaxPage(['action' => 'my-action', 'data' => ['id' => 23], 'nonce' => $nonce]);\n
                                                                                                                                                    Parameters
                                                                                                                                                    • string/\\Codeception\\Module\\array $queryVars - A string or array of query variables to append to the AJAX path. amOnAdminPage

                                                                                                                                                      Go to a page in the admininstration area of the site.

                                                                                                                                                      $I->loginAs('user', 'password');\n  // Go to the plugins management screen.\n  $I->amOnAdminPage('/plugins.php');\n
                                                                                                                                                      Parameters
                                                                                                                                                      • string $page - The path, relative to the admin area URL, to the page.
                                                                                                                                                      amOnCronPage

                                                                                                                                                      Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

                                                                                                                                                      // Triggers the cron job with an optional query argument.\n  $I->amOnCronPage('/?some-query-var=some-value');\n
                                                                                                                                                      Parameters
                                                                                                                                                      • string/\\Codeception\\Module\\array $queryVars - A string or array of query variables to append to the AJAX path. amOnPage

                                                                                                                                                        Go to a page on the site. The module will try to reach the page, relative to the URL specified in the module configuration, without applying any permalink resolution.

                                                                                                                                                        // Go the the homepage.\n  $I->amOnPage('/');\n  // Go to the single page of post with ID 23.\n  $I->amOnPage('/?p=23');\n  // Go to search page for the string \"foo\".\n  $I->amOnPage('/?s=foo');\n
                                                                                                                                                        Parameters
                                                                                                                                                        • string $page - The path to the page, relative to the the root URL.
                                                                                                                                                        amOnPagesPage

                                                                                                                                                        Go the \"Pages\" administration screen. The method will not handle authentication.

                                                                                                                                                        $I->loginAsAdmin();\n  $I->amOnPagesPage();\n  $I->see('Add New');\n
                                                                                                                                                        amOnPluginsPage

                                                                                                                                                        Go to the plugins administration screen. The method will not handle authentication.

                                                                                                                                                        $I->loginAsAdmin();\n  $I->amOnPluginsPage();\n  $I->activatePlugin('hello-dolly');\n
                                                                                                                                                        dontSeePluginInstalled

                                                                                                                                                        Assert a plugin is not installed in the plugins administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                        $I->loginAsAdmin();\n  $I->amOnPluginsPage();\n  $I->dontSeePluginInstalled('my-plugin');\n
                                                                                                                                                        Parameters
                                                                                                                                                        • string $pluginSlug - The plugin slug, like \"hello-dolly\".
                                                                                                                                                        extractCookie

                                                                                                                                                        Grab a cookie value from the current session, sets it in the $_COOKIE array and returns its value. This method utility is to get, in the scope of test code, the value of a cookie set during the tests.

                                                                                                                                                        $id = $I->haveUserInDatabase('user', 'subscriber', ['user_pass' => 'pass']);\n  $I->loginAs('user', 'pass');\n  // The cookie is now set in the `$_COOKIE` super-global.\n  $I->extractCookie(LOGGED_IN_COOKIE);\n  // Generate a nonce using WordPress methods (see WPLoader in loadOnly mode) with correctly set context.\n  wp_set_current_user($id);\n  $nonce = wp_create_nonce('wp_rest');\n  // Use the generated nonce to make a request to the the REST API.\n  $I->haveHttpHeader('X-WP-Nonce', $nonce);\n
                                                                                                                                                        Parameters
                                                                                                                                                        • string $cookie - The cookie name.
                                                                                                                                                        • array/\\Codeception\\Module\\array/array $params - Parameters to filter the cookie value. getResponseContent

                                                                                                                                                          Returns content of the last response. This method exposes an underlying API for custom assertions.

                                                                                                                                                          // In test class.\n  $this->assertContains($text, $this->getResponseContent(), \"foo-bar\");\n
                                                                                                                                                          getWpRootFolder

                                                                                                                                                          Returns the absolute path to the WordPress root folder.

                                                                                                                                                          $root = $I->getWpRootFolder();\n  $this->assertFileExists($root . '/someFile.txt');\n
                                                                                                                                                          grabWordPressTestCookie

                                                                                                                                                          Returns WordPress default test cookie object if present.

                                                                                                                                                          // Grab the default WordPress test cookie.\n  $wpTestCookie = $I->grabWordPressTestCookie();\n  // Grab a customized version of the test cookie.\n  $myTestCookie = $I->grabWordPressTestCookie('my_test_cookie');\n
                                                                                                                                                          Parameters
                                                                                                                                                          • string $name - Optional, overrides the default cookie name.
                                                                                                                                                          logOut

                                                                                                                                                          Navigate to the default WordPress logout page and click the logout link.

                                                                                                                                                          // Log out using the `wp-login.php` form and return to the current page.\n  $I->logOut(true);\n  // Log out using the `wp-login.php` form and remain there.\n  $I->logOut(false);\n  // Log out using the `wp-login.php` form and move to another page.\n  $I->logOut('/some-other-page');\n
                                                                                                                                                          Parameters
                                                                                                                                                          • bool/bool/string $redirectTo - Whether to redirect to another (optionally specified) page after the logout.
                                                                                                                                                          loginAs

                                                                                                                                                          Login as the specified user. The method will not follow redirection, after the login, to any page.

                                                                                                                                                          $I->loginAs('user', 'password');\n  $I->amOnAdminPage('/');\n  $I->seeElement('.admin');\n
                                                                                                                                                          Parameters
                                                                                                                                                          • string $username - The user login name.
                                                                                                                                                          • string $password - The user password in plain text.
                                                                                                                                                          loginAsAdmin

                                                                                                                                                          Login as the administrator user using the credentials specified in the module configuration. The method will not follow redirection, after the login, to any page.

                                                                                                                                                          $I->loginAsAdmin();\n  $I->amOnAdminPage('/');\n  $I->see('Dashboard');\n
                                                                                                                                                          seeErrorMessage

                                                                                                                                                          In an administration screen look for an error admin notice. The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area. .notice.notice-error ones.

                                                                                                                                                          $I->loginAsAdmin()\n  $I->amOnAdminPage('/');\n  $I->seeErrorMessage('.my-plugin');\n
                                                                                                                                                          Parameters
                                                                                                                                                          • string/string/\\Codeception\\Module\\array $classes - A list of classes the notice should have other than the seeMessage

                                                                                                                                                            In an administration screen look for an admin notice. The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

                                                                                                                                                            $I->loginAsAdmin()\n  $I->amOnAdminPage('/');\n  $I->seeMessage('.missing-api-token.my-plugin');\n
                                                                                                                                                            Parameters
                                                                                                                                                            • string/\\Codeception\\Module\\array/string $classes - A list of classes the message should have in addition to the .notice one. seePluginActivated

                                                                                                                                                              Assert a plugin is activated in the plugin administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              $I->loginAsAdmin();\n  $I->amOnPluginsPage();\n  $I->seePluginActivated('my-plugin');\n
                                                                                                                                                              Parameters
                                                                                                                                                              • string $pluginSlug - The plugin slug, like \"hello-dolly\".
                                                                                                                                                              seePluginDeactivated

                                                                                                                                                              Assert a plugin is not activated in the plugins administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              $I->loginAsAdmin();\n  $I->amOnPluginsPage();\n  $I->seePluginDeactivated('my-plugin');\n
                                                                                                                                                              Parameters
                                                                                                                                                              • string $pluginSlug - The plugin slug, like \"hello-dolly\".
                                                                                                                                                              seePluginInstalled

                                                                                                                                                              Assert a plugin is installed, no matter its activation status, in the plugin administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              $I->loginAsAdmin();\n  $I->amOnPluginsPage();\n  $I->seePluginInstalled('my-plugin');\n
                                                                                                                                                              Parameters
                                                                                                                                                              • string $pluginSlug - The plugin slug, like \"hello-dolly\".
                                                                                                                                                              seeWpDiePage

                                                                                                                                                              Checks that the current page is one generated by the wp_die function. The method will try to identify the page based on the default WordPress die page HTML attributes.

                                                                                                                                                              $I->loginAs('user', 'password');\n  $I->amOnAdminPage('/forbidden');\n  $I->seeWpDiePage();\n

                                                                                                                                                              This class extends \\Codeception\\Lib\\Framework

                                                                                                                                                              This class implements \\Codeception\\Lib\\Interfaces\\Web, \\Codeception\\Lib\\Interfaces\\PageSourceSaver, \\Codeception\\Lib\\Interfaces\\ElementLocator, \\Codeception\\Lib\\Interfaces\\ConflictsWithModule, \\Codeception\\Lib\\Interfaces\\DependsOnModule

                                                                                                                                                              "},{"location":"v3/tutorials/automatically-change-db-in-tests/","title":"Automatically change database during acceptance and functional tests","text":"

                                                                                                                                                              This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                              "},{"location":"v3/tutorials/automatically-change-db-in-tests/#automatically-change-database-during-acceptance-and-functional-tests","title":"Automatically change database during acceptance and functional tests","text":"

                                                                                                                                                              You should always back up any site you run tests on if you care about the site content.

                                                                                                                                                              Now this disclaimer has been made ad nauseam; there's a simple way to use a different database when during tests.

                                                                                                                                                              "},{"location":"v3/tutorials/automatically-change-db-in-tests/#identifying-requests","title":"Identifying requests","text":"

                                                                                                                                                              The first component of this solution is identifying the source of the current HTTP request. WordPress makes this identification before deciding which database to use.

                                                                                                                                                              To provide the WordPress installation with this information, you can set the headers entry of the WPBrowser or WPWebDriver module in the suite configuration file.

                                                                                                                                                              As an example here is an acceptance suite configuration file setting two custom headers, X_WPBROWSER_REQUEST and X_TEST_REQUEST, on each request sent by the WPWebDriver module:

                                                                                                                                                              actor: AcceptanceTester\nmodules:\n    enabled:\n        - WPDb\n        - WPBrowser\n        - \\Helper\\Acceptance\n    config:\n        WPDb:\n            dsn: 'mysql:host=localhost;dbname=tests'\n            user: 'root'\n            password: 'root'\n            dump: 'tests/_data/dump.sql'\n            populate: true\n            cleanup: true\n            waitlock: 10\n            url: 'http://wp.test'\n            urlReplacement: true\n            tablePrefix: 'wp_'\n        WPBrowser:\n            url: 'http://wp.test'\n            adminUsername: 'admin'\n            adminPassword: 'admin'\n            adminPath: '/wp-admin'\n            headers:\n                X_WPBROWSER_REQUEST: 1\n                X_TEST_REQUEST: 1\n

                                                                                                                                                              The two headers are sent on each HTTP request type, not just on GET type requests.

                                                                                                                                                              "},{"location":"v3/tutorials/automatically-change-db-in-tests/#using-a-different-database-to-handle-test-requests","title":"Using a different database to handle test requests","text":"

                                                                                                                                                              Now that each request made by the WPWebDriver module contains those two headers, it's time for WordPress to check those and change the database to use accordingly.

                                                                                                                                                              The database to use is set by the DB_NAME constant that is, in turn, set in the wp-config.php file. Different setups could involve more complex configurations for the wp-config.php file but, for the sake of simplicity, I assume the default WordPress wp-config.php file structure. In the example below, the default database name is wordpress, while the name of the test database is tests.

                                                                                                                                                              - define( 'DB_NAME', 'wordpress' );\n+ if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {\n+     define( 'DB_NAME', 'tests' );\n+ } else {\n+     define( 'DB_NAME', 'wordpress' );\n+ }\n

                                                                                                                                                              The diff shows the replacement done in the WordPress installation wp-config.php file.

                                                                                                                                                              For copy-and-paste pleasure, replace the line starting with:

                                                                                                                                                              define( 'DB_NAME', 'default_db_name' );\n

                                                                                                                                                              With this snippet:

                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {\n      define( 'DB_NAME', 'test_db_name' );\n} else {\n      define( 'DB_NAME', 'default_db_name' );\n}\n

                                                                                                                                                              Where default_db_name is the name of the database your test WordPress installation normally uses.

                                                                                                                                                              Happy, and safer, testing.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/","title":"Setting up wp-browser on Local by Flywheel to test a plugin","text":"

                                                                                                                                                              This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#setting-up-wp-browser-with-local-by-flywheel-to-test-a-plugin","title":"Setting up wp-browser with Local by Flywheel to test a plugin","text":"

                                                                                                                                                              Note: the original version of this guide used, on Mac, the version of Local by Flywheel based on VirtualBox and Docker containers. That version has been replaced by a new one that will not use any virtualization layer. The UI is almost the same but, for back-compatibility purposes, I've not removed the references to the previous version; I have, instead, pointed out where the set up values and procedures might differ due to the changes.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#requirements","title":"Requirements","text":"
                                                                                                                                                              • A Mac or Windows machine
                                                                                                                                                              • A working installation of Local By Flywheel.
                                                                                                                                                              • You should be able to create sites and visit them from your browser without issues.
                                                                                                                                                              • Composer installed and working on your terminal PATH, you should be able to run composer --version at the terminal and see the version correctly.
                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#install-local-by-flywheel","title":"Install Local by Flywheel","text":"

                                                                                                                                                              This walk-through starts after Local by Flywheel has been installed and is correctly running on your machine; you can download Local from the site and follow the installation instructions.

                                                                                                                                                              In the context of this guide I'm assuming the sites directory is ~/Local Sites, the default \"Sites Path\" in Local preferences.

                                                                                                                                                              If your document root lies elsewhere, replace the ~/Local Sites path with the actual directory in each command.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#creating-the-databases-and-installing-wordpress","title":"Creating the databases and installing WordPress","text":"

                                                                                                                                                              Using Local UI create a new site:

                                                                                                                                                              • The site name is myplugin.
                                                                                                                                                              • The site administrator user name is admin.
                                                                                                                                                              • The site administrator password is password.

                                                                                                                                                              Once Local provisioned and installed the new site, open the \"Database\" administration tab and, depending on your OS, start a database administration UI or website. In the image below I'm using Adminer:

                                                                                                                                                              Create a database called tests:

                                                                                                                                                              Make sure you can visit the WordPress installation at http://myplugin.local and that you can correctly access the administration area at http://myplugin.local/wp-admin.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#scaffolding-the-project-folder","title":"Scaffolding the project folder","text":"

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins. Create the main plugin file in the WordPress installation plugins directory, in the ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin/my-plugin.php file:

                                                                                                                                                              <?php\n/**\n * Plugin Name: My plugin\n */ \n

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the WordPress installation at http://myplugin.local/wp-admin/plugins.php.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#installing-wp-browser","title":"Installing wp-browser","text":"

                                                                                                                                                              Open a terminal window and navigate to the plugin directory and initialize the Composer project:

                                                                                                                                                              cd ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin\ncomposer init\n

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. Here is the composer.json file generated by the above answers:

                                                                                                                                                              {\n    \"name\": \"local/my-plugin\",\n    \"type\": \"wordpress-plugin\",\n    \"require\": {}\n}\n

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              composer require --dev lucatume/wp-browser\n

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder. To check Codeception is correctly installed run this command:

                                                                                                                                                              vendor/bin/codecept --version\n

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#setting-up-wp-browser","title":"Setting up wp-browser","text":"

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and \"WordPress unit\" tests.
                                                                                                                                                              • How to connect to the WordPress site \"normal\" database: this is the database that stores the data of the site I would see when visiting the local installation URL at http://myplugin.local.
                                                                                                                                                              • How to connect to the database dedicated to the integration and \"WordPress unit\" tests: this database will be used to install WordPress during integration and \"WordPress unit\" tests.

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that your first step should be to backup the site database.

                                                                                                                                                              You can create a backup of the current site database contents using whatever tool the version of Local you're using provides. In this example I'm using Adminer:

                                                                                                                                                              At any moment you can re-import the site database dump using, again, phpMyAdmin, under the \"Import\" tab:

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#bootstrapping-and-configuring-wp-browser","title":"Bootstrapping and configuring wp-browser","text":"

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              cd ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin\nvendor/bin/codecept init wpbrowser\n

                                                                                                                                                              The initialization guide will ask a number of questions.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#windows-configuration","title":"Windows configuration","text":"

                                                                                                                                                              In the screenshots below are the answers I used to configure wp-browser on Windows.

                                                                                                                                                              Note that I've set up the database host using the values provided by Local UI, yours might differ depending on the version of Local you're using:

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • What is the path of the WordPress root directory? ~/Local Sites/myplugin/app/public
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • What is the host of the test database used by the test site? localhost:10003
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost:10003
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • What is the URL the test site? http://myplugin.local
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@myplugin.local
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#mac-configuration","title":"Mac configuration","text":"

                                                                                                                                                              In the screenshots below are the answers I used to configure wp-browser on Mac.

                                                                                                                                                              Note that I've set up the database host using the values provided by Local UI, yours might differ.

                                                                                                                                                              This screenshot is from the previous version of Local, the one based on VirtualBox and Docker:

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • What is the path of the WordPress root directory? ~/Local Sites/myplugin/app/public
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • What is the host of the test database used by the test site? /Users/lucatume/Library/Application Support/Local/run/FjKWfVMGd/mysql/mysqld.sock ( or 192.168.95.100:4055 on an older version of Local)
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • What is the host of the test database WPLoader should use? /Users/lucatume/Library/Application Support/Local/run/FjKWfVMGd/mysql/mysqld.sock (or 192.168.95.100:4055 on an older version of Local)
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • What is the URL the test site? http://myplugin.local
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@myplugin.local
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#setting-up-the-starting-database-fixture","title":"Setting up the starting database fixture","text":"

                                                                                                                                                              A \"fixture\", in testing terms, is a minimal, starting environment shared by all tests. In BDD it's the Background any scenario will share. In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.

                                                                                                                                                              You should set up this fixture \"manually\", using the site administration UI at http://myplugin.local/wp-admin.

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              When you're done setting up the initial database fixture, export it using the \"Export\" tab of your database tool of choice, and move the file to the ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin/tests/_data/dump.sql directory.

                                                                                                                                                              There is one last step left to complete the setup.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#using-the-tests-database-in-acceptance-and-functional-tests","title":"Using the tests database in acceptance and functional tests","text":"

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the ~/Local Sites/myplugin/app/public/wp-config.php file, the DB_NAME constant is set to local.

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              • If the request is a normal one, use the local database.
                                                                                                                                                              • If the request comes from a test, use the tests database.

                                                                                                                                                              In your IDE/text-editor of choice edit the ~/Local Sites/myplugin/app/public/wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              - define( 'DB_NAME', 'local' );\n+ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { \n+    define( 'DB_NAME', 'tests' );\n+ } else {\n+    define( 'DB_NAME', 'local' );\n+ }\n

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {\n        define( 'DB_NAME', 'tests' );\n} else {\n        define( 'DB_NAME', 'local' );\n}\n

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              headers:\n    X_TEST_REQUEST: 1\n    X_WPBROWSER_REQUEST: 1\n

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers. Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              "},{"location":"v3/tutorials/local-flywheel-setup/#sanity-check","title":"Sanity check","text":"

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works. Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              cd ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin \nvendor/bin/codecept run acceptance\nvendor/bin/codecept run functional\nvendor/bin/codecept run wpunit\nvendor/bin/codecept run unit\n

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept to see a list of the available commands.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/","title":"Setting up wp-browser on MAMP for Mac to test a plugin","text":"

                                                                                                                                                              This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#setting-up-wp-browser-with-mamp-on-mac-to-test-a-plugin","title":"Setting up wp-browser with MAMP on Mac to test a plugin","text":""},{"location":"v3/tutorials/mamp-mac-setup/#requirements","title":"Requirements","text":"
                                                                                                                                                              • A Mac machine
                                                                                                                                                              • A working installation of MAMP.
                                                                                                                                                              • You should be able to create sites and visit them from your browser without issues.
                                                                                                                                                              • Composer installed and working on your terminal PATH, you should be able to run composer --version at the terminal and see the version correctly.

                                                                                                                                                              The version of MAMP used in this tutorial is the free, non PRO, one. MAMP PRO provides more features, but the setup instructions should remain valid.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#install-and-configure-mamp","title":"Install and configure MAMP","text":"

                                                                                                                                                              This walk-through starts after MAMP has been installed and is correctly running on the host machine; you can download MAMP from the site and follow the installation instructions. In the context of this guide I'm assuming the \"Document Root\" directory is the default one, in the /Applications/MAMP/htdocs directory. If your document root lies elsewhere, replace the /Applications/MAMP/htdocs path with the actual directory in each command.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#creating-the-databases-and-installing-wordpress","title":"Creating the databases and installing WordPress","text":"

                                                                                                                                                              Go to the http://localhost/phpMyAdmin/ page and create two new databases:

                                                                                                                                                              • wordpress is the database you will use for WordPress
                                                                                                                                                              • tests is the database you will use for the tests

                                                                                                                                                              Unzip the the WordPress files into the /Applications/MAMP/htdocs and head over to http://localhost to install WordPress.

                                                                                                                                                              The database credentials for the installation are:

                                                                                                                                                              • Database name: wordpress
                                                                                                                                                              • Database user: root
                                                                                                                                                              • Database password: root
                                                                                                                                                              • Database host: localhost

                                                                                                                                                              Use admin as administrator user name and password as password for the administrator user.

                                                                                                                                                              Make sure you can visit the WordPress installation at http://localhost and that you can correctly access the administration area at http://localhost/wp-admin.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#scaffolding-the-project-folder","title":"Scaffolding the project folder","text":"

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins. Create the main plugin file in the WordPress installation plugins directory, in the /Applications/MAMP/htdocs/wp-content/plugins/my-plugin/my-plugin.php file:

                                                                                                                                                              <?php\n/**\n * Plugin Name: My plugin\n */ \n

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the WordPress installation at http://localhost/wp-admin/plugins.php.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#installing-wp-browser","title":"Installing wp-browser","text":"

                                                                                                                                                              Open a terminal window and navigate to the plugin directory and initialize the Composer project:

                                                                                                                                                              cd /Applications/MAMP/htdocs/wp-content/plugins/my-plugin\ncomposer init\n

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. Here is the composer.json file generated by the above answers:

                                                                                                                                                              {\n    \"name\": \"mamp/my-plugin\",\n    \"type\": \"wordpress-plugin\",\n    \"require\": {}\n}\n

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              composer require --dev lucatume/wp-browser\n

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder. To check Codeception is correctly installed run this command:

                                                                                                                                                              vendor/bin/codecept --version\n

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#setting-up-wp-browser","title":"Setting up wp-browser","text":"

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and \"WordPress unit\" tests.
                                                                                                                                                              • How to connect to the WordPress site \"normal\" database: this is the database that stores the data of the site I would see when visiting the local installation URL at http://localhost.
                                                                                                                                                              • How to connect to the database dedicated to the integration and \"WordPress unit\" tests: this database will be used to install WordPress during integration and \"WordPress unit\" tests.

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that your first step should be to backup the site database.

                                                                                                                                                              You can create a backup of the current site database contents using phpMyAdmin, at http://localhost/phpMyAdmin/, under the \"Export\" tab:

                                                                                                                                                              At any moment you can re-import the site database dump using, again, phpMyAdmin, under the \"Import\" tab:

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#bootstrapping-and-configuring-wp-browser","title":"Bootstrapping and configuring wp-browser","text":"

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              cd /Applications/MAMP/htdocs/wp-content/plugins/my-plugin\nvendor/bin/codecept init wpbrowser\n

                                                                                                                                                              The initialization guide will ask a number of questions. In the screenshots below are the answers I used to configure wp-browser.

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • What is the path of the WordPress root directory? /Applications/MAMP/htdocs
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • What is the host of the test database used by the test site? localhost
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • What is the URL the test site? http://localhost
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@wp.test
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#setting-up-the-starting-database-fixture","title":"Setting up the starting database fixture","text":"

                                                                                                                                                              A \"fixture\", in testing terms, is a minimal, starting environment shared by all tests. In BDD it's the Background any scenario will share. In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.

                                                                                                                                                              You should set up this fixture \"manually\", using the site administration UI at http://localhost/wp-admin.

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              When you're done setting up the initial database fixture, export it using the \"Export\" tab of phpMyAdmin, at http://localhost/phpMyAdmin/ and move the file to the /Applications/MAMP/htdocs/wp-content/plugins/my-plugin/tests/_data/dump.sql directory.

                                                                                                                                                              There is one last step left to complete the setup.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#using-the-tests-database-in-acceptance-and-functional-tests","title":"Using the tests database in acceptance and functional tests","text":"

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the /Applications/MAMP/htdocs/wp-config.php file, the DB_NAME constant is set to wordpress.

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              • If the request is a normal one, use the wordpress database.
                                                                                                                                                              • If the request comes from a test, use the tests database.

                                                                                                                                                              In your IDE/text-editor of choice edit the /Applications/MAMP/htdocs/wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              - define( 'DB_NAME', 'wordpress' );\n+ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { \n+    define( 'DB_NAME', 'tests' );\n+ } else {\n+    define( 'DB_NAME', 'wordpress' );\n+ }\n

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {\n        define( 'DB_NAME', 'tests' );\n} else {\n        define( 'DB_NAME', 'wordpress' );\n}\n

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              headers:\n    X_TEST_REQUEST: 1\n    X_WPBROWSER_REQUEST: 1\n

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers. Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              "},{"location":"v3/tutorials/mamp-mac-setup/#sanity-check","title":"Sanity check","text":"

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works. Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              cd /Applications/MAMP/htdocs/wp-content/plugins/my-plugin \nvendor/bin/codecept run acceptance\nvendor/bin/codecept run functional\nvendor/bin/codecept run wpunit\nvendor/bin/codecept run unit\n

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept to see a list of the available commands.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/","title":"Setting up wp-browser on VVV to test a plugin","text":"

                                                                                                                                                              This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#setting-up-wp-browser-on-vvv-to-test-a-plugin","title":"Setting up wp-browser on VVV to test a plugin","text":""},{"location":"v3/tutorials/vvv-setup/#requirements","title":"Requirements","text":"
                                                                                                                                                              • A Windows, Linux or Mac machine (I'll call this the \"host machine\" or just \"host\").
                                                                                                                                                              • A working installation of VVV; you should be able to navigate to VVV root directory, run the vagrant up command, and have VVV up and running.
                                                                                                                                                              • On the VVV installation you should be able to visit the two default sites URLs without issues; the two default sites addresses are:
                                                                                                                                                                • http://one.wordpress.test
                                                                                                                                                                • http://two.wordpress.test
                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#why-vvv","title":"Why VVV?","text":"

                                                                                                                                                              The VVV project provides a \"a Vagrant configuration for developing with WordPress\" and is an excellent, no-frills, starting point to develop WordPress projects (themes, plugins and whole sites. Based on Vagrant and Virtual Box, VVV removes the differences between systems by providing a uniform, Ubuntu Linux based, virtual machine that will bahave the same on Windows, Linux and Mac. Configuring it to run WordPress tests is easy: let's get started.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#check-vvv-works-correctly","title":"Check VVV works correctly","text":"

                                                                                                                                                              This walk-through starts after VVV has been installed and is running on the host machine; the installation guide is clear and simple to follow and I'm not duplicating it here. In the context of this guide I'm assuming VVV lives in the ~/Repos/VVV directory, that we are working on the my-plugin project and that the plugin is being developed in the default (wordpress-one) WordPress installation provided by the box. If your VVV installation lies elsewhere, replace the ~/Repos/VVV with the actual directory in each command.

                                                                                                                                                              After completing the installation of VVV navigate to VVV root folder and run the vagrant up command:

                                                                                                                                                              cd ~/Repos/VVV\nvagrant up\n

                                                                                                                                                              After the automatic bootstrap and initialization process completed, VVV makes two WordPress sites available:

                                                                                                                                                              • http://one.wordpress.test/ is the first default site address.
                                                                                                                                                              • http://two.wordpress.test/ is the second default site address.
                                                                                                                                                              • http://vvv.test/ is VVV dashboard address.

                                                                                                                                                              You should be able to reach each one of the URLs above without issues, should this not be the case something during VVV setup did not go according to the plan and you should fix it before moving on.

                                                                                                                                                              If the sanity check above is complete it's time to move to the following part specific to Codeception and wp-browser setup.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#in-and-out-host-and-guest","title":"In and out, host and guest","text":"

                                                                                                                                                              The Vagrant box provided by VVV goes beyond a simple MySQL, PHP and Ngnix server stack and provides a complete WordPress development environment; tools like Composer, [grunt-cli][4992-0003], and [wp-cli][4992-0006] are ready to use.

                                                                                                                                                              This allows the entire development, when it comes to the CLI tools, to happen in the virtual machine and not outside of it.

                                                                                                                                                              \"Inside the virtual machine\" means the first CLI instruction to run from the ~/Repos/VVV folder (assuming that is the folder where VVV was installed) is this:

                                                                                                                                                              cd ~/Repos/VVV\nvagrant ssh\n

                                                                                                                                                              This will connect, via SSH, to the virtual machine as the vagrant user. To exit from the SSH session inside the box, just type exit and return.

                                                                                                                                                              Note: any further instruction I'm showing here, beside the code editing that will happen in a dedicated PHP IDE like [PHPStorm][4992-0004] or [Sublime Text][4992-0005] on the host machine, will happen \"inside the virtual machine\".

                                                                                                                                                              When I say \"host machine\" I mean your laptop, desktop or whatever computer you're working on; when I say \"guest machine\" I mean VVV virtual machine; this is usually the case for any virtual-ish setup (Vagrant, Docker and the like).

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#scaffolding-the-project-folder","title":"Scaffolding the project folder","text":"

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins. Create the main plugin file in the http://one.wordpress.test installation plugins directory, in the ~/Repos/VVV/www/wordpress-one/public_html/wp-content/plugins/my-plugin/my-plugin.php file:

                                                                                                                                                              <?php\n/**\n * Plugin Name: My plugin\n */ \n

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the VVV default WordPress installation at http://one.wordpress.test/wp-admin/plugins.php.

                                                                                                                                                              By default, VVV administrator user name is admin and password is password.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#installing-wp-browser","title":"Installing wp-browser","text":"

                                                                                                                                                              Since Composer is provided from VVV, installing wp-browser requires entering the virtual machine (if you did not already):

                                                                                                                                                              cd ~/Repos/VVV\nvagrant ssh\n

                                                                                                                                                              Once inside navigate to the plugins folder. The path is now relative to VVV filesystem structure so it won't be the same as the one used above that was, instead, in the context of the \"host machine\":

                                                                                                                                                              cd /srv/www/wordpress-one/public_html/wp-content/plugins/my-plugin \ncomposer init\n

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. Here is the composer.json file generated by the above answers:

                                                                                                                                                              {\n    \"name\": \"vagrant/my-plugin\",\n    \"type\": \"wordpress-plugin\",\n    \"require\": {}\n}\n

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              composer require --dev lucatume/wp-browser\n

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder. To check Codeception is correctly installed run this command:

                                                                                                                                                              vendor/bin/codecept --version\n

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#setting-up-wp-browser","title":"Setting up wp-browser","text":"

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and \"WordPress unit\" tests.
                                                                                                                                                              • How to connect to the WordPress site \"normal\" database: this is the database that stores the data of the site I would see when visiting the local installation URL (http://one.wordpress.test in the case of the VVV default installation).
                                                                                                                                                              • How to connect to the database dedicated to the integration and \"WordPress unit\" tests: this database will be used to install WordPress during integration and \"WordPress unit\" tests.

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that if I am using VVV for my day to day WordPress development my first step should be to backup the site database.

                                                                                                                                                              You can create a backup of the current site database contents using wp-cli from within the virtual machine:

                                                                                                                                                              cd /srv/www/wordpress-one/public_html\nwp db export wordpress-one-backup.sql\n

                                                                                                                                                              At any moment you can re-import the site database dump using this command, the site database will be reset to the state it was when you created the database dump:

                                                                                                                                                              cd /srv/www/wordpress-one/public_html\nwp db import wordpress-one-backup.sql\n

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#creating-the-database-dedicated-to-the-tests","title":"Creating the database dedicated to the tests","text":"

                                                                                                                                                              wp-browser will use the databases it works on in a destructive way: between tests the data will be lost.

                                                                                                                                                              After the backup you should have done in the previous step, the next step is creating a database dedicated to the test.

                                                                                                                                                              At the VVV box command line run:

                                                                                                                                                              mysql -u root -p -e \"CREATE DATABASE if not exists tests\"\nmysql -u root -p -e \"GRANT ALL PRIVILEGES ON tests.* TO 'wp'@'localhost';\"\n

                                                                                                                                                              When prompted for the password enter root. The first command creates the tests database, if it does not exist; the second command grants the wp user all privileges on it.

                                                                                                                                                              In VVV the root database user name is root and the password is root.

                                                                                                                                                              Check the database was correctly created running this command:

                                                                                                                                                              mysql -u root -p -e \"SHOW DATABASES\"\n

                                                                                                                                                              The tests database should be present in the list.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#bootstrapping-and-configuring-wp-browser","title":"Bootstrapping and configuring wp-browser","text":"

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              cd /srv/www/wordpress-one/public_html/wp-content/plugins/my-plugin\nvendor/bin/codecept init wpbrowser\n

                                                                                                                                                              The initialization guide will ask a number of questions. In the screenshots below are the answers I used to configure wp-browser.

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • What is the path of the WordPress root directory? /srv/www/wordpress-one/public_html
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • What is the host of the test database used by the test site? localhost
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • What is the URL the test site? http://one.wordpress.test
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@one.wordpress.test
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#setting-up-the-starting-database-fixture","title":"Setting up the starting database fixture","text":"

                                                                                                                                                              A \"fixture\", in testing terms, is a minimal, starting environment shared by all tests. In BDD it's the Background any scenario will share. In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.

                                                                                                                                                              You can set up this fixture \"manually\", using the site administration UI at http://one.wordpress.test/wp-admin, or use wp-cli and save precious time.

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              As it's been the case so far, I'm running the following command from within the VVV box (use vagrant ssh to log in):

                                                                                                                                                              cd /srv/www/wordpress-one/public_html\nwp site empty --yes --uploads\nwp plugin deactivate --all\nwp plugin activate my-plugin\nwp db export wp-content/plugins/my-plugin/tests/_data/dump.sql\n

                                                                                                                                                              The initial database fixture has been created, now there's one last step to complete.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#using-the-tests-database-in-acceptance-and-functional-tests","title":"Using the tests database in acceptance and functional tests","text":"

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the /srv/www/wordpress-one/public_html/wp-config.php file, the DB_NAME constant is set to wordpress-one.

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              • If the request is a normal one, use the wordpress-one database.
                                                                                                                                                              • If the request comes from a test, use the tests database.

                                                                                                                                                              In your IDE/text-editor of choice edit the ~/Repos/VVV/www/wordpress-one/public_html/wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              - define( 'DB_NAME', 'wordpress-one' );\n+ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { \n+    define( 'DB_NAME', 'tests' );\n+ } else {\n+    define( 'DB_NAME', 'wordpress-one' );\n+ }\n

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {\n        define( 'DB_NAME', 'tests' );\n} else {\n        define( 'DB_NAME', 'wordpress-one' );\n}\n

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              headers:\n    X_TEST_REQUEST: 1\n    X_WPBROWSER_REQUEST: 1\n

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers. Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              "},{"location":"v3/tutorials/vvv-setup/#sanity-check","title":"Sanity check","text":"

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works. Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              cd /srv/www/wordpress-one/public_html/wp-content/plugins/my-plugin \nvendor/bin/codecept run acceptance\nvendor/bin/codecept run functional\nvendor/bin/codecept run wpunit\nvendor/bin/codecept run unit\n

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept to see a list of the available commands.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/","title":"Setting up wp-browser on WAMP for Windows to test a plugin","text":"

                                                                                                                                                              This is the documentation for version 3 of the project. The current version is version 4 and the documentation can be found here.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#setting-up-wp-browser-with-wamp-on-windows-to-test-a-plugin","title":"Setting up wp-browser with WAMP on Windows to test a plugin","text":""},{"location":"v3/tutorials/wamp-setup/#requirements","title":"Requirements","text":"
                                                                                                                                                              • A Windows machine
                                                                                                                                                              • A working installation of WAMP.
                                                                                                                                                              • You should be able to create sites and visit them from your browser without issues.
                                                                                                                                                              • Composer installed and working on your terminal PATH, you should be able to run composer --version at the terminal and see the version correctly.
                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#install-and-configure-wamp","title":"Install and configure WAMP","text":"

                                                                                                                                                              This walk-through starts after WAMP has been installed and is correctly running on the host machine; you can download WAMP from the site and follow the installation instructions. In the context of this guide I'm installing the test WordPress installation in the C:\\wamp64\\www\\wp directory. If your installation lies elsewhere, replace the C:\\wamp64\\www\\wp path with the actual directory in each command.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#creating-the-databases-and-installing-wordpress","title":"Creating the databases and installing WordPress","text":"

                                                                                                                                                              Go to the http://localhost/phpmyadmin/index.php page and create two new databases:

                                                                                                                                                              • wordpress is the database you will use for WordPress
                                                                                                                                                              • tests is the database you will use for the tests

                                                                                                                                                              The default database user is root, the default password is empty.

                                                                                                                                                              Unzip the the WordPress files into the C:\\wamp64\\www\\wp and head over to http://localhost/wp to install WordPress. The database credentials for the installation are:

                                                                                                                                                              • Database name: wordpress
                                                                                                                                                              • Database user: root
                                                                                                                                                              • Database password is empty
                                                                                                                                                              • Database host: localhost

                                                                                                                                                              Use admin as administrator user name and password as password for the administrator user.

                                                                                                                                                              Make sure you can visit the WordPress installation at http://localhost/wp and that you can correctly access the administration area at http://localhost/wp/wp-admin.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#scaffolding-the-project-folder","title":"Scaffolding the project folder","text":"

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins. Create the main plugin file in the WordPress installation plugins directory, in the C:\\wamp64\\www\\wp\\wp-content\\plugins\\my-plugin\\my-plugin.php file:

                                                                                                                                                              <?php\n/**\n * Plugin Name: My plugin\n */ \n

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the WordPress installation at http://localhost/wp/wp-admin/plugins.php.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#installing-wp-browser","title":"Installing wp-browser","text":"

                                                                                                                                                              Open a terminal window and navigate to the plugin directory and initialize the Composer project. I'm using Cmder as terminal emulator on Windows, but you can use the default one.

                                                                                                                                                              cd C:\\wamp64\\www\\wp\\wp-content\\plugins\\my-plugin\ncomposer init\n

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. Here is the composer.json file generated by the above answers:

                                                                                                                                                              {\n    \"name\": \"wamp/my-plugin\",\n    \"type\": \"wordpress-plugin\",\n    \"require\": {}\n}\n

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              composer require --dev lucatume/wp-browser\n

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder. To check Codeception is correctly installed run this command:

                                                                                                                                                              vendor\\bin\\codecept.bat --version\n

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#setting-up-wp-browser","title":"Setting up wp-browser","text":"

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and \"WordPress unit\" tests.
                                                                                                                                                              • How to connect to the WordPress site \"normal\" database: this is the database that stores the data of the site I would see when visiting the local installation URL at http://localhost/wp.
                                                                                                                                                              • How to connect to the database dedicated to the integration and \"WordPress unit\" tests: this database will be used to install WordPress during integration and \"WordPress unit\" tests.

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that your first step should be to backup the site database.

                                                                                                                                                              You can create a backup of the current site database contents using phpMyAdmin, at http://localhost/phpmyadmin/, under the \"Export\" tab:

                                                                                                                                                              At any moment you can re-import the site database dump using, again, phpMyAdmin, under the \"Import\" tab:

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#bootstrapping-and-configuring-wp-browser","title":"Bootstrapping and configuring wp-browser","text":"

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              cd C:\\wamp64\\www\\wp\\wp-content\\plugins\\my-plugin\nvendor/bin/codecept.bat init wpbrowser\n

                                                                                                                                                              The initialization guide will ask a number of questions. In the screenshots below are the answers I used to configure wp-browser.

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • What is the path of the WordPress root directory? C:/wamp64/www/wp
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • What is the host of the test database used by the test site? localhost
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • What is the password of the test database used by the test site? ``
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • What is the password of the test database WPLoader should use? ``
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • What is the URL the test site? http://localhost/wp
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@wp.test
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#setting-up-the-starting-database-fixture","title":"Setting up the starting database fixture","text":"

                                                                                                                                                              A \"fixture\", in testing terms, is a minimal, starting environment shared by all tests. In BDD it's the Background any scenario will share. In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.

                                                                                                                                                              You should set up this fixture \"manually\", using the site administration UI at http://localhost/wp/wp-admin.

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              When you're done setting up the initial database fixture, export it using the \"Export\" tab of phpMyAdmin, at http://localhost/phpmyadmin/ and move the file to the C:\\wamp64\\www\\wp\\wp-content\\plugins\\my-plugin\\tests\\_data\\dump.sql directory.

                                                                                                                                                              There is one last step left to complete the setup.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#using-the-tests-database-in-acceptance-and-functional-tests","title":"Using the tests database in acceptance and functional tests","text":"

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the C:\\wamp64\\www\\wp\\wp-config.php file, the DB_NAME constant is set to wordpress.

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              • If the request is a normal one, use the wordpress database.
                                                                                                                                                              • If the request comes from a test, use the tests database.

                                                                                                                                                              In your IDE/text-editor of choice edit the C:\\wamp64\\www\\wp\\wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              - define( 'DB_NAME', 'wordpress' );\n+ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { \n+    define( 'DB_NAME', 'tests' );\n+ } else {\n+    define( 'DB_NAME', 'wordpress' );\n+ }\n

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {\n        define( 'DB_NAME', 'tests' );\n} else {\n        define( 'DB_NAME', 'wordpress' );\n}\n

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              headers:\n    X_TEST_REQUEST: 1\n    X_WPBROWSER_REQUEST: 1\n

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers. Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              "},{"location":"v3/tutorials/wamp-setup/#sanity-check","title":"Sanity check","text":"

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works. Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              cd C:\\wamp64\\www\\wp\\wp-content\\plugins\\my-plugin \nvendor/bin/codecept run acceptance\nvendor/bin/codecept run functional\nvendor/bin/codecept run wpunit\nvendor/bin/codecept run unit\n

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept.bat to see a list of the available commands.

                                                                                                                                                              "}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..37e5d15ee --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,207 @@ + + + + https://wpbrowser.wptestkit.dev/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/DispatcherAPI/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/commands/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/custom-configuration/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/default-configuration/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/migration/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/troubleshooting/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/BuiltInServerController/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/ChromeDriverController/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/DockerComposeController/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/EventDispatcherBridge/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/IsolationSupport/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/MySqlServerController/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/extensions/Symlinker/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/AirplaneMode/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPBrowser/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPCLI/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPDb/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPFilesystem/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPLoader/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPQueries/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/modules/WPWebDriver/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/traits/UopzFunctions/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/codeception-4-support/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/codeception-phpunit-and-wpbrowser/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/commands/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/configuration/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/events-api/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/extensions/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/faq/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/installation/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/levels-of-testing/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/requirements/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/setting-up-minimum-wordpress-installation/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/advanced/run-in-separate-process/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/migration/from-version-2-to-version-3/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPBrowser/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPCLI/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPDb/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPFilesystem/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPLoader/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPQueries/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WPWebDriver/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/modules/WordPress/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/tutorials/automatically-change-db-in-tests/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/tutorials/local-flywheel-setup/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/tutorials/mamp-mac-setup/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/tutorials/vvv-setup/ + 2024-09-11 + + + https://wpbrowser.wptestkit.dev/v3/tutorials/wamp-setup/ + 2024-09-11 + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 000000000..561299ff7 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/traits/UopzFunctions/index.html b/traits/UopzFunctions/index.html new file mode 100644 index 000000000..f4a6b56a2 --- /dev/null +++ b/traits/UopzFunctions/index.html @@ -0,0 +1,4914 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UopzFunctions trait - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              UopzFunctions trait

                                                                                                                                                              + +

                                                                                                                                                              This trait provides a set of methods to manipulate functions, methods and class attributes using the uopz PHP +extension.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Warning

                                                                                                                                                              +

                                                                                                                                                              This test trait requires the uopz PHP extension.

                                                                                                                                                              +

                                                                                                                                                              See the Installing the extension locally section of this page for more information about how to do that.
                                                                                                                                                              +If you need to install the extension in a CI environment, see the Installing the extension in CI section of this page.

                                                                                                                                                              +

                                                                                                                                                              If the uopz extension is not installed, test methods using methods from the UopzFunctions trait will be marked as skipped.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Why require an extension?

                                                                                                                                                              +

                                                                                                                                                              Why use a PHP extension instead of a user-land solution, i.e. a PHP library that does not require installing an +extension?

                                                                                                                                                              +

                                                                                                                                                              I've written such a solution myself, function-mocker, but have grown frustrated with its limitations, and the +limitation of other similar solutions.

                                                                                                                                                              +

                                                                                                                                                              All user-land, monkey-patching, pure PHP solutions rely on stream-wrapping.
                                                                                                                                                              +This is a very powerful feature that this project uses for some of its functionality, but it has a drawbacks when used +extensively for monkey-patching functions and methods:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • the files patch must be included after the library loaded
                                                                                                                                                              • +
                                                                                                                                                              • the files have to patched, or patched and cached, on each run
                                                                                                                                                              • +
                                                                                                                                                              • there are some random and difficult to track issues introduced by how function and method patching works; e.g. + functions manipulating values by reference will not work as expected
                                                                                                                                                              • +
                                                                                                                                                              • some constants like __METHOD__ and __FUNCTION__ will not work as expected in the patched files
                                                                                                                                                              • +
                                                                                                                                                              • monkey-patching code will be "inserted" in the function stack, lengthening the stack trace and making it very + difficult to debug
                                                                                                                                                              • +
                                                                                                                                                              • all this processing together with XDebug spells doom for the performance of the test suite
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The uopz extension is a solid and fast solution that has been created and maintained by people that know PHP +internals and the PHP language very well that has none of the drawbacks of the above-mentioned solutions.

                                                                                                                                                              +

                                                                                                                                                              It is just a better tool for the job.

                                                                                                                                                              +

                                                                                                                                                              Installing the extension locally

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Locate your php.ini file: +
                                                                                                                                                                php --ini
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • Download the latest DLL stable version of the extension from the releases page. You'll likely need the NTS x64 version.
                                                                                                                                                              • +
                                                                                                                                                              • Unzip the file and copy the php_uopz.dll file to the ext folder of your PHP installation. If your php.ini file is located at C:\tools\php81\php.ini, the extensions directory will be located at C:\tools\php81\ext.
                                                                                                                                                              • +
                                                                                                                                                              • Edit your php.ini file and add the following line to enable and configure the extension: +
                                                                                                                                                                extension=uopz
                                                                                                                                                                +uopz.exit=1
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • Make sure the extension is correctly installed by running php -m and making sure the uopz extension appears in the list of extensions.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              You can find more information about installing PHP extensions on Windows in the PHP manual and in the uopz extension install guide.

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Use the pecl command to install the extension: +
                                                                                                                                                                pecl install uopz
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • Configure the extension to ensure it will allow exit and die calls to terminate the script execution.
                                                                                                                                                                + Add the following line to either the main PHP configuration file (php.ini), or a dedicated configuration file: +
                                                                                                                                                                uopz.exit=1
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • Make sure the extension is correctly installed by running php -m and making sure the uopz extension appears in the list of extensions.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Alternatively, you can build the extension from source as detailed in the uopz extension install guide.

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Use the pecl command to install the extension: +
                                                                                                                                                                pecl install uopz
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • Configure the extension to ensure it will allow exit and die calls to terminate the script execution.
                                                                                                                                                                + Add the following line to either the main PHP configuration file (php.ini), or a dedicated configuration file: +
                                                                                                                                                                uopz.exit=1
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • Make sure the extension is correctly installed by running php -m and making sure the uopz extension appears in the list of extensions.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Alternatively, you can build the extension from source as detailed in the uopz extension install guide.

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Installing the extension in CI

                                                                                                                                                              +

                                                                                                                                                              Depending on your Continuous Integration (CI) solution of choice, the configuration required to install and set up +the uopz extensions will be different.

                                                                                                                                                              +

                                                                                                                                                              As an example, here is how you can set up the uopz extension in a GitHub Actions job:

                                                                                                                                                              +
                                                                                                                                                              - name: Setup PHP 8.1 with uopz
                                                                                                                                                              +uses: shivammathur/setup-php@v2
                                                                                                                                                              +with:
                                                                                                                                                              +  php-version: 8.1
                                                                                                                                                              +  extensions: uopz
                                                                                                                                                              +  ini-values: uopz.exit=1
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This project uses the very same setup.

                                                                                                                                                              +

                                                                                                                                                              Most CI systems are based on Linux OSes: if you're not using GitHub Actions, you can reference to the +Linux local installation instructions to set up and install the extension for your +CI solution of choice.

                                                                                                                                                              +

                                                                                                                                                              Usage

                                                                                                                                                              +

                                                                                                                                                              Include the UopzFunctions trait in your test class and use the methods provided by the trait to manipulate functions, +methods and class attributes.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\WPTestCase;
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_mock_wp_create_nonce()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setFunctionReturn('wp_create_nonce', 'super-secret-nonce');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('super-secret-nonce', wp_create_nonce('some-action'));
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after +each test.

                                                                                                                                                              +

                                                                                                                                                              You can use the UopzFunctions trait in test cases extending the PHUnit\Framework\TestCase class as well:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use PHPUnit\Framework\TestCase;
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends TestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_mock_my_function()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setFunctionReturn('someFunction', 'mocked-value');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('mocked-value', someFunction());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you need to reset a function return or mock during a test, you can use the unset Closure returned by each method setting up a mock or return value:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +function someFunction()
                                                                                                                                                              +{
                                                                                                                                                              +    return 'original-value';
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTestWithUopzFunctions extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_mock_my_function()
                                                                                                                                                              +    {
                                                                                                                                                              +        $unsetSomeFunctionReturn = $this->setFunctionReturn('someFunction', 'mocked-value');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('mocked-value', someFunction());
                                                                                                                                                              +
                                                                                                                                                              +        $unsetSomeFunctionReturn();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('original-value', someFunction());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Methods

                                                                                                                                                              +

                                                                                                                                                              The UopzFunctions trait provides the following methods:

                                                                                                                                                              +

                                                                                                                                                              setFunctionReturn

                                                                                                                                                              +

                                                                                                                                                              setFunctionReturn(string $function, mixed $value, bool $execute = false): Closure

                                                                                                                                                              +

                                                                                                                                                              Set the return value for the function $function to $value. +The Closure returned by this method can be used to unset the return value.

                                                                                                                                                              +

                                                                                                                                                              If $value is a closure and $execute is true, then the return value will be the return value of the closure.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_function_return()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setFunctionReturn('wp_generate_nonce', 'super-secret-nonce');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('super-secret-nonce', wp_create_nonce('some-action'));
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If $value is a closure, the original function can be called within the closure to relay the original return value:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_function_return_with_closure()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setFunctionReturn(
                                                                                                                                                              +            'wp_generate_nonce',
                                                                                                                                                              +            fn(string $action) => $action === 'test' ? 'test-nonce' : wp_create_nonce($action),
                                                                                                                                                              +            true
                                                                                                                                                              +        );
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('test-nonce', wp_create_nonce('test'));
                                                                                                                                                              +        $this->assertNotEquals('test-nonce', wp_create_nonce('some-other-action'));
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetFunctionReturn

                                                                                                                                                              +

                                                                                                                                                              unsetFunctionReturn(string $function): void

                                                                                                                                                              +

                                                                                                                                                              Unset the return value for the function $function previously set with setFunctionReturn.

                                                                                                                                                              +

                                                                                                                                                              You do not need to unset the return value for a function that was set with setFunctionReturn +using unsetFunctionReturn explicitly: the trait will take care of cleaning up all the modifications made to the +functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              setMethodReturn

                                                                                                                                                              +

                                                                                                                                                              setMethodReturn(string $class, string $method, mixed $value, bool $execute = false): Closure

                                                                                                                                                              +

                                                                                                                                                              Sets the return value for the static or instance method $method of the class $class to $value. +The Closure returned by this method can be used to unset the return value.

                                                                                                                                                              +

                                                                                                                                                              If $value is a closure and $execute is true, then the return value will be the return value of the closure.

                                                                                                                                                              +

                                                                                                                                                              Magic methods like __construct, __destruct, __call and so on cannot be mocked using this method. +See the setClassMock method for more information about how to mock magic class methods.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class SomeLegacyClass {
                                                                                                                                                              +    public static function staticMethod(){
                                                                                                                                                              +        return 'some-static-value';
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function instanceMethod(){
                                                                                                                                                              +        return 'some-instance-value';
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_method_return()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setMethodReturn(SomeLegacyClass::class, 'staticMethod', 'STATIC');
                                                                                                                                                              +        $this->setMethodReturn(SomeLegacyClass::class, 'instanceMethod', 'TEST');
                                                                                                                                                              +
                                                                                                                                                              +        $legacyClass = new SomeLegacyClass();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('STATIC', SomeLegacyClass::staticMethod());
                                                                                                                                                              +        $this->assertEquals('TEST', $legacyClass->instanceMethod());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If $value is a closure, the original static or instance method can be called within the closure, with correctly +bound self and $this context, to relay the original return value:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class SomeLegacyClass {
                                                                                                                                                              +    public static function raiseStaticFlag(bool $flag = false){
                                                                                                                                                              +        return $flag ? 'static-flag-raised' : 'static-flag-lowered';
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function raiseFlag(bool $flag = false){
                                                                                                                                                              +        return $flag ? 'flag-raised' : 'flag-lowered';
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_method_return_with_closure()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setMethodReturn(
                                                                                                                                                              +            SomeLegacyClass::class,
                                                                                                                                                              +            'raiseStaticFlag',
                                                                                                                                                              +            fn(bool $flag) => $flag ? 'STATIC' : self::raiseStaticFlag($flag),
                                                                                                                                                              +            true
                                                                                                                                                              +        );
                                                                                                                                                              +        $this->setMethodReturn(
                                                                                                                                                              +            SomeLegacyClass::class,
                                                                                                                                                              +            'raiseFlag',
                                                                                                                                                              +            fn(bool $flag) => $flag ? 'TEST' : $this->raiseFlag($flag),
                                                                                                                                                              +            true
                                                                                                                                                              +        );
                                                                                                                                                              +
                                                                                                                                                              +        $legacyClass = new SomeLegacyClass();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('STATIC', SomeLegacyClass::raiseStaticFlag(true));
                                                                                                                                                              +        $this->assertEquals('static-flag-lowered', SomeLegacyClass::raiseStaticFlag(false));
                                                                                                                                                              +        $this->assertEquals('TEST', $legacyClass->raiseFlag(true));
                                                                                                                                                              +        $this->assertEquals('flag-lowered', $legacyClass->raiseFlag(false));
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetMethodReturn

                                                                                                                                                              +

                                                                                                                                                              unsetmethodreturn(string $class, string $method): void

                                                                                                                                                              +

                                                                                                                                                              Unset the return value for the static or instance method $method of the class $class previously set +with setMethodReturn.

                                                                                                                                                              +

                                                                                                                                                              You do not need to unset the return value for a method that was set with setMethodReturn +using unsetMethodReturn explicitly: the trait will take care of cleaning up all the modifications made to the +functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              setFunctionHook

                                                                                                                                                              +

                                                                                                                                                              setFunctionHook(string $function, Closure $hook): Closure

                                                                                                                                                              +

                                                                                                                                                              Execute $hook when entering the function $function. +The Closure returned by this method can be used to unset the hook.

                                                                                                                                                              +

                                                                                                                                                              Hooks can be set on both internal and user-defined functions.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_hook()
                                                                                                                                                              +    {
                                                                                                                                                              +        $log = [];
                                                                                                                                                              +        $this->setFunctionHook(
                                                                                                                                                              +            'header', 
                                                                                                                                                              +            function($header, bool $replace = true, int $response_code = 0) use (&$log): void {
                                                                                                                                                              +                $log[] = $header;
                                                                                                                                                              +            }
                                                                                                                                                              +        );
                                                                                                                                                              +
                                                                                                                                                              +        header('X-Plugin-Version: 1.0.0');
                                                                                                                                                              +        header('X-Plugin-REST-Enabled: 1');
                                                                                                                                                              +        header('X-Plugin-GraphQL-Enabled: 0');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals([
                                                                                                                                                              +            [
                                                                                                                                                              +                'X-Plugin-Version' => '1.0.0',
                                                                                                                                                              +                'X-Plugin-REST-Enabled' => '1',
                                                                                                                                                              +                'X-Plugin-GraphQL-Enabled' => '0'
                                                                                                                                                              +        ], $log);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetFunctionHook

                                                                                                                                                              +

                                                                                                                                                              unsetFunctionHook(string $function): void

                                                                                                                                                              +

                                                                                                                                                              Unset the hook for the function $function previously set with setFunctionHook.

                                                                                                                                                              +

                                                                                                                                                              You do not need to unset the hook for a function that was set with setFunctionHook +using unsetFunctionHook explicitly: the trait will take care of cleaning up all the modifications made to the +functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              setMethodHook

                                                                                                                                                              +

                                                                                                                                                              setMethodHook(string $class, string $method, Closure $hook): Closure

                                                                                                                                                              +

                                                                                                                                                              Execute $hook when entering the static or instance method $method of the class $class.
                                                                                                                                                              +The Closure returned by this method can be used to unset the hook.

                                                                                                                                                              +

                                                                                                                                                              The keywords self and $this will be correctly bound to the class and the class instance respectively.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class LegacyApiController {
                                                                                                                                                              +    private static array $connections = [];
                                                                                                                                                              +    private ?array $cachedItems = null;
                                                                                                                                                              +
                                                                                                                                                              +    public static function connect(): self {
                                                                                                                                                              +        $connected = new self;
                                                                                                                                                              +        self::$connections[] = $connected;
                                                                                                                                                              +        return $connected;
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function getItems(int $count, int $from = 0): array {
                                                                                                                                                              +        if($this->cachedItems === null){
                                                                                                                                                              +            $this->cachedItems = wp_remote_get('https://example.com/items');
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        return array_slice($this->cachedItems, $from, $count);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_method_hook()
                                                                                                                                                              +    {
                                                                                                                                                              +        $connections = 0;
                                                                                                                                                              +        $this->setMethodHook(
                                                                                                                                                              +            LegacyApiController::class, 
                                                                                                                                                              +            'connect', 
                                                                                                                                                              +            function() use (&$connections): void {
                                                                                                                                                              +                $connections  = count(self::$connections) + 1;
                                                                                                                                                              +            }
                                                                                                                                                              +        );
                                                                                                                                                              +        $itemsCacheHits = 0;
                                                                                                                                                              +        $this->setMethodHook(
                                                                                                                                                              +            LegacyApiController::class, 
                                                                                                                                                              +            'getItems', 
                                                                                                                                                              +            function(int $count, int $from = 0) use (&$itemsCacheHit): bool {
                                                                                                                                                              +                if($this->cachedItems !== null){
                                                                                                                                                              +                    $itemsCacheHits++;
                                                                                                                                                              +                }
                                                                                                                                                              +            }
                                                                                                                                                              +        );
                                                                                                                                                              +
                                                                                                                                                              +        $connectedController1 = LegacyApiController::connect();
                                                                                                                                                              +        $connectedController2 = LegacyApiController::connect();
                                                                                                                                                              +        $connectedController1->getItems(10, 0);
                                                                                                                                                              +        $connectedController1->getItems(10, 10);
                                                                                                                                                              +        $connectedController2->getItems(10, 0);
                                                                                                                                                              +        $connectedController2->getItems(10, 10);
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals(2, $connections);
                                                                                                                                                              +        $this->assertEquals(4, $itemsCacheHits);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetMethodHook

                                                                                                                                                              +

                                                                                                                                                              unsetMethodHook(string $class, string $method): void

                                                                                                                                                              +

                                                                                                                                                              Unset the hook for the static or instance method $method of the class $class previously set +with setMethodHook.

                                                                                                                                                              +

                                                                                                                                                              You do not need to unset the hook for a method that was set with seMethodHook +using unsetClassMethodHook explicitly: the trait will take care of cleaning up all the modifications made to the +functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              setConstant

                                                                                                                                                              +

                                                                                                                                                              setConstant(string $constant, mixed $value): Closure

                                                                                                                                                              +

                                                                                                                                                              Set the constant $constant to the value $value. +The Closure returned by this method can be used to unset the constant or reset it to its original value.

                                                                                                                                                              +

                                                                                                                                                              If the constant is not already defined, it will be defined and set to the value $value.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_constant()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setconstant('WP_ADMIN', true);
                                                                                                                                                              +        $this->setconstant('TEST_CONST', 23);
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertTrue(wp_is_admin());
                                                                                                                                                              +        $this->assertEquals(23, TEST_CONST);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetConstant

                                                                                                                                                              +

                                                                                                                                                              unsetConstant(string $constant): void

                                                                                                                                                              +

                                                                                                                                                              Unset an existing constant or restores the original value of the constant if set with setConstant.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_unset_constant()
                                                                                                                                                              +    {
                                                                                                                                                              +        // The test is starting in Admin context.
                                                                                                                                                              +        $this->assertTrue(is_admin());
                                                                                                                                                              +
                                                                                                                                                              +        $this->unsetConstant('WP_ADMIN');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertFalse(is_admin());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You do not need to undefine a constant defined with setConstant using unsetConstant explicitly: the +trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each +test.

                                                                                                                                                              +

                                                                                                                                                              setClassConstant

                                                                                                                                                              +

                                                                                                                                                              setClassConstant(string $class, string $constant, mixed $value): Closure

                                                                                                                                                              +

                                                                                                                                                              Set the constant $constant of the class $class to the value $value. +The Closure returned by this method can be used to unset the constant or reset it to its original value.

                                                                                                                                                              +

                                                                                                                                                              If the class constant is not already defined, it will be defined and set to the value $value.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyPlugin {
                                                                                                                                                              +    const VERSION = '89.0.0';
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_class_constant()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setClassConstant(MyPlugin::class, 'VERSION', '23.89.0');
                                                                                                                                                              +        $this->setClassConstant(MyPlugin::class, 'NOT_EXISTING', 'TEST');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('23.89.0', MyPlugin::VERSION);
                                                                                                                                                              +        $this->assertEquals('TEST', MyPlugin::NOT_EXISTING);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetClassConstant

                                                                                                                                                              +

                                                                                                                                                              unsetClassConstant(string $class, string $constant): void

                                                                                                                                                              +

                                                                                                                                                              Restore the constant $constant of the class $class to its original value or removes it if it was not defined.

                                                                                                                                                              +

                                                                                                                                                              You do not need to undefine a constant defined with setClassConstant +using undefineClassConstant explicitly: the trait will take care of cleaning up all the modifications made to the +functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              setClassMock

                                                                                                                                                              +

                                                                                                                                                              setClassMock(string $class, string|object $mock): Closure

                                                                                                                                                              +

                                                                                                                                                              Use $mock instead of $class when creating new instances of the class $class. +The Closure returned by this method can be used to unset the mock.

                                                                                                                                                              +

                                                                                                                                                              This method allows you to override magic methods as well as you would do with a normal class extension.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MockPaymentApi extends PaymentApi {
                                                                                                                                                              +    public static function version($name, $arguments){
                                                                                                                                                              +        return '23.89.0';
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_class_mock()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setClassMock(PaymentApi::class, MockPaymentApi::class);
                                                                                                                                                              +
                                                                                                                                                              +        $paymentApi = new PaymentApi();
                                                                                                                                                              +        $this->assertInstanceOf(MyPluginMock::class, $paymentApi);
                                                                                                                                                              +        $this->assertSame('23.89.0', $paymentApi::version());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you set the $mock to an object, then the same mock object will be used for all the new instances of the +class $class:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MockPaymentApi extends PaymentApi {
                                                                                                                                                              +    public function getIds($name, $arguments){
                                                                                                                                                              +        return [1, 23, 89];
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_class_mock()
                                                                                                                                                              +    {
                                                                                                                                                              +        $mockPaymentApi = new MockPaymentApi();
                                                                                                                                                              +
                                                                                                                                                              +        $this->setClassMock(PaymentApi::class, $mockPaymentApi);
                                                                                                                                                              +
                                                                                                                                                              +        $api1 = new PaymentApi();
                                                                                                                                                              +        $this->assertSame($mockPaymentApi, $api1);
                                                                                                                                                              +        $this->assertSame([1, 23, 89], $api1->getIds());
                                                                                                                                                              +        $api2 = new PaymentApi();
                                                                                                                                                              +        $this->assertSame($mockPaymentApi, $api2);
                                                                                                                                                              +        $this->assertSame([1, 23, 89], $api2->getIds());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The $mock class, or instance, is not required to be a subclass of the class $class by the trait; although it +might be required from the code you're testing by means of type hinting.

                                                                                                                                                              +

                                                                                                                                                              If the class or method you would like to set a mock for is final, then you can combine this method with +the unsetClassFinalAttribute +and unsetMethodFinalAttribute methods to avoid the final attribute being set on the +class:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +final class LegacyPaymentApi {
                                                                                                                                                              +    public function getIds(){
                                                                                                                                                              +        // ... fetch ids from a real external API ...
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class LegacyCacheController {
                                                                                                                                                              +    protected final function get(string $key){
                                                                                                                                                              +        // ... fetch data from a real cache ...
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_class_mock()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->unsetClassFinalAttribute(LegacyPaymentApi::class);
                                                                                                                                                              +        $mockPaymentApi = new class extends LegacyPaymentApi {
                                                                                                                                                              +            public function getIds(){
                                                                                                                                                              +                return [1, 23, 89];
                                                                                                                                                              +            }
                                                                                                                                                              +        };
                                                                                                                                                              +        $this->setClassMock(LegacyPaymentApi::class, $mockPaymentApi);
                                                                                                                                                              +        $this->unsetMethodFinalAttribute(LegacyCacheController::class, 'get');
                                                                                                                                                              +        $mockCacheController = new class extends LegacyCacheController {
                                                                                                                                                              +            public function get(string $key){
                                                                                                                                                              +                return 'some-value';
                                                                                                                                                              +            }
                                                                                                                                                              +        };
                                                                                                                                                              +
                                                                                                                                                              +        $paymentApi = new LegacyPaymentApi();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertSame($mockPaymentApi, $paymentApi);
                                                                                                                                                              +        $this->assertSame([1, 23, 89], $paymentApi->getIds());
                                                                                                                                                              +
                                                                                                                                                              +        $cacheController = new LegacyCacheController();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertSame($mockCacheController, $cacheController);
                                                                                                                                                              +        $this->assertSame('some-value', $cacheController->get('some-key'));
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              unsetClassMock

                                                                                                                                                              +

                                                                                                                                                              unsetClassMock(string $class): void

                                                                                                                                                              +

                                                                                                                                                              Remove the mock for the class $class previously set with setMock.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_unset_class_mock()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setClassMock(MyPlugin::class, new MyPluginMock());
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertInstanceOf(MyPluginMock::class, new MyPlugin());
                                                                                                                                                              +
                                                                                                                                                              +        $this->unsetClassMock(MyPlugin::class);
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertInstanceOf(MyPlugin::class, new MyPlugin());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You do not need to unset the mock for a class that was set with setClassMock using unsetClassMock +explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class +attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              unsetClassFinalAttribute

                                                                                                                                                              +

                                                                                                                                                              unsetClassFinalAttribute(string $class): Closure

                                                                                                                                                              +

                                                                                                                                                              Remove the final attribute from the class $class. +The Closure returned by this method can be used to reset the final attribute.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +final class LegacyPaymentApi {}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_remove_class_final_attribute()
                                                                                                                                                              +    {
                                                                                                                                                              +        $post = static::factory()->post->createAndGet();
                                                                                                                                                              +
                                                                                                                                                              +        $this->unsetClassFinalAttribute(LegacyPaymentApi::class);
                                                                                                                                                              +
                                                                                                                                                              +        // The class is not final anymore; it can be extended for testing purposes.
                                                                                                                                                              +        $mockPaymentApi = new class extends LegacyPaymentApi {
                                                                                                                                                              +            public function getIds(){
                                                                                                                                                              +                return [1, 23, 89];
                                                                                                                                                              +            }
                                                                                                                                                              +        };
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertSame([1, 23, 89], $mockPaymentApi->getIds());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              resetClassFinalAttribute

                                                                                                                                                              +

                                                                                                                                                              resetClassFinalAttribute(string $class): void

                                                                                                                                                              +

                                                                                                                                                              Reset the final attribute of the class $class previously removed with +the unsetClassFinalAttribute method.

                                                                                                                                                              +

                                                                                                                                                              You do not need to restore the class final attribute for a class that was set +with unsetClassFinalAttribute using setClassFinalAttribute explicitly: the trait will +take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              unsetMethodFinalAttribute

                                                                                                                                                              +

                                                                                                                                                              unsetMethodFinalAttribute(string $class, string $method): Closure

                                                                                                                                                              +

                                                                                                                                                              Remove the final attribute from the static or instance method $method of the class $class. +The Closure returned by this method can be used to reset the final attribute.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_remove_method_final_attribute()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->unsetMethodFinalAttribute(LegacyAjaxController::class, 'printResponseAndExit');
                                                                                                                                                              +
                                                                                                                                                              +        // Build a class to avoid the `printResponseAndExit` method from exiting.
                                                                                                                                                              +        $testLegacyAdminController = new class extends LegacyAjaxController {
                                                                                                                                                              +            public string $response = '';
                                                                                                                                                              +
                                                                                                                                                              +            public function printResponseAndExit(){
                                                                                                                                                              +                $this->response = $this->template->render('list', return: true);
                                                                                                                                                              +                return;
                                                                                                                                                              +            }
                                                                                                                                                              +        };
                                                                                                                                                              +
                                                                                                                                                              +        // Set up things for the test ...
                                                                                                                                                              +
                                                                                                                                                              +        $testLegacyAjaxController->printResponseAndExit();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('<ul><li>Item One</li><li>Item Two</li></ul>', $testLegacyAjaxController->response);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              restoreMethodFinalAttribute

                                                                                                                                                              +

                                                                                                                                                              restoreMethodFinalAttribute(string $class, string $method): void

                                                                                                                                                              +

                                                                                                                                                              Restore the final attribute of the method static or instance $method of the class $class previously removed with +the unsetMethodFinalAttribute method.

                                                                                                                                                              +

                                                                                                                                                              You do not need to restore the method final attribute for a method that was set +with unsetMethodFinalAttribute using restoreMethodFinalAttribute explicitly: the trait +will take care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              addClassMethod

                                                                                                                                                              +

                                                                                                                                                              addClassMethod(string $class, string $method, Closure $closure, bool $static = false): Closure

                                                                                                                                                              +

                                                                                                                                                              Add a public static ($static = true) or instance ($static = false) method to the class $class with the +name $method and the code provided by the closure $closure. +The Closure returned by this method can be used to remove the method.

                                                                                                                                                              +

                                                                                                                                                              Differently from the setClassMock method, this method will work on already existing instances of +the class $class, not just new instances.

                                                                                                                                                              +

                                                                                                                                                              The closure $this will be bound to the class instance.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class LegacySingletonController {
                                                                                                                                                              +    private static $instance;
                                                                                                                                                              +    private array $cache = null;
                                                                                                                                                              +    private int $cacheCount = 0;
                                                                                                                                                              +
                                                                                                                                                              +    public static function getInstance(){
                                                                                                                                                              +        if(!self::$instance){
                                                                                                                                                              +            self::$instance = new self();
                                                                                                                                                              +        }
                                                                                                                                                              +        return self::$instance;
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function getItems(int $count, int $from = 0){
                                                                                                                                                              +        if($this->cache === null){
                                                                                                                                                              +            $this->cache = wp_remote_get('https://example.com/items');
                                                                                                                                                              +            $this->cacheCount = count($cache);
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        return array_slice($this->cache, $from, $count);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_add_class_method()
                                                                                                                                                              +    {
                                                                                                                                                              +        $controller = LegacySingletonController::getInstance();
                                                                                                                                                              +
                                                                                                                                                              +        $this->addClassMethod(
                                                                                                                                                              +            LegacySingletonController::class, 
                                                                                                                                                              +            'setCache',
                                                                                                                                                              +            function(array $cache): void {
                                                                                                                                                              +                $this->cache = $cache;
                                                                                                                                                              +                $this->cacheCount = count($cache);
                                                                                                                                                              +            }
                                                                                                                                                              +        );
                                                                                                                                                              +
                                                                                                                                                              +        // Set the singletong instance cache for testing purposes.
                                                                                                                                                              +        $controller->setCache(range(1,100));
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals([1,2,3], $controller->getItems(3, 0));
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              removeClassMethod

                                                                                                                                                              +

                                                                                                                                                              removeClassMethod(string $class, string $method): void

                                                                                                                                                              +

                                                                                                                                                              Remove the static or instance method $method added with addClassMethod from the class $class.

                                                                                                                                                              +

                                                                                                                                                              You do not need to remove a method added with addClassMethod, +or addClassStaticMethod, using removeClassMethod explicitly: the trait will take care of +cleaning up all the modifications made to the functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              setObjectProperty

                                                                                                                                                              +

                                                                                                                                                              setObjectProperty(string|object $classOrObject, string $property, mixed $value): Closure

                                                                                                                                                              +

                                                                                                                                                              If $classOrInstance is a string, set the property $property of the class $classOrObject to the value $value. +If $classOrInstance is an object, set the property $property of the object $classOrObject to the value $value. +The Closure returned by this method can be used to unset the property.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class Payment {
                                                                                                                                                              +    private string $uuid;
                                                                                                                                                              +    private string $from;
                                                                                                                                                              +    private string $to;
                                                                                                                                                              +
                                                                                                                                                              +    public function __construct(string $from, $string $to){
                                                                                                                                                              +        $this->uuid = UUID::generate();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function getHash(): string {
                                                                                                                                                              +        return wp_hash(serialize([
                                                                                                                                                              +            'uuid' => $this->uuid
                                                                                                                                                              +            'from' => $this->from,
                                                                                                                                                              +            'to' => $this->to
                                                                                                                                                              +        ]));
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_object_property()
                                                                                                                                                              +    {
                                                                                                                                                              +        $payment = new Payment('Bob', 'Alice');
                                                                                                                                                              +
                                                                                                                                                              +        $this->setObjectProperty($payment, 'uuid', '550e8400-e29b-41d4-a716-446655440000');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals(wp_hash(serialize([
                                                                                                                                                              +            'uuid' => '550e8400-e29b-41d4-a716-446655440000',
                                                                                                                                                              +            'from' => 'Bob',
                                                                                                                                                              +            'to' => 'Alice'
                                                                                                                                                              +        ])), $payment->getHash());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You do not need to reset the property of an object that was set with setObjectProperty explicitly: the trait will take +care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              getObjectProperty

                                                                                                                                                              +

                                                                                                                                                              getObjectProperty(object $object, string $property): mixed

                                                                                                                                                              +

                                                                                                                                                              Get the value of the static or instance property $property of the object $object.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class LegacyController {
                                                                                                                                                              +    private Template $template;
                                                                                                                                                              +
                                                                                                                                                              +    public function __construct(){
                                                                                                                                                              +        $this->template = new Template();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // ...
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_get_object_property()
                                                                                                                                                              +    {
                                                                                                                                                              +        $controller = new LegacyController();
                                                                                                                                                              +
                                                                                                                                                              +        $templateEngine $this->getObjectProperty($controller, 'template'));
                                                                                                                                                              +
                                                                                                                                                              +        // ... do something with the template ...
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              resetObjectProperty

                                                                                                                                                              +

                                                                                                                                                              resetObjectProperty(string|object $classOrObject, string $property): void

                                                                                                                                                              +

                                                                                                                                                              Reset the property $property of the class $class or object $object to its original value.

                                                                                                                                                              +

                                                                                                                                                              You do not need to reset the property of an object that was set with setObjectProperty explicitly: the trait will take +care of cleaning up all the modifications made to the functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              getMethodStaticVariables

                                                                                                                                                              +

                                                                                                                                                              getMethodStaticVariables(string $class, string $method): array

                                                                                                                                                              +

                                                                                                                                                              Get the value of the static variables of the class $class and method $method.

                                                                                                                                                              +

                                                                                                                                                              The method will work for both static and instance methods of the class $class.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class RequestLogger {
                                                                                                                                                              +    public function log(int $code, string $response):void {
                                                                                                                                                              +        static $requestId;
                                                                                                                                                              +
                                                                                                                                                              +        if($requestId === null){
                                                                                                                                                              +            $requestId = md5(microtime());
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        printf("Request %s: %d %s\n", $requestId, $code, $response);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_get_class_method_static_variables()
                                                                                                                                                              +    {
                                                                                                                                                              +        $requestLogger = new RequestLogger();
                                                                                                                                                              +
                                                                                                                                                              +        ob_start();
                                                                                                                                                              +        $requestLogger->log(200, 'OK');
                                                                                                                                                              +        $requestLogger->log(403, 'Forbidden');
                                                                                                                                                              +        $requestLogger->log(200, 'OK');
                                                                                                                                                              +        $buffer = ob_get_clean();
                                                                                                                                                              +
                                                                                                                                                              +        $requestId = $this->getClassMethodStaticVariables(RequestLogger::class, 'log')['requestId'];
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals("Request $requestId: 200 OK\nRequest $requestId: 403 Forbidden\nRequest $requestId: 200 OK\n", $buffer);
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              setMethodStaticVariables

                                                                                                                                                              +

                                                                                                                                                              setMethodStaticVariables(string $class, string $method, array $values): Closure

                                                                                                                                                              +

                                                                                                                                                              Set the static variablesof the class $class and method $method to the values $values. +The Closure returned by this method can be used to unset the static variables.

                                                                                                                                                              +

                                                                                                                                                              This will work on both static and instance methods.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class ListComponent {
                                                                                                                                                              +    public function render(){
                                                                                                                                                              +        static $hash;
                                                                                                                                                              +
                                                                                                                                                              +        if(!$hash){
                                                                                                                                                              +            $hash = md5(microtime());
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        return '<ul screen=' . $hash . '><li>Item One</li><li>Item Two</li></ul>';
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_class_method_static_variables()
                                                                                                                                                              +    {
                                                                                                                                                              +        $newValues = array_merge(
                                                                                                                                                              +            $this->getMethodStaticVariables(ListComponent::class, 'render'),
                                                                                                                                                              +            ['hash' => 'some-hash']
                                                                                                                                                              +        );
                                                                                                                                                              +        $this->setClassMethodStaticVariables( ListComponent::class, 'render', [
                                                                                                                                                              +          'hash' => 'some-hash'
                                                                                                                                                              +        ]);
                                                                                                                                                              +
                                                                                                                                                              +        $component = new ListComponent();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals(
                                                                                                                                                              +            '<ul data-screen="some-hash"><li>Item One</li><li>Item Two</li></ul>', 
                                                                                                                                                              +            $component->render()
                                                                                                                                                              +        );
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You do not need to reset the static variable of a class method that was set with setMethodStaticVariables explicitly +using resetMethodStaticVariables explicitly: the trait will take care of cleaning up all the modifications made to the +functions, methods and class attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              resetMethodStaticVariables

                                                                                                                                                              +

                                                                                                                                                              resetMethodStaticVariables(string $class, string $method): void

                                                                                                                                                              +

                                                                                                                                                              Resets the static variables of the class $class method $method to their original values.

                                                                                                                                                              +

                                                                                                                                                              setFunctionStaticVariable

                                                                                                                                                              +

                                                                                                                                                              setFunctionStaticVariables(string $function, string $variable, mixed $value): Closure

                                                                                                                                                              +

                                                                                                                                                              Set the static variable $variable of the function $function to the value $value. +The Closure returned by this method can be used to unset the static variable.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +function renderScreen(): string{
                                                                                                                                                              +    static $rendered;
                                                                                                                                                              +
                                                                                                                                                              +    if($rendered){
                                                                                                                                                              +        return;
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    $html = '<p>Some HTML</p>';
                                                                                                                                                              +
                                                                                                                                                              +    $rendered = true;
                                                                                                                                                              +
                                                                                                                                                              +    return $html;
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_function_static_variables()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->setFunctionStaticVariables('renderScreen', ['rendered' => false]);
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('<p>Some HTML</p>', renderScreen());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You do not need to reset the value of a function static variable set using the resetFunctionStaticVariables method +explicitly: the trait will take care of cleaning up all the modifications made to the functions, methods and class +attributes after each test.

                                                                                                                                                              +

                                                                                                                                                              getFunctionStaticVariables

                                                                                                                                                              +

                                                                                                                                                              getFunctionStaticVariables(string $function, ): array

                                                                                                                                                              +

                                                                                                                                                              Get the value of the static variable $variable of the function $function.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +function renderScreen(): string {
                                                                                                                                                              +    static $screenHash;
                                                                                                                                                              +
                                                                                                                                                              +    if(!$screenHash){
                                                                                                                                                              +        $screenHash = md5(microtime());
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    return '<p data-screen="' . $screenHash . '">Some HTML</p>';
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_set_function_static_variables()
                                                                                                                                                              +    {
                                                                                                                                                              +        $screenHash = $this->getFunctionStaticVariables('renderScreen')['screenHash'];
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('<p data-screen="' . $screenHash . '">Some HTML</p>', renderScreen());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              resetFunctionStaticVariables

                                                                                                                                                              +

                                                                                                                                                              resetFunctionStaticVariables(string $function): void

                                                                                                                                                              +

                                                                                                                                                              Resets the static variables of the function $function set with the setFunctionStaticVariables method.

                                                                                                                                                              +

                                                                                                                                                              addFunction

                                                                                                                                                              +

                                                                                                                                                              addFunction(string $function, Closure $closure): void

                                                                                                                                                              +

                                                                                                                                                              Add a global or namespaced function to the current scope.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_add_function()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->addFunction('myGlobalFunction', fn() => 23);
                                                                                                                                                              +        $this->addFunction('Acme\Project\namespacedFunction', fn() => 89);
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals(23, myGlobalFunction());
                                                                                                                                                              +        $this->assertEquals(89, Acme\Project\namespacedFunction());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              removeFunction

                                                                                                                                                              +

                                                                                                                                                              removeFunction(string $function): void

                                                                                                                                                              +

                                                                                                                                                              Removes the global or namespaced function $function from the current scope. +This will work for functions defined using the addFunction method or defined elsewhere.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_add_function()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->addFunction('myGlobalFunction', fn() => 23);
                                                                                                                                                              +        $this->addFunction('Acme\Project\namespacedFunction', fn() => 89);
                                                                                                                                                              +
                                                                                                                                                              +        $this->removeFunction('some_plugin_function');
                                                                                                                                                              +        $this->removeFunction('Acme\Project\namespacedFunction');
                                                                                                                                                              +
                                                                                                                                                              +        // Added with addFunction.
                                                                                                                                                              +        $this->assertFalse(function_exists('myGlobalFunction');
                                                                                                                                                              +        $this->assertFalse(function_exists('Acme\Project\namespacedFunction');
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertFalse(function_exists('some_plugin_function');
                                                                                                                                                              +        $this->assertFalse(function_exists('Another\Plugin\some_function');
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You do not need to remove a function added with addFunction using removeFunction explicitly: the +trait will take care of cleaning up all the modifications made to the functions, methods and class attributes after each +test.

                                                                                                                                                              +

                                                                                                                                                              preventExit

                                                                                                                                                              +

                                                                                                                                                              preventExit(): void

                                                                                                                                                              +

                                                                                                                                                              Prevents exit or die calls executed after the method from terminating the PHP process calling exit or die.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use lucatume\WPBrowser\Traits\UopzFunctions;
                                                                                                                                                              +use lucatume\WPBrowser\TestCase\WPTestCase;
                                                                                                                                                              +
                                                                                                                                                              +function printAndDie(): void{
                                                                                                                                                              +    print 'Some HTML';
                                                                                                                                                              +    die();
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class MyTest extends WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    use UopzFunctions;
                                                                                                                                                              +
                                                                                                                                                              +    public function test_can_prevent_exit()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->preventExit();
                                                                                                                                                              +
                                                                                                                                                              +        ob_start();
                                                                                                                                                              +        printAndDie();
                                                                                                                                                              +        $buffer = ob_get_clean();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertEquals('Some HTML', $buffer);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              restoreExit

                                                                                                                                                              +

                                                                                                                                                              allowExit(): void

                                                                                                                                                              +

                                                                                                                                                              Restores the original behavior of the exit and die functions.

                                                                                                                                                              +

                                                                                                                                                              You do not need to restore the exit behavior for a exit that was prevented using preventExit +using allowExit explicitly: the trait will take care of cleaning up all the modifications made to the functions, +methods and class attributes after each test.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/troubleshooting/index.html b/troubleshooting/index.html new file mode 100644 index 000000000..e32aa6d91 --- /dev/null +++ b/troubleshooting/index.html @@ -0,0 +1,3001 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Troubleshooting - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Troubleshooting

                                                                                                                                                              + +

                                                                                                                                                              Troubleshooting common issues

                                                                                                                                                              +

                                                                                                                                                              Downloads fail in Windows

                                                                                                                                                              +

                                                                                                                                                              If you're using code or commands, e.g. the chromedriver:update one, that download files and those keep failing with a message like the following:

                                                                                                                                                              +
                                                                                                                                                              File ... download failed: SSL certificate problem: unable to get local issuer certificate
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              It's likely the issue originates from PHP not having access to the system certificate store.

                                                                                                                                                              +

                                                                                                                                                              You can fix this by downloading the certificates file and setting the curl.cainfo and openssl.cafile PHP configuration options to point to it:

                                                                                                                                                              +
                                                                                                                                                              curl.cainfo = "C:\path\to\cacert.pem"
                                                                                                                                                              +openssl.cafile = "C:\path\to\cacert.pem"
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/advanced/run-in-separate-process/index.html b/v3/advanced/run-in-separate-process/index.html new file mode 100644 index 000000000..9f6805e88 --- /dev/null +++ b/v3/advanced/run-in-separate-process/index.html @@ -0,0 +1,3266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Running tests in separate processes - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Running tests in separate processes

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Running tests in separate processes

                                                                                                                                                              +

                                                                                                                                                              PHPUnit offers the possibility to run tests in a separate PHP process; Codeception does not officially support the option as of version 4.0.

                                                                                                                                                              +

                                                                                                                                                              The wp-browser project tries to fill that gap by supporting the @runInSeparateProcess annotation.
                                                                                                                                                              +This support comes with some caveats, though:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              1. The support is only for test cases extending the Codeception\TestCase\WPTestCase class (the base test case for integration or "WordPress unit" tests)
                                                                                                                                                              2. +
                                                                                                                                                              3. The support wp-browser provides only supports the @preserveGlobalState annotation with the disabled value; this means there is no support for preserving global state between tests.
                                                                                                                                                              4. +
                                                                                                                                                              +

                                                                                                                                                              Read more about what this means in PHPUnit documentation.

                                                                                                                                                              +

                                                                                                                                                              Why run tests in a separate PHP process?

                                                                                                                                                              +

                                                                                                                                                              One main reason: isolation.

                                                                                                                                                              +

                                                                                                                                                              What does "isolation" means?

                                                                                                                                                              +

                                                                                                                                                              Before answering that question, it's essential to understand, via an example, why a lack of isolation might be an issue.

                                                                                                                                                              +

                                                                                                                                                              I want to test the get_api function. The function will return the correct singleton instance of an API handling class: an instance of Api when the function is called in non-admin context, and an instance of AdminApi when the function is called in admin context. The get_api function is acting as a service locator.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +function get_api(){
                                                                                                                                                              +    static $api;
                                                                                                                                                              +
                                                                                                                                                              +    if(null !== $api){
                                                                                                                                                              +        return $api;
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    if( is_admin() ) {
                                                                                                                                                              +        $api = new Admin_Api();
                                                                                                                                                              +    } else {
                                                                                                                                                              +        $api = new Api();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    return $api;
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              There are two challenges to testing this function:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              1. The is_admin function, defined by WordPress, looks up a WP_ADMIN constant to know if the context of the current request is an administration UI one or not.
                                                                                                                                                              2. +
                                                                                                                                                              3. The get_api function will check for the context and resolve and build the correct instance only once, the first time it's called in the context of a request.
                                                                                                                                                              4. +
                                                                                                                                                              +

                                                                                                                                                              There are some possible solutions to this problem:

                                                                                                                                                              +

                                                                                                                                                              a. Refactor the get_api function into a method of an Api_Factory object taking the context as a dependency, thus allowing injection of the "context" (which implies the creation of a Context adapter that will proxy its is_admin method to the is_admin function). You can find the code for such refactoring in the OOP refactoring of get_api section. +b. Refactor the get_api function to accept the current is_admin value as an input argument, get_api( $is_admin ), this refactoring moves part of the complexity of getting hold of the correct instance of the API handler on the client code. Adding more build condition and checks, e.g., if the current request is a REST request or not or some tests on the user authorizations, then, requires adding more input arguments to the get_api function: the knowledge of the implementation of the get_api method will "leak" to the client code having to replicate complexity throughout the system.

                                                                                                                                                              +

                                                                                                                                                              I want to layout possible solutions to the problem to show there is always a design alternative to make code testable that might or might not fit the current time or scope constraint.

                                                                                                                                                              +

                                                                                                                                                              In this example, I've inherited the get_api function from the existing code, and it cannot be changed, yet I want to test it dealing with the two problems outlined above.

                                                                                                                                                              +

                                                                                                                                                              Running tests in separate PHP processes

                                                                                                                                                              +

                                                                                                                                                              To test the get_api function shown above I've created a new wpunit type of test:

                                                                                                                                                              +
                                                                                                                                                              vendor/bin/codecept g:wpunit integration "api"
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command scaffolds a test/integration/apiTest.php file that I've modified to ensure full coverage of the get_api function:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class apiTest extends \Codeception\TestCase\WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function test_get_api_exists()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->assertTrue(function_exists('get_api'));
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_get_api_will_cache()
                                                                                                                                                              +    {
                                                                                                                                                              +        $this->assertSame(get_api(), get_api());
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    /**
                                                                                                                                                              +     * @runInSeparateProcess
                                                                                                                                                              +     * @preserveGlobalState disabled
                                                                                                                                                              +     */
                                                                                                                                                              +    public function test_get_api_will_return_api_if_not_admin()
                                                                                                                                                              +    {
                                                                                                                                                              +        // Let's make sure we're NOT in admin context.
                                                                                                                                                              +        define('WP_ADMIN', false);
                                                                                                                                                              +
                                                                                                                                                              +        $api = get_api();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertInstanceOf(Api::class, $api);
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    /**
                                                                                                                                                              +     * @runInSeparateProcess
                                                                                                                                                              +     * @preserveGlobalState disabled
                                                                                                                                                              +     */
                                                                                                                                                              +    public function test_get_api_will_cache_api_if_not_admin()
                                                                                                                                                              +    {
                                                                                                                                                              +        // Let's make sure we're NOT in admin context.
                                                                                                                                                              +        define('WP_ADMIN', false);
                                                                                                                                                              +
                                                                                                                                                              +        $api = get_api();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertSame(get_api(), $api);
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    /**
                                                                                                                                                              +     * @runInSeparateProcess
                                                                                                                                                              +     * @preserveGlobalState disabled
                                                                                                                                                              +     */
                                                                                                                                                              +    public function test_get_api_will_return_api_if_is_admin()
                                                                                                                                                              +    {
                                                                                                                                                              +        // Let's make sure we're NOT in admin context.
                                                                                                                                                              +        define('WP_ADMIN', true);
                                                                                                                                                              +
                                                                                                                                                              +        $api = get_api();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertInstanceOf(AdminApi::class, $api);
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    /**
                                                                                                                                                              +     * @runInSeparateProcess
                                                                                                                                                              +     * @preserveGlobalState disabled
                                                                                                                                                              +     */
                                                                                                                                                              +    public function test_get_api_will_cache_api_if_is_admin()
                                                                                                                                                              +    {
                                                                                                                                                              +        // Let's make sure we're NOT in admin context.
                                                                                                                                                              +        define('WP_ADMIN', true);
                                                                                                                                                              +
                                                                                                                                                              +        $api = get_api();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertSame(get_api(), $api);
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Some pieces of this code are worth pointing out:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              1. There are two test methods, test_get_api_exists and test_get_api_will_cache that are not running in a separate process. Running tests in a separate process provide isolation at the cost of speed, only tests that require isolation should run in a separate PHP process.
                                                                                                                                                              2. +
                                                                                                                                                              3. I instruct the Codeception and PHPUnit test runner to run a test method in a different process by adding two annotations that are both required ** precisely as shown**: +
                                                                                                                                                                /**
                                                                                                                                                                + * @runInSeparateProcess
                                                                                                                                                                + * @preserveGlobalState disabled
                                                                                                                                                                + */
                                                                                                                                                                +
                                                                                                                                                              4. +
                                                                                                                                                              5. The isolation part of this testing approach shines through when I define, in the last four tests, the WP_ADMIN constant multiple times. If I try to do that in test code running in the same PHP process, then the second define call would cause a fatal error.
                                                                                                                                                              6. +
                                                                                                                                                              7. The isolation has also taken care of the second issue where the get_api function caches the $api instance after its first resolution in a static variable: since each test happens in a self-contained, dedicated PHP process, the static $api variable will be null at the start of each test.
                                                                                                                                                              8. +
                                                                                                                                                              +

                                                                                                                                                              Can I run some tests in the same process and some in a separate process?

                                                                                                                                                              +

                                                                                                                                                              Yes. In the example test code in the previous section, the test_get_api_exists and test_get_api_will_cache test methods are not running in separate processes.

                                                                                                                                                              +

                                                                                                                                                              In your test cases extending the Codeception\TestCase\WPTestCase, you can mix test methods running in the primary PHP process and those running in a separate PHP process without issues.

                                                                                                                                                              +

                                                                                                                                                              OOP refactoring of get_api

                                                                                                                                                              +

                                                                                                                                                              In the Why run tests in a separate PHP process? section I've outlined a possible refactoring of the get_api function to make it testable without requiring the use of separate PHP processes.

                                                                                                                                                              +

                                                                                                                                                              I'm providing this refactoring code below for the sake of completeness, the judgment of which approach is "better" is up to the reader.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class Context_Adapter{
                                                                                                                                                              +
                                                                                                                                                              +    public function is_admin(){
                                                                                                                                                              +        return \is_admin();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +class Api_Factory{
                                                                                                                                                              +
                                                                                                                                                              +    private $api;
                                                                                                                                                              +    private $context;
                                                                                                                                                              +
                                                                                                                                                              +    public function __construct(Context_Adapter $context){
                                                                                                                                                              +        $this->context = $context;
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function getApi(){
                                                                                                                                                              +        if(null !== $this->api){
                                                                                                                                                              +            return $this->api;    
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        if($this->context->is_admin()){
                                                                                                                                                              +            $api = new Admin_Api;
                                                                                                                                                              +        } else {
                                                                                                                                                              +            $api = new Api;
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        return $api;
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Now the Api_Factory class can be injected by injecting a mocked Context_Adapter class, modifying the return value of the Context_Adapter::is_admin method.

                                                                                                                                                              +

                                                                                                                                                              Due to the supposed requirement of the API instance being a singleton, this solution will also require some container or service-locator to ensure at most only one instance of the Api_Factory exists at any given time in the context of a request.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/codeception-4-support/index.html b/v3/codeception-4-support/index.html new file mode 100644 index 000000000..2fdf8b5bb --- /dev/null +++ b/v3/codeception-4-support/index.html @@ -0,0 +1,3010 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Using wp-browser with Codeception 4.0 - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Using wp-browser with Codeception 4.0

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Using wp-browser with Codeception 4.0

                                                                                                                                                              +

                                                                                                                                                              Codeception version 4.0 introduced a number of new features to the framework and it's the version of wp-browser that will be maintained from now on.

                                                                                                                                                              +

                                                                                                                                                              I've made an effort to keep wp-browser compatible with PHP 5.6 and Codeception versions from 2.5 up.

                                                                                                                                                              +

                                                                                                                                                              One the biggest changes of Codeception version 4.0 is that modules have been broken out into separate packages.
                                                                                                                                                              +To use wp-browser with Codeception 4.0 all you need to do is to add this to your project composer.json file:

                                                                                                                                                              +
                                                                                                                                                              {
                                                                                                                                                              +  "require-dev": {
                                                                                                                                                              +    "lucatume/wp-browser": "^2.4",
                                                                                                                                                              +    "codeception/module-asserts": "^1.0",
                                                                                                                                                              +    "codeception/module-phpbrowser": "^1.0",
                                                                                                                                                              +    "codeception/module-webdriver": "^1.0",
                                                                                                                                                              +    "codeception/module-db": "^1.0",
                                                                                                                                                              +    "codeception/module-filesystem": "^1.0",
                                                                                                                                                              +    "codeception/module-cli": "^1.0",
                                                                                                                                                              +    "codeception/util-universalframework": "^1.0"
                                                                                                                                                              +  }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You might not need all the modules listed here, depending on the wp-browser modules you use in your test suites.
                                                                                                                                                              +This is a scheme of what Codeception modules you will need for which wp-browser module to help you choose only the required modules:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • "codeception/module-asserts" - Required for Codeception 4.0 compatibility.
                                                                                                                                                              • +
                                                                                                                                                              • "codeception/module-phpbrowser" - Required by the WPBrowser module.
                                                                                                                                                              • +
                                                                                                                                                              • "codeception/module-webdriver" - Required by the WPWebDriver module.
                                                                                                                                                              • +
                                                                                                                                                              • "codeception/module-db" - Required by the WPDb module.
                                                                                                                                                              • +
                                                                                                                                                              • "codeception/module-filesystem" - Required by the WPFilesystem module.
                                                                                                                                                              • +
                                                                                                                                                              • "codeception/module-cli" - Required by the WPCLI module.
                                                                                                                                                              • +
                                                                                                                                                              • "codeception/util-universalframework" - Required by the WordPress framework module.
                                                                                                                                                              • +
                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/codeception-phpunit-and-wpbrowser/index.html b/v3/codeception-phpunit-and-wpbrowser/index.html new file mode 100644 index 000000000..b862fb1d0 --- /dev/null +++ b/v3/codeception-phpunit-and-wpbrowser/index.html @@ -0,0 +1,3076 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Codeception, PHPUnit and wp-browser - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Codeception, PHPUnit and wp-browser

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The wp-browser stack

                                                                                                                                                              +

                                                                                                                                                              The wp-browser project is built leveraging the power of a number of open-source projects.

                                                                                                                                                              +

                                                                                                                                                              While I'm not listing all of them here it's worth mentioning those that will come up, again and again, in the documentation.

                                                                                                                                                              +

                                                                                                                                                              WordPress

                                                                                                                                                              +

                                                                                                                                                              WordPress is open source software you can use to create a beautiful website, blog, or app.

                                                                                                                                                              +

                                                                                                                                                              The line is taken directly from WordPress.org site.

                                                                                                                                                              +

                                                                                                                                                              In the context of this documentation WordPress is the PHP and JavaScript framework websites and web applications can be built on, the one anyone can download from here.

                                                                                                                                                              +

                                                                                                                                                              Codeception

                                                                                                                                                              +

                                                                                                                                                              Codeception (home) is a modern, powerful PHP testing framework written in PHP.

                                                                                                                                                              +

                                                                                                                                                              It comes with a number of modules and extensions that are comparable to WordPress plugins and themes.

                                                                                                                                                              +

                                                                                                                                                              Modules and extensions are combined in suites to be able to run a specific type of test. Each suite will handle a specific type of test for a specific set of code.

                                                                                                                                                              +

                                                                                                                                                              wp-browser is none other than a collection of modules and extensions for Codeception made specifically to test WordPress applications.

                                                                                                                                                              +

                                                                                                                                                              PHPUnit

                                                                                                                                                              +

                                                                                                                                                              PHPUnit is the most widely known PHP testing framework. As the name implies it was born to make unit testing of PHP code easier but its scope and power has grown well below that.

                                                                                                                                                              +

                                                                                                                                                              Codeception is based, and uses, PhpUnit to wrap some of its functionalities into an easy-to-use API.
                                                                                                                                                              +The two are so compatible one with the other that Codeception can run PHPUnit tests with little to no changes.

                                                                                                                                                              +

                                                                                                                                                              This documentation will not cover this subject and will only deal with Codeception-native test methods but you can find more information here.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/commands/index.html b/v3/commands/index.html new file mode 100644 index 000000000..5307566ee --- /dev/null +++ b/v3/commands/index.html @@ -0,0 +1,3375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Commands - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Custom commands provided by wp-browser

                                                                                                                                                              +

                                                                                                                                                              The project comes with its own set of custom Codeception commands.

                                                                                                                                                              +

                                                                                                                                                              The commands provide functionalities to quickly scaffold different types of tests. +Any other codecept command remains intact and available.

                                                                                                                                                              +

                                                                                                                                                              Adding the commands to an existing project

                                                                                                                                                              +

                                                                                                                                                              The commands are added to the main Codeception configuration file, codeception.yml, when scaffolding a project via the codecept init wp-browser command.

                                                                                                                                                              +

                                                                                                                                                              They can be added to any existing project adding, or editing, the commands section of the configuration file:

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    commands:
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPUnit"
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPRestApi"
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPRestController"
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPRestPostTypeController"
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPAjax"
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPCanonical"
                                                                                                                                                              +        - "Codeception\\Command\\GenerateWPXMLRPC"
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Generation commands

                                                                                                                                                              +

                                                                                                                                                              The library provides commands to quickly scaffold integration test cases for specific types of WordPress components, see levels of testing for more information.

                                                                                                                                                              +

                                                                                                                                                              The tests are almost identical to the ones you could write in a PHPUnit based Core suite with the exception of extending the Codeception\TestCase\WPTestCase test case.

                                                                                                                                                              +

                                                                                                                                                              generate:wpunit

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wpunit suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              generate:wprest

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPRestApiTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wprest suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPRestApiTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              generate:wprestcontroller

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPRestControllerTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wprest suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPRestControllerTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              generate:wprestposttypecontroller

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPRestPostTypeControllerTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wprest suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPRestPostTypeControllerTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              generate:wpajax

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPAjaxTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wpajax suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPAjaxTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              generate:wpxmlrpc

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPXMLRPCTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wpxmlrpc suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPXMLRPCTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              generate:wpcanonical

                                                                                                                                                              +

                                                                                                                                                              Generates a test case extending the \Codeception\TestCase\WPCanonicalTestCase class using the

                                                                                                                                                              +
                                                                                                                                                                codecept generate:wpcanonical suite SomeClass
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The command will generate a skeleton test case like

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +class SomeClassTest extends \Codeception\TestCase\WPCanonicalTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function setUp()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::setUp();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function tearDown()
                                                                                                                                                              +    {
                                                                                                                                                              +      parent::tearDown();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    // tests
                                                                                                                                                              +    public function testMe()
                                                                                                                                                              +    {
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/configuration/index.html b/v3/configuration/index.html new file mode 100644 index 000000000..f9ee28ba3 --- /dev/null +++ b/v3/configuration/index.html @@ -0,0 +1,3957 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Configuration - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Configuration

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Initializing wp-browser

                                                                                                                                                              +

                                                                                                                                                              While wp-browser can be configured manually creating each file the fastest way to bootstrap its configuration is by using its initialization template.

                                                                                                                                                              +

                                                                                                                                                              Throughout the steps below I will use the WordPress setup I've prepared before +From the root folder of the project, /Users/luca/Sites/wordpress/wp-content/plugins/acme-plugin in the example, run the command:

                                                                                                                                                              +
                                                                                                                                                              vendor/bin/codecept init wpbrowser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Composer installed Codeception binary (codecept) in the vendor folder of my project.

                                                                                                                                                              +

                                                                                                                                                              With the command above I'm telling Codeception to initialize a wp-browser project in the current folder.
                                                                                                                                                              +When I click enter I'm presented with a list of questions, each answer will be used to configure the wp-browser project for me; one by one.

                                                                                                                                                              +

                                                                                                                                                              In the screenshot the answers I've provided to each question, with reference to the setup above:

                                                                                                                                                              +

                                                                                                                                                              codecept init wpbrowser 1

                                                                                                                                                              +

                                                                                                                                                              codecept init wpbrowser 2

                                                                                                                                                              +

                                                                                                                                                              wp-browser will try to provide a brief explanation of what each question is but below is the long version.

                                                                                                                                                              +

                                                                                                                                                              Long question explanation

                                                                                                                                                              +

                                                                                                                                                              I've tried to condense as much clarity as possible in the questions the codecept init wpbrowser command will ask but, for sake of brevity and space, there's no way I could provide inline a deeper explanation of each.

                                                                                                                                                              +

                                                                                                                                                              Below is a longer explanation of each question:

                                                                                                                                                              + +

                                                                                                                                                              How would you like the acceptance suite to be called?

                                                                                                                                                              +

                                                                                                                                                              With reference to the testing levels definition this question provides you with the possibility to change the name of the acceptance-like test suite.

                                                                                                                                                              +

                                                                                                                                                              Common, alternative, names are ui, rest and user.

                                                                                                                                                              +

                                                                                                                                                              How would you like the functional suite to be called?

                                                                                                                                                              +

                                                                                                                                                              With reference to the testing levels definition this question provides you with the possibility to change the name of the functional-like test suite.

                                                                                                                                                              +

                                                                                                                                                              A common alternative name is service.

                                                                                                                                                              +

                                                                                                                                                              How would you like the WordPress unit and integration suite to be called?

                                                                                                                                                              +

                                                                                                                                                              With reference to the testing levels definition this question provides you with the possibility to change the name of the suite dedicated to integration and "WordPress unit" tests.

                                                                                                                                                              +

                                                                                                                                                              A common alternative name is integration.

                                                                                                                                                              +

                                                                                                                                                              How would you like to call the env configuration file?

                                                                                                                                                              +

                                                                                                                                                              Instead of configuring each module in each suite with the same parameters over and over Codeception supports dynamic configuration via environment files.

                                                                                                                                                              +

                                                                                                                                                              wp-browser will scaffold such a configuration for you and will use, by default, a file called .env to store the configuration parameters.

                                                                                                                                                              +

                                                                                                                                                              The file name might not suit all setups especially and this question allows changing that file name; common, alternative, file names are .env.tests, .env.codeception and similar.

                                                                                                                                                              +

                                                                                                                                                              Where is WordPress installed?

                                                                                                                                                              +

                                                                                                                                                              During tests the test code will need to access WordPress code, precisely wp-browser requires being pointed to the folder that contains the wp-load.php file.

                                                                                                                                                              +

                                                                                                                                                              The answer can be an absolute path, like /Users/luca/Sites/wordrpress, or a path relative to the folder where Codeception is installed like vendor/wordpress.

                                                                                                                                                              +

                                                                                                                                                              This path should be accessible by the machine that is running the tests; if you're running the tests from your machine (e.g. your laptop) that's just the path to the folder where WordPress is installed, /Users/luca/Sites/wordpress in the example configuration above.

                                                                                                                                                              +

                                                                                                                                                              If you are, instead, running the tests from within a virtualized machine (e.g. Vagrant or Docker) then the path should be the one used by the virtualized machine.

                                                                                                                                                              +

                                                                                                                                                              To make an example:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • on my machine WordPress is installed at /Users/luca/Sites/wordpress
                                                                                                                                                              • +
                                                                                                                                                              • I've created a Docker container using the official WordPress image and bound the above folder into the container
                                                                                                                                                              • +
                                                                                                                                                              • internally the container will put WordPress in the /var/www/html folder
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              If I run the tests from my host machine then WordPress root directory will be /Users/luca/Sites/wordpress, if I run the tests from within the Docker container then WordPress root folder will be /var/www/html.

                                                                                                                                                              +

                                                                                                                                                              Another example is Local by Flywheel:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • in the host machine the path to the WordPress root folder will be /Users/luca/Local\ Sites/wordpress/app/public
                                                                                                                                                              • +
                                                                                                                                                              • from within the Docker container managed by Local the path will be /app/public
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              If you need a solution that will work in both instances use a relative path: wp-browser will accept paths like ./../../../wordpress and will attempt to resolve them.

                                                                                                                                                              +

                                                                                                                                                              What is the path, relative to WordPress root URL, of the admin area of the test site?

                                                                                                                                                              +

                                                                                                                                                              This is usually /wp-admin but you might have the web-server, or a plugin, redirect or hide requests for the administration area to another path.

                                                                                                                                                              +

                                                                                                                                                              Some examples are /admin, /login and the like.

                                                                                                                                                              +

                                                                                                                                                              Mind that this is not the path to the login page but the path to the administrationo area; this will be used by wp-browser to find to the administration area in acceptance and functional tests.

                                                                                                                                                              +

                                                                                                                                                              What is the name of the test database used by the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's wordpress.

                                                                                                                                                              +

                                                                                                                                                              This is the name of the database that is storing the information used by the site I can reach at http://localhost:8080.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              I want to underline the word "test". Any site and any database you use and expose to wp-browser should be intended for tests; this means that it does not contain any data you care about as it will be lost.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              What is the host of the test database used by the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's 127.0.0.1:3306.

                                                                                                                                                              +

                                                                                                                                                              Here the same principle valid for Where is WordPress installed? applies: the database host is relative to the machine that is running the tests.

                                                                                                                                                              +

                                                                                                                                                              In my example I'm hosting the database locally, on my laptop, and my machine can reach it at the localhost address (127.0.0.1) on MySQL default port (3306).

                                                                                                                                                              +

                                                                                                                                                              If I am using the database of a Local by Flywheel site from my host machine then it might be something like 192.168.92.100:4050 (from the site "Database" tab); the same principle applies if I am using a Vagrant-based or Docker-based solution.

                                                                                                                                                              +

                                                                                                                                                              If I am running the tests from within a virtualized machine (a Docker container, a Vagrant box et cetera) then it would probably be localhost or 1270.0.0.1.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used in the context of acceptance and functional tests by the WPDb module.

                                                                                                                                                              +

                                                                                                                                                              What is the user of the test database used by the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's root as I'm using MySQL server root user to access the database during tests.

                                                                                                                                                              +

                                                                                                                                                              Depending on your setup it might be different; since wp-browser will need to not only read but write too to the database make sure to use a user that has full access to the database specified in the answer to the What is the host of the test database used by the test site? question.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used in the context of acceptance and functional tests by the WPDb module.

                                                                                                                                                              +

                                                                                                                                                              What is the password of the test database used by the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's empty as I've not set any password for the root account.

                                                                                                                                                              +

                                                                                                                                                              In your case it might be different and it should be the password associated with the user specified in the answer to the What is the user of the test database used by the test site? question.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used in the context of acceptance and functional tests by the WPDb module.

                                                                                                                                                              +

                                                                                                                                                              What is the table prefix of the test database used by the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's wp_; that value is taken from the WordPress installation configuration file.

                                                                                                                                                              +

                                                                                                                                                              To have any influence on the site wp-browser will need to modify the same database tables WordPress is using; as I did you can take this value from the wp-config.php file directly: it's the value of the $table_prefix variable.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used in the context of acceptance and functional tests by the WPDb module.

                                                                                                                                                              +

                                                                                                                                                              What is the name of the test database WPLoader should use?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's tests.

                                                                                                                                                              +

                                                                                                                                                              During integration, or WordPress "unit" tests, wp-loader will need to load WordPress code.

                                                                                                                                                              +

                                                                                                                                                              Since WordPress code is not meant to be "modular" it does not support auto-loading or loading just parts of it; it's either almost all or nothing.

                                                                                                                                                              +

                                                                                                                                                              One of the first things WordPress does, when loading, is trying to connect to a database: if that database is not available then WordPress will not load.

                                                                                                                                                              +

                                                                                                                                                              In the answer to the question Where is WordPress installed? I've told wp-browser where to find WordPress code, in this answer I'm telling wp-browser what database it should use to bootstrap WordPress.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress. +It's highly recommended to use a different database from the one used for functional and acceptance tests.

                                                                                                                                                              +

                                                                                                                                                              What is the host of the test database WPLoader should use?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's 127.0.0.1:3306.

                                                                                                                                                              +

                                                                                                                                                              As in the answer to the question What is the name of the test database WPLoader should use? we're providing connection details about the database that should be used to bootstrap WordPress during integration and WordPress "unit" tests.

                                                                                                                                                              +

                                                                                                                                                              Again the database host is in relation to the machine running the tests, all the considerations done for What is the host of the test database used by the test site? apply.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress.

                                                                                                                                                              +

                                                                                                                                                              What is the user of the test database WPLoader should use?

                                                                                                                                                              +

                                                                                                                                                              In my example it's root.

                                                                                                                                                              +

                                                                                                                                                              Similar to the question What is the user of the test database used by the test site? but in relation to the database specified in the question What is the name of the test database WPLoader should use?.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress.

                                                                                                                                                              +

                                                                                                                                                              What is the password of the test database WPLoader should use?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's empty as I've not set any password for the root account.

                                                                                                                                                              +

                                                                                                                                                              Similar to the question What is the password of the test database used by the test site? but in relation to the database specified in the question What is the name of the test database WPLoader should use?.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress.

                                                                                                                                                              +

                                                                                                                                                              What is the table prefix of the test database WPLoader should use?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's wp_.

                                                                                                                                                              +

                                                                                                                                                              Similar to the question What is the table prefix of the test database used by the test site? but in relation to the database specified in the question What is the name of the test database WPLoader should use?.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress.

                                                                                                                                                              +

                                                                                                                                                              What is the URL the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's http://localhost:8080.

                                                                                                                                                              +

                                                                                                                                                              This is the full URL you would have to enter in the browser, on the machine that is running the tests, to reach the test WordPress site homepage.

                                                                                                                                                              +

                                                                                                                                                              What is the email of the test site WordPress administrator?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's admin@wp.localhost.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and, while required, it's usually not relevant unless you're testing email communications.

                                                                                                                                                              +

                                                                                                                                                              What is the title of the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's Acme Plugin Test Site.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and, while required, it's usually not relevant unless you're testing around the site title.

                                                                                                                                                              +

                                                                                                                                                              What is the login of the administrator user of the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's admin.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPBrowser or WPWebDriver modules to fill in the login details for the administrator user.

                                                                                                                                                              +

                                                                                                                                                              It should be the same as the one that allows you to access the site administration area in the WordPress test site, http://localhost:8080/wp-admin in my example.

                                                                                                                                                              +

                                                                                                                                                              What is the password of the administrator user of the test site?

                                                                                                                                                              +

                                                                                                                                                              In my example setup it's password.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPBrowser or WPWebDriver modules to fill in the login details for the administrator user.

                                                                                                                                                              +

                                                                                                                                                              It should be the same as the one that allows you to access the site administration area in the WordPress test site, http://localhost:8080/wp-admin in my example.

                                                                                                                                                              +

                                                                                                                                                              Are you testing a plugin, a theme or a combination of both?

                                                                                                                                                              +

                                                                                                                                                              Depending on the answer the WPLoader module will load, during integration or WordPress "unit" tests, your WordPress plugin or theme.

                                                                                                                                                              +

                                                                                                                                                              If you replied with both (for "a combination of both") then you'll be able to choose the plugins and theme to load in integration and WordPress "unit" tests in the following questions.

                                                                                                                                                              +

                                                                                                                                                              What is the folder/plugin.php name of the plugin?

                                                                                                                                                              +

                                                                                                                                                              This question will be asked only if you replied plugin to the question Are you testing a plugin, a theme or a combination of both?.
                                                                                                                                                              +In my example setup it's acme-plugin/plugin.php.

                                                                                                                                                              +

                                                                                                                                                              This is the <folder>/<main-plugin-file>.php path, relative to the WordPress installation plugins folder, to the plugin you are testing.

                                                                                                                                                              +

                                                                                                                                                              The main plugin file is the one that contains the plugin header.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load your plugin or theme in integration and WordPress "unit" tests.

                                                                                                                                                              +

                                                                                                                                                              Are you developing a child theme?

                                                                                                                                                              +

                                                                                                                                                              This question will be asked only if you replied theme to the question Are you testing a plugin, a theme or a combination of both?.
                                                                                                                                                              +Enter yes if you are developing a child theme.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load a parent theme along with your theme in integration and WordPress "unit" tests.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Please note that wp-browser will not download and install the parent theme in the WordPress installation for you.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Are you using a child theme?

                                                                                                                                                              +

                                                                                                                                                              This question will be asked only if you replied both to the question Are you testing a plugin, a theme or a combination of both?.
                                                                                                                                                              +Enter yes if you are using a child theme.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load a parent theme along with your theme in integration and WordPress "unit" tests.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Please note that wp-browser will not download and install the parent theme in the WordPress installation for you.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              What is the slug of the parent theme?

                                                                                                                                                              +

                                                                                                                                                              This question will be asked only if you replied yes to the question Are you developing a child theme?.

                                                                                                                                                              +

                                                                                                                                                              Reply with the slug of the parent theme, that's usually the name of the folder the parent theme lives in, e.g. twentyseventeen.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load a parent theme along with your theme in integration and WordPress "unit" tests.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Please note that wp-browser will not download and install the parent theme in the WordPress installation for you.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              What is the slug of the theme?

                                                                                                                                                              +

                                                                                                                                                              This question will be asked only if you replied theme to the question Are you testing a plugin, a theme or a combination of both?.
                                                                                                                                                              +Reply with the slug of the theme, that's usually the name of the folder the theme lives in, e.g. twentyseventeen.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load your theme in integration and WordPress "unit" tests.

                                                                                                                                                              +

                                                                                                                                                              What is the slug of the theme you are using?

                                                                                                                                                              +

                                                                                                                                                              This question will be asked only if you replied both to the question Are you testing a plugin, a theme or a combination of both?.
                                                                                                                                                              +Reply with the slug of the theme you are using, that's usually the name of the folder the theme lives in, e.g. twentyseventeen.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load the theme integration and WordPress "unit" tests.

                                                                                                                                                              +

                                                                                                                                                              Does your project needs additional plugins to be activated to work?

                                                                                                                                                              +

                                                                                                                                                              Whether you're testing a plugin, a theme or a combination of both you might need some additional plugins to run your tests.

                                                                                                                                                              +

                                                                                                                                                              As an example if I'm testing a WooCommerce extension I need the WooCommerce plugin to test it; this is the place where I can define it.

                                                                                                                                                              +

                                                                                                                                                              The required plugins follow the same format as the one used in the question What is the folder/plugin.php name of the plugin?: <plugin-folder>/<plugin-main-file>.php; in the case of WooCommerce it would be woocommerce/woocommerce.php.

                                                                                                                                                              +

                                                                                                                                                              This detail will be used by the WPLoader module to bootstrap WordPress and load the required plugins in integration and WordPress "unit" tests.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Please note that wp-browser will not download and install the required plugins in the WordPress installation for you.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you entered a wrong value

                                                                                                                                                              +

                                                                                                                                                              No worries, just correct the value in the environment file or in the suites configuration files.

                                                                                                                                                              +

                                                                                                                                                              The environment file will have the name you specified in the answer the question How would you like to call the env configuration file?.

                                                                                                                                                              +

                                                                                                                                                              The suites configuration files can be found in tests/<suite>.suite.yml; e.g. the wpunit suite configuration file will be tests/wpunit.suite.yml file.

                                                                                                                                                              +

                                                                                                                                                              Final steps

                                                                                                                                                              +

                                                                                                                                                              To complete the setup I have removed any demo content from the site and activated my plugin in the plugins administration page.

                                                                                                                                                              +

                                                                                                                                                              In the tests/acceptance.suite.yml file and in the tests/functional.suite.yml file, the configuration file for the acceptance and functional suites respectively, the WPDb module configuration contains a dump configuration parameter:

                                                                                                                                                              +
                                                                                                                                                              class_name: AcceptanceTester
                                                                                                                                                              +modules:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - WPDb
                                                                                                                                                              +    config:
                                                                                                                                                              +        WPDb:
                                                                                                                                                              +            dump: 'tests/_data/dump.sql'
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The dump parameter is inherited by the WPDb module from the Codeception Db module and defines the SQL dump file that should be loaded before, and between, tests to reset the testing environment to a base known state.

                                                                                                                                                              +

                                                                                                                                                              As for any other database-related operation wp-browser will not create the dump for me. +I use MySQL binary to export the database state (a dump) with the command:

                                                                                                                                                              +
                                                                                                                                                              mysqldump -u root -h 127.0.0.1 -P 3306 wordpress > /Users/luca/Sites/wordpress/wp-content/plugins/acme-plugin/tests/_data/dump.sql
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              I could use any other combination of tools to produce the dump; using mysql binary is not a requirement.

                                                                                                                                                              +

                                                                                                                                                              Graphic interfaces like SequelPro, Adminer and the like would be perfectly fine.

                                                                                                                                                              +

                                                                                                                                                              Pre-flight check

                                                                                                                                                              +

                                                                                                                                                              There is one last check I need to make before jumping into the creation of tests: making sure all the paths and credentials I've configured wp-browser with are correct.

                                                                                                                                                              +

                                                                                                                                                              The bootstrap process generated four suites for me: acceptance, functional, integration and unit. If you have modified the default suite names during the setup your suites names might differ though.

                                                                                                                                                              +

                                                                                                                                                              To test the setup I will run each suite and make sure it can run correctly empty of any test. To run a suite of tests I will use the codecept run command:

                                                                                                                                                              +
                                                                                                                                                              codecept run acceptance
                                                                                                                                                              +codecept run functional
                                                                                                                                                              +codecept run integration
                                                                                                                                                              +codecept run unit
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              How comes I'm not using the command codecept run (without specifying the suite names)? See the FAQ entry.

                                                                                                                                                              +

                                                                                                                                                              Pre-flight check

                                                                                                                                                              +

                                                                                                                                                              If you cannot run all the suites without issues then check your configuration settings again, read the errors and see If you entered a wrong value

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/events-api/index.html b/v3/events-api/index.html new file mode 100644 index 000000000..e987afa35 --- /dev/null +++ b/v3/events-api/index.html @@ -0,0 +1,3082 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Events API - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Events API

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Events API

                                                                                                                                                              +

                                                                                                                                                              Codeception comes with a set of events modules and extensions can subscribe to.

                                                                                                                                                              +

                                                                                                                                                              Codeception Events API is, but, only available to Modules and Extensions, and while that might be good for most cases, it might not cover a number of edge cases.

                                                                                                                                                              +

                                                                                                                                                              Similarly to WordPress add_action function, wp-browser provides the tad\WPBrowser\addListener function:

                                                                                                                                                              +
                                                                                                                                                              function addListener($eventName, callable $listener, $priority = 0);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The priority works the reverse way as it does in WordPress: highest number will be processed first!

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Again similarly to WordPress do_action function, the tad\WPBrowser\dispatch function:

                                                                                                                                                              +
                                                                                                                                                              function dispatch($eventName, $origin = null, array $context = []);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This is the kind of API that is better shown with an example, though.

                                                                                                                                                              +

                                                                                                                                                              Example

                                                                                                                                                              +

                                                                                                                                                              In this example I'm writing acceptance tests and would like to avoid the performance hit that the cleanup configuration parameter of the Db, or WPDb, module implies.
                                                                                                                                                              +The cleanup parameter will trigger the drop of all tables in the test database and the re-import of the SQL dump file, or files, between each test.
                                                                                                                                                              +This will ensure a clean starting fixture between tests, but for larger setup fixtures this might be a long operation that wastes precious seconds when, say, the only change is the addition of 3 posts, as in this example.

                                                                                                                                                              +

                                                                                                                                                              The Events API allows implementing a tailored clean-up procedure that can avoid costly clean ups between tests.

                                                                                                                                                              +

                                                                                                                                                              In the suite bootstrap file, e.g. tests/acceptance/_bootstrap.php, I add a listener on the my-plugin-test/setup-posts event.
                                                                                                                                                              +The event will contain information about what post IDs I've set up in the tests and will provide an instance of the tester object to handle database manipulation.
                                                                                                                                                              +With that information, the costly cleanup procedure can be avoided.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +$registerPostsCleanup = static function (tad\WPBrowser\Events\WpbrowserEvent $event) {
                                                                                                                                                              +    $ids = $event->get('ids', []);
                                                                                                                                                              +    /** @var \EventsTester $db */
                                                                                                                                                              +    $db = $event->get('db');
                                                                                                                                                              +
                                                                                                                                                              +    // When tests are done, then remove all the posts we've created at the start of the test, if any.
                                                                                                                                                              +    tad\WPBrowser\addListener(
                                                                                                                                                              +        Codeception\Events::TEST_AFTER,
                                                                                                                                                              +        static function () use ($ids, $db) {
                                                                                                                                                              +            foreach ($ids as $id) {
                                                                                                                                                              +                $db->dontHavePostInDatabase([ 'ID' => $id ], true);
                                                                                                                                                              +                // Ensure the clean up did happen correctly.
                                                                                                                                                              +                $db->dontSeePostInDatabase([ 'ID' => $id ]);
                                                                                                                                                              +                $db->dontSeePostMetaInDatabase([ 'post_id' => $id ]);
                                                                                                                                                              +            }
                                                                                                                                                              +        }
                                                                                                                                                              +    );
                                                                                                                                                              +};
                                                                                                                                                              +
                                                                                                                                                              +// Listen for this event to register the posts to remove, along with their custom fields, after the test.
                                                                                                                                                              +tad\WPBrowser\addListener('test-event-1/setup-posts', $registerPostsCleanup);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              In this simple test I'm adding 3 posts [using the factory provided by the WPLoader module in loadOnly mode][2] and want to make sure those, and the relative meta, are removed at the end of the tests. +The WPDb module, extending the Db module from Codeception, will remove the inserted rows, but will not take care of modified rows, or rows not inserted by the WPDb module.

                                                                                                                                                              +

                                                                                                                                                              Mirroring the requirement of the clean up function I've defined above, I'm passing the post IDs of the posts I've created and the current tester to provide the clean up function with database handling capabilities.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +/** @var Codeception\Scenario $scenario */
                                                                                                                                                              +$I = new AcceptanceTester($scenario);
                                                                                                                                                              +$I->wantTo('add posts and clean them up using the Events API');
                                                                                                                                                              +
                                                                                                                                                              +/*
                                                                                                                                                              + * Use WordPress methods, thanks to the `WPLoader` module, to use WordPress, or our own, API to insert posts.
                                                                                                                                                              + * This will prevent, but, `WPDb` from removing the inserted rows and clean up, so we remove the posts and meta
                                                                                                                                                              + * with an event and our custom clean-up function.
                                                                                                                                                              + */
                                                                                                                                                              +$ids = $I->factory()->post->create_many(3, [ 'post_type' => 'some_post_type' ]);
                                                                                                                                                              +
                                                                                                                                                              +tad\WPBrowser\dispatch('test-event-1/setup-posts', __FILE__, [
                                                                                                                                                              +    'ids' => $ids,
                                                                                                                                                              +    'db'  => $I
                                                                                                                                                              +]);
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/extensions/index.html b/v3/extensions/index.html new file mode 100644 index 000000000..a8f364a16 --- /dev/null +++ b/v3/extensions/index.html @@ -0,0 +1,3198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extensions - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Extensions

                                                                                                                                                              +

                                                                                                                                                              The Codeception testing framework can be extended in a number of ways.

                                                                                                                                                              +

                                                                                                                                                              The one this project leverages the most are modules but [extensions are another way].

                                                                                                                                                              +

                                                                                                                                                              Modules extend the functionality of Codeception in the context of the tests, while extensions extend its interaction capacities; this is by no means a strict rule but that's usually the case.

                                                                                                                                                              +

                                                                                                                                                              The package contains two additional extensions to facilitate testers' life.

                                                                                                                                                              +

                                                                                                                                                              Symlinker

                                                                                                                                                              +

                                                                                                                                                              The tad\WPBrowser\Extension\Symlinker extension provides an automation to have the Codeception root directory symbolically linked in a WordPress local installation.

                                                                                                                                                              +

                                                                                                                                                              Since version 3.9 WordPress supports this feature (with some precautions) and the extension takes charge of:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • symbolically linking a plugin or theme folder in the specified destination before any suite boots up
                                                                                                                                                              • +
                                                                                                                                                              • unlinking that symbolic link after all of the suites did run
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              It's the equivalent of doing something like this from the command line (on a Mac):

                                                                                                                                                              +
                                                                                                                                                              ln -s /my/central/plugin/folder/my-plugin /my/local/wordpress/installation/wp-content/plugins/my-plugin
                                                                                                                                                              +/my/central/plugin/folder/my-plugin/vendor/bin/codecept run
                                                                                                                                                              +rm -rf /my/local/wordpress/installation/wp-content/plugins/my-plugin
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The extension needs small configuration in the codeception.yml file:

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - tad\WPBrowser\Extension\Symlinker
                                                                                                                                                              +    config:
                                                                                                                                                              +        tad\WPBrowser\Extension\Symlinker:
                                                                                                                                                              +            mode: plugin
                                                                                                                                                              +            destination: /my/local/wordpress/installation/wp-content/plugins
                                                                                                                                                              +            rootFolder: /some/plugin/folder
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The arguments are:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • mode - can be plugin or theme and indicates whether the current Codeception root folder being symlinked is a plugin or a theme one
                                                                                                                                                              • +
                                                                                                                                                              • destination - the absolute path to the WordPress local installation plugins or themes folder; to take the never ending variety of possible setups into account the extension will make no checks on the nature of the destination: could be any folder.
                                                                                                                                                              • +
                                                                                                                                                              • rootFolder - optional absolute path to the WordPress plugin or theme to be symlinked root folder; will default to the Codeception root folder
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Copier

                                                                                                                                                              +

                                                                                                                                                              The tad\WPBrowser\Extension\Copier extension provides an automation to have specific files and folders copied to specified destination files and folders before the suites run.

                                                                                                                                                              +

                                                                                                                                                              While WordPress handles symbolic linking pretty well there are some cases, like themes and drop-ins, where there is a need for "real" files to be put in place.

                                                                                                                                                              +

                                                                                                                                                              One of such cases is, currently, one where Docker is used to to host and serve the code under test: symbolically linked files cannot be bound inside a container and Docker containers will fail to start in this case.

                                                                                                                                                              +

                                                                                                                                                              The extension follows the standard Codeception extension activation and has one configuration parameter only:

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - tad\WPBrowser\Extension\Copier
                                                                                                                                                              +    config:
                                                                                                                                                              +        tad\WPBrowser\Extension\Copier:
                                                                                                                                                              +            files:
                                                                                                                                                              +                tests/_data/required-drop-in.php: /var/www/wordpress/wp-content/drop-in.php
                                                                                                                                                              +                tests/_data/themes/dummy: /var/www/wordpress/wp-content/themes/dummy
                                                                                                                                                              +                /Users/Me/Repos/required-plugin: /var/www/wordpress/wp-content/plugins/required-plugin.php
                                                                                                                                                              +                /Users/Me/Repos/mu-plugin.php: ../../../../wp-content/mu-plugins/mu-plugin.php
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The extension will handle absolute and relative paths for sources and destinations and will resolve relative paths from the project root folder.

                                                                                                                                                              +

                                                                                                                                                              When copying directories the extension will only create the destination folder and not the folder tree required; in the example configuration above the last entry specifies that a mu-plugin.php file should be copied to the mu-plugins folder: that mu-plugins folder must be there already.

                                                                                                                                                              +

                                                                                                                                                              Environments support

                                                                                                                                                              +

                                                                                                                                                              Being able to symlink a plugin or theme folder into a WordPress installation for testing purposes could make sense when trying to test, as an example, a plugin in a single site and in multi site environment.

                                                                                                                                                              +

                                                                                                                                                              Codeception supports environments and the extension does as well specifying a destination for each.

                                                                                                                                                              +

                                                                                                                                                              As an example the acceptance.suite.yml file might be configured to support single and multisite environments:

                                                                                                                                                              +
                                                                                                                                                              env:
                                                                                                                                                              +    single:
                                                                                                                                                              +        modules:
                                                                                                                                                              +            config:
                                                                                                                                                              +                WPBrowser:
                                                                                                                                                              +                    url: 'http://wp.dev'
                                                                                                                                                              +                WPDb:
                                                                                                                                                              +                    dsn: 'mysql:host=127.0.0.1;dbname=wp'
                                                                                                                                                              +    multisite:
                                                                                                                                                              +        modules:
                                                                                                                                                              +            config:
                                                                                                                                                              +                WPBrowser:
                                                                                                                                                              +                    url: 'http://mu.dev'
                                                                                                                                                              +                WPDb:
                                                                                                                                                              +                    dsn: 'mysql:host=127.0.0.1;dbname=mu'
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              In the codeception.yml file specifying a destination for each supported environment will tell the extension to symbolically link the plugin or theme file to different locations according to the current environment:

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - tad\WPBrowser\Extension\Symlinker
                                                                                                                                                              +    config:
                                                                                                                                                              +        tad\WPBrowser\Extension\Symlinker:
                                                                                                                                                              +            mode: plugin
                                                                                                                                                              +            destination:
                                                                                                                                                              +                single: /var/www/wp/wp-content/plugins
                                                                                                                                                              +                multisite: /var/www/mu/wp-content/plugins
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If no destination is specified for the current environment the extension will fallback to the first specified one.

                                                                                                                                                              +

                                                                                                                                                              A default destination can be specified to override this behaviour.

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - tad\WPBrowser\Extension\Symlinker
                                                                                                                                                              +    config:
                                                                                                                                                              +        tad\WPBrowser\Extension\Symlinker:
                                                                                                                                                              +            mode: plugin
                                                                                                                                                              +            destination:
                                                                                                                                                              +                default: /var/www/default/wp-content/plugins
                                                                                                                                                              +                single: /var/www/wp/wp-content/plugins
                                                                                                                                                              +                multisite: /var/www/mu/wp-content/plugins
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              When running a suite specifying more than one environment like

                                                                                                                                                              +
                                                                                                                                                              codecept run acceptance --env foo,baz,multisite
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Then the extension will use the first matched one, in the case above the multisite destination will be used.

                                                                                                                                                              +

                                                                                                                                                              The rootFolder parameter too can be set to be environment-aware and it will follow the same logic as the destination:

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - tad\WPBrowser\Extension\Symlinker
                                                                                                                                                              +    config:
                                                                                                                                                              +        tad\WPBrowser\Extension\Symlinker:
                                                                                                                                                              +            mode: plugin
                                                                                                                                                              +            rootFolder:
                                                                                                                                                              +                dev: /
                                                                                                                                                              +                dist: /dist
                                                                                                                                                              +                default: /
                                                                                                                                                              +            destination:
                                                                                                                                                              +                default: /var/www/dev/wp-content/plugins
                                                                                                                                                              +                dev: /var/www/dev/wp-content/plugins
                                                                                                                                                              +                dist: /var/www/dist/wp-content/plugins
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              When running a suite specifying more than one environment like

                                                                                                                                                              +
                                                                                                                                                              codecept run acceptance --env dist
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Then the extension will symlink the files from /dist into the /var/www/dist/wp-content/plugins folder.

                                                                                                                                                              +

                                                                                                                                                              Events

                                                                                                                                                              +

                                                                                                                                                              Due to some internal changes in Codeception 4.0, the internal API (really a collection of low-level hacks on my part) that allowed wp-browser to dispatch, and listen for, events in the modules has been removed.

                                                                                                                                                              +

                                                                                                                                                              If you want to leverage [the event system wp-browser provides] with Codeception default events (e.g. suite.init or test.before), then you will need to use this extension.

                                                                                                                                                              +

                                                                                                                                                              You will not need this extension if you're not using Codeception version 4.0.

                                                                                                                                                              +

                                                                                                                                                              You will need to enable it in your Codeception main configuration file (e.g. codeception.dist.yml).

                                                                                                                                                              +
                                                                                                                                                              extensions:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - tad\WPBrowser\Extension\Events
                                                                                                                                                              +    config:
                                                                                                                                                              +      tad\WPBrowser\Extension\Events:
                                                                                                                                                              +        suites: ['acceptance']
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The extension only configuration is the suites parameter that allows specifying the suites the extension should apply to.
                                                                                                                                                              +If the suites parameter is not specified, then the extension will apply to all suites.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/faq/index.html b/v3/faq/index.html new file mode 100644 index 000000000..1f4ade9b2 --- /dev/null +++ b/v3/faq/index.html @@ -0,0 +1,3360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Frequently asked questions - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Frequently asked questions

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Some common questions

                                                                                                                                                              +

                                                                                                                                                              There are questions I keep receiving via email, GitHub or in person at conferences.

                                                                                                                                                              +

                                                                                                                                                              I tried to address some of them here.

                                                                                                                                                              +

                                                                                                                                                              Is Codeception/wp-browser PHP 5.2 compatible?

                                                                                                                                                              +

                                                                                                                                                              No, Codeception, and wp-browser by extension, will require PHP 5.6 minimum.

                                                                                                                                                              +

                                                                                                                                                              This does not mean your code cannot be PHP 5.2 compatible: you can test your code using all the possibilities of newer PHP versions and still keep it PHP 5.2 compatible.

                                                                                                                                                              +

                                                                                                                                                              Just because you can doesn't mean you should though: this documentation will assume a minimum PHP version, for the example and test code, of PHP 5.6.

                                                                                                                                                              +

                                                                                                                                                              Can I run unit tests with wp-browser/Codeception?

                                                                                                                                                              +

                                                                                                                                                              Yes, with some distinctions.

                                                                                                                                                              +

                                                                                                                                                              In the WordPress ecosystem there's a tendency to call any kind of test a "unit test". Under that definition will fall tests that are not "unit" tests at all.

                                                                                                                                                              +

                                                                                                                                                              Without drowning into a long and painful battle for definitions this guide will use the following definitions for different levels of testing.

                                                                                                                                                              +

                                                                                                                                                              The next section will detail the conventions this documentation uses to define different levels of testing in more detail.

                                                                                                                                                              +

                                                                                                                                                              Isn't WordPress untestable?

                                                                                                                                                              +

                                                                                                                                                              No; it's sometimes difficult to test and not as straightforward as other PHP frameworks but it's definitely not untestable.

                                                                                                                                                              +

                                                                                                                                                              You are writing code that runs on WordPress, not the Core code for WordPress so the question should really be: will you write testable code?

                                                                                                                                                              +

                                                                                                                                                              It's up to you to decide at what level you want to make your code testable and how much you want to test it.

                                                                                                                                                              +

                                                                                                                                                              Do I need to use a specific local development environment to use wp-browser?

                                                                                                                                                              +

                                                                                                                                                              No. I've started using wp-browser on a vanilla PHP built-in server to, then, move to MAMP (or XAMP) and, from there, to other solutions.

                                                                                                                                                              +

                                                                                                                                                              I've configured and used wp-browser on Docker, Vagrant, VVV, Valet and various CI solutions.

                                                                                                                                                              +

                                                                                                                                                              To this day I keep using different setups on different machines and personally prefer Docker for its portability.

                                                                                                                                                              +

                                                                                                                                                              Can I only test plugins with wp-browser?

                                                                                                                                                              +

                                                                                                                                                              No, you can test any kind of WordPress application.

                                                                                                                                                              +

                                                                                                                                                              With "application" I mean any PHP software built on top of WordPress: plugins, themes, whole sites.

                                                                                                                                                              +

                                                                                                                                                              If I'm testing a site do I have to use the default WordPress file structure?

                                                                                                                                                              +

                                                                                                                                                              No, you can use any file structure you want.

                                                                                                                                                              +

                                                                                                                                                              Some wp-browser modules will need a little help to find your code but, so far, I've never been unable to set it up.

                                                                                                                                                              +

                                                                                                                                                              Can I use wp-browser even if my WordPress application doesn't use Composer?

                                                                                                                                                              +

                                                                                                                                                              Yes, although wp-browser, as a development tool, cannot be installed without Composer.

                                                                                                                                                              +

                                                                                                                                                              Should I use wp-browser to test my production servers?

                                                                                                                                                              +

                                                                                                                                                              No. Unless you know very well what you're doing that's a dangerous idea that might leave you with a broken site and an empty database.

                                                                                                                                                              +

                                                                                                                                                              As almost any testing tool, wp-browser should be used locally on local installations of WordPress that do not contain any valuable information.

                                                                                                                                                              +

                                                                                                                                                              How can I avoid the WPDb module from replacing the contents of my database?

                                                                                                                                                              +

                                                                                                                                                              You should always backup any database that contains any information you care about before running any test.

                                                                                                                                                              +

                                                                                                                                                              You can read the answer to this question in the WPDb module documentation.

                                                                                                                                                              +

                                                                                                                                                              Can I run all my tests with one command?

                                                                                                                                                              +

                                                                                                                                                              Theoretically: yes, in practice: no.

                                                                                                                                                              +

                                                                                                                                                              When you use codecept run Codeception will run all the tests from all the suites.

                                                                                                                                                              +

                                                                                                                                                              This, done in the context of other frameworks, will generally not create any problem but, in the context of WordPress it will.

                                                                                                                                                              +

                                                                                                                                                              While handling a single HTTP request WordPress will set, and use, a number of constants and globals and, likewise, will do plugins and themes that follow WordPress standards.

                                                                                                                                                              +

                                                                                                                                                              This means that the global context (variable scope) will be left "dirty" and contain "left-over" constants and globals from the previous tests.

                                                                                                                                                              +

                                                                                                                                                              An example is one where a test for the handling of Ajax requests sets the DOING_AJAX constant: this will be now set for any test after the one that set it thus breaking, or worse altering, all the following ones.

                                                                                                                                                              +

                                                                                                                                                              So, in short, run each suite separately.

                                                                                                                                                              +

                                                                                                                                                              Can I have more than one suite of one kind?

                                                                                                                                                              +

                                                                                                                                                              Yes, you should.

                                                                                                                                                              +

                                                                                                                                                              As an example you might have a frontend suite running acceptance tests on the site frontend and a backend suite running acceptance tests on the site backend.

                                                                                                                                                              +

                                                                                                                                                              Think of suites as a tool to organize your tests: there's a good measure between too organized and not organized at all.

                                                                                                                                                              +

                                                                                                                                                              I've used PHPUnit before for my unit tests, can I reuse that knowledge and code with wp-browser?

                                                                                                                                                              +

                                                                                                                                                              Yes.

                                                                                                                                                              +

                                                                                                                                                              Codeception uses PHPUnit as one of its main components and can run PHPUnit tests with little or no modification.

                                                                                                                                                              +

                                                                                                                                                              As such you can just move your existing PHPUnit tests in a dedicated suite and be ready to run in minutes.

                                                                                                                                                              +

                                                                                                                                                              I've already set up my tests to run using the Core PHPUnit-based test suite, can I keep using my tests?

                                                                                                                                                              +

                                                                                                                                                              Yes.

                                                                                                                                                              +

                                                                                                                                                              Codeception uses PHPUnit as one of its main components and can run PHPUnit tests with little or no modification.

                                                                                                                                                              +

                                                                                                                                                              One of the goals of wp-browser was to make it easier to test WordPress application at an integration level (or "WordPress unit" level).

                                                                                                                                                              +

                                                                                                                                                              As such migrating those tests could be a matter of minutes requiring no modification to the tests if not for moving some files and creating a dedicated suite.

                                                                                                                                                              +

                                                                                                                                                              Why is the project called wp-browser?

                                                                                                                                                              +

                                                                                                                                                              When I started working with Codeception to run my acceptance tests I kept creating steps that I would reuse over and over in my projects.

                                                                                                                                                              +

                                                                                                                                                              I packed them in a module extending the PHPBrowser module.

                                                                                                                                                              +

                                                                                                                                                              Being a natural talent in naming things I've called the module WPBrowser and published it. As I started relying on Codeception more and more I kept adding modules but the name remained.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/images/codecept-init-wpbrowser-01.png b/v3/images/codecept-init-wpbrowser-01.png new file mode 100644 index 000000000..688a58098 Binary files /dev/null and b/v3/images/codecept-init-wpbrowser-01.png differ diff --git a/v3/images/codecept-init-wpbrowser-02.png b/v3/images/codecept-init-wpbrowser-02.png new file mode 100644 index 000000000..c2b9dcb5d Binary files /dev/null and b/v3/images/codecept-init-wpbrowser-02.png differ diff --git a/v3/images/codecept-run.png b/v3/images/codecept-run.png new file mode 100644 index 000000000..000ff012b Binary files /dev/null and b/v3/images/codecept-run.png differ diff --git a/v3/images/initial-setup.png b/v3/images/initial-setup.png new file mode 100644 index 000000000..c0e32e416 Binary files /dev/null and b/v3/images/initial-setup.png differ diff --git a/v3/index.html b/v3/index.html new file mode 100644 index 000000000..e029dcac4 --- /dev/null +++ b/v3/index.html @@ -0,0 +1,2916 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Welcome - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Welcome

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The wp-browser project provides a Codeception based solution to test WordPress plugins, themes and whole sites at all levels of testing.

                                                                                                                                                              +

                                                                                                                                                              The purpose of this documentation is to help you set up, run and iterate over your project and test code using the powerful APIs provided by Codeception while trying to alleviate the pains of setting it up for WordPress projects.

                                                                                                                                                              +

                                                                                                                                                              Throughout the documentation you will find references to test terminology: I've tried to condense those into small, digestable chunks to provide a rough idea without and a limited context; where required I tried to provide links to dive deeper into the subjects.

                                                                                                                                                              +

                                                                                                                                                              Happy testing!

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/installation/index.html b/v3/installation/index.html new file mode 100644 index 000000000..475bddfe2 --- /dev/null +++ b/v3/installation/index.html @@ -0,0 +1,3086 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Installation - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Installation

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Installation

                                                                                                                                                              +

                                                                                                                                                              Where should I install wp-browser?

                                                                                                                                                              +

                                                                                                                                                              As a rule-of-thumb wp-browser should be installed in the root folder of your +project.

                                                                                                                                                              +

                                                                                                                                                              If your project is a plugin then it should be installed in the root folder of your plugin; if your project is a theme it should be installed in the root folder of your theme.

                                                                                                                                                              +

                                                                                                                                                              If your project is a site I'd, personally install it in the site root folder.

                                                                                                                                                              +

                                                                                                                                                              The purpose of installing wp-browser in the root folder of a project is to keep the code and its tests under version control together.

                                                                                                                                                              +

                                                                                                                                                              Exceptions apply but, for most projects, that's what I would do.

                                                                                                                                                              +

                                                                                                                                                              Initializing the Composer project

                                                                                                                                                              +

                                                                                                                                                              Since Composer is a requirement of wp-browser and the only way to install it you should, first thing, initialize the Composer project.

                                                                                                                                                              +

                                                                                                                                                              If you've already initialized the Composer project you can skip this section.

                                                                                                                                                              +

                                                                                                                                                              Once you've decided where to install wp-browser navigate to that folder using the terminal and type:

                                                                                                                                                              +
                                                                                                                                                              composer init
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Composer will take you through a number of questions to setup some meta information about your project.

                                                                                                                                                              +

                                                                                                                                                              Do not install any dependency yet when asked (unless you know what you're doing) and, as a suggestion, set wordpress-plugin as "Package Type".

                                                                                                                                                              +

                                                                                                                                                              Also, since WordPress is licensed under the GPL-2.0+ you might want to set the "License" of your project to GPL-2.0-or-later.

                                                                                                                                                              +

                                                                                                                                                              Installing wp-browser as a development dependency

                                                                                                                                                              +

                                                                                                                                                              Once you've initialized the Composer project it's time to require wp-browser ; you can read more about the usage of the require command on the Composer documentation.

                                                                                                                                                              +

                                                                                                                                                              wp-browser is a testing tool and, as such, should be installed as a project development dependency, not as a normal (production) one.

                                                                                                                                                              +

                                                                                                                                                              From the terminal type:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev lucatume/wp-browser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This will install the latest stable version of wp-browser and, along with it, Codeception and PHPUnit in the vendor folder of your project.

                                                                                                                                                              +

                                                                                                                                                              Once that's done it's time to move to the setup and configuration of wp-browser.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/levels-of-testing/index.html b/v3/levels-of-testing/index.html new file mode 100644 index 000000000..bd2a55ee7 --- /dev/null +++ b/v3/levels-of-testing/index.html @@ -0,0 +1,3356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Levels of testing - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Levels of testing

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              What is a unit test? An acceptance test?

                                                                                                                                                              +

                                                                                                                                                              This page has no pretense to be THE source of truth about what is called how in the context of tests; the purpose of this page is to lay out the terminology that I'll use in the documentation to define the levels and component of testing. Wikipedia, forums and other documents online will offer alternate, and equally valid, definitions.

                                                                                                                                                              +

                                                                                                                                                              The signup page example

                                                                                                                                                              +

                                                                                                                                                              Let's assume I'm testing a WordPress plugin that adds mailing list management and subscription functionalities to a site.

                                                                                                                                                              +

                                                                                                                                                              The plugin provides a number of functions and, among them, it will add a sign-up page to receive users applications.

                                                                                                                                                              +

                                                                                                                                                              Acceptance tests

                                                                                                                                                              +

                                                                                                                                                              In brief: make assertions as a user would.

                                                                                                                                                              +

                                                                                                                                                              The user might be tech-savvy as much as I want her to be but still make assertions only on what feedback the site provides.

                                                                                                                                                              +

                                                                                                                                                              The code below tests a user can subscribe to the mailing list:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// UserSuccessfulSignupTest.php
                                                                                                                                                              +
                                                                                                                                                              +// Add a page that contains the shortcode that will render the signup form.
                                                                                                                                                              +$I->havePageInDatabase( [
                                                                                                                                                              +    'post_name' => 'signup',
                                                                                                                                                              +    'post_content'=> 'Sign-up for our awesome thing! [signup]',
                                                                                                                                                              +] );
                                                                                                                                                              +
                                                                                                                                                              +// Go to the page.
                                                                                                                                                              +$I->amOnPage( '/signup' );
                                                                                                                                                              +
                                                                                                                                                              +// Submit the form as a user would submit it. 
                                                                                                                                                              +$I->submitForm( '#signup-form', [
                                                                                                                                                              +  'name' => 'Luca',
                                                                                                                                                              +  'email' => 'luca@theAverageDev.com',
                                                                                                                                                              +] );
                                                                                                                                                              +
                                                                                                                                                              +// Make sure I see a confirmation message. 
                                                                                                                                                              +$I->waitForElement( '#signup-confirmation' );
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Functional tests

                                                                                                                                                              +

                                                                                                                                                              In brief: make assertions as a developer would.

                                                                                                                                                              +

                                                                                                                                                              The test code below asserts front-end submissions are correctly processed from the developer perspective:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// file tests/functional/SignupSubmissionCest.php
                                                                                                                                                              +
                                                                                                                                                              +class SignupSubmissionCest {
                                                                                                                                                              +
                                                                                                                                                              +    public function _before( FunctionalTester $I ) {
                                                                                                                                                              +        // Add a page that contains the shortcode that will render the signup form.
                                                                                                                                                              +        $I->havePageInDatabase( [
                                                                                                                                                              +            'post_name' => 'signup',
                                                                                                                                                              +            'post_content'=> 'Sign-up for our awesome thing! [signup]',
                                                                                                                                                              +        ] );
                                                                                                                                                              +
                                                                                                                                                              +        $I->amOnPage( '/signup' );
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_good_signup( FunctionalTester $I ) {
                                                                                                                                                              +        $I->sendAjaxPostRequest( '/wp-json/acme/v1/signup', [
                                                                                                                                                              +          '_wpnonce' => $I->grabAttributeFrom( '#signup-nonce', 'value' ),
                                                                                                                                                              +          'name' => 'Luca',
                                                                                                                                                              +          'email' => 'luca@theAverageDev.com',
                                                                                                                                                              +        ] );
                                                                                                                                                              +
                                                                                                                                                              +        $I->seeResponseCodeIsSuccessful();
                                                                                                                                                              +        $I->seeUserInDatabase( [ 'user_login' => 'luca', 'user_email' => 'luca@theaveragedev.com' ] );
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_bad_email_signup( FunctionalTester $I ) {
                                                                                                                                                              +        $I->sendAjaxPostRequest( '/wp-json/acme/v1/signup', [
                                                                                                                                                              +          '_wpnonce' => $I->grabAttributeFrom( '#signup-nonce', 'value' ),
                                                                                                                                                              +          'name' => 'Luca',
                                                                                                                                                              +          'email' => 'not-really-an-email',
                                                                                                                                                              +        ] );
                                                                                                                                                              +
                                                                                                                                                              +        $I->seeResponseCodeIs( 400 );
                                                                                                                                                              +        $I->dontSeeUserInDatabase( [ 'user_login' => 'luca', 'user_email' => 'not-really-an-email' ] );
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The code looks, initially, like an acceptance test, but differs in its action and assertion phase: in place of filling a form and clicking "Submit" it sends a POST request to a REST API endpoint and checks the effect of the submission in the database.

                                                                                                                                                              +

                                                                                                                                                              All of these actions fall squarely into what a developer would do, not into what a user could/should be able to do.

                                                                                                                                                              +

                                                                                                                                                              Furthermore, the format of the test is not the same as the one used in the acceptance test.

                                                                                                                                                              +

                                                                                                                                                              The acceptance test is written in the most eloquent testing format supported by Codeception, the Cept format, this test uses a more PHPUnit-like format, the Cest format.

                                                                                                                                                              +

                                                                                                                                                              While the first is easier to skim for non-developers the second harnesses the power of a re-using pieces of code, the page creation and navigation in the example, to optimize the test code.

                                                                                                                                                              +

                                                                                                                                                              Integration tests

                                                                                                                                                              +

                                                                                                                                                              In brief: test code modules in the context of a WordPress website.

                                                                                                                                                              +

                                                                                                                                                              In this type of test the WordPress, and additional plugins code, is loaded in the same variable scope as the tests; this is why in the example below I'm using classes (WP_REST_Request, WP_REST_Response) and methods (register_rest_route) defined by WordPress, not the plugin code.

                                                                                                                                                              +

                                                                                                                                                              The REST API request sent by the application form will be handled by a class, Acme\Signup\SubmissionHandler, that's been attached to the /wp-json/acme/v1/signup path:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// file src/rest.php
                                                                                                                                                              +
                                                                                                                                                              +add_action( 'rest_api_init', function () {
                                                                                                                                                              +    register_rest_route( 'acme/v1', '/signup', array(
                                                                                                                                                              +        'methods' => 'POST',
                                                                                                                                                              +        'callback' => function( WP_Rest_Request $request ) {
                                                                                                                                                              +            $email_validator = new Acme\Signup\EmailValidator();
                                                                                                                                                              +            $handler = new Acme\Signup\SubmissionHandler( $email_validator );
                                                                                                                                                              +
                                                                                                                                                              +            return $handler->handle( $request );
                                                                                                                                                              +        },
                                                                                                                                                              +    ) );
                                                                                                                                                              +} );
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              I want to test the chain of classes and methods that's handling such a request in the context of a WordPress installation.

                                                                                                                                                              +

                                                                                                                                                              Integration is usually about testing "modules" of code: groups of classes and functions working together to provide a service or complete a task.

                                                                                                                                                              +

                                                                                                                                                              In the context of integration testing the class dependencies and/or the context are not mocked.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// file tests/integration/SubmissionHandlingTest.php
                                                                                                                                                              +
                                                                                                                                                              +class SubmissionHandlingTest extends \Codeception\TestCase\WPTestCase {
                                                                                                                                                              +    public function test_good_request() {
                                                                                                                                                              +        $request = new WP_Rest_Request();
                                                                                                                                                              +        $request->set_body_params( [ 'name' => 'luca', 'email' => 'luca@theaveragedev.com' ] );
                                                                                                                                                              +        $handler = new  Acme\Signup\SubmissionHandler();
                                                                                                                                                              +
                                                                                                                                                              +        $response = $handler->handle( $request );
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertIntsanceOf( WP_REST_Response::class, $response );
                                                                                                                                                              +        $this->assertEquals( 200, $response->get_status() );
                                                                                                                                                              +        $this->assertInstanceOf( Acme\Signup\Submission_Good::class, $handler->last_submission() );
                                                                                                                                                              +        $this->assertEquals( 'luca', $handler->last_submission()->name() );
                                                                                                                                                              +        $this->assertEquals( 'luca@theaveragedev.com', $handler->last_submission()->email() );
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_bad_email_request() {
                                                                                                                                                              +        $request = new WP_Rest_Request();
                                                                                                                                                              +        $request->set_body_params( [ 'name' => 'luca', 'email' => 'not-a-valid-email' ] );
                                                                                                                                                              +        $handler = new  Acme\Signup\SubmissionHandler();
                                                                                                                                                              +
                                                                                                                                                              +        $response = $handler->handle( $request );
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertIntsanceOf( WP_REST_Response::class, $response );
                                                                                                                                                              +        $this->assertEquals( 400, $response->get_status() );
                                                                                                                                                              +        $this->assertInstanceOf( Acme\Signup\Submission_Bad::class, $handler->last_submission() );
                                                                                                                                                              +        $this->assertEquals( 'luca', $handler->last_submission()->name() );
                                                                                                                                                              +        $this->assertEquals( 'not-a-valid-email', $handler->last_submission()->email() );
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The test format used is the familiar PhpUnit one; the only difference is the base test class that's being extended (\Codeception\TestCase\WPTestCase) is one provided by wp-browser.

                                                                                                                                                              +

                                                                                                                                                              In the context of WordPress "integration" might also mean testing that filters used by the code have the expected effect.

                                                                                                                                                              +

                                                                                                                                                              Unit tests

                                                                                                                                                              +

                                                                                                                                                              In brief: test single classes or functions in isolation.

                                                                                                                                                              +

                                                                                                                                                              The email address is validated by the Acme\Signup\EmailValidator class.

                                                                                                                                                              +

                                                                                                                                                              In the test code below I want to make sure the validation works as intended.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// file tests/unit/EmailValidatorTest.php
                                                                                                                                                              +
                                                                                                                                                              +class EmailValidatorTest extends Codeception\Test\Test {
                                                                                                                                                              +    public function test_good_email_validation() {
                                                                                                                                                              +        $validator = new Acme\Signup\EmailValidator();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertTrue( $validator->validate( 'luca@theaveragedev.com' ) ); 
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_bad_email_validation(){
                                                                                                                                                              +        $validator = new Acme\Signup\EmailValidator();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertTrue( $validator->validate( 'not-an-email' ) );
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_tricky_email_validation() {
                                                                                                                                                              +        $validator = new Acme\Signup\EmailValidator();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertTrue( $validator->validate( 'luca+signup@theaveragedev.com' ) ); 
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_validation_with_service(){
                                                                                                                                                              +        // Stub the validation service.
                                                                                                                                                              +        $validation_service = $this->prophesize( Acme\Signup\ValidationService::class );
                                                                                                                                                              +        $validation_service->validate( 'luca@theaveragedev.com' )->willReturn( true );
                                                                                                                                                              +        $validation_service->validate( 'lucas@theaveragedev.com' )->willReturn( false );
                                                                                                                                                              +        // Build the validator and set it to use the mock validation service.
                                                                                                                                                              +        $validator = new Acme\Signup\EmailValidator();
                                                                                                                                                              +        $validator->use_service( $validation_service->reveal() );
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertTrue( $validator->validate( 'luca@theaveragedev.com' ) );
                                                                                                                                                              +        $this->assertFalse( $validator->validate( 'lucas@theaveragedev.com' ) );
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Unit tests is where stubbing/mocking/spying of dependencies is used to gain total control over the input and context the class is using.

                                                                                                                                                              +

                                                                                                                                                              In the last test method I'm doing exactly that testing the email validator with an external validation service.

                                                                                                                                                              +

                                                                                                                                                              In the example I'm using the Prophecy mock engine that comes with PHPUnit along with its own mocking/stubbing/spying solutions.

                                                                                                                                                              +

                                                                                                                                                              There are other mocking engines (e.g Mockery) that could be used.

                                                                                                                                                              +

                                                                                                                                                              WordPress "unit" tests

                                                                                                                                                              +

                                                                                                                                                              In brief: test single classes or functions that require WordPress code in as much isolation as possible.

                                                                                                                                                              +

                                                                                                                                                              This is what most people referring to "unit tests" in the context of WordPress is talking about.

                                                                                                                                                              +

                                                                                                                                                              The purpose of this kind of tests is to test one class of a WordPress application, or one function, that requires a WordPress-defined function or class with a unit testing approach.

                                                                                                                                                              +

                                                                                                                                                              In the example below I'm testing the Acme\Signup\SubmissionHandler class on a "unit" level making sure it will mark a request as bad if the email is not a valid one.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// file tests/unit/SubmissionHandlerTest.php
                                                                                                                                                              +class SubmissionHandlerTest extends Codeception\Test\Test {
                                                                                                                                                              +    protected  $request;
                                                                                                                                                              +    protected $validator;
                                                                                                                                                              +
                                                                                                                                                              +    public function setUp() {
                                                                                                                                                              +        // Mock the request.
                                                                                                                                                              +        $this->request = $this->prophesize( WP_REST_Request::class );
                                                                                                                                                              +        // Spy on the validator.
                                                                                                                                                              +        $this->validator = $this->prophesize( Acme\Signup\EmailValidator::class );
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_email_is_validated_by_default() {
                                                                                                                                                              +        $this->request->get_param( 'name' )->willReturn( 'luca' );
                                                                                                                                                              +        $this->request->get_param( 'email' )->willReturn( 'luca@theaveragedev.com' );
                                                                                                                                                              +
                                                                                                                                                              +        $handler = new Acme\Signup\SubmissionHandler( $this->validator->reveal() );
                                                                                                                                                              +        $handler->set_validator( $this->validator );
                                                                                                                                                              +        $response = $handler->handle( $this->request->reveal() );
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertInstanceOf( WP_REST_Response::class, $response );
                                                                                                                                                              +        // Verify on the validator spy.
                                                                                                                                                              +        $this->validator->validate( 'luca@theaveragedev.com' )->shouldHaveBeenCalled();
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_will_not_validate_email_if_missing() {
                                                                                                                                                              +        $this->request->get_param( 'name' )->willReturn( 'luca' );
                                                                                                                                                              +        $this->request->get_param( 'email' )->willReturn( '' );
                                                                                                                                                              +
                                                                                                                                                              +        $handler = new Acme\Signup\SubmissionHandler( $this->validator->reveal() );
                                                                                                                                                              +        $handler->set_validator( $this->validator );
                                                                                                                                                              +        $response = $handler->handle( $this->request->reveal() );
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertInstanceOf( WP_REST_Response::class, $response );
                                                                                                                                                              +        // Verify on the validator spy.
                                                                                                                                                              +        $this->validator->validate( Argument::any() )->shouldNotHaveBeenCalled();
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The class uses the WP_REST_Request and WP_Rest_Response classes as input and output and will probably, internally, use more functions defined by WordPress.

                                                                                                                                                              +

                                                                                                                                                              One solution to avoid loading WordPress, could be to rewrite test versions of each and all the WordPress functions and classes needed by all the classes I want to unit test; this would require updating each time the classes requirements change.

                                                                                                                                                              +

                                                                                                                                                              Furthermore internationalization (e.g. __()) and filtering (e.g apply_filters) functions would not need to be mocked if not in specific cases and would pretty much be copy and paste versions of the WordPres ones.

                                                                                                                                                              +

                                                                                                                                                              Loading single pieces of WordPress is a dangerous and brittle endeavour and it's not supported by the +framework.

                                                                                                                                                              +

                                                                                                                                                              To avoid all this WordPress "unit tests" pay the price of having to bootstrap WordPress, thus requiring a database connection.

                                                                                                                                                              +

                                                                                                                                                              This kind of test setup and level is the one you can see in the PHPUnit Core suite of WordPress itself.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/migration/from-version-2-to-version-3/index.html b/v3/migration/from-version-2-to-version-3/index.html new file mode 100644 index 000000000..8dcc32a8f --- /dev/null +++ b/v3/migration/from-version-2-to-version-3/index.html @@ -0,0 +1,3001 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Version 2 to version 3 - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Version 2 to version 3

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Migrating projects from version 2 of wp-browser to version 3

                                                                                                                                                              +

                                                                                                                                                              Version 3 of wp-browser removed, to allow for broader compatibility with PHP and Composer versions, some of its +dependencies and modified some of its methods.
                                                                                                                                                              +Here is a list of changes and the suggested courses of action:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Removed symfony/process to launch and manage external processes; re-add it your project development +requirements using composer require --dev symfony/process.
                                                                                                                                                              • +
                                                                                                                                                              • Removed the wp-cli/wp-cli-bundle dependency; if you were relying on non-core + packages, then re-add it to your project development requirements using composer require --dev wp-cli/wp-cli-bundle.
                                                                                                                                                              • +
                                                                                                                                                              • Removed the WithWpCli::executeBackgroundWpCliCommand trait method, and, as a consequence, the +WPCLI::executeBackgroundWpCliCommand module method; you could have used the latter, if this was the case, then +require the symfony/process as explained above and launch processes in background using its API; find out more.
                                                                                                                                                              • +
                                                                                                                                                              • Refactored the WPCLI module to build and escape string command lines differently; the handling of command-line arguments +for the WPCLI module has been modified to make it a bit more consistent and robust; as a consequence, you might experience +some breakages in string commands that used to work correctly before; should this be the case then either modify +your code to provide the command in array format (taking care of the correct escaping in your code), or make sure to +pass a correctly structured command string to the WPCLI module.
                                                                                                                                                              • +
                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPBrowser/index.html b/v3/modules/WPBrowser/index.html new file mode 100644 index 000000000..e086e53f3 --- /dev/null +++ b/v3/modules/WPBrowser/index.html @@ -0,0 +1,3588 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPBrowser - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WPBrowser module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in acceptance and functional tests, see levels of testing for more information.

                                                                                                                                                              +

                                                                                                                                                              This module extends the PHPBrowser module adding WordPress-specific configuration parameters and methods.

                                                                                                                                                              +

                                                                                                                                                              The module simulates a user interaction with the site without Javascript support; if you need to test your project with Javascript support use the WPWebDriver module.

                                                                                                                                                              +

                                                                                                                                                              Module requirements for Codeception 4.0+

                                                                                                                                                              +

                                                                                                                                                              This module requires the codeception/module-phpbrowser Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                              +

                                                                                                                                                              To install the package run:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev codeception/module-phpbrowser:^1.0
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +

                                                                                                                                                              Since this module extends the PHPBrowser module provided by Codeception, please refer to the PHPBrowser configuration section for more information about the base configuration parameters.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • url required - Start URL of your WordPress project, e.g. http://wp.test.
                                                                                                                                                              • +
                                                                                                                                                              • headers - Default headers are set before each test; this might be useful to simulate a specific user agent during the tests or to identify the request source. Note that the headers defined in the config should be prefaced with HTTP_ in your wp-config.php file. This can be used to select which database to use.
                                                                                                                                                              • +
                                                                                                                                                              • handler (default: curl) - The Guzzle handler to use. By default curl is used, also possible to pass stream, or any valid class name as Handler.
                                                                                                                                                              • +
                                                                                                                                                              • middleware - The Guzzle middlewares to add. An array of valid callables is required; see here for more information.
                                                                                                                                                              • +
                                                                                                                                                              • curl - curl options; only applied if using the curl handler; more options are available.
                                                                                                                                                              • +
                                                                                                                                                              • adminUsername required - This is the login name, not the "nice" name, of the administrator user of the WordPress test site. This will be used to fill the username field in WordPress login page.
                                                                                                                                                              • +
                                                                                                                                                              • adminPassword required - This is the the password of the administrator use of the WordPress test site. This will be used to fill the password in WordPress login page.
                                                                                                                                                              • +
                                                                                                                                                              • adminPath required - The path, relative to the WordPress test site home URL, to the administration area, usually /wp-admin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                                modules:
                                                                                                                                                              +      enabled:
                                                                                                                                                              +          - WPBrowser
                                                                                                                                                              +      config:
                                                                                                                                                              +          WPBrowser:
                                                                                                                                                              +              url: 'http://wordpress.localhost'
                                                                                                                                                              +              adminUsername: 'admin'
                                                                                                                                                              +              adminPassword: 'password'
                                                                                                                                                              +              adminPath: '/wp-admin'
                                                                                                                                                              +              headers:
                                                                                                                                                              +                X_TEST_REQUEST: 1
                                                                                                                                                              +                X_WPBROWSER_REQUEST: 1
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Read here how to use the headers information to automatically change the database during acceptance and functional tests.

                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • activatePlugin($pluginSlug) : void
                                                                                                                                                                + In the plugin administration screen activates a plugin clicking the "Activate" link.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication to the admin area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • activateTheme($slug) : void
                                                                                                                                                                + Activates a theme.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amEditingPostWithId($id) : void
                                                                                                                                                                + Go to the admin page to edit the post with the specified ID.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication the admin area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amEditingUserWithId($id) : void
                                                                                                                                                                + Go to the admin page to edit the user with the specified ID.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication the admin area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                amHttpAuthenticated($username, $password) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnAdminAjaxPage([$queryVars]) : void
                                                                                                                                                                + Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication, nonces or authorization.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amOnAdminPage($page) : void
                                                                                                                                                                + Go to a page in the admininstration area of the site.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              This method will not handle authentication to the administration area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                amOnCronPage([$queryVars]) : void
                                                                                                                                                                + Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnPage($page) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnPagesPage() : void
                                                                                                                                                                + Go the "Pages" administration screen.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amOnPluginsPage() : void
                                                                                                                                                                + Go to the plugins administration screen.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                amOnSubdomain($subdomain) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnThemesPage() : void
                                                                                                                                                                + Moves to the themes administration page.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnUrl($url) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                attachFile($field, $filename) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                checkOption($option) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                click($link, [$context]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                deactivatePlugin($pluginSlug) : void
                                                                                                                                                                + In the plugin administration screen deactivate a plugin clicking the "Deactivate" link.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugins administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • deleteHeader($name) : void
                                                                                                                                                                + Deletes the header with the passed name. Subsequent requests + will not have the deleted header in its request.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example: +

                                                                                                                                                              <?php
                                                                                                                                                              +$I->haveHttpHeader('X-Requested-With', 'Codeception');
                                                                                                                                                              +$I->amOnPage('test-headers.php');
                                                                                                                                                              +// ...
                                                                                                                                                              +$I->deleteHeader('X-Requested-With');
                                                                                                                                                              +$I->amOnPage('some-other-page.php');
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                dontSee($text, [$selector]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCheckboxIsChecked($checkbox) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCurrentUrlEquals($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCurrentUrlMatches($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeElement($selector, [$attributes]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInCurrentUrl($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInField($field, $value) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInFormFields($formSelector, array $params) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInSource($raw) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInTitle($title) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeLink($text, [$url]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeOptionIsSelected($selector, $optionText) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeePluginInstalled($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is not installed in the plugins administration screen.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • dontSeeResponseCodeIs($code) : void
                                                                                                                                                                + Checks that response code is equal to value provided.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->dontSeeResponseCodeIs(200);
                                                                                                                                                              +
                                                                                                                                                              +// recommended \Codeception\Util\HttpCode
                                                                                                                                                              +$I->dontSeeResponseCodeIs(\Codeception\Util\HttpCode::OK);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • executeInGuzzle(Closure $function) : void
                                                                                                                                                                + Low-level API method. + If Codeception commands are not enough, use Guzzle HTTP Client methods directly
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->executeInGuzzle(function (\GuzzleHttp\Client $client) {
                                                                                                                                                              +     $client->get('/get', ['query' => ['foo' => 'bar']]);
                                                                                                                                                              +});
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              It is not recommended to use this command on a regular basis. + If Codeception lacks important Guzzle Client methods, implement them and submit patches.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                fillField($field, $value) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                followRedirect() : void
                                                                                                                                                                + Follow pending redirect if there is one.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->followRedirect();
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • grabActiveTheme() : void
                                                                                                                                                                + Returns the slug of the currently active themes.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                grabAttributeFrom($cssOrXpath, $attribute) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabAvailableThemes([$classes]) : void
                                                                                                                                                                + Returns the list of available themes.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                grabCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabCookiesWithPattern($cookiePattern) : void
                                                                                                                                                                + Returns all the cookies whose name matches a regex pattern.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabFromCurrentUrl([$uri]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabMultiple($cssOrXpath, [$attribute]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabPageSource() : void
                                                                                                                                                                + Grabs current page source code.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabTextFrom($cssOrXPathOrRegex) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabValueFrom($field) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabWordPressTestCookie([$name]) : void
                                                                                                                                                                + Returns WordPress default test cookie object if present.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                haveHttpHeader($name, $value) : void
                                                                                                                                                                + Sets the HTTP header to the passed value - which is used on + subsequent HTTP requests through PhpBrowser.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example: +

                                                                                                                                                              <?php
                                                                                                                                                              +$I->haveHttpHeader('X-Requested-With', 'Codeception');
                                                                                                                                                              +$I->amOnPage('test-headers.php');
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              To use special chars in Header Key use HTML Character Entities: + Example: + Header with underscore - 'Client_Id' + should be represented as - 'Client_Id' or 'Client_Id'

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->haveHttpHeader('Client&#95;Id', 'Codeception');
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • haveServerParameter($name, $value) : void
                                                                                                                                                                + Sets SERVER parameter valid for all next requests.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              $I->haveServerParameter('name', 'value');
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                logOut([$redirectTo]) : void
                                                                                                                                                                + Navigate to the default WordPress logout page and click the logout link.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                loginAs($username, $password) : void
                                                                                                                                                                + Login as the specified user.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not follow redirection, after the login, to any page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • loginAsAdmin() : void
                                                                                                                                                                + Login as the administrator user using the credentials specified in the module configuration.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not follow redirection, after the login, to any page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                makeHtmlSnapshot([$name]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                moveBack([$numberOfSteps]) : void
                                                                                                                                                                + Moves back in history.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                resetCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                see($text, [$selector]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCheckboxIsChecked($checkbox) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCurrentUrlEquals($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCurrentUrlMatches($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeElement($selector, [$attributes]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeErrorMessage([$classes]) : void
                                                                                                                                                                + In an administration screen look for an error admin notice.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The check is class-based to decouple from internationalization. + The method will not handle authentication and navigation the administration area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeInCurrentUrl($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInField($field, $value) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInFormFields($formSelector, array $params) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInSource($raw) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInTitle($title) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeLink($text, [$url]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeMessage([$classes]) : void
                                                                                                                                                                + In an administration screen look for an admin notice.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The check is class-based to decouple from internationalization. + The method will not handle authentication and navigation the administration area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeNumberOfElements($selector, $expected) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeOptionIsSelected($selector, $optionText) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seePageNotFound() : void
                                                                                                                                                                + Asserts that current page has 404 response status code.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seePluginActivated($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is activated in the plugin administration screen.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seePluginDeactivated($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is not activated in the plugins administration screen.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seePluginInstalled($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is installed, no matter its activation status, in the plugin administration screen.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seeResponseCodeIs($code) : void
                                                                                                                                                                + Checks that response code is equal to value provided.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->seeResponseCodeIs(200);
                                                                                                                                                              +
                                                                                                                                                              +// recommended \Codeception\Util\HttpCode
                                                                                                                                                              +$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeResponseCodeIsBetween($from, $to) : void
                                                                                                                                                                + Checks that response code is between a certain range. Between actually means [from <= CODE <= to]

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeResponseCodeIsClientError() : void
                                                                                                                                                                + Checks that the response code is 4xx

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeResponseCodeIsRedirection() : void
                                                                                                                                                                + Checks that the response code 3xx

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeResponseCodeIsServerError() : void
                                                                                                                                                                + Checks that the response code is 5xx

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeResponseCodeIsSuccessful() : void
                                                                                                                                                                + Checks that the response code 2xx

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeThemeActivated($slug) : void
                                                                                                                                                                + Verifies that a theme is active.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seeWpDiePage() : void
                                                                                                                                                                + Checks that the current page is one generated by the wp_die function.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will try to identify the page based on the default WordPress die page HTML attributes.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                selectOption($select, $option) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                sendAjaxGetRequest($uri, [$params]) : void
                                                                                                                                                                + Sends an ajax GET request with the passed parameters. + See sendAjaxPostRequest()

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                sendAjaxPostRequest($uri, [$params]) : void
                                                                                                                                                                + Sends an ajax POST request with the passed parameters. + The appropriate HTTP header is added automatically: + X-Requested-With: XMLHttpRequest + Example: +

                                                                                                                                                                <?php
                                                                                                                                                                +$I->sendAjaxPostRequest('/add-task', ['task' => 'lorem ipsum']);
                                                                                                                                                                +
                                                                                                                                                                + Some frameworks (e.g. Symfony) create field names in the form of an "array": + <input type="text" name="form[task]"> + In this case you need to pass the fields like this: +
                                                                                                                                                                <?php
                                                                                                                                                                +$I->sendAjaxPostRequest('/add-task', ['form' => [
                                                                                                                                                                +    'task' => 'lorem ipsum',
                                                                                                                                                                +    'category' => 'miscellaneous',
                                                                                                                                                                +]]);
                                                                                                                                                                +

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                sendAjaxRequest($method, $uri, [$params]) : void
                                                                                                                                                                + Sends an ajax request, using the passed HTTP method. + See sendAjaxPostRequest() + Example: +

                                                                                                                                                                <?php
                                                                                                                                                                +$I->sendAjaxRequest('PUT', '/posts/7', ['title' => 'new title']);
                                                                                                                                                                +

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                setCookie($name, $val, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                setHeader($name, $value) : void
                                                                                                                                                                + Alias to haveHttpHeader

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                setMaxRedirects($maxRedirects) : void
                                                                                                                                                                + Sets the maximum number of redirects that the Client can follow.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->setMaxRedirects(2);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • setServerParameters(array $params) : void
                                                                                                                                                                + Sets SERVER parameters valid for all next requests. + this will remove old ones.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              $I->setServerParameters([]);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • startFollowingRedirects() : void
                                                                                                                                                                + Enables automatic redirects to be followed by the client.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->startFollowingRedirects();
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • stopFollowingRedirects() : void
                                                                                                                                                                + Prevents automatic redirects to be followed by the client.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->stopFollowingRedirects();
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                submitForm($selector, array $params, [$button]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                switchToIframe($name) : void
                                                                                                                                                                + Switch to iframe or frame on the page.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example: +

                                                                                                                                                              <iframe name="another_frame" src="http://example.com">
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +# switch to iframe
                                                                                                                                                              +$I->switchToIframe("another_frame");
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • uncheckOption($option) : void
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              This class extends \Codeception\Module\PhpBrowser

                                                                                                                                                              +

                                                                                                                                                              This class implements \Codeception\Lib\Interfaces\MultiSession, \Codeception\Lib\Interfaces\Remote, \Codeception\Lib\Interfaces\Web, \Codeception\Lib\Interfaces\PageSourceSaver, \Codeception\Lib\Interfaces\ElementLocator, \Codeception\Lib\Interfaces\ConflictsWithModule

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPCLI/index.html b/v3/modules/WPCLI/index.html new file mode 100644 index 000000000..403a473c0 --- /dev/null +++ b/v3/modules/WPCLI/index.html @@ -0,0 +1,3388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPCLI - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WPCLI module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in acceptance and functional tests to setup, or verify, tests pre and post conditions using WP-CLI commands.
                                                                                                                                                              +This module allows invoking WP-CLI commands, refer to the official site for more information.

                                                                                                                                                              +

                                                                                                                                                              The module will use its own version of WP-CLI, not the one installed in the machine running the tests!

                                                                                                                                                              +

                                                                                                                                                              By default, wp-browser will only include the wp-cli/wp-cli package; this package contains the basic files to run WP-CLI and does not contain all the commands that come with a typical wp-cli installation.
                                                                                                                                                              +If, in your tests, you require all the commands that usually come installed with WP-CLI, then you should require the wp-cli/wp-cli-bundle package as a development dependency of your project, see below.

                                                                                                                                                              +

                                                                                                                                                              Fixing "not a registered command" issue

                                                                                                                                                              +

                                                                                                                                                              To keep the conflicts at a manageable level, the wp-browser project does not include all the commands WP-CLI usually comes bundled with.
                                                                                                                                                              +Running, in the context of an automated test, a WP-CLI command that would work on your machine, e.g. wp plugin list --status=active, will not work on a default installation of wp-browser and you will get the following error message:

                                                                                                                                                              +
                                                                                                                                                              [ModuleException] WPCLI: wp-cli terminated with status [1] and output [Error: 'plugin' is not a registered wp command. See 'wp help' for available commands.]
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              To resolve the message just add the package you require as a development dependency or add the whole WP-CLI bundle:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev wp-cli/wp-cli-bundle
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The package will make all the default WP-CLI commands available to the WP-CLI version used in tests.

                                                                                                                                                              +

                                                                                                                                                              Module requirements for Codeception 4.0+

                                                                                                                                                              +

                                                                                                                                                              This module requires the codeception/module-cli Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                              +

                                                                                                                                                              To install the package run:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev codeception/module-cli:^1.0
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Detecting requests coming from this module

                                                                                                                                                              +

                                                                                                                                                              When it runs this module will set the WPBROWSER_HOST_REQUEST environment variable.
                                                                                                                                                              +You can detect and use that information to, as an example, use the correct database in your test site wp-config.php file: +

                                                                                                                                                              <?php
                                                                                                                                                              +if ( 
                                                                                                                                                              +    // Custom header.
                                                                                                                                                              +    isset( $_SERVER['HTTP_X_TESTING'] )
                                                                                                                                                              +    // Custom user agent.
                                                                                                                                                              +    || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )
                                                                                                                                                              +    // The env var set by the WPClIr or WordPress modules.
                                                                                                                                                              +    || getenv( 'WPBROWSER_HOST_REQUEST' )
                                                                                                                                                              +) {
                                                                                                                                                              +    // Use the test database if the request comes from a test.
                                                                                                                                                              +    define( 'DB_NAME', 'wordpress_test' );
                                                                                                                                                              +} else {
                                                                                                                                                              +    // Else use the default one.
                                                                                                                                                              +    define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              +}
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • path required - the absolute, or relative, path to the WordPress root folder. This will be mapped to the --path argument of the wp-cli binary.
                                                                                                                                                              • +
                                                                                                                                                              • throw - defaults to true to throw an exception when a wp-cli command does not return an exit status of 0; if set to false then the exit status of the commands will be returned as is.
                                                                                                                                                              • +
                                                                                                                                                              • timeout - defaults to 60 (seconds) to set each process execution timeout to a certain value; set to null, false or 0 to disable timeout completely.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Additionally the module configuration will forward any configuration parameter to wp-cli as a flag or option. +In the example configuration below the allow-root flag and the some-option option will be passed to wp-cli directly and prepended to the command as global options.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Note: these extract configuration flags and options will be prepended to all commands executed by wp-cli!

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Environment configuration

                                                                                                                                                              +

                                                                                                                                                              The wp-cli binary supports a set of environment variables to modify its behavior.

                                                                                                                                                              +

                                                                                                                                                              These environment variables can be set on the commands ran by the WPCLI module using the optional env array in the module configuration.
                                                                                                                                                              +The example configuration below shows all of them with some example values.
                                                                                                                                                              +Most of the times you won't need any of these, but they are there for more fine-grained control over the module operations.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The module is not validating the environment variables in any way! Those values will be evaluated by wp-cli at runtime and might generate errors if not correctly configured.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                              modules:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - WPCLI
                                                                                                                                                              +    config:
                                                                                                                                                              +        WPCLI:
                                                                                                                                                              +            path: /Users/Luca/Sites/wp
                                                                                                                                                              +            throw: true
                                                                                                                                                              +            timeout: 60
                                                                                                                                                              +            # This will be prepended to the command, `wp --allow-root <command>`.
                                                                                                                                                              +            allow-root: true
                                                                                                                                                              +            # This will be prepended to the command, `wp --some-option=some-value <command>`.
                                                                                                                                                              +            some-option: some-value
                                                                                                                                                              +            env:
                                                                                                                                                              +                # Any one of these, if provided, will be set as environment variable for the the cli command process. 
                                                                                                                                                              +                # See https://make.wordpress.org/cli/handbook/config/#environment-variables for information.
                                                                                                                                                              +                # Equivalent to `WP_CLI_STRICT_ARGS_MODE=1 wp <command>'.
                                                                                                                                                              +                strict-args: true
                                                                                                                                                              +                # Equivalent to `WP_CLI_CACHE_DIR=/tmp/wp-cli-cache wp <command>'.
                                                                                                                                                              +                cache-dir: '/tmp/wp-cli-cache'
                                                                                                                                                              +                # Equivalent to `WP_CLI_CONFIG_PATH=/app/public wp <command>'.
                                                                                                                                                              +                config-path: '/app/public'
                                                                                                                                                              +                # Equivalent to `WP_CLI_CUSTOM_SHELL=/bin/zsh wp <command>'.
                                                                                                                                                              +                custom-shell: '/bin/zsh'
                                                                                                                                                              +                # Equivalent to `WP_CLI_DISABLE_AUTO_CHECK_UPDATE=1 wp <command>'.
                                                                                                                                                              +                disable-auto-update: true
                                                                                                                                                              +                # Equivalent to `WP_CLI_PACKAGES_DIR=/wp-cli/packages wp <command>'.
                                                                                                                                                              +                packages-dir: '/wp-cli/packages'
                                                                                                                                                              +                # Equivalent to `WP_CLI_PHP=/usr/local/bin/php/7.2/php wp <command>'.
                                                                                                                                                              +                php: '/usr/local/bin/php/7.2/php'
                                                                                                                                                              +                # Equivalent to `WP_CLI_PHP_ARGS='foo=bar some=23' wp <command>'.
                                                                                                                                                              +                php-args: 'foo=bar some=23'
                                                                                                                                                              +
                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              + + +

                                                                                                                                                              buildFullCommand

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Builds the full command to run including the PHP binary and the wp-cli boot file path.

                                                                                                                                                              +
                                                                                                                                                              // This method is defined in the WithWpCli trait.
                                                                                                                                                              +  // Set the wp-cli path, `$this` is a test case.
                                                                                                                                                              +  $this->setUpWpCli( '/var/www/html' );
                                                                                                                                                              +  // Builds the full wp-cli command, including the `path` variable.
                                                                                                                                                              +  $fullCommand =  $this->buildFullCommand(['core', 'version']);
                                                                                                                                                              +  // The full command can then be used to run it with another process handler.
                                                                                                                                                              +  $wpCliProcess = new Process($fullCommand);
                                                                                                                                                              +  $wpCliProcess->run();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/string $command - The command to run.
                                                                                                                                                              + +

                                                                                                                                                              cli

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Executes a wp-cli command targeting the test WordPress installation. minus wp. For back-compatibility purposes you can still pass the commandline as a string, but the array format is the preferred and supported method.

                                                                                                                                                              +
                                                                                                                                                              // Activate a plugin via wp-cli in the test WordPress site.
                                                                                                                                                              +  $I->cli(['plugin', 'activate', 'my-plugin']);
                                                                                                                                                              +  // Change a user password.
                                                                                                                                                              +  $I->cli(['user', 'update', 'luca', '--user_pass=newpassword']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/string/\Codeception\Module\array $userCommand - The string of command and parameters as it would be passed to wp-cli
                                                                                                                                                              + +

                                                                                                                                                              cliToArray

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the output of a wp-cli command as an array optionally allowing a callback to process the output. minus wp. For back-compatibility purposes you can still pass the commandline as a string, but the array format is the preferred and supported method.

                                                                                                                                                              +
                                                                                                                                                              // Return a list of inactive themes, like ['twentyfourteen', 'twentyfifteen'].
                                                                                                                                                              +  $inactiveThemes = $I->cliToArray(['theme', 'list', '--status=inactive', '--field=name']);
                                                                                                                                                              +  // Get the list of installed plugins and only keep the ones starting with "foo".
                                                                                                                                                              +  $fooPlugins = $I->cliToArray(['plugin', 'list', '--field=name'], function($output){
                                                                                                                                                              +  return array_filter(explode(PHP_EOL, $output), function($name){
                                                                                                                                                              +  return strpos(trim($name), 'foo') === 0;
                                                                                                                                                              +  });
                                                                                                                                                              +  });
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/string/\Codeception\Module\array $userCommand - The string of command and parameters as it would be passed to wp-cli
                                                                                                                                                              • +
                                                                                                                                                              • \callable $splitCallback - An optional callback function to split the results array.
                                                                                                                                                              + +

                                                                                                                                                              cliToString

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the output of a wp-cli command as a string. minus wp. For back-compatibility purposes you can still pass the commandline as a string, but the array format is the preferred and supported method.

                                                                                                                                                              +
                                                                                                                                                              // Return the current site administrator email, using string command format.
                                                                                                                                                              +  $adminEmail = $I->cliToString('option get admin_email');
                                                                                                                                                              +  // Get the list of active plugins in JSON format, two ways.
                                                                                                                                                              +  $activePlugins = $I->cliToString(['plugin', 'list','--status=active', '--format=json']);
                                                                                                                                                              +  $activePlugins = $I->cliToString(['option', 'get', 'active_plugins' ,'--format=json']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/\Codeception\Module\array $userCommand - The string of command and parameters as it would be passed to wp-cli
                                                                                                                                                              + +

                                                                                                                                                              dontSeeInShellOutput

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that output from last command doesn't contain text.

                                                                                                                                                              +
                                                                                                                                                              // Return the current site administrator email, using string command format.
                                                                                                                                                              +  $I->cli('plugin list --status=active');
                                                                                                                                                              +  $I->dontSeeInShellOutput('my-inactive/plugin.php');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $text - The text to assert is not in the output.
                                                                                                                                                              + +

                                                                                                                                                              seeInShellOutput

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that output from last command contains text.

                                                                                                                                                              +
                                                                                                                                                              // Return the current site administrator email, using string command format.
                                                                                                                                                              +  $I->cli('option get admin_email');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $text - The text to assert is in the output.
                                                                                                                                                              + +

                                                                                                                                                              seeResultCodeIs

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks the result code from the last command.

                                                                                                                                                              +
                                                                                                                                                              // Return the current site administrator email, using string command format.
                                                                                                                                                              +  $I->cli('option get admin_email');
                                                                                                                                                              +  $I->seeResultCodeIs(0);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $code - The desired result code.
                                                                                                                                                              + +

                                                                                                                                                              seeResultCodeIsNot

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks the result code from the last command.

                                                                                                                                                              +
                                                                                                                                                              // Return the current site administrator email, using string command format.
                                                                                                                                                              +  $I->cli('invalid command');
                                                                                                                                                              +  $I->seeResultCodeIsNot(0);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $code - The result code the command should not have exited with.
                                                                                                                                                              + +

                                                                                                                                                              seeShellOutputMatches

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that output from the last command matches a given regular expression.

                                                                                                                                                              +
                                                                                                                                                              // Return the current site administrator email, using string command format.
                                                                                                                                                              +  $I->cli('option get admin_email');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $regex - The regex pattern, including delimiters, to assert the output matches against.
                                                                                                                                                              + +

                                                                                                                                                              This class extends \Codeception\Module

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPDb/index.html b/v3/modules/WPDb/index.html new file mode 100644 index 000000000..35efac2eb --- /dev/null +++ b/v3/modules/WPDb/index.html @@ -0,0 +1,5555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPDb - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WPDb module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in acceptance and functional tests, see levels of testing for more information.
                                                                                                                                                              +This module extends the Db module adding WordPress-specific configuration parameters and methods.
                                                                                                                                                              +The module provides methods to read, write and update the WordPress database directly, without relying on WordPress methods, using WordPress functions or triggering WordPress filters.

                                                                                                                                                              +

                                                                                                                                                              Module requirements for Codeception 4.0+

                                                                                                                                                              +

                                                                                                                                                              This module requires the codeception/module-db Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                              +

                                                                                                                                                              To install the package run:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev codeception/module-db:^1.0
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Backup your content

                                                                                                                                                              +

                                                                                                                                                              This module, like the Codeception Db one it extends, by default will load a database dump in the database it's using.
                                                                                                                                                              +This means that the database contents will be replaced by the dump contents on each run of a suite using the module.
                                                                                                                                                              +You can set the populate and cleanup parameters to false to prevent this default behavior but it's usually not what you need in an automated test.
                                                                                                                                                              +Make a backup of any database you're using in tests that contains any information you care about before you run any test!

                                                                                                                                                              +

                                                                                                                                                              Change the database used depending on whether you're running tests or not

                                                                                                                                                              +

                                                                                                                                                              The chore of having to plug different databases, or backup them, depending on whether you're manually testing the site or automatically testing can be mitigated switching them automatically depending on the browser user agent or request headers.
                                                                                                                                                              +This module was born to be used in acceptance and functional tests (see levels of testing for more information) and will often be coupled with modules like the WPBrowser one or the WPWebDriver one.
                                                                                                                                                              +Depending on which of the two modules is being used in the suite there are different ways to automate the "database switching".

                                                                                                                                                              +

                                                                                                                                                              Automatically changing database based on the browser user agent

                                                                                                                                                              +

                                                                                                                                                              If you would like to automate the "switching above" below you will find an example setup.
                                                                                                                                                              +Update the test site wp-config.php file from this: +

                                                                                                                                                              define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              +
                                                                                                                                                              + to this: +
                                                                                                                                                              <?php
                                                                                                                                                              +if ( 
                                                                                                                                                              +    // Custom header.
                                                                                                                                                              +    isset( $_SERVER['HTTP_X_TESTING'] )
                                                                                                                                                              +    // Custom user agent.
                                                                                                                                                              +    || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )
                                                                                                                                                              +    // The env var set by the WPClIr or WordPress modules.
                                                                                                                                                              +    || getenv( 'WPBROWSER_HOST_REQUEST' )
                                                                                                                                                              +) {
                                                                                                                                                              +    // Use the test database if the request comes from a test.
                                                                                                                                                              +    define( 'DB_NAME', 'wordpress_test' );
                                                                                                                                                              +} else {
                                                                                                                                                              +    // Else use the default one.
                                                                                                                                                              +    define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              +}
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              If you're using the WPWebDriver module set the user agent in the browser, in this example I'm setting the user agent in Chromedriver: +

                                                                                                                                                              class_name: AcceptanceTester
                                                                                                                                                              +modules:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - \Helper\Acceptance
                                                                                                                                                              +        - WPDb
                                                                                                                                                              +        - WPWebDriver
                                                                                                                                                              +    config:
                                                                                                                                                              +        WPDb:
                                                                                                                                                              +            dsn: 'mysql:host=%WP_DB_HOST%;dbname=%WP_DB_NAME%'
                                                                                                                                                              +            user: %WP_DB_USER%
                                                                                                                                                              +            password: %WP_DB_PASSWORD%
                                                                                                                                                              +            dump: tests/_data/dump.sql
                                                                                                                                                              +            populate: true
                                                                                                                                                              +            cleanup: false
                                                                                                                                                              +            url: '%WP_URL%'
                                                                                                                                                              +            tablePrefix: %WP_TABLE_PREFIX%
                                                                                                                                                              +            urlReplacement: true
                                                                                                                                                              +        WPWebDriver:
                                                                                                                                                              +            url: '%WP_URL%'
                                                                                                                                                              +            adminUsername: '%WP_ADMIN_USERNAME%'
                                                                                                                                                              +            adminPassword: '%WP_ADMIN_PASSWORD%'
                                                                                                                                                              +            adminPath: '%WP_ADMIN_PATH%'
                                                                                                                                                              +            browser: chrome
                                                                                                                                                              +            host: localhost
                                                                                                                                                              +            port: 4444
                                                                                                                                                              +            window_size: false
                                                                                                                                                              +            wait: 5
                                                                                                                                                              +            capabilities:
                                                                                                                                                              +              "goog:chromeOptions":
                                                                                                                                                              +                args:
                                                                                                                                                              +                  - "--headless"
                                                                                                                                                              +                  - "--disable-gpu"
                                                                                                                                                              +                  - "--disable-dev-shm-usage"
                                                                                                                                                              +                  - "--proxy-server='direct://'"
                                                                                                                                                              +                  - "--proxy-bypass-list=*"
                                                                                                                                                              +                  - "--no-sandbox"
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              If you're using the WPBrowser module send a specific header in the context of test requests: +

                                                                                                                                                              class_name: AcceptanceTester
                                                                                                                                                              +modules:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - \Helper\Acceptance
                                                                                                                                                              +        - WPDb
                                                                                                                                                              +        - WPBrowser
                                                                                                                                                              +    config:
                                                                                                                                                              +        WPDb:
                                                                                                                                                              +              dsn: 'mysql:host=%DB_HOST%;dbname=%WP_DB_NAME%'
                                                                                                                                                              +              user: %WP_DB_USER%
                                                                                                                                                              +              password: %WP_DB_PASSWORD%
                                                                                                                                                              +              dump: 'tests/_data/dump.sql'
                                                                                                                                                              +              populate: true
                                                                                                                                                              +              cleanup: true
                                                                                                                                                              +              reconnect: false
                                                                                                                                                              +              url: '%WP_URL%'
                                                                                                                                                              +              tablePrefix: 'wp_'
                                                                                                                                                              +        WPBrowser:
                                                                                                                                                              +              url: '%WP_URL%'
                                                                                                                                                              +              adminUsername: 'admin'
                                                                                                                                                              +              adminPassword: 'admin'
                                                                                                                                                              +              adminPath: '/wp-admin'
                                                                                                                                                              +              headers: 
                                                                                                                                                              +                X-Testing: 'wp-browser'
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • dsn required - the database POD DSN connection details; read more on PHP PDO documentation. If the database is accessible (as is the case on the latest version of [Local by Flywheel][http://localwp.com]) via unix socket, then the string to insert here should look like this mysql:unix_socket=/path/to/the/mysql.sock;dbname=wordpress.
                                                                                                                                                              • +
                                                                                                                                                              • user required - the database user.
                                                                                                                                                              • +
                                                                                                                                                              • password required - the database password.
                                                                                                                                                              • +
                                                                                                                                                              • url required - the full URL, including the HTTP scheme, of the website whose database is being accessed. WordPress uses hard-codece URLs in the database, that URL will be set by this module when applying the SQL dump file during population or cleanup.
                                                                                                                                                              • +
                                                                                                                                                              • dump required - defaults to null; sets the path, relative to the project root folder, or absolute to the SQL dump file that will be used to set the tests initial database fixture. If set to null then the populate, cleanup and populator parameters will be ignored.
                                                                                                                                                              • +
                                                                                                                                                              • populate - defaults to true to empty the target database and import the SQL dump(s) specified in the dump argument before the test suite is started.
                                                                                                                                                              • +
                                                                                                                                                              • cleanup - defaults to true empty the target database and import the SQL dump(s) specified in the dump argument before each test.
                                                                                                                                                              • +
                                                                                                                                                              • urlReplacement - defaults to true to replace, while using the built-in, PHP-based, dump import solution the hard-coded WordPress URL in the database with the specified one.
                                                                                                                                                              • +
                                                                                                                                                              • originalUrl - specifies the original URL hard-coded into the version controlled SQL dump files. This can help prevent some URL replacement issues when the urlReplacement configuration parameter is set to true.
                                                                                                                                                              • +
                                                                                                                                                              • populator - defaults to null, if set to an executable shell command then that command will be used to populate the database in place of the built-in PHP solution; URL replacement will not apply in this case. Read more about this on Codeception documentation.
                                                                                                                                                              • +
                                                                                                                                                              • reconnect - defaults to true to force the module to reconnect to the database before each test in place of only connecting at the start of the tests.
                                                                                                                                                              • +
                                                                                                                                                              • waitlock - defaults to 10; wait lock (in seconds) that the database session should use for DDL statements.
                                                                                                                                                              • +
                                                                                                                                                              • tablePrefix - defaults to wp_; sets the prefix of the tables that the module will manipulate.
                                                                                                                                                              • +
                                                                                                                                                              • letAdminEmailVerification - defaults to an empty value to remove the Administrator Email Verification screen introduced in WordPress 5.3. Set to true to not remove the screen and show it when an administrator user first logs in.
                                                                                                                                                              • +
                                                                                                                                                              • letCron - defaults to an empty value to avoid wp-cron from being spawned during tests. Setting this to true will let wp-cron requests to fire during tests.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                              modules:
                                                                                                                                                              +  enabled:
                                                                                                                                                              +      - WPDb
                                                                                                                                                              +  config:
                                                                                                                                                              +      WPDb:
                                                                                                                                                              +          dsn: 'mysql:host=localhost;dbname=wordpress'
                                                                                                                                                              +          user: 'root'
                                                                                                                                                              +          password: 'password'
                                                                                                                                                              +          dump: 'tests/_data/dump.sql'
                                                                                                                                                              +          populate: true
                                                                                                                                                              +          cleanup: true
                                                                                                                                                              +          waitlock: 10
                                                                                                                                                              +          url: 'http://wordpress.localhost'
                                                                                                                                                              +          urlReplacement: true
                                                                                                                                                              +          tablePrefix: 'wp_'
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Using the module with the WPLoader one

                                                                                                                                                              +

                                                                                                                                                              This module is often used in conjunction with the WPLoader one to use WordPress-defined functions, classes and methods in acceptance or functional tests.
                                                                                                                                                              +The WPLoader module should be set to only load WordPress and this module should be listed, in the modules.enabled section of the suite configuration file before the WPLoader one:

                                                                                                                                                              +

                                                                                                                                                              modules:
                                                                                                                                                              +  enabled:
                                                                                                                                                              +      - WPDb # this before...
                                                                                                                                                              +      - WPLoader # ...this one.
                                                                                                                                                              +  config:
                                                                                                                                                              +      WPDb:
                                                                                                                                                              +        # ...
                                                                                                                                                              +      WPLoader:
                                                                                                                                                              +        loadOnly: true
                                                                                                                                                              +        # ... 
                                                                                                                                                              +
                                                                                                                                                              +This will avoid issues where the WPLoader module could exit, terminating the test run, due to an inconsistent database state.

                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              + + +

                                                                                                                                                              countRowsInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the number of table rows matching a criteria.

                                                                                                                                                              +
                                                                                                                                                              $I->haveManyPostsInDatabase(3, ['post_status' => 'draft' ]);
                                                                                                                                                              +  $I->haveManyPostsInDatabase(3, ['post_status' => 'private' ]);
                                                                                                                                                              +  // Make sure there are now the expected number of draft posts.
                                                                                                                                                              +  $postsTable = $I->grabPostsTableName();
                                                                                                                                                              +  $draftsCount = $I->countRowsInDatabase($postsTable, ['post_status' => 'draft']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $table - The table to count the rows in.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $criteria - Search criteria, if empty all table rows will be counted.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveAttachmentFilesInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes all the files attached with an attachment post, it will not remove the database entries. Requires the WPFilesystem module to be loaded in the suite.

                                                                                                                                                              +
                                                                                                                                                              $posts = $I->grabPostsTableName();
                                                                                                                                                              +  $attachmentIds = $I->grabColumnFromDatabase($posts, 'ID', ['post_type' => 'attachment']);
                                                                                                                                                              +  // This will only remove the files, not the database entries.
                                                                                                                                                              +  $I->dontHaveAttachmentFilesInDatabase($attachmentIds);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/int $attachmentIds - An attachment post ID or an array of attachment post IDs.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveAttachmentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an attachment from the posts table. table. the suite.

                                                                                                                                                              +
                                                                                                                                                              $postmeta = $I->grabpostmetatablename();
                                                                                                                                                              +  $thumbnailId = $I->grabFromDatabase($postmeta, 'meta_value', [
                                                                                                                                                              +  'post_id' => $id,
                                                                                                                                                              +  'meta_key'=>'thumbnail_id'
                                                                                                                                                              +  ]);
                                                                                                                                                              +  // Remove only the database entry (including postmeta) but not the files.
                                                                                                                                                              +  $I->dontHaveAttachmentInDatabase($thumbnailId);
                                                                                                                                                              +  // Remove the database entry (including postmeta) and the files.
                                                                                                                                                              +  $I->dontHaveAttachmentInDatabase($thumbnailId, true, true);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria to find the attachment post in the posts
                                                                                                                                                              • +
                                                                                                                                                              • bool $purgeMeta - If set to true then the meta for the attachment will be purged too.
                                                                                                                                                              • +
                                                                                                                                                              • bool $removeFiles - Remove all files too, requires the WPFilesystem module to be loaded in
                                                                                                                                                              + +

                                                                                                                                                              dontHaveBlogInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes one ore more blogs from the database.

                                                                                                                                                              +
                                                                                                                                                              // Remove the blog, all its tables and files.
                                                                                                                                                              +  $I->dontHaveBlogInDatabase(['path' => 'test/one']);
                                                                                                                                                              +  // Remove the blog entry, not the tables though.
                                                                                                                                                              +  $I->dontHaveBlogInDatabase(['blog_id' => $blogId]);
                                                                                                                                                              +  // Remove multiple blogs.
                                                                                                                                                              +  $I->dontHaveBlogInDatabase(['domain' => 'test']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria to find the blog rows in the blogs table.
                                                                                                                                                              • +
                                                                                                                                                              • bool $removeTables - Remove the blog tables.
                                                                                                                                                              • +
                                                                                                                                                              • bool $removeUploads - Remove the blog uploads; requires the WPFilesystem module.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveCommentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the comments table.

                                                                                                                                                              +
                                                                                                                                                              $I->dontHaveCommentInDatabase(['comment_post_ID' => 23, 'comment_url' => 'http://example.copm']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              • +
                                                                                                                                                              • bool $purgeMeta - If set to true then the meta for the comment will be purged too.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveCommentMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a post comment meta from the database

                                                                                                                                                              +
                                                                                                                                                              // Remove all meta for the comment with an ID of 23.
                                                                                                                                                              +  $I->dontHaveCommentMetaInDatabase(['comment_id' => 23]);
                                                                                                                                                              +  // Remove the `count` comment meta for the comment with an ID of 23.
                                                                                                                                                              +  $I->dontHaveCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'count']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Deletes a database entry. criteria.

                                                                                                                                                              +
                                                                                                                                                              $I->dontHaveInDatabase('custom_table', ['book_ID' => 23, 'book_genre' => 'fiction']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $table - The table name.
                                                                                                                                                              • +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An associative array of the column names and values to use as deletion
                                                                                                                                                              + +

                                                                                                                                                              dontHaveLinkInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a link from the database.

                                                                                                                                                              +
                                                                                                                                                              $I->dontHaveLinkInDatabase(['link_url' => 'http://example.com']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the options table.

                                                                                                                                                              +
                                                                                                                                                              // Remove the `foo` option.
                                                                                                                                                              +  $I->dontHaveOptionInDatabase('foo');
                                                                                                                                                              +  // Remove the 'bar' option only if it has the `baz` value.
                                                                                                                                                              +  $I->dontHaveOptionInDatabase('bar', 'baz');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - If set the option will only be removed if its value matches the passed one.
                                                                                                                                                              + +

                                                                                                                                                              dontHavePostInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the posts table.

                                                                                                                                                              +
                                                                                                                                                              $posts = $I->haveManyPostsInDatabase(3, ['post_title' => 'Test {{n}}']);
                                                                                                                                                              +  $I->dontHavePostInDatabase(['post_title' => 'Test 2']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              • +
                                                                                                                                                              • bool $purgeMeta - If set to true then the meta for the post will be purged too.
                                                                                                                                                              + +

                                                                                                                                                              dontHavePostMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the postmeta table.

                                                                                                                                                              +
                                                                                                                                                              $postId = $I->havePostInDatabase(['meta_input' => ['rating' => 23]]);
                                                                                                                                                              +  $I->dontHavePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'rating']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontHavePostThumbnailInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Remove the thumbnail (featured image) from a post, if any. Please note: the method will NOT remove the attachment post, post meta and file.

                                                                                                                                                              +
                                                                                                                                                              $attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));
                                                                                                                                                              +  $postId = $I->havePostInDatabase();
                                                                                                                                                              +  // Attach the thumbnail to the post.
                                                                                                                                                              +  $I->havePostThumbnailInDatabase($postId, $attachmentId);
                                                                                                                                                              +  // Remove the thumbnail from the post.
                                                                                                                                                              +  $I->dontHavePostThumbnailInDatabase($postId);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $postId - The post ID to remove the thumbnail (featured image) from.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveSiteOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a site option from the database.

                                                                                                                                                              +
                                                                                                                                                              // Remove the `foo_count` option.
                                                                                                                                                              +  $I->dontHaveSiteOptionInDatabase('foo_count');
                                                                                                                                                              +  // Remove the `foo_count` option only if its value is `23`.
                                                                                                                                                              +  $I->dontHaveSiteOptionInDatabase('foo_count', 23);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - If set the option will only be removed it its value matches the specified one.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveSiteTransientInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a site transient from the database.

                                                                                                                                                              +
                                                                                                                                                              $I->dontHaveSiteTransientInDatabase(['my_plugin_site_buffer']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The name of the transient to delete.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveTableInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a table from the database. The case where a table does not exist is handled without raising an error.

                                                                                                                                                              +
                                                                                                                                                              $ordersTable = $I->grabPrefixedTableNameFor('orders');
                                                                                                                                                              +  $I->dontHaveTableInDatabase($ordersTable);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $fullTableName - The full table name, including the table prefix.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveTermInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a term from the database.

                                                                                                                                                              +
                                                                                                                                                              $I->dontHaveTermInDatabase(['name' => 'romance']);
                                                                                                                                                              +  $I->dontHaveTermInDatabase(['slug' => 'genre--romance']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              • +
                                                                                                                                                              • bool $purgeMeta - Whether the terms meta should be purged along side with the meta or not.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveTermMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a term meta from the database.

                                                                                                                                                              +
                                                                                                                                                              // Remove the "karma" key.
                                                                                                                                                              +  $I->dontHaveTermMetaInDatabase(['term_id' => $termId, 'meta_key' => 'karma']);
                                                                                                                                                              +  // Remove all meta for the term.
                                                                                                                                                              +  $I->dontHaveTermMetaInDatabase(['term_id' => $termId]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveTermRelationshipInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the term_relationships table.

                                                                                                                                                              +
                                                                                                                                                              // Remove the relation between a post and a category.
                                                                                                                                                              +  $I->dontHaveTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $ttaxId]);
                                                                                                                                                              +  // Remove all terms for a post.
                                                                                                                                                              +  $I->dontHaveTermMetaInDatabase(['object_id' => $postId]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveTermTaxonomyInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the term_taxonomy table.

                                                                                                                                                              +
                                                                                                                                                              // Remove a specific term from the genre taxonomy.
                                                                                                                                                              +  $I->dontHaveTermTaxonomyInDatabase(['term_id' => $postId, 'taxonomy' => 'genre']);
                                                                                                                                                              +  // Remove all terms for a taxonomy.
                                                                                                                                                              +  $I->dontHaveTermTaxonomyInDatabase(['taxonomy' => 'genre']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveTransientInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a transient from the database.

                                                                                                                                                              +
                                                                                                                                                              // Removes the `tweets` transient from the database, if set.
                                                                                                                                                              +  $I->dontHaveTransientInDatabase('tweets');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $transient - The name of the transient to delete.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveUserInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a user from the database.

                                                                                                                                                              +
                                                                                                                                                              $bob = $I->haveUserInDatabase('bob');
                                                                                                                                                              +  $alice = $I->haveUserInDatabase('alice');
                                                                                                                                                              +  // Remove Bob's user and meta.
                                                                                                                                                              +  $I->dontHaveUserInDatabase('bob');
                                                                                                                                                              +  // Remove Alice's user but not meta.
                                                                                                                                                              +  $I->dontHaveUserInDatabase($alice);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int/string $userIdOrLogin - The user ID or login name.
                                                                                                                                                              • +
                                                                                                                                                              • bool $purgeMeta - Whether the user meta should be purged alongside the user or not.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveUserInDatabaseWithEmail

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes a user(s) from the database using the user email address.

                                                                                                                                                              +
                                                                                                                                                              $luca = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $userEmail - The email of the user to remove.
                                                                                                                                                              • +
                                                                                                                                                              • bool $purgeMeta - Whether the user meta should be purged alongside the user or not.
                                                                                                                                                              + +

                                                                                                                                                              dontHaveUserMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Removes an entry from the usermeta table.

                                                                                                                                                              +
                                                                                                                                                              // Remove the `karma` user meta for a user.
                                                                                                                                                              +  $I->dontHaveUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);
                                                                                                                                                              +  // Remove all the user meta for a user.
                                                                                                                                                              +  $I->dontHaveUserMetaInDatabase(['user_id' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeAttachmentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that an attachment is not in the database.

                                                                                                                                                              +
                                                                                                                                                              $url = 'https://example.org/images/foo.png';
                                                                                                                                                              +  $I->dontSeeAttachmentInDatabase(['guid' => $url]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeBlogInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a row is not present in the blogs table.

                                                                                                                                                              +
                                                                                                                                                              $I->haveManyBlogsInDatabase(2, ['path' => 'test-{{n}}'], false)
                                                                                                                                                              +  $I->dontSeeBlogInDatabase(['path' => '/test-3/'])
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeCommentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a comment is not in the database. Will look up the "comments" table.

                                                                                                                                                              +
                                                                                                                                                              // Checks for one comment.
                                                                                                                                                              +  $I->dontSeeCommentInDatabase(['comment_ID' => 23]);
                                                                                                                                                              +  // Checks for comments from a user.
                                                                                                                                                              +  $I->dontSeeCommentInDatabase(['user_id' => 89]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - The search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeCommentMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a comment meta value is not in the database. Will look up the "commentmeta" table.

                                                                                                                                                              +
                                                                                                                                                              // Delete a comment `karma` meta.
                                                                                                                                                              +  $I->dontSeeCommentMetaInDatabase(['comment_id' => 23, 'meta_key' => 'karma']);
                                                                                                                                                              +  // Delete all meta for a comment.
                                                                                                                                                              +  $I->dontSeeCommentMetaInDatabase(['comment_id' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeLinkInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a link is not in the links database table.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeLinkInDatabase(['link_url' => 'http://example.com']);
                                                                                                                                                              +  $I->dontSeeLinkInDatabase(['link_url' => 'http://example.com', 'link_name' => 'example']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that an option is not in the database for the current blog. If the value is an object or an array then the serialized option will be checked.

                                                                                                                                                              +
                                                                                                                                                              $I->dontHaveOptionInDatabase('posts_per_page');
                                                                                                                                                              +  $I->dontSeeOptionInDatabase('posts_per_page');
                                                                                                                                                              +  $I->dontSeeOptionInDatabase('posts_per_page', 23);
                                                                                                                                                              +  $I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page']);
                                                                                                                                                              +  $I->dontSeeOptionInDatabase(['option_name' => 'posts_per_page', 'option_value' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/string $criteriaOrName - An array of search criteria or the option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                                                                                                                              + +

                                                                                                                                                              dontSeePageInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a page is not in the database.

                                                                                                                                                              +
                                                                                                                                                              // Assert a page with an ID does not exist.
                                                                                                                                                              +  $I->dontSeePageInDatabase(['ID' => 23]);
                                                                                                                                                              +  // Assert a page with a slug and ID.
                                                                                                                                                              +  $I->dontSeePageInDatabase(['post_name' => 'test', 'ID' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeePostInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a post is not in the database.

                                                                                                                                                              +
                                                                                                                                                              // Asserts a post with title 'Test' is not in the database.
                                                                                                                                                              +  $I->dontSeePostInDatabase(['post_title' => 'Test']);
                                                                                                                                                              +  // Asserts a post with title 'Test' and content 'Test content' is not in the database.
                                                                                                                                                              +  $I->dontSeePostInDatabase(['post_title' => 'Test', 'post_content' => 'Test content']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeePostMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a post meta value does not exist. If the meta value is an object or an array then the check will be made on its serialized version.

                                                                                                                                                              +
                                                                                                                                                              $postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']]);
                                                                                                                                                              +  $I->dontSeePostMetaInDatabase(['post_id' => $postId, 'meta_key' => 'woot']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeePostWithTermInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a post to term relation does not exist in the database. The method will check the "term_relationships" table.

                                                                                                                                                              +
                                                                                                                                                              $fiction = $I->haveTermInDatabase('fiction', 'genre');
                                                                                                                                                              +  $nonFiction = $I->haveTermInDatabase('non-fiction', 'genre');
                                                                                                                                                              +  $postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);
                                                                                                                                                              +  $I->dontSeePostWithTermInDatabase($postId, $nonFiction['term_taxonomy_id], );
                                                                                                                                                              +  passed this parameter will be interpreted as a `term_id`, else as a
                                                                                                                                                              +  the
                                                                                                                                                              +  term order.
                                                                                                                                                              +  to build a `taxonomy_term_id` from the `term_id`.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $post_id - The post ID.
                                                                                                                                                              • +
                                                                                                                                                              • int $term_taxonomy_id - The term term_id or term_taxonomy_id; if the $taxonomy argument is
                                                                                                                                                              • +
                                                                                                                                                              • int/null $term_order - The order the term applies to the post, defaults to null to not use
                                                                                                                                                              • +
                                                                                                                                                              • string/null $taxonomy - The taxonomy the term_id is for; if passed this parameter will be used
                                                                                                                                                              + +

                                                                                                                                                              dontSeeSiteOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a site option is not in the database.

                                                                                                                                                              +
                                                                                                                                                              // Check that the option is not set in the database.
                                                                                                                                                              +  $I->dontSeeSiteOptionInDatabase('foo_count');
                                                                                                                                                              +  // Check that the option is not set with a specific value.
                                                                                                                                                              +  $I->dontSeeSiteOptionInDatabase('foo_count', 23);
                                                                                                                                                              +  $I->dontSeeSiteOptionInDatabase(['option_name => 'foo_count', 'option_value' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/string $criteriaOrName - An array of search criteria or the option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeTableInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a table is not in the database.

                                                                                                                                                              +
                                                                                                                                                              $options = $I->grabPrefixedTableNameFor('options');
                                                                                                                                                              +  $I->dontHaveTableInDatabase($options)
                                                                                                                                                              +  $I->dontSeeTableInDatabase($options);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $table - The full table name, including the table prefix.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeTermInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Makes sure a term is not in the database. Looks up both the terms table and the term_taxonomy tables. and the term_taxonomy tables.

                                                                                                                                                              +
                                                                                                                                                              // Asserts a 'fiction' term is not in the database.
                                                                                                                                                              +  $I->dontSeeTermInDatabase(['name' => 'fiction']);
                                                                                                                                                              +  // Asserts a 'fiction' term with slug 'genre--fiction' is not in the database.
                                                                                                                                                              +  $I->dontSeeTermInDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of criteria to search for the term, can be columns from the terms
                                                                                                                                                              + +

                                                                                                                                                              dontSeeTermMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a term meta is not in the database.

                                                                                                                                                              +
                                                                                                                                                              list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
                                                                                                                                                              +  $I->haveTermMetaInDatabase($termId, 'rating', 4);
                                                                                                                                                              +  $I->dontSeeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'average_review']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeTermTaxonomyInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a term taxonomy is not in the database.

                                                                                                                                                              +
                                                                                                                                                              list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
                                                                                                                                                              +  $I->dontSeeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'country']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeUserInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a user is not in the database.

                                                                                                                                                              +
                                                                                                                                                              // Asserts a user does not exist in the database.
                                                                                                                                                              +  $I->dontSeeUserInDatabase(['user_login' => 'luca']);
                                                                                                                                                              +  // Asserts a user with email and login is not in the database.
                                                                                                                                                              +  $I->dontSeeUserInDatabase(['user_login' => 'luca', 'user_email' => 'luca@theaveragedev.com']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeUserMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Check that a user meta value is not in the database.

                                                                                                                                                              +
                                                                                                                                                              // Asserts a user does not have a 'karma' meta assigned.
                                                                                                                                                              +  $I->dontSeeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);
                                                                                                                                                              +  // Asserts no user has any 'karma' meta assigned.
                                                                                                                                                              +  $I->dontSeeUserMetaInDatabase(['meta_key' => 'karma']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              getSiteDomain

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the site domain inferred from the url set in the config.

                                                                                                                                                              +
                                                                                                                                                              $domain = $I->getSiteDomain();
                                                                                                                                                              +  // We should be redirected to the HTTPS version when visiting the HTTP version.
                                                                                                                                                              +  $I->amOnPage('http://' . $domain);
                                                                                                                                                              +  $I->seeCurrentUrlEquals('https://' . $domain);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              getUsersTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the prefixed users table name.

                                                                                                                                                              +
                                                                                                                                                              // Given a `wp_` table prefix returns `wp_users`.
                                                                                                                                                              +  $usersTable = $I->getUsersTableName();
                                                                                                                                                              +  // Given a `wp_` table prefix returns `wp_users`.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $usersTable = $I->getUsersTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabAllFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns all entries matching a criteria from the database.

                                                                                                                                                              +
                                                                                                                                                              $books = $I->grabPrefixedTableNameFor('books');
                                                                                                                                                              +  $I->grabAllFromDatabase($books, 'title', ['genre' => 'fiction']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $table - The table to grab the values from.
                                                                                                                                                              • +
                                                                                                                                                              • string $column - The column to fetch.
                                                                                                                                                              • +
                                                                                                                                                              • \Codeception\Module\array $criteria - The search criteria.
                                                                                                                                                              + +

                                                                                                                                                              grabAttachmentAttachedFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the path, as stored in the database, of an attachment _wp_attached_file meta. The attached file is, usually, an attachment origal file.

                                                                                                                                                              +
                                                                                                                                                              $file = $I->grabAttachmentAttachedFile($attachmentId);
                                                                                                                                                              +  $fileInfo = new SplFileInfo($file);
                                                                                                                                                              +  $I->assertEquals('jpg', $fileInfo->getExtension());
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $attachmentPostId - The attachment post ID.
                                                                                                                                                              + +

                                                                                                                                                              grabAttachmentMetadata

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the metadata array for an attachment post. This is the value of the _wp_attachment_metadata meta.

                                                                                                                                                              +
                                                                                                                                                              $metadata = $I->grabAttachmentMetadata($attachmentId);
                                                                                                                                                              +  $I->assertEquals(['thumbnail', 'medium', 'medium_large'], array_keys($metadata['sizes']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $attachmentPostId - The attachment post ID.
                                                                                                                                                              + +

                                                                                                                                                              grabBlogDomain

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns a blog domain given its ID.

                                                                                                                                                              +
                                                                                                                                                              $blogIds = $I->haveManyBlogsInDatabase(3);
                                                                                                                                                              +  $domains = array_map(function($blogId){
                                                                                                                                                              +  return $I->grabBlogDomain($blogId);
                                                                                                                                                              +  }, $blogIds);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The blog ID.
                                                                                                                                                              + +

                                                                                                                                                              grabBlogPath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Grabs a blog domain from the blogs table.

                                                                                                                                                              +
                                                                                                                                                              $blogId = $I->haveBlogInDatabase('test');
                                                                                                                                                              +  $path = $I->grabBlogDomain($blogId);
                                                                                                                                                              +  $I->amOnSubdomain($path);
                                                                                                                                                              +  $I->amOnPage('/');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The blog ID.
                                                                                                                                                              + +

                                                                                                                                                              grabBlogTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the full name of a table for a blog from a multisite installation database.

                                                                                                                                                              +
                                                                                                                                                              $blogOptionTable = $I->grabBlogTableName($blogId, 'option');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The blog ID.
                                                                                                                                                              • +
                                                                                                                                                              • string $table - The table name, without table prefix.
                                                                                                                                                              + +

                                                                                                                                                              grabBlogTableNames

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns a list of tables for a blog ID.

                                                                                                                                                              +
                                                                                                                                                              $blogId = $I->haveBlogInDatabase('test');
                                                                                                                                                              +  $tables = $I->grabBlogTableNames($blogId);
                                                                                                                                                              +  $options = array_filter($tables, function($tableName){
                                                                                                                                                              +  return str_pos($tableName, 'options') !== false;
                                                                                                                                                              +  });
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The ID of the blog to fetch the tables for.
                                                                                                                                                              + +

                                                                                                                                                              grabBlogTablePrefix

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the table prefix for a blog.

                                                                                                                                                              +
                                                                                                                                                              $blogId = $I->haveBlogInDatabase('test');
                                                                                                                                                              +  $blogTablePrefix = $I->getBlogTablePrefix($blogId);
                                                                                                                                                              +  $blogOrders = $I->blogTablePrefix . 'orders';
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The blog ID.
                                                                                                                                                              + +

                                                                                                                                                              grabBlogVersionsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed blog_versions table name.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a `wp_` table prefix it will return `wp_blog_versions`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabBlogVersionsTableName();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a `wp_` table prefix it will return `wp_blog_versions`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabBlogVersionsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabBlogsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed blogs table name.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a `wp_` table prefix it will return `wp_blogs`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabBlogsTableName();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a `wp_` table prefix it will return `wp_blogs`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabBlogsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabCommentmetaTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the prefixed comment meta table name.

                                                                                                                                                              +
                                                                                                                                                              // Get all the values of 'karma' for all comments.
                                                                                                                                                              +  $commentMeta = $I->grabCommentmetaTableName();
                                                                                                                                                              +  $I->grabAllFromDatabase($commentMeta, 'meta_value', ['meta_key' => 'karma']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabCommentsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the comments table name.

                                                                                                                                                              +
                                                                                                                                                              // Will be `wp_comments`.
                                                                                                                                                              +  $comments = $I->grabCommentsTableName();
                                                                                                                                                              +  // Will be `wp_23_comments`.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $comments = $I->grabCommentsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabLatestEntryByFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the id value of the last table entry.

                                                                                                                                                              +
                                                                                                                                                              $I->haveManyPostsInDatabase();
                                                                                                                                                              +  $postsTable = $I->grabPostsTableName();
                                                                                                                                                              +  $last = $I->grabLatestEntryByFromDatabase($postsTable, 'ID');
                                                                                                                                                              +  items.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $tableName - The table to fetch the last insertion for.
                                                                                                                                                              • +
                                                                                                                                                              • string $idColumn - The column that is used, in the table, to uniquely identify
                                                                                                                                                              + +

                                                                                                                                                              grabLinksTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the prefixed links table name.

                                                                                                                                                              +
                                                                                                                                                              // Given a `wp_` table prefix returns `wp_links`.
                                                                                                                                                              +  $linksTable = $I->grabLinksTableName();
                                                                                                                                                              +  // Given a `wp_` table prefix returns `wp_23_links`.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $linksTable = $I->grabLinksTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabOptionFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets an option value from the database.

                                                                                                                                                              +
                                                                                                                                                              $count = $I->grabOptionFromDatabase('foo_count');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $option_name - The name of the option to grab from the database.
                                                                                                                                                              + +

                                                                                                                                                              grabPostMetaFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the value of one or more post meta values from the database.

                                                                                                                                                              +
                                                                                                                                                              $thumbnail_id = $I->grabPostMetaFromDatabase($postId, '_thumbnail_id', true);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $postId - The post ID.
                                                                                                                                                              • +
                                                                                                                                                              • string $metaKey - The key of the meta to retrieve.
                                                                                                                                                              • +
                                                                                                                                                              • bool $single - Whether to return a single meta value or an array of all available meta values.
                                                                                                                                                              + +

                                                                                                                                                              grabPostmetaTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the prefixed post meta table name.

                                                                                                                                                              +
                                                                                                                                                              // Returns 'wp_postmeta'.
                                                                                                                                                              +  $I->grabPostmetaTableName();
                                                                                                                                                              +  // Returns 'wp_23_postmeta'.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $I->grabPostmetaTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabPostsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the posts prefixed table name.

                                                                                                                                                              +
                                                                                                                                                              // Given a `wp_` table prefix returns `wp_posts`.
                                                                                                                                                              +  $postsTable = $I->grabPostsTableName();
                                                                                                                                                              +  // Given a `wp_` table prefix returns `wp_23_posts`.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $postsTable = $I->grabPostsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabPrefixedTableNameFor

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns a prefixed table name for the current blog. If the table is not one to be prefixed (e.g. users) then the proper table name will be returned.

                                                                                                                                                              +
                                                                                                                                                              // Will return wp_users.
                                                                                                                                                              +  $usersTable = $I->grabPrefixedTableNameFor('users');
                                                                                                                                                              +  // Will return wp_options.
                                                                                                                                                              +  $optionsTable = $I->grabPrefixedTableNameFor('options');
                                                                                                                                                              +  // Use a different blog and get its options table.
                                                                                                                                                              +  $I->useBlog(2);
                                                                                                                                                              +  $blogOptionsTable = $I->grabPrefixedTableNameFor('options');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $tableName - The table name, e.g. options.
                                                                                                                                                              + +

                                                                                                                                                              grabRegistrationLogTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed registration_log table name.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a `wp_` table prefix it will return `wp_registration_log`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabRegistrationLogTableName();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a `wp_` table prefix it will return `wp_registration_log`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabRegistrationLogTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabSignupsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed signups table name.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a `wp_` table prefix it will return `wp_signups`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabSignupsTableName();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a `wp_` table prefix it will return `wp_signups`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabSignupsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabSiteMetaTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed sitemeta table name.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a `wp_` table prefix it will return `wp_sitemeta`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabSiteMetaTableName();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a `wp_` table prefix it will return `wp_sitemeta`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabSiteMetaTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabSiteOptionFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets a site option from the database.

                                                                                                                                                              +
                                                                                                                                                              $fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The name of the option to read from the database.
                                                                                                                                                              + +

                                                                                                                                                              grabSiteTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed site table name.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a `wp_` table prefix it will return `wp_site`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabSiteTableName();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a `wp_` table prefix it will return `wp_site`.
                                                                                                                                                              +  $blogVersionsTable = $I->grabSiteTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabSiteTransientFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets a site transient from the database.

                                                                                                                                                              +
                                                                                                                                                              $I->grabSiteTransientFromDatabase('total_comments');
                                                                                                                                                              +  $I->grabSiteTransientFromDatabase('api_data');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The site transient to fetch the value for, w/o the _site_transient_ prefix.
                                                                                                                                                              + +

                                                                                                                                                              grabSiteUrl

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the current site URL as specified in the module configuration.

                                                                                                                                                              +
                                                                                                                                                              $shopPath = $I->grabSiteUrl('/shop');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - A path that should be appended to the site URL.
                                                                                                                                                              + +

                                                                                                                                                              grabTablePrefix

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the table prefix, namespaced for secondary blogs if selected.

                                                                                                                                                              +
                                                                                                                                                              // Assuming a table prefix of `wp_` it will return `wp_`;
                                                                                                                                                              +  $tablePrefix = $I->grabTablePrefix();
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Assuming a table prefix of `wp_` it will return `wp_23_`;
                                                                                                                                                              +  $tablePrefix = $I->grabTablePrefix();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabTermIdFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets a term ID from the database. Looks up the prefixed terms table, e.g. wp_terms.

                                                                                                                                                              +
                                                                                                                                                              // Return the 'fiction' term 'term_id'.
                                                                                                                                                              +  $termId = $I->grabTermIdFromDatabase(['name' => 'fiction']);
                                                                                                                                                              +  // Get a term ID by more stringent criteria.
                                                                                                                                                              +  $termId = $I->grabTermIdFromDatabase(['name' => 'fiction', 'slug' => 'genre--fiction']);
                                                                                                                                                              +  // Return the 'term_id' of the first term for a group.
                                                                                                                                                              +  $termId = $I->grabTermIdFromDatabase(['term_group' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              grabTermMetaTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the terms meta table prefixed name.

                                                                                                                                                              +
                                                                                                                                                              // Returns 'wp_termmeta'.
                                                                                                                                                              +  $I->grabTermMetaTableName();
                                                                                                                                                              +  // Returns 'wp_23_termmeta'.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $I->grabTermMetaTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabTermRelationshipsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed term relationships table name, e.g. wp_term_relationships.

                                                                                                                                                              +
                                                                                                                                                              $I->grabTermRelationshipsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabTermTaxonomyIdFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets a term_taxonomy_id from the database. Looks up the prefixed terms_relationships table, e.g. wp_term_relationships.

                                                                                                                                                              +
                                                                                                                                                              // Get the `term_taxonomy_id` for a term and a taxonomy.
                                                                                                                                                              +  $I->grabTermTaxonomyIdFromDatabase(['term_id' => $fictionId, 'taxonomy' => 'genre']);
                                                                                                                                                              +  // Get the `term_taxonomy_id` for the first term with a count of 23.
                                                                                                                                                              +  $I->grabTermTaxonomyIdFromDatabase(['count' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              grabTermTaxonomyTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed term and taxonomy table name, e.g. wp_term_taxonomy.

                                                                                                                                                              +
                                                                                                                                                              // Returns 'wp_term_taxonomy'.
                                                                                                                                                              +  $I->grabTermTaxonomyTableName();
                                                                                                                                                              +  // Returns 'wp_23_term_taxonomy'.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $I->grabTermTaxonomyTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabTermsTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the prefixed terms table name, e.g. wp_terms.

                                                                                                                                                              +
                                                                                                                                                              // Returns 'wp_terms'.
                                                                                                                                                              +  $I->grabTermsTableName();
                                                                                                                                                              +  // Returns 'wp_23_terms'.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $I->grabTermsTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabUserIdFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets the a user ID from the database using the user login.

                                                                                                                                                              +
                                                                                                                                                              $userId = $I->grabUserIdFromDatabase('luca');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $userLogin - The user login name.
                                                                                                                                                              + +

                                                                                                                                                              grabUserMetaFromDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Gets a user meta from the database.

                                                                                                                                                              +
                                                                                                                                                              // Returns a user 'karma' value.
                                                                                                                                                              +  $I->grabUserMetaFromDatabase($userId, 'karma');
                                                                                                                                                              +  // Returns an array, the unserialized version of the value stored in the database.
                                                                                                                                                              +  $I->grabUserMetaFromDatabase($userId, 'api_data');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $userId - The ID of th user to get the meta for.
                                                                                                                                                              • +
                                                                                                                                                              • string $meta_key - The meta key to fetch the value for.
                                                                                                                                                              + +

                                                                                                                                                              grabUsermetaTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the prefixed users meta table name.

                                                                                                                                                              +
                                                                                                                                                              // Given a `wp_` table prefix returns `wp_usermeta`.
                                                                                                                                                              +  $usermetaTable = $I->grabUsermetaTableName();
                                                                                                                                                              +  // Given a `wp_` table prefix returns `wp_usermeta`.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $usermetaTable = $I->grabUsermetaTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabUsersTableName

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the prefixed users table name.

                                                                                                                                                              +
                                                                                                                                                              // Given a `wp_` table prefix returns `wp_users`.
                                                                                                                                                              +  $usersTable = $I->grabUsersTableName();
                                                                                                                                                              +  // Given a `wp_` table prefix returns `wp_users`.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  $usersTable = $I->grabUsersTableName();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              haveAttachmentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates the database entries representing an attachment and moves the attachment file to the right location. timestamp that should be used to build the "year/time" uploads sub-folder structure. override the image sizes created by default.

                                                                                                                                                              +
                                                                                                                                                              $file = codecept_data_dir('images/test.png');
                                                                                                                                                              +  $attachmentId = $I->haveAttachmentInDatabase($file);
                                                                                                                                                              +  $image = codecept_data_dir('images/test-2.png');
                                                                                                                                                              +  $lastWeekAttachment = $I->haveAttachmentInDatabase($image, '-1 week');
                                                                                                                                                              +  Requires the WPFilesystem module.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The absolute path to the attachment file.
                                                                                                                                                              • +
                                                                                                                                                              • string/string/int $date - Either a string supported by the strtotime function or a UNIX
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An associative array of values overriding the default ones.
                                                                                                                                                              • +
                                                                                                                                                              • \Codeception\Module\array> $imageSizes - An associative array in the format [ => [,]] to
                                                                                                                                                              + +

                                                                                                                                                              haveBlogInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a blog in the blogs table.

                                                                                                                                                              +
                                                                                                                                                              // Create the `test` subdomain blog.
                                                                                                                                                              +  $blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId]);
                                                                                                                                                              +  // Create the `/test` subfolder blog.
                                                                                                                                                              +  $blogId = $I->haveBlogInDatabase('test', ['administrator' => $userId], false);
                                                                                                                                                              +  or subfolder (`true`)
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $domainOrPath - The subdomain or the path to the be used for the blog.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An array of values to override the defaults.
                                                                                                                                                              • +
                                                                                                                                                              • bool $subdomain - Whether the new blog should be created as a subdomain (true)
                                                                                                                                                              + +

                                                                                                                                                              haveCommentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a comment in the database.

                                                                                                                                                              +
                                                                                                                                                              $I->haveCommentInDatabase($postId, ['comment_content' => 'Test Comment', 'comment_karma' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $comment_post_ID - The id of the post the comment refers to.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $data - The comment data overriding default and random generated values.
                                                                                                                                                              + +

                                                                                                                                                              haveCommentMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a comment meta field in the database. Array and object meta values will be serialized.

                                                                                                                                                              +
                                                                                                                                                              $I->haveCommentMetaInDatabase($commentId, 'api_ID', 23);
                                                                                                                                                              +  // The value will be serialized.
                                                                                                                                                              +  $apiData = ['ID' => 23, 'user' => 89, 'origin' => 'twitter'];
                                                                                                                                                              +  $I->haveCommentMetaInDatabase($commentId, 'api_data', $apiData);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $comment_id - The ID of the comment to insert the meta for.
                                                                                                                                                              • +
                                                                                                                                                              • string $meta_key - The key of the comment meta to insert.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $meta_value - The value of the meta to insert, if serializable it will be serialized.
                                                                                                                                                              + +

                                                                                                                                                              haveLinkInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a link in the database.

                                                                                                                                                              +
                                                                                                                                                              $linkId = $I->haveLinkInDatabase(['link_url' => 'http://example.org']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - The data to insert.
                                                                                                                                                              + +

                                                                                                                                                              haveManyBlogsInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts many blogs in the database. by the count.

                                                                                                                                                              +
                                                                                                                                                              $blogIds = $I->haveManyBlogsInDatabase(3, ['domain' =>'test-{{n}}']);
                                                                                                                                                              +  foreach($blogIds as $blogId){
                                                                                                                                                              +  $I->useBlog($blogId);
                                                                                                                                                              +  $I->haveManuPostsInDatabase(3);
                                                                                                                                                              +  }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $count - The number of blogs to create.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An array of values to override the default ones; {{n}} will be replaced
                                                                                                                                                              • +
                                                                                                                                                              • bool $subdomain - Whether the new blogs should be created as a subdomain or subfolder.
                                                                                                                                                              + +

                                                                                                                                                              haveManyCommentsInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts many comments in the database.

                                                                                                                                                              +
                                                                                                                                                              // Insert 3 random comments for a post.
                                                                                                                                                              +  $I->haveManyCommentsInDatabase(3, $postId);
                                                                                                                                                              +  // Insert 3 random comments for a post.
                                                                                                                                                              +  $I->haveManyCommentsInDatabase(3, $postId, ['comment_content' => 'Comment {{n}}']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $count - The number of comments to insert.
                                                                                                                                                              • +
                                                                                                                                                              • int $comment_post_ID - The comment parent post ID.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An associative array to override the defaults.
                                                                                                                                                              + +

                                                                                                                                                              haveManyLinksInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts many links in the database links table.

                                                                                                                                                              +
                                                                                                                                                              // Insert 3 randomly generated links in the database.
                                                                                                                                                              +  $linkIds = $I->haveManyLinksInDatabase(3);
                                                                                                                                                              +  // Inserts links in the database replacing the `n` placeholder.
                                                                                                                                                              +  $linkIds = $I->haveManyLinksInDatabase(3, ['link_url' => 'http://example.org/test-{{n}}']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $count - The number of links to insert.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - Overrides for the default arguments.
                                                                                                                                                              + +

                                                                                                                                                              haveManyPostsInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts many posts in the database returning their IDs. An array of values to override the defaults. The {{n}} placeholder can be used to have the post count inserted in its place; e.g. Post Title - {{n}} will be set to Post Title - 0 for the first post, Post Title - 1 for the second one and so on. The same applies to meta values as well.

                                                                                                                                                              +
                                                                                                                                                              // Insert 3 random posts.
                                                                                                                                                              +  $I->haveManyPostsInDatabase(3);
                                                                                                                                                              +  // Insert 3 posts with generated titles.
                                                                                                                                                              +  $I->haveManyPostsInDatabase(3, ['post_title' => 'Test post {{n}}']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $count - The number of posts to insert.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides
                                                                                                                                                              + +

                                                                                                                                                              haveManyTermsInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts many terms in the database.

                                                                                                                                                              +
                                                                                                                                                              $terms = $I->haveManyTermsInDatabase(3, 'genre-{{n}}', 'genre');
                                                                                                                                                              +  $termIds = array_column($terms, 0);
                                                                                                                                                              +  $termTaxonomyIds = array_column($terms, 1);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $count - The number of terms to insert.
                                                                                                                                                              • +
                                                                                                                                                              • string $name - The term name template, can include the {{n}} placeholder.
                                                                                                                                                              • +
                                                                                                                                                              • string $taxonomy - The taxonomy to insert the terms for.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An associative array of default overrides.
                                                                                                                                                              + +

                                                                                                                                                              haveManyUsersInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts many users in the database.

                                                                                                                                                              +
                                                                                                                                                              $subscribers = $I->haveManyUsersInDatabase(5, 'user-{{n}}');
                                                                                                                                                              +  $editors = $I->haveManyUsersInDatabase(
                                                                                                                                                              +  5,
                                                                                                                                                              +  'user-{{n}}',
                                                                                                                                                              +  'editor',
                                                                                                                                                              +  ['user_email' => 'user-{{n}}@example.org']
                                                                                                                                                              +  );
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $count - The number of users to insert.
                                                                                                                                                              • +
                                                                                                                                                              • string $user_login - The user login name.
                                                                                                                                                              • +
                                                                                                                                                              • string $role - The user role.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An array of values to override the default ones.
                                                                                                                                                              + +

                                                                                                                                                              haveMenuInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates and adds a menu to a theme location in the database.

                                                                                                                                                              +
                                                                                                                                                              list($termId, $termTaxId) = $I->haveMenuInDatabase('test', 'sidebar');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $slug - The menu slug.
                                                                                                                                                              • +
                                                                                                                                                              • string $location - The theme menu location the menu will be assigned to.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An array of values to override the defaults.
                                                                                                                                                              + +

                                                                                                                                                              haveMenuItemInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Adds a menu element to a menu for the current theme. post meta.

                                                                                                                                                              +
                                                                                                                                                              $I->haveMenuInDatabase('test', 'sidebar');
                                                                                                                                                              +  $I->haveMenuItemInDatabase('test', 'Test one', 0);
                                                                                                                                                              +  $I->haveMenuItemInDatabase('test', 'Test two', 1);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $menuSlug - The menu slug the item should be added to.
                                                                                                                                                              • +
                                                                                                                                                              • string $title - The menu item title.
                                                                                                                                                              • +
                                                                                                                                                              • int/null $menuOrder - An optional menu order, 1 based.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $meta - An associative array that will be prefixed with _menu_item_ for the item
                                                                                                                                                              + +

                                                                                                                                                              haveOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts an option in the database.

                                                                                                                                                              +
                                                                                                                                                              $I->haveOptionInDatabase('posts_per_page', 23);
                                                                                                                                                              +  $I->haveOptionInDatabase('my_plugin_options', ['key_one' => 'value_one', 'key_two' => 89]);
                                                                                                                                                              +  If the option value is an object or an array then the value will be serialized.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $option_name - The option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $option_value - The option value; if an array or object it will be serialized.
                                                                                                                                                              • +
                                                                                                                                                              • string $autoload - Weather the option should be autoloaded by WordPress or not.
                                                                                                                                                              + +

                                                                                                                                                              havePageInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a page in the database.

                                                                                                                                                              +
                                                                                                                                                              // Creates a test page in the database with random values.
                                                                                                                                                              +  $randomPageId = $I->havePageInDatabase();
                                                                                                                                                              +  // Creates a test page in the database defining its title.
                                                                                                                                                              +  $testPageId = $I->havePageInDatabase(['post_title' => 'Test page']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An array of values to override the default ones.
                                                                                                                                                              + +

                                                                                                                                                              havePostInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a post in the database. values.

                                                                                                                                                              +
                                                                                                                                                              // Insert a post with random values in the database.
                                                                                                                                                              +  $randomPostId = $I->havePostInDatabase();
                                                                                                                                                              +  // Insert a post with specific values in the database.
                                                                                                                                                              +  $I->havePostInDatabase([
                                                                                                                                                              +  'post_type' => 'book',
                                                                                                                                                              +  'post_title' => 'Alice in Wonderland',
                                                                                                                                                              +  'meta_input' => [
                                                                                                                                                              +  'readers_count' => 23
                                                                                                                                                              +  ],
                                                                                                                                                              +  'tax_input' => [
                                                                                                                                                              +  ['genre' => 'fiction']
                                                                                                                                                              +  ]
                                                                                                                                                              +  ]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • array/\Codeception\Module\array/array $data - An associative array of post data to override default and random generated
                                                                                                                                                              + +

                                                                                                                                                              havePostThumbnailInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Assigns the specified attachment ID as thumbnail (featured image) to a post.

                                                                                                                                                              +
                                                                                                                                                              $attachmentId = $I->haveAttachmentInDatabase(codecept_data_dir('some-image.png'));
                                                                                                                                                              +  $postId = $I->havePostInDatabase();
                                                                                                                                                              +  $I->havePostThumbnailInDatabase($postId, $attachmentId);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $postId - The post ID to assign the thumbnail (featured image) to.
                                                                                                                                                              • +
                                                                                                                                                              • int $thumbnailId - The post ID of the attachment.
                                                                                                                                                              + +

                                                                                                                                                              havePostmetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Adds one or more meta key and value couples in the database for a post.

                                                                                                                                                              +
                                                                                                                                                              // Set the post-meta for a post.
                                                                                                                                                              +  $I->havePostmetaInDatabase($postId, 'karma', 23);
                                                                                                                                                              +  // Set an array post-meta for a post, it will be serialized in the db.
                                                                                                                                                              +  $I->havePostmetaInDatabase($postId, 'data', ['one', 'two']);
                                                                                                                                                              +  // Use a loop to insert one meta per row.
                                                                                                                                                              +  foreach( ['one', 'two'] as $value){
                                                                                                                                                              +  $I->havePostmetaInDatabase($postId, 'data', $value);
                                                                                                                                                              +  }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $postId - The post ID.
                                                                                                                                                              • +
                                                                                                                                                              • string $meta_key - The meta key.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $meta_value - The value to insert in the database, objects and arrays will be serialized.
                                                                                                                                                              + +

                                                                                                                                                              haveSiteOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a site option in the database. If the value is an array or an object then the value will be serialized.

                                                                                                                                                              +
                                                                                                                                                              $fooCountOptionId = $I->haveSiteOptionInDatabase('foo_count','23');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The name of the option to insert.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $value - The value to insert for the option.
                                                                                                                                                              + +

                                                                                                                                                              haveSiteTransientInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a site transient in the database. If the value is an array or an object then the value will be serialized.

                                                                                                                                                              +
                                                                                                                                                              $I->haveSiteTransientInDatabase('total_comments_count', 23);
                                                                                                                                                              +  // This value will be serialized.
                                                                                                                                                              +  $I->haveSiteTransientInDatabase('api_data', ['user' => 'luca', 'token' => '11ae3ijns-j83']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The key of the site transient to insert, w/o the _site_transient_ prefix.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $value - The value to insert; if serializable the value will be serialized.
                                                                                                                                                              + +

                                                                                                                                                              haveTermInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a term in the database.

                                                                                                                                                              +
                                                                                                                                                              // Insert a random 'genre' term in the database.
                                                                                                                                                              +  $I->haveTermInDatabase('non-fiction', 'genre');
                                                                                                                                                              +  // Insert a term in the database with term meta.
                                                                                                                                                              +  $I->haveTermInDatabase('fiction', 'genre', [
                                                                                                                                                              +  'slug' => 'genre--fiction',
                                                                                                                                                              +  'meta' => [
                                                                                                                                                              +  'readers_count' => 23
                                                                                                                                                              +  ]
                                                                                                                                                              +  ]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $name - The term name, e.g. "Fuzzy".
                                                                                                                                                              • +
                                                                                                                                                              • string $taxonomy - The term taxonomy
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An array of values to override the default ones.
                                                                                                                                                              + +

                                                                                                                                                              haveTermMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a term meta row in the database. Objects and array meta values will be serialized.

                                                                                                                                                              +
                                                                                                                                                              $I->haveTermMetaInDatabase($fictionId, 'readers_count', 23);
                                                                                                                                                              +  // Insert some meta that will be serialized.
                                                                                                                                                              +  $I->haveTermMetaInDatabase($fictionId, 'flags', [3, 4, 89]);
                                                                                                                                                              +  // Use a loop to insert one meta per row.
                                                                                                                                                              +  foreach([3, 4, 89] as $value) {
                                                                                                                                                              +  $I->haveTermMetaInDatabase($fictionId, 'flag', $value);
                                                                                                                                                              +  }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $term_id - The ID of the term to insert the meta for.
                                                                                                                                                              • +
                                                                                                                                                              • string $meta_key - The key of the meta to insert.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $meta_value - The value of the meta to insert, if serializable it will be serialized.
                                                                                                                                                              + +

                                                                                                                                                              haveTermRelationshipInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates a term relationship in the database. No check about the consistency of the insertion is made. E.g. a post could be assigned a term from a taxonomy that's not registered for that post type.

                                                                                                                                                              +
                                                                                                                                                              // Assign the `fiction` term to a book.
                                                                                                                                                              +  $I->haveTermRelationshipInDatabase($bookId, $fictionId);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $object_id - A post ID, a user ID or anything that can be assigned a taxonomy term.
                                                                                                                                                              • +
                                                                                                                                                              • int $term_taxonomy_id - The term_taxonomy_id of the term and taxonomy to create a relation with.
                                                                                                                                                              • +
                                                                                                                                                              • int $term_order - Defaults to 0.
                                                                                                                                                              + +

                                                                                                                                                              haveTransientInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a transient in the database. If the value is an array or an object then the value will be serialized. Since the transients are set in the context of tests it's not possible to set an expiration directly.

                                                                                                                                                              +
                                                                                                                                                              // Store an array in the `tweets` transient.
                                                                                                                                                              +  $I->haveTransientInDatabase('tweets', $tweets);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $transient - The transient name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $value - The transient value.
                                                                                                                                                              + +

                                                                                                                                                              haveUserCapabilitiesInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets a user capabilities in the database.

                                                                                                                                                              +
                                                                                                                                                              // Assign one user a role in a blog.
                                                                                                                                                              +  $blogId = $I->haveBlogInDatabase('test');
                                                                                                                                                              +  $editor = $I->haveUserInDatabase('luca', 'editor');
                                                                                                                                                              +  $capsIds = $I->haveUserCapabilitiesInDatabase($editor, [$blogId => 'editor']);
                                                                                                                                                              +  // Assign a user two roles in blog 1.
                                                                                                                                                              +  $capsIds = $I->haveUserCapabilitiesInDatabase($userId, ['editor', 'subscriber']);
                                                                                                                                                              +  // Assign one user different roles in different blogs.
                                                                                                                                                              +  $capsIds = $I->haveUserCapabilitiesInDatabase($userId, [$blogId1 => 'editor', $blogId2 => 'author']);
                                                                                                                                                              +  // Assign a user a role and an additional capability in blog 1.
                                                                                                                                                              +  $I->haveUserCapabilitiesInDatabase($userId, ['editor' => true, 'edit_themes' => true]);
                                                                                                                                                              +  // Assign a user a mix of roles and capabilities in different blogs.
                                                                                                                                                              +  $capsIds = $I->haveUserCapabilitiesInDatabase(
                                                                                                                                                              +  $userId,
                                                                                                                                                              +  [
                                                                                                                                                              +  $blogId1 => ['editor' => true, 'edit_themes' => true],
                                                                                                                                                              +  $blogId2 => ['administrator' => true, 'edit_themes' => false]
                                                                                                                                                              +  ]
                                                                                                                                                              +  );
                                                                                                                                                              +  associative array of blog IDs/roles for a multisite
                                                                                                                                                              +  installation (e.g. `[1 => 'administrator`, 2 =>
                                                                                                                                                              +  'subscriber']`).
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $userId - The ID of the user to set the capabilities of.
                                                                                                                                                              • +
                                                                                                                                                              • string/\Codeception\Module\array/\Codeception\Module\array $role - Either a role string (e.g. administrator),an
                                                                                                                                                              + +

                                                                                                                                                              haveUserInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Inserts a user and its meta in the database. defaults to subscriber. If more than one role is specified, then the first role in the list will be the user primary role and the wp_user_level will be set to that role. in the users and usermeta table.

                                                                                                                                                              +
                                                                                                                                                              // Create an editor user in blog 1 w/ specific email.
                                                                                                                                                              +  $userId = $I->haveUserInDatabase('luca', 'editor', ['user_email' => 'luca@example.org']);
                                                                                                                                                              +  // Create a subscriber user in blog 1.
                                                                                                                                                              +  $subscriberId = $I->haveUserInDatabase('subscriber');
                                                                                                                                                              +  // Create a user editor in blog 1, author in blog 2, administrator in blog 3.
                                                                                                                                                              +  $userWithMeta = $I->haveUserInDatabase('luca',
                                                                                                                                                              +  [
                                                                                                                                                              +  1 => 'editor',
                                                                                                                                                              +  2 => 'author',
                                                                                                                                                              +  3 => 'administrator'
                                                                                                                                                              +  ], [
                                                                                                                                                              +  'user_email' => 'luca@example.org'
                                                                                                                                                              +  'meta' => ['a meta_key' => 'a_meta_value']
                                                                                                                                                              +  ]
                                                                                                                                                              +  );
                                                                                                                                                              +  // Create editor in blog 1 w/ `edit_themes` cap, author in blog 2, admin in blog 3 w/o `manage_options` cap.
                                                                                                                                                              +  $userWithMeta = $I->haveUserInDatabase('luca',
                                                                                                                                                              +  [
                                                                                                                                                              +  1 => ['editor', 'edit_themes'],
                                                                                                                                                              +  2 => 'author',
                                                                                                                                                              +  3 => ['administrator' => true, 'manage_options' => false]
                                                                                                                                                              +  ]
                                                                                                                                                              +  );
                                                                                                                                                              +  // Create a user w/o role.
                                                                                                                                                              +  $userId = $I->haveUserInDatabase('luca', '');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $user_login - The user login name.
                                                                                                                                                              • +
                                                                                                                                                              • string/string/\Codeception\Module\array $role - The user role slug(s), e.g. administrator or ['author', 'editor'];
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $overrides - An associative array of column names and values overriding defaults
                                                                                                                                                              + +

                                                                                                                                                              haveUserLevelsInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the user access level meta in the database for a user. IDs/roles for a multisite installation (e.g. [1 => 'administrator, 2 => 'subscriber']`).

                                                                                                                                                              +
                                                                                                                                                              $userId = $I->haveUserInDatabase('luca', 'editor');
                                                                                                                                                              +  $moreThanAnEditorLessThanAnAdmin = 8;
                                                                                                                                                              +  $I->haveUserLevelsInDatabase($userId, $moreThanAnEditorLessThanAnAdmin);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $userId - The ID of the user to set the level for.
                                                                                                                                                              • +
                                                                                                                                                              • \Codeception\Module\array/string $role - Either a role string (e.g. administrator) or an array of blog
                                                                                                                                                              + +

                                                                                                                                                              haveUserMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets a user meta in the database.

                                                                                                                                                              +
                                                                                                                                                              $userId = $I->haveUserInDatabase('luca', 'editor');
                                                                                                                                                              +  $I->haveUserMetaInDatabase($userId, 'karma', 23);
                                                                                                                                                              +  values will trigger the insertion of multiple rows.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $userId - The user ID.
                                                                                                                                                              • +
                                                                                                                                                              • string $meta_key - The meta key to set the value for.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $meta_value - Either a single value or an array of values; objects will be serialized while array of
                                                                                                                                                              + +

                                                                                                                                                              importSql

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Loads a set SQL code lines in the current database.

                                                                                                                                                              +
                                                                                                                                                              // Import a SQL string.
                                                                                                                                                              +  $I->importSql([$sqlString]);
                                                                                                                                                              +  // Import a set of SQL strings.
                                                                                                                                                              +  $I->importSql($sqlStrings);
                                                                                                                                                              +  // Import a prepared set of SQL strings.
                                                                                                                                                              +  $preparedSqlStrings = array_map(function($line){
                                                                                                                                                              +  return str_replace('{{date}}', date('Y-m-d H:i:s'), $line);
                                                                                                                                                              +  }, $sqlTemplate);
                                                                                                                                                              +  $I->importSql($preparedSqlStrings);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $sql - The SQL strings to load.
                                                                                                                                                              + +

                                                                                                                                                              importSqlDumpFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Import the SQL dump file if populate is enabled.

                                                                                                                                                              +
                                                                                                                                                              // Import a dump file passing the absolute path.
                                                                                                                                                              +  $I->importSqlDumpFile(codecept_data_dir('dumps/start.sql'));
                                                                                                                                                              +  Specifying a dump file that file will be imported.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/null $dumpFile - The dump file that should be imported in place of the default one.
                                                                                                                                                              + +

                                                                                                                                                              seeAttachmentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for an attachment in the database.

                                                                                                                                                              +
                                                                                                                                                              $url = 'https://example.org/images/foo.png';
                                                                                                                                                              +  $I->seeAttachmentInDatabase(['guid' => $url]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeBlogInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a blog in the blogs table.

                                                                                                                                                              +
                                                                                                                                                              // Search for a blog by `blog_id`.
                                                                                                                                                              +  $I->seeBlogInDatabase(['blog_id' => 23]);
                                                                                                                                                              +  // Search for all blogs on a path.
                                                                                                                                                              +  $I->seeBlogInDatabase(['path' => '/sub-path/']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeCommentInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a comment in the database. Will look up the "comments" table.

                                                                                                                                                              +
                                                                                                                                                              $I->seeCommentInDatabase(['comment_ID' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeCommentMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a comment meta value is in the database. Will look up the "commentmeta" table.

                                                                                                                                                              +
                                                                                                                                                              // Assert a specified meta for a comment exists.
                                                                                                                                                              +  $I->seeCommentMetaInDatabase(['comment_ID' => $commentId, 'meta_key' => 'karma', 'meta_value' => 23]);
                                                                                                                                                              +  // Assert the comment has at least one meta set.
                                                                                                                                                              +  $I->seeCommentMetaInDatabase(['comment_ID' => $commentId]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeLinkInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a link in the links table of the database.

                                                                                                                                                              +
                                                                                                                                                              // Asserts a link exists by name.
                                                                                                                                                              +  $I->seeLinkInDatabase(['link_name' => 'my-link']);
                                                                                                                                                              +  // Asserts at least one link exists for the user.
                                                                                                                                                              +  $I->seeLinkInDatabase(['link_owner' => $userId]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks if an option is in the database for the current blog, either by criteria or by name and value. If checking for an array or an object then the serialized version will be checked for.

                                                                                                                                                              +
                                                                                                                                                              // Checks an option is in the database.
                                                                                                                                                              +  $I->seeOptionInDatabase('tables_version');
                                                                                                                                                              +  // Checks an option is in the database and has a specific value.
                                                                                                                                                              +  $I->seeOptionInDatabase('tables_version', '1.0');
                                                                                                                                                              +  $I->seeOptionInDatabase(['option_name' => 'tables_version', 'option_value' => 1.0']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/string $criteriaOrName - An array of search criteria or the option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                                                                                                                              + +

                                                                                                                                                              seePageInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a page in the database.

                                                                                                                                                              +
                                                                                                                                                              // Asserts a page with an exists in the database.
                                                                                                                                                              +  $I->seePageInDatabase(['ID' => 23]);
                                                                                                                                                              +  // Asserts a page with a slug and ID exists in the database.
                                                                                                                                                              +  $I->seePageInDatabase(['post_title' => 'Test Page', 'ID' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seePostInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a post in the database.

                                                                                                                                                              +
                                                                                                                                                              // Assert a post exists in the database.
                                                                                                                                                              +  $I->seePostInDatabase(['ID' => 23]);
                                                                                                                                                              +  // Assert a post with a slug and ID exists in the database.
                                                                                                                                                              +  $I->seePostInDatabase(['post_content' => 'test content', 'ID' => 23]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seePostMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a post meta value in the database for the current blog. If the meta_value is an object or an array then the check will be made for serialized values.

                                                                                                                                                              +
                                                                                                                                                              $postId = $I->havePostInDatabase(['meta_input' => ['foo' => 'bar']];
                                                                                                                                                              +  $I->seePostMetaInDatabase(['post_id' => '$postId', 'meta_key' => 'foo']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seePostWithTermInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a post to term relation exists in the database. The method will check the "term_relationships" table.

                                                                                                                                                              +
                                                                                                                                                              $fiction = $I->haveTermInDatabase('fiction', 'genre');
                                                                                                                                                              +  $postId = $I->havePostInDatabase(['tax_input' => ['genre' => ['fiction']]]);
                                                                                                                                                              +  $I->seePostWithTermInDatabase($postId, $fiction['term_taxonomy_id']);
                                                                                                                                                              +  passed this parameter will be interpreted as a `term_id`, else as a
                                                                                                                                                              +  the
                                                                                                                                                              +  term order.
                                                                                                                                                              +  to build a `taxonomy_term_id` from the `term_id`.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $post_id - The post ID.
                                                                                                                                                              • +
                                                                                                                                                              • int $term_taxonomy_id - The term term_id or term_taxonomy_id; if the $taxonomy argument is
                                                                                                                                                              • +
                                                                                                                                                              • int/null $term_order - The order the term applies to the post, defaults to null to not use
                                                                                                                                                              • +
                                                                                                                                                              • string/null $taxonomy - The taxonomy the term_id is for; if passed this parameter will be used
                                                                                                                                                              + +

                                                                                                                                                              seeSiteOptionInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a site option is in the database.

                                                                                                                                                              +
                                                                                                                                                              // Check that the option is set in the database.
                                                                                                                                                              +  $I->seeSiteOptionInDatabase('foo_count');
                                                                                                                                                              +  // Check that the option is set and has a specific value.
                                                                                                                                                              +  $I->seeSiteOptionInDatabase('foo_count', 23);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/string $criteriaOrName - An array of search criteria or the option name.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - The optional value to try and match, only used if the option name is provided.
                                                                                                                                                              + +

                                                                                                                                                              seeSiteSiteTransientInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a site option is in the database.

                                                                                                                                                              +
                                                                                                                                                              // Check a transient exists.
                                                                                                                                                              +  $I->seeSiteSiteTransientInDatabase('total_counts');
                                                                                                                                                              +  // Check a transient exists and has a specific value.
                                                                                                                                                              +  $I->seeSiteSiteTransientInDatabase('total_counts', 23);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $key - The name of the transient to check for, w/o the _site_transient_ prefix.
                                                                                                                                                              • +
                                                                                                                                                              • mixed/null $value - If provided then the assertion will include the value.
                                                                                                                                                              + +

                                                                                                                                                              seeTableInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a table is in the database.

                                                                                                                                                              +
                                                                                                                                                              $options = $I->grabPrefixedTableNameFor('options');
                                                                                                                                                              +  $I->seeTableInDatabase($options);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $table - The full table name, including the table prefix.
                                                                                                                                                              + +

                                                                                                                                                              seeTermInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a term in the database. Looks up the terms and term_taxonomy prefixed tables. and the term_taxonomy tables.

                                                                                                                                                              +
                                                                                                                                                              $I->seeTermInDatabase(['slug' => 'genre--fiction']);
                                                                                                                                                              +  $I->seeTermInDatabase(['name' => 'Fiction', 'slug' => 'genre--fiction']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of criteria to search for the term, can be columns from the terms
                                                                                                                                                              + +

                                                                                                                                                              seeTermMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a term meta in the database.

                                                                                                                                                              +
                                                                                                                                                              list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
                                                                                                                                                              +  $I->haveTermMetaInDatabase($termId, 'rating', 4);
                                                                                                                                                              +  $I->seeTermMetaInDatabase(['term_id' => $termId,'meta_key' => 'rating', 'meta_value' => 4]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeTermRelationshipInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a term relationship in the database.

                                                                                                                                                              +
                                                                                                                                                              $postId = $I->havePostInDatabase(['tax_input' => ['category' => 'one']]);
                                                                                                                                                              +  $I->seeTermRelationshipInDatabase(['object_id' => $postId, 'term_taxonomy_id' => $oneTermTaxId]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeTermTaxonomyInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a taxonomy taxonomy in the database.

                                                                                                                                                              +
                                                                                                                                                              list($termId, $termTaxonomyId) = $I->haveTermInDatabase('fiction', 'genre');
                                                                                                                                                              +  $I->seeTermTaxonomyInDatabase(['term_id' => $termId, 'taxonomy' => 'genre']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeUserInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a user is in the database. The method will check the "users" table.

                                                                                                                                                              +
                                                                                                                                                              $I->seeUserInDatabase([
                                                                                                                                                              +  "user_email" => "test@example.org",
                                                                                                                                                              +  "user_login" => "login name"
                                                                                                                                                              +  ])
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              seeUserMetaInDatabase

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks for a user meta value in the database.

                                                                                                                                                              +
                                                                                                                                                              $I->seeUserMetaInDatabase(['user_id' => 23, 'meta_key' => 'karma']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \Codeception\Module\array/array $criteria - An array of search criteria.
                                                                                                                                                              + +

                                                                                                                                                              useBlog

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the blog to be used. This has nothing to do with WordPress switch_to_blog function, this code will affect the table prefixes used.

                                                                                                                                                              +
                                                                                                                                                              // Switch to the blog with ID 23.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Switch back to the main blog.
                                                                                                                                                              +  $I->useMainBlog();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The ID of the blog to use.
                                                                                                                                                              + +

                                                                                                                                                              useMainBlog

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the current blog to the main one (blog_id 1).

                                                                                                                                                              +
                                                                                                                                                              // Switch to the blog with ID 23.
                                                                                                                                                              +  $I->useBlog(23);
                                                                                                                                                              +  // Switch back to the main blog.
                                                                                                                                                              +  $I->useMainBlog();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              useTheme

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the current theme options.

                                                                                                                                                              +
                                                                                                                                                              $I->useTheme('twentyseventeen');
                                                                                                                                                              +  $I->useTheme('child-of-twentyseventeen', 'twentyseventeen');
                                                                                                                                                              +  $I->useTheme('acme', 'acme', 'Acme Theme');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $stylesheet - The theme stylesheet slug, e.g. twentysixteen.
                                                                                                                                                              • +
                                                                                                                                                              • string $template - The theme template slug, e.g. twentysixteen, defaults to $stylesheet.
                                                                                                                                                              • +
                                                                                                                                                              • string $themeName - The theme name, e.g. Acme, defaults to the "title" version of
                                                                                                                                                              + +

                                                                                                                                                              This class extends \Codeception\Module\Db

                                                                                                                                                              +

                                                                                                                                                              This class implements \Codeception\Lib\Interfaces\Db

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPFilesystem/index.html b/v3/modules/WPFilesystem/index.html new file mode 100644 index 000000000..91bce6faf --- /dev/null +++ b/v3/modules/WPFilesystem/index.html @@ -0,0 +1,3798 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPFilesystem - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WPFilesystem module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in acceptance and functional tests, see levels of testing for more information.
                                                                                                                                                              +This module extends the Filesystem module adding WordPress-specific configuration parameters and methods.
                                                                                                                                                              +The module provides methods to read, write and update the WordPress filesystem directly, without relying on WordPress methods, using WordPress functions or triggering WordPress filters.
                                                                                                                                                              +This module also provides methods to scaffold plugins and themes on the fly in the context of tests and auto-remove them after each test.

                                                                                                                                                              +

                                                                                                                                                              Module requirements for Codeception 4.0+

                                                                                                                                                              +

                                                                                                                                                              This module requires the codeception/module-filesystem Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                              +

                                                                                                                                                              To install the package run:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev codeception/module-filesystem:^1.0
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • wpRootFolder required The absolute, or relative to the project root folder, path to the root WordPress installation folder. The WordPress installation root folder is the one that contains the wp-load.php file.
                                                                                                                                                              • +
                                                                                                                                                              • themes - defaults to /wp-content/themes; the path, relative to the the WordPress installation root folder, to the themes folder.
                                                                                                                                                              • +
                                                                                                                                                              • plugins - defaults to /wp-content/plugins; the path, relative to the WordPress installation root folder, to the plugins folder.
                                                                                                                                                              • +
                                                                                                                                                              • mu-plugins - defaults to wp-content/mu-plugins; the path, relative to the WordPress installation root folder, to the must-use plugins folder.
                                                                                                                                                              • +
                                                                                                                                                              • uploads - defaults to /wp-content/uploads; the path, relative to the WordPress installation root folder, to the uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                              modules:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - WPFilesystem
                                                                                                                                                              +    config:
                                                                                                                                                              +        WPFilesystem:
                                                                                                                                                              +            wpRootFolder: "/var/www/wordpress"
                                                                                                                                                              +
                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              + + +

                                                                                                                                                              amInMuPluginPath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the current working folder to a folder in a mu-plugin.

                                                                                                                                                              +
                                                                                                                                                              $I->amInMuPluginPath('mu-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - The path to the folder, relative to the mu-plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              amInPluginPath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the current working folder to a folder in a plugin.

                                                                                                                                                              +
                                                                                                                                                              $I->amInPluginPath('my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - The folder path, relative to the root uploads folder, to change to.
                                                                                                                                                              + +

                                                                                                                                                              amInThemePath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Sets the current working folder to a folder in a theme.

                                                                                                                                                              +
                                                                                                                                                              $I->amInThemePath('my-theme');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - The path to the theme folder, relative to themes root folder.
                                                                                                                                                              + +

                                                                                                                                                              amInUploadsPath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Enters, changing directory, to the uploads folder in the local filesystem.

                                                                                                                                                              +
                                                                                                                                                              $I->amInUploadsPath('/logs');
                                                                                                                                                              +  $I->seeFileFound('shop.log');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - The path, relative to the site uploads folder.
                                                                                                                                                              + +

                                                                                                                                                              cleanMuPluginDir

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Cleans, emptying it, a folder in a mu-plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->cleanMuPluginDir('mu-plugin1/foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $dir - The path to the directory, relative to the mu-plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              cleanPluginDir

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Cleans, emptying it, a folder in a plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->cleanPluginDir('my-plugin/foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $dir - The path to the folder, relative to the plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              cleanThemeDir

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Clears, emptying it, a folder in a theme folder.

                                                                                                                                                              +
                                                                                                                                                              $I->cleanThemeDir('my-theme/foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $dir - The path to the folder, relative to the themese root folder.
                                                                                                                                                              + +

                                                                                                                                                              cleanUploadsDir

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Clears a folder in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->cleanUploadsDir('some/folder');
                                                                                                                                                              +  $I->cleanUploadsDir('some/folder', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $dir - The path to the directory to delete, relative to the uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int/[\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                              + +

                                                                                                                                                              copyDirToMuPlugin

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Copies a folder to a folder in a mu-plugin.

                                                                                                                                                              +
                                                                                                                                                              $I->copyDirToMuPlugin(codecept_data_dir('foo'), 'mu-plugin/foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $src - The path to the source file to copy.
                                                                                                                                                              • +
                                                                                                                                                              • string $pluginDst - The path to the destination folder, relative to the mu-plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              copyDirToPlugin

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Copies a folder to a folder in a plugin.

                                                                                                                                                              +
                                                                                                                                                              // Copy the 'foo' folder to the 'foo' folder in the plugin.
                                                                                                                                                              +  $I->copyDirToPlugin(codecept_data_dir('foo'), 'my-plugin/foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $src - The path to the source directory to copy.
                                                                                                                                                              • +
                                                                                                                                                              • string $pluginDst - The destination path, relative to the plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              copyDirToTheme

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Copies a folder in a theme folder.

                                                                                                                                                              +
                                                                                                                                                              $I->copyDirToTheme(codecept_data_dir('foo'), 'my-theme');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $src - The path to the source file.
                                                                                                                                                              • +
                                                                                                                                                              • string $themeDst - The path to the destination folder, relative to the themes root folder.
                                                                                                                                                              + +

                                                                                                                                                              copyDirToUploads

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Copies a folder to the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo');
                                                                                                                                                              +  $I->copyDirToUploads(codecept_data_dir('foo'), 'uploadsFoo', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $src - The path to the source file, relative to the current uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $dst - The path to the destination file, relative to the current uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int/[\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                              + +

                                                                                                                                                              deleteMuPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Deletes a file in a mu-plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->deleteMuPluginFile('mu-plugin1/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the mu-plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              deletePluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Deletes a file in a plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->deletePluginFile('my-plugin/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The folder path, relative to the plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              deleteThemeFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Deletes a file in a theme folder.

                                                                                                                                                              +
                                                                                                                                                              $I->deleteThemeFile('my-theme/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file to delete, relative to the themes root folder.
                                                                                                                                                              + +

                                                                                                                                                              deleteUploadedDir

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Deletes a dir in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->deleteUploadedDir('folder');
                                                                                                                                                              +  $I->deleteUploadedDir('folder', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $dir - The path to the directory to delete, relative to the uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int/[\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                              + +

                                                                                                                                                              deleteUploadedFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Deletes a file in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->deleteUploadedFile('some-file.txt');
                                                                                                                                                              +  $I->deleteUploadedFile('some-file.txt', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeInMuPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in a mu-plugin folder does not contain a string.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the mu-plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The contents to check the file for.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeInPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in a plugin folder does not contain a string.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeInPluginFile('my-plugin/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The contents to check the file for.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeInThemeFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in a theme folder does not contain a string.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeInThemeFile('my-theme/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The contents to check the file for.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeInUploadedFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in the uploads folder does contain a string. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeInUploadedFile('some-file.txt', 'foo');
                                                                                                                                                              +  $I->dontSeeInUploadedFile('some-file.txt','foo', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The not expected file contents or part of them.
                                                                                                                                                              • +
                                                                                                                                                              • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeMuPluginFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file is not found in a mu-plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeMuPluginFileFound('mu-plugin1/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the mu-plugins folder.
                                                                                                                                                              + +

                                                                                                                                                              dontSeePluginFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file is not found in a plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeePluginFileFound('my-plugin/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeThemeFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file is not found in a theme folder.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeThemeFileFound('my-theme/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                              + +

                                                                                                                                                              dontSeeUploadedFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks thata a file does not exist in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->dontSeeUploadedFileFound('some-file.txt');
                                                                                                                                                              +  $I->dontSeeUploadedFileFound('some-file.txt','today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                              + +

                                                                                                                                                              getBlogUploadsPath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the absolute path to a blog uploads folder or file.

                                                                                                                                                              +
                                                                                                                                                              $blogId = $I->haveBlogInDatabase('test');
                                                                                                                                                              +  $testTodayUploads = $I->getBlogUploadsPath($blogId);
                                                                                                                                                              +  $testLastMonthLogs = $I->getBlogUploadsPath($blogId, '/logs', '-1 month');
                                                                                                                                                              +  file or folder.
                                                                                                                                                              +  sub-folders in the year/month format; a UNIX timestamp or
                                                                                                                                                              +  a string supported by the `strtotime` function; defaults
                                                                                                                                                              +  to `now`.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $blogId - The blog ID to get the path for.
                                                                                                                                                              • +
                                                                                                                                                              • string $file - The path, relatitve to the blog uploads folder, to the
                                                                                                                                                              • +
                                                                                                                                                              • null/string/[\DateTime](http://php.net/manual/en/class.datetime.php)/[\DateTime](http://php.net/manual/en/class.datetime.php)Immutable $date - The date that should be used to build the uploads
                                                                                                                                                              + +

                                                                                                                                                              getUploadsPath

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the path to the specified uploads file of folder. Not providing a value for $file and $date will return the uploads folder path.

                                                                                                                                                              +
                                                                                                                                                              $todaysPath = $I->getUploadsPath();
                                                                                                                                                              +  $lastWeek = $I->getUploadsPath('', '-1 week');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The file path, relative to the uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • mixed $date - A string compatible with strtotime, a Unix timestamp or a Date object.
                                                                                                                                                              + +

                                                                                                                                                              getWpRootFolder

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the absolute path to WordPress root folder without trailing slash.

                                                                                                                                                              +
                                                                                                                                                              $rootFolder = $I->getWpRootFolder();
                                                                                                                                                              +  $I->assertFileExists($rootFolder . 'wp-load.php');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              haveMuPlugin

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates a mu-plugin file, including plugin header, in the mu-plugins folder. The code can not contain the opening '<?php' tag.

                                                                                                                                                              +
                                                                                                                                                              $code = 'echo "Hello world!"';
                                                                                                                                                              +  $I->haveMuPlugin('foo-mu-plugin.php', $code);
                                                                                                                                                              +  // Load the code from a file.
                                                                                                                                                              +  $code = file_get_contents(codecept_data_dir('code/mu-plugin.php'));
                                                                                                                                                              +  $I->haveMuPlugin('foo-mu-plugin.php', $code);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $filename - The path to the file to create, relative to the plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $code - The content of the plugin file with or without the opening PHP tag.
                                                                                                                                                              + +

                                                                                                                                                              havePlugin

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates a plugin file, including plugin header, in the plugins folder. The plugin is just created and not activated; the code can not contain the opening '<?php' tag.

                                                                                                                                                              +
                                                                                                                                                              $code = 'echo "Hello world!"';
                                                                                                                                                              +  $I->havePlugin('foo/plugin.php', $code);
                                                                                                                                                              +  // Load the code from a file.
                                                                                                                                                              +  $code = file_get_contents(codecept_data_dir('code/plugin.php'));
                                                                                                                                                              +  $I->havePlugin('foo/plugin.php', $code);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - The path to the file to create, relative to the plugins folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $code - The content of the plugin file with or without the opening PHP tag.
                                                                                                                                                              + +

                                                                                                                                                              haveTheme

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates a theme file structure, including theme style file and index, in the themes folder. The theme is just created and not activated; the code can not contain the opening '<?php' tag.

                                                                                                                                                              +
                                                                                                                                                              $code = 'sayHi();';
                                                                                                                                                              +  $functionsCode  = 'function sayHi(){echo "Hello world";};';
                                                                                                                                                              +  $I->haveTheme('foo', $indexCode, $functionsCode);
                                                                                                                                                              +  // Load the code from a file.
                                                                                                                                                              +  $indexCode = file_get_contents(codecept_data_dir('code/index.php'));
                                                                                                                                                              +  $functionsCode = file_get_contents(codecept_data_dir('code/functions.php'));
                                                                                                                                                              +  $I->haveTheme('foo', $indexCode, $functionsCode);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $folder - The path to the theme to create, relative to the themes root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $indexFileCode - The content of the theme index.php file with or without the opening PHP tag.
                                                                                                                                                              • +
                                                                                                                                                              • string $functionsFileCode - The content of the theme functions.php file with or without the opening PHP tag.
                                                                                                                                                              + +

                                                                                                                                                              makeUploadsDir

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Creates an empty folder in the WordPress installation uploads folder.

                                                                                                                                                              +
                                                                                                                                                              $logsDir = $I->makeUploadsDir('logs/acme');
                                                                                                                                                              +  to create.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - The path, relative to the WordPress installation uploads folder, of the folder
                                                                                                                                                              + +

                                                                                                                                                              openUploadedFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Opens a file in the the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->openUploadedFile('some-file.txt');
                                                                                                                                                              +  $I->openUploadedFile('some-file.txt', 'time');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $filename - The path to the file, relative to the current uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int/[\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                              + +

                                                                                                                                                              seeInMuPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in a mu-plugin folder contains a string.

                                                                                                                                                              +
                                                                                                                                                              $I->seeInMuPluginFile('mu-plugin1/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path the file, relative to the mu-plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The contents to check the file for.
                                                                                                                                                              + +

                                                                                                                                                              seeInPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in a plugin folder contains a string.

                                                                                                                                                              +
                                                                                                                                                              $I->seeInPluginFile('my-plugin/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The contents to check the file for.
                                                                                                                                                              + +

                                                                                                                                                              seeInThemeFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in a theme folder contains a string.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +  $I->seeInThemeFile('my-theme/some-file.txt', 'foo');
                                                                                                                                                              +  ?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The contents to check the file for.
                                                                                                                                                              + +

                                                                                                                                                              seeInUploadedFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file in the uploads folder contains a string. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->seeInUploadedFile('some-file.txt', 'foo');
                                                                                                                                                              +  $I->seeInUploadedFile('some-file.txt','foo', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $contents - The expected file contents or part of them.
                                                                                                                                                              • +
                                                                                                                                                              • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                              + +

                                                                                                                                                              seeMuPluginFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file is found in a mu-plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->seeMuPluginFileFound('mu-plugin1/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the mu-plugins folder.
                                                                                                                                                              + +

                                                                                                                                                              seePluginFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file is found in a plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->seePluginFileFound('my-plugin/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to thep plugins root folder.
                                                                                                                                                              + +

                                                                                                                                                              seeThemeFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that a file is found in a theme folder.

                                                                                                                                                              +
                                                                                                                                                              $I->seeThemeFileFound('my-theme/some-file.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the themes root folder.
                                                                                                                                                              + +

                                                                                                                                                              seeUploadedFileFound

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks if file exists in the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->seeUploadedFileFound('some-file.txt');
                                                                                                                                                              +  $I->seeUploadedFileFound('some-file.txt','today');
                                                                                                                                                              +  ?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $filename - The file path, relative to the uploads folder or the current folder.
                                                                                                                                                              • +
                                                                                                                                                              • string/int $date - A string compatible with strtotime or a Unix timestamp.
                                                                                                                                                              + +

                                                                                                                                                              writeToMuPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Writes a file in a mu-plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->writeToMuPluginFile('mu-plugin1/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the destination file, relative to the mu-plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $data - The data to write to the file.
                                                                                                                                                              + +

                                                                                                                                                              writeToPluginFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Writes a file in a plugin folder.

                                                                                                                                                              +
                                                                                                                                                              $I->writeToPluginFile('my-plugin/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the plugins root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $data - The data to write in the file.
                                                                                                                                                              + +

                                                                                                                                                              writeToThemeFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Writes a string to a file in a theme folder.

                                                                                                                                                              +
                                                                                                                                                              $I->writeToThemeFile('my-theme/some-file.txt', 'foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $file - The path to the file, relative to the themese root folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $data - The data to write to the file.
                                                                                                                                                              + +

                                                                                                                                                              writeToUploadedFile

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Writes a string to a file in the the uploads folder. The date argument can be a string compatible with strtotime or a Unix timestamp that will be used to build the Y/m uploads subfolder path.

                                                                                                                                                              +
                                                                                                                                                              $I->writeToUploadedFile('some-file.txt', 'foo bar');
                                                                                                                                                              +  $I->writeToUploadedFile('some-file.txt', 'foo bar', 'today');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $filename - The path to the destination file, relative to the current uploads folder.
                                                                                                                                                              • +
                                                                                                                                                              • string $data - The data to write to the file.
                                                                                                                                                              • +
                                                                                                                                                              • string/int/[\DateTime](http://php.net/manual/en/class.datetime.php) $date - The date of the uploads to delete, will default to now.
                                                                                                                                                              + +

                                                                                                                                                              This class extends \Codeception\Module\Filesystem

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPLoader/index.html b/v3/modules/WPLoader/index.html new file mode 100644 index 000000000..82a6ac128 --- /dev/null +++ b/v3/modules/WPLoader/index.html @@ -0,0 +1,3427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPLoader - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WPLoader module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in integration tests, see levels of testing for more information, to bootstrap WordPress code in the context of the tests.
                                                                                                                                                              +Setting the loadOnly parameter to true the module can be additionally used in acceptance and functional tests to access WordPress code in the tests context.
                                                                                                                                                              +This module is a wrapper around the functionalities provided by the WordPress PHPUnit Core test suite, as such it provides the same method and facilities.
                                                                                                                                                              +The parameters provided to the module duplicate the ones used in the WordPress configuration file: the WPLoader module will not bootstrap WordPress using the wp-config.php file, it will define and use its own WordPress configuration built from the module parameters.

                                                                                                                                                              +

                                                                                                                                                              Everything happens in a transaction

                                                                                                                                                              +

                                                                                                                                                              When used to bootstrap and install WordPress (loadOnly: false) exactly as the the WordPress PHPUnit Core test suite it is based on, this module will operate any change to the database in a transaction.
                                                                                                                                                              +This means that, in the context of integration tests, the result of any write or delete operation done during the tests will be rolled back at the end of each test method; this is done for a number of reasons like performance and tests independence.
                                                                                                                                                              +Inspection of the database during tests, e.g. stopping execution using XDebug, will not show any change in the database. +Keep this in mind while trying to debug integration tests using the WPLoader module.
                                                                                                                                                              +When configured to only load WordPress (loadOnly: true) then any database operation will be committed and written to the database.

                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • wpRootFolder required The absolute, or relative to the project root folder, path to the root WordPress installation folder. The WordPress installation root folder is the one that contains the wp-load.php file.
                                                                                                                                                              • +
                                                                                                                                                              • dbName required - The name of the database used by the WordPress installation, same as the DB_NAME constant.
                                                                                                                                                              • +
                                                                                                                                                              • dbHost required - The host of the database used by the WordPress installation, same as the DB_HOST constant. If the database is accessible (as is the case on the latest version of [Local by Flywheel][http://localwp.com]) via unix socket, then the string to insert here should look like this localhost:/path/to/the/mysql.sock.
                                                                                                                                                              • +
                                                                                                                                                              • dbUser required - The user of the database used by the WordPress installation, same as the DB_USER constant.
                                                                                                                                                              • +
                                                                                                                                                              • dbPassword required - The password of the database used by the WordPress installation, same as DB_PASSWORD constant.
                                                                                                                                                              • +
                                                                                                                                                              • loadOnly - defaults to false; whether to only load WordPress, without bootstrapping a fresh installation for tests or not. Read more in the "Using WPLoader in acceptance and functional tests" section. If this parameter is set to true the following parameters will not apply.
                                                                                                                                                              • +
                                                                                                                                                              • isolatedInstall - defaults to true, whether to install and bootstrap the WordPress installation in a secondary PHP thread for thread safety or not. Maintained for back-compatibility purposes with wp-browser first versions: to get a replica of the bootstrap process used by WordPress Core PHPUnit tests leave this to true.
                                                                                                                                                              • +
                                                                                                                                                              • installationTableHandling - defaults to empty; it controls how tables created by WordPress and plugins will be handled during the installation of WordPress during tests. By default tables will be emptied of any content, but some plugins might require tables to be dropped before WordPress is installed and after plugins are activated (this used to be the default behavior). Supported values are drop to drop the tables, empty to just empty the tables and let to do nothing about the tables. If you get errors from database queries while the WPLoader module installs the tests, then try changing this parameter value.
                                                                                                                                                              • +
                                                                                                                                                              • wpDebug - defaults to true, the value the WP_DEBUG constant will be set to.
                                                                                                                                                              • +
                                                                                                                                                              • multisite - defaults to false, the value the MULTISITE constant will be set to.
                                                                                                                                                              • +
                                                                                                                                                              • skipPluggables - defaults to false, if set to true will skip the definition of pluggable functions.
                                                                                                                                                              • +
                                                                                                                                                              • dbCharset - defaults to utf8, the value the DB_CHARSET constant will be set to.
                                                                                                                                                              • +
                                                                                                                                                              • dbCollate - defaults to an empty string, the value the DB_COLLATE constant will be set to.
                                                                                                                                                              • +
                                                                                                                                                              • tablePrefix - defaults to wptests_, the value the $table_prefix variable will be set to.
                                                                                                                                                              • +
                                                                                                                                                              • domain - defaults to example.org, the domain of the WordPress site to scaffold for the tests.
                                                                                                                                                              • +
                                                                                                                                                              • adminEmail - defaults to admin@example.org, the email of the WordPress site to scaffold for the tests.
                                                                                                                                                              • +
                                                                                                                                                              • title - defaults to Test Blog, the title of the WordPress site to scaffolded for the tests.
                                                                                                                                                              • +
                                                                                                                                                              • phpBinary - defaults to php, the PHP binary the host machine will have to use to bootstrap and load the test WordPress installation.
                                                                                                                                                              • +
                                                                                                                                                              • language - defaults to an empty string, the language of the WordPress installation to scaffold.
                                                                                                                                                              • +
                                                                                                                                                              • configFile - defaults to an empty string, an additional configuration file to include before loading WordPress. Any instruction in this fill will run before any WordPress file is included.
                                                                                                                                                              • +
                                                                                                                                                              • contentFolder - defaults to an empty string; the path, relative to the wpRootFolder or absolute, to the content folder if different from the default one or the one defined by the WP_CONTENT_DIR constant; if the WP_CONTENT_DIR constant is defined in a config file (see the configFile parameter) this will be ignored.
                                                                                                                                                              • +
                                                                                                                                                              • pluginsFolder - defaults to an empty string; the path, relative to the wpRootFolder or absolute, to the plugins folder from the wpRootFolder if different from the default one or the one defined by the WP_PLUGIN_DIR constant; if the WP_PLUGIN_DIR constant is defined in a config file (see the configFile parameter) this will be ignored.
                                                                                                                                                              • +
                                                                                                                                                              • plugins - defaults to an empty array; a list of plugins that should be loaded before any test case runs and after mu-plugins have been loaded; these should be defined in the folder/plugin-file.php format.
                                                                                                                                                              • +
                                                                                                                                                              • activateplugins - defaults to an empty array, a list of plugins that will be activated before any test case runs and after wordpress is fully loaded and set up; these should be defined in the folder/plugin-file.php format; when the multisite option is set to true the plugins will be network activated during the installation.
                                                                                                                                                              • +
                                                                                                                                                              • activatePluginsSilently - defaults to an empty array, a list of plugins that will be silently activated, thus not firing the plugins' activation actions, before any test case runs and after wordpress is fully loaded and set up; these should be defined in the folder/plugin-file.php format; when the multisite option is set to true the plugins will be network activated during the installation.
                                                                                                                                                              • +
                                                                                                                                                              • bootstrapActions - defaults to an empty string, a list of actions, static functions or functions that should be called after before any test case runs, after plugins have been loaded and activated; static functions should be defined in the YAML array format: +
                                                                                                                                                                bootstrapActions:
                                                                                                                                                                +    - action_one
                                                                                                                                                                +    - action_two
                                                                                                                                                                +    - [MyClass, myStaticMethod]
                                                                                                                                                                +    - my_function
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                theme - defaults to an empty string, the theme that should be activated for the tests; if a string is passed then both template and stylesheet options will be set to the passed value; if an array is passed then the template and stylesheet will be set in that order:

                                                                                                                                                                +
                                                                                                                                                                theme: my-theme
                                                                                                                                                                +
                                                                                                                                                                +

                                                                                                                                                                The theme will be set to my-theme.

                                                                                                                                                                +
                                                                                                                                                                theme: [ parent, child ]
                                                                                                                                                                +
                                                                                                                                                                +

                                                                                                                                                                The template will be set to parent, the stylesheet will be set to child.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              A word of caution: right now the only way to write tests able to take advantage of the suite is to use the WP_UnitTestCase test case class; while the module will load fine and will raise no problems WP_UnitTestCase will take care of handling the database as intended and using another test case class will almost certainly result in an error if the test case defines more than one test method.

                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                                modules:
                                                                                                                                                              +      enabled:
                                                                                                                                                              +          - WPLoader
                                                                                                                                                              +      config:
                                                                                                                                                              +          WPLoader:
                                                                                                                                                              +              multisite: false
                                                                                                                                                              +              wpRootFolder: "/Users/luca/www/wordpress"
                                                                                                                                                              +              dbName: "wordpress_tests"
                                                                                                                                                              +              dbHost: "localhost"
                                                                                                                                                              +              dbUser: "root"
                                                                                                                                                              +              dbPassword: "password"
                                                                                                                                                              +              isolatedInstall: true
                                                                                                                                                              +              installationTableHandling: drop
                                                                                                                                                              +              tablePrefix: "wptests_"
                                                                                                                                                              +              domain: "wordrpess.localhost"
                                                                                                                                                              +              adminEmail: "admin@wordpress.localhost"
                                                                                                                                                              +              title: "Test Blog"
                                                                                                                                                              +              theme: my-theme
                                                                                                                                                              +              plugins: ['hello.php', 'my-plugin/my-plugin.php']
                                                                                                                                                              +              activatePlugins: ['hello.php', 'my-plugin/my-plugin.php']
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Usage in integration or "WordPress unit" tests

                                                                                                                                                              +

                                                                                                                                                              The most common use of this module is to run integration, or "WordPress unit" tests (see levels of testing for more information).

                                                                                                                                                              +

                                                                                                                                                              As a first step generate a WPTestCase using Codeception command-line utility (see the commands provided by wp-browser):

                                                                                                                                                              +
                                                                                                                                                              codecept generate:wpunit my_suite "Acme\User"
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Codeception will generate the tests/my_suite/Acme/UserTest.php class. +The class extends the Codeception\TestCase\WPTestCase class provided by wp-browser; this looks like a normal PHPUnit test case but has some perks due to it's mixed breed nature.
                                                                                                                                                              +Understanding them might help you work with it:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • WordPress is installed and configured for the tests before the test case is loaded; WordPress defined functions and classes (and those of the plugins and themes loaded with it) will be available in the setUpBeforeClass method.
                                                                                                                                                              • +
                                                                                                                                                              • WordPress is not loaded when PHPUnit will call the data provider methods; this means the post_provider method will generate a function not found exception when the test case runs as the WordPress defined methods are not loaded yet: +
                                                                                                                                                                public function post_provider(){
                                                                                                                                                                +        // `wp_insert_post` is loaded with WordPress and WordPress has not been loaded yet!
                                                                                                                                                                +        return [
                                                                                                                                                                +                [wp_insert_post(['post_title' => 'Test', 'post_status' => 'publish'])]
                                                                                                                                                                +        ];
                                                                                                                                                                +}
                                                                                                                                                                +
                                                                                                                                                                +public function test_posts($post_id){
                                                                                                                                                                +        $this->assertInstanceOf(WP_Post::class, get_post($post_id));
                                                                                                                                                                +}
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • WordPress is reset to an initial known state before each test runs; the database transaction is rolled back to wipe any data and tables you might have manipulated in the tests, the global space is cleaned. See Everything happens in a transaction.
                                                                                                                                                              • +
                                                                                                                                                              • This is a Codeception Unit test, as such it does provide access to the $this->tester property to access the methods defined in other modules loaded in the suite and to Codeception test doubles
                                                                                                                                                              • +
                                                                                                                                                              • This is a PhpUnit test case too; there are way too many testing functions to cover to report them here but, to highlight a few: mocking with Prophecy and the wealth of PHPUnit assertion methods.
                                                                                                                                                              • +
                                                                                                                                                              • This is kind of a WordPress Core suite test case; as such it provides access to its functions and to the often-overlooked static::factory() method; in this instance too there are too many methods to list them all but it's worth noting how easy it is to set up test fixtures with the factory: +
                                                                                                                                                                public function test_post_creation(){
                                                                                                                                                                +        $random_post_id = static::factory()->post->create();
                                                                                                                                                                +
                                                                                                                                                                +        $this->assertInstanceOf(WP_Post::class, get_post($random_post_id));
                                                                                                                                                                +}
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • The factory property can be accessed on the tester property too and will work the same way as if called using static::factory(): +
                                                                                                                                                                public function test_post_creation(){
                                                                                                                                                                +        $random_post_id = $this->tester->factory()->post->create();
                                                                                                                                                                +
                                                                                                                                                                +        $this->assertInstanceOf(WP_Post::class, get_post($random_post_id));
                                                                                                                                                                +}
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              WPLoader to only bootstrap WordPress

                                                                                                                                                              +

                                                                                                                                                              If the need is to just bootstrap the WordPress installation in the context of the tests variable scope then the WPLoader module loadOnly parameter should be set to true; this could be the case for functional tests in need to access WordPress provided methods, functions and values.
                                                                                                                                                              +An example configuration for the module in this mode is this one:

                                                                                                                                                              +
                                                                                                                                                                modules:
                                                                                                                                                              +      enabled:
                                                                                                                                                              +          - WPDb # BEFORE the WPLoader one!
                                                                                                                                                              +          - WPLoader # AFTER the WPDb one!
                                                                                                                                                              +      config:
                                                                                                                                                              +          WPDb:
                                                                                                                                                              +              dsn: 'mysql:host=localhost;dbname=wordpress'
                                                                                                                                                              +              user: 'root'
                                                                                                                                                              +              password: 'password'
                                                                                                                                                              +              dump: 'tests/_data/dump.sql'
                                                                                                                                                              +              populate: true
                                                                                                                                                              +              cleanup: true
                                                                                                                                                              +              waitlock: 10
                                                                                                                                                              +              url: 'http://wordpress.localhost'
                                                                                                                                                              +              urlReplacement: true
                                                                                                                                                              +              tablePrefix: 'wp_'
                                                                                                                                                              +          WPLoader:
                                                                                                                                                              +              loadOnly: true 
                                                                                                                                                              +              wpRootFolder: "/Users/User/www/wordpress"
                                                                                                                                                              +              dbName: "wpress-tests"
                                                                                                                                                              +              dbHost: "localhost"
                                                                                                                                                              +              dbUser: "root"
                                                                                                                                                              +              dbPassword: "root"
                                                                                                                                                              +              domain: "wordpress.localhost"
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              With reference to the table above the module will not take care of the test WordPress installation state before and after the tests, the installed and activated plugins, and theme.
                                                                                                                                                              +The module can be used in conjunction with a WPDb module to provide the tests with a WordPress installation suiting the tests at hand; when doing so please take care to list, in the suite configuration file modules section (see example above) the WPDb module before the WPLoader one.
                                                                                                                                                              +Codeception will initialize the modules in the same order they are listed in the modules section of the suite configuration file and the WPLoader module needs the database to be populated by the WPDb module before it runs! +As an example this is a correct suite configuration: +

                                                                                                                                                              modules:
                                                                                                                                                              +  enabled:
                                                                                                                                                              +      - WPDb # this before...
                                                                                                                                                              +      - WPLoader # ...this one.
                                                                                                                                                              +  config:
                                                                                                                                                              +      WPDb:
                                                                                                                                                              +        # ...
                                                                                                                                                              +      WPLoader:
                                                                                                                                                              +        loadOnly: true
                                                                                                                                                              +        # ... 
                                                                                                                                                              +

                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              + + +

                                                                                                                                                              debugWpActionFinal

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Debugs a single WordPress action final call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                              +
                                                                                                                                                              // Start debugging all WordPress actions final value.
                                                                                                                                                              +  add_action('all', [$this,'debugWpActionFinal']);
                                                                                                                                                              +  // Run some code firing actions and debug them.
                                                                                                                                                              +  // Stop debugging all WordPress actions final value.
                                                                                                                                                              +  remove_action('all', [$this,'debugWpActionFinal']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • mixed $args
                                                                                                                                                              + +

                                                                                                                                                              debugWpActionInitial

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Debugs a single WordPress action initial call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                              +
                                                                                                                                                              // Start debugging all WordPress actions initial value.
                                                                                                                                                              +  add_action('all', [$this,'debugWpActionInitial']);
                                                                                                                                                              +  // Run some code firing actions and debug them.
                                                                                                                                                              +  // Stop debugging all WordPress actions initial value.
                                                                                                                                                              +  remove_action('all', [$this,'debugWpActionInitial']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • mixed $args
                                                                                                                                                              + +

                                                                                                                                                              debugWpFilterFinal

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Debugs a single WordPress filter final call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                              +
                                                                                                                                                              // Start debugging all WordPress filters final value.
                                                                                                                                                              +  add_filter('all', [$this,'debugWpFilterFinal']);
                                                                                                                                                              +  // Run some code firing filters and debug them.
                                                                                                                                                              +  // Stop debugging all WordPress filters final value.
                                                                                                                                                              +  remove_filter('all', [$this,'debugWpFilterFinal']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • mixed $args
                                                                                                                                                              + +

                                                                                                                                                              debugWpFilterInitial

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Debugs a single WordPress filter initial call using Codeception debug functions. The output will show following the selected output verbosity (--debug and -vvv CLI options).

                                                                                                                                                              +
                                                                                                                                                              // Start debugging all WordPress filters initial value.
                                                                                                                                                              +  add_filter('all', [$this,'debugWpFilterInitial']);
                                                                                                                                                              +  // Run some code firing filters and debug them.
                                                                                                                                                              +  // Stop debugging all WordPress filters initial value.
                                                                                                                                                              +  remove_filter('all', [$this,'debugWpFilterInitial']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • mixed $args
                                                                                                                                                              + +

                                                                                                                                                              factory

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Accessor method to get the object storing the factories for things. This methods gives access to the same factories provided by the Core test suite.

                                                                                                                                                              +
                                                                                                                                                              $postId = $I->factory()->post->create();
                                                                                                                                                              +  $userId = $I->factory()->user->create(['role' => 'administrator']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              getContentFolder

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the absolute path to the WordPress content directory.

                                                                                                                                                              +
                                                                                                                                                              $content = $this->getContentFolder();
                                                                                                                                                              +  $themes = $this->getContentFolder('themes');
                                                                                                                                                              +  $twentytwenty = $this->getContentFolder('themes/twentytwenty');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - An optional path to append to the content directory absolute path.
                                                                                                                                                              + +

                                                                                                                                                              getPluginsFolder

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the absolute path to the plugins directory. The value will first look at the WP_PLUGIN_DIR constant, then the pluginsFolder configuration parameter and will, finally, look in the default path from the WordPress root directory.

                                                                                                                                                              +
                                                                                                                                                              $plugins = $this->getPluginsFolder();
                                                                                                                                                              +  $hello = $this->getPluginsFolder('hello.php');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $path - A relative path to append to te plugins directory absolute path.
                                                                                                                                                              + +

                                                                                                                                                              startWpFiltersDebug

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Starts the debug of all WordPress filters and actions. The method hook on all filters and actions to debug their value.

                                                                                                                                                              +
                                                                                                                                                              // Start debugging all WordPress filters and action final and initial values.
                                                                                                                                                              +  $this->startWpFiltersDebug();
                                                                                                                                                              +  // Run some code firing filters and debug them.
                                                                                                                                                              +  // Stop debugging all WordPress filters and action final and initial values.
                                                                                                                                                              +  $this->stopWpFiltersDebug();
                                                                                                                                                              +  the array of arguments as input.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \callable $format - A callback function to format the arguments debug output; the callback will receive
                                                                                                                                                              + +

                                                                                                                                                              stopWpFiltersDebug

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Stops the debug of all WordPress filters and actions.

                                                                                                                                                              +
                                                                                                                                                              // Start debugging all WordPress filters and action final and initial values.
                                                                                                                                                              +  $this->startWpFiltersDebug();
                                                                                                                                                              +  // Run some code firing filters and debug them.
                                                                                                                                                              +  // Stop debugging all WordPress filters and action final and initial values.
                                                                                                                                                              +  $this->stopWpFiltersDebug();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This class extends \Codeception\Module

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPQueries/index.html b/v3/modules/WPQueries/index.html new file mode 100644 index 000000000..101362031 --- /dev/null +++ b/v3/modules/WPQueries/index.html @@ -0,0 +1,3749 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPQueries - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WPQueries module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in integration tests, see levels of testing for more information, to make assertions on the database queries made by the global $wpdb object.
                                                                                                                                                              +This module requires the WPLoader module to work.
                                                                                                                                                              +The module will set, if not set already, the SAVEQUERIES constant to true and will throw an exception if the constant is already set to a falsy value.

                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +

                                                                                                                                                              This module does not require any configuration, but requires the WPLoader module to work correctly.

                                                                                                                                                              +

                                                                                                                                                              Usage

                                                                                                                                                              +

                                                                                                                                                              This module must be used in a test case extending the \Codeception\TestCase\WPTestCase class.

                                                                                                                                                              +

                                                                                                                                                              The module public API is accessible calling via the \Codeception\TestCase\WPTestCase::queries() method:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +
                                                                                                                                                              +use Codeception\Module\WPQueries;
                                                                                                                                                              +
                                                                                                                                                              +class WPQueriesUsageTest extends \Codeception\TestCase\WPTestCase
                                                                                                                                                              +{
                                                                                                                                                              +    public function test_queries_made_by_factory_are_not_tracked()
                                                                                                                                                              +    {
                                                                                                                                                              +        $currentQueriesCount = $this->queries()->countQueries();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertNotEmpty($currentQueriesCount);
                                                                                                                                                              +
                                                                                                                                                              +        static::factory()->post->create_many(3);
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertNotEmpty($currentQueriesCount);
                                                                                                                                                              +        $this->assertEquals($currentQueriesCount, $this->queries()->countQueries());
                                                                                                                                                              +    }
                                                                                                                                                              +
                                                                                                                                                              +    public function test_count_queries()
                                                                                                                                                              +    {
                                                                                                                                                              +        $currentQueriesCount = $this->queries()->countQueries();
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertNotEmpty($currentQueriesCount);
                                                                                                                                                              +
                                                                                                                                                              +        foreach (range(1, 3) as $i) {
                                                                                                                                                              +            wp_insert_post(['post_title' => 'Post ' . $i, 'post_content' => str_repeat('test', $i)]);
                                                                                                                                                              +        }
                                                                                                                                                              +
                                                                                                                                                              +        $this->assertNotEmpty($currentQueriesCount);
                                                                                                                                                              +        $this->assertGreaterThan($currentQueriesCount, $this->queries()->countQueries());
                                                                                                                                                              +    }
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              + + +

                                                                                                                                                              assertCountQueries

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries have been made.

                                                                                                                                                              +
                                                                                                                                                              $posts = $this->factory()->post->create_many(3);
                                                                                                                                                              +  $cachedUsers = $this->factory()->user->create_many(2);
                                                                                                                                                              +  $nonCachedUsers = $this->factory()->user->create_many(2);
                                                                                                                                                              +  foreach($cachedUsers as $userId){
                                                                                                                                                              +  wp_cache_set('page-posts-for-user-' . $userId, $posts, 'acme');
                                                                                                                                                              +  }
                                                                                                                                                              +  // Run the same query as different users
                                                                                                                                                              +  foreach(array_merge($cachedUsers, $nonCachedUsers) as $userId){
                                                                                                                                                              +  $pagePosts = $plugin->getPagePostsForUser($userId);
                                                                                                                                                              +  }
                                                                                                                                                              +  $I->assertCountQueries(2, 'A query should be made for each user missing cached posts.')
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueries

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $posts = $this->factory()->post->create_many(3);
                                                                                                                                                              +  wp_cache_set('page-posts', $posts, 'acme');
                                                                                                                                                              +  $pagePosts = $plugin->getPagePosts();
                                                                                                                                                              +  $I->assertNotQueries('Queries should not be made if the cache is set.')
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByAction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made as a consequence of the specified action. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_action( 'edit_post', function($postId){
                                                                                                                                                              +  $count = get_option('acme_title_updates_count');
                                                                                                                                                              +  update_option('acme_title_updates_count', ++$count);
                                                                                                                                                              +  } );
                                                                                                                                                              +  wp_delete_post($bookId);
                                                                                                                                                              +  $this->assertNotQueriesByAction('edit_post');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $action - The action name, e.g. 'init'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByFilter

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made as a consequence of the specified filter. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_filter('the_title', function($title, $postId){
                                                                                                                                                              +  $post = get_post($postId);
                                                                                                                                                              +  if($post->post_type !== 'book'){
                                                                                                                                                              +  return $title;
                                                                                                                                                              +  }
                                                                                                                                                              +  $new = get_option('acme_new_prefix');
                                                                                                                                                              +  return "{$new} - " . $title;
                                                                                                                                                              +  });
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);
                                                                                                                                                              +  $this->assertNotQueriesByFilter('the_title');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByFunction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made by the specified function. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $this->assertEmpty(Acme\get_orphaned_posts());
                                                                                                                                                              +  Acme\delete_orphaned_posts();
                                                                                                                                                              +  $this->assertNotQueriesByFunction('Acme\delete_orphaned_posts');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $function - The fully qualified name of the function to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByMethod

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries have been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $options = new Acme\Options();
                                                                                                                                                              +  $options->update('adsSource', 'not-a-real-url.org');
                                                                                                                                                              +  $I->assertNotQueriesByMethod('Acme\Options', 'update');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $class - The fully qualified name of the class to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $method - The name of the method to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByStatement

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries have been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $bookRepository = new Acme\BookRepository();
                                                                                                                                                              +  $repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);
                                                                                                                                                              +  $this->assertNotQueriesByStatement('INSERT', 'Deferred write should happen on __destruct');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByStatementAndAction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made as a consequence of the specified action containing the SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_action( 'edit_post', function($postId){
                                                                                                                                                              +  $count = get_option('acme_title_updates_count');
                                                                                                                                                              +  update_option('acme_title_updates_count', ++$count);
                                                                                                                                                              +  } );
                                                                                                                                                              +  wp_delete_post($bookId);
                                                                                                                                                              +  $this->assertNotQueriesByStatementAndAction('DELETE', 'delete_post');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $action - The action name, e.g. 'init'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByStatementAndFilter

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made as a consequence of the specified filter containing the specified SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_filter('the_title', function($title, $postId){
                                                                                                                                                              +  $post = get_post($postId);
                                                                                                                                                              +  if($post->post_type !== 'book'){
                                                                                                                                                              +  return $title;
                                                                                                                                                              +  }
                                                                                                                                                              +  $new = get_option('acme_new_prefix');
                                                                                                                                                              +  return "{$new} - " . $title;
                                                                                                                                                              +  });
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);
                                                                                                                                                              +  $this->assertNotQueriesByStatementAndFilter('SELECT', 'the_title');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByStatementAndFunction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made by the specified function starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              wp_insert_post(['ID' => $bookId, 'post_title' => 'The Call of the Wild']);
                                                                                                                                                              +  $this->assertNotQueriesByStatementAndFunction('INSERT', 'wp_insert_post');
                                                                                                                                                              +  $this->assertQueriesByStatementAndFunction('UPDATE', 'wp_insert_post');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $function - The name of the function to check the assertions for.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertNotQueriesByStatementAndMethod

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that no queries were made by the specified class method starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              Acme\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();
                                                                                                                                                              +  $this->assertQueriesByStatementAndMethod('INSERT', Acme\BookRepository::class, 'commit');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $class - The fully qualified name of the class to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $method - The name of the method to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueries

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least one query was made during the test. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              wp_cache_delete('page-posts', 'acme');
                                                                                                                                                              +  $pagePosts = $plugin->getPagePosts();
                                                                                                                                                              +  $I->assertQueries('Queries should be made to set the cache.')
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByAction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least one query was made as a consequence of the specified action. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_action( 'edit_post', function($postId){
                                                                                                                                                              +  $count = get_option('acme_title_updates_count');
                                                                                                                                                              +  update_option('acme_title_updates_count', ++$count);
                                                                                                                                                              +  } );
                                                                                                                                                              +  wp_update_post(['ID' => $bookId, 'post_title' => 'New Title']);
                                                                                                                                                              +  $this->assertQueriesByAction('edit_post');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $action - The action name, e.g. 'init'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByFilter

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least one query was made as a consequence of the specified filter. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_filter('the_title', function($title, $postId){
                                                                                                                                                              +  $post = get_post($postId);
                                                                                                                                                              +  if($post->post_type !== 'book'){
                                                                                                                                                              +  return $title;
                                                                                                                                                              +  }
                                                                                                                                                              +  $new = get_option('acme_new_prefix');
                                                                                                                                                              +  return "{$new} - " . $title;
                                                                                                                                                              +  });
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);
                                                                                                                                                              +  $this->assertQueriesByFilter('the_title');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByFunction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that queries were made by the specified function. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              acme_clean_queue();
                                                                                                                                                              +  $this->assertQueriesByFunction('acme_clean_queue');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $function - The fully qualified name of the function to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByMethod

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least one query has been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $options = new Acme\Options();
                                                                                                                                                              +  $options->update('showAds', false);
                                                                                                                                                              +  $I->assertQueriesByMethod('Acme\Options', 'update');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $class - The fully qualified name of the class to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $method - The name of the method to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByStatement

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least a query starting with the specified statement was made. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              wp_cache_flush();
                                                                                                                                                              +  cached_get_posts($args);
                                                                                                                                                              +  $I->assertQueriesByStatement('SELECT');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByStatementAndAction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least one query was made as a consequence of the specified action containing the SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_action( 'edit_post', function($postId){
                                                                                                                                                              +  $count = get_option('acme_title_updates_count');
                                                                                                                                                              +  update_option('acme_title_updates_count', ++$count);
                                                                                                                                                              +  } );
                                                                                                                                                              +  wp_update_post(['ID' => $bookId, 'post_title' => 'New']);
                                                                                                                                                              +  $this->assertQueriesByStatementAndAction('UPDATE', 'edit_post');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $action - The action name, e.g. 'init'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByStatementAndFilter

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that at least one query was made as a consequence of the specified filter containing the SQL query. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_filter('the_title', function($title, $postId){
                                                                                                                                                              +  $post = get_post($postId);
                                                                                                                                                              +  if($post->post_type !== 'book'){
                                                                                                                                                              +  return $title;
                                                                                                                                                              +  }
                                                                                                                                                              +  $new = get_option('acme_new_prefix');
                                                                                                                                                              +  return "{$new} - " . $title;
                                                                                                                                                              +  });
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookId)->post_title, $bookId);
                                                                                                                                                              +  $this->assertQueriesByStatementAndFilter('SELECT', 'the_title');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByStatementAndFunction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that queries were made by the specified function starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              wp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);
                                                                                                                                                              +  $this->assertQueriesByStatementAndFunction('INSERT', 'wp_insert_post');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $function - The fully qualified function name.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesByStatementAndMethod

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that queries were made by the specified class method starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              Acme\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();
                                                                                                                                                              +  $this->assertQueriesByStatementAndMethod('UPDATE', Acme\BookRepository::class, 'commit');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $class - The fully qualified name of the class to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $method - The name of the method to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByAction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made as a consequence of the specified action. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_action( 'edit_post', function($postId){
                                                                                                                                                              +  $count = get_option('acme_title_updates_count');
                                                                                                                                                              +  update_option('acme_title_updates_count', ++$count);
                                                                                                                                                              +  } );
                                                                                                                                                              +  wp_update_post(['ID' => $bookOneId, 'post_title' => 'One']);
                                                                                                                                                              +  wp_update_post(['ID' => $bookTwoId, 'post_title' => 'Two']);
                                                                                                                                                              +  wp_update_post(['ID' => $bookThreeId, 'post_title' => 'Three']);
                                                                                                                                                              +  $this->assertQueriesCountByAction(3, 'edit_post');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $action - The action name, e.g. 'init'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByFilter

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made as a consequence of the specified filter. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_filter('the_title', function($title, $postId){
                                                                                                                                                              +  $post = get_post($postId);
                                                                                                                                                              +  if($post->post_type !== 'book'){
                                                                                                                                                              +  return $title;
                                                                                                                                                              +  }
                                                                                                                                                              +  $new = get_option('acme_new_prefix');
                                                                                                                                                              +  return "{$new} - " . $title;
                                                                                                                                                              +  });
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($notABookId)->post_title, $notABookId);
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);
                                                                                                                                                              +  $this->assertQueriesCountByFilter(2, 'the_title');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByFunction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made by the specified function. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $this->assertCount(3, Acme\get_orphaned_posts());
                                                                                                                                                              +  Acme\delete_orphaned_posts();
                                                                                                                                                              +  $this->assertQueriesCountByFunction(3, 'Acme\delete_orphaned_posts');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $function - The function to check the queries for.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByMethod

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries have been made by the specified class method. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $bookRepository = new Acme\BookRepository();
                                                                                                                                                              +  $repository->where('ID', 23)->commit('title', 'Peter Pan');
                                                                                                                                                              +  $repository->where('ID', 89)->commit('title', 'Moby-dick');
                                                                                                                                                              +  $repository->where('ID', 2389)->commit('title', 'The call of the wild');
                                                                                                                                                              +  $this->assertQueriesCountByMethod(3, 'Acme\BookRepository', 'commit');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $class - The fully qualified name of the class to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $method - The name of the method to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByStatement

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries starting with the specified statement were made. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              $bookRepository = new Acme\BookRepository();
                                                                                                                                                              +  $repository->where('ID', 23)->set('title', 'Peter Pan', $deferred = true);
                                                                                                                                                              +  $repository->where('ID', 89)->set('title', 'Moby-dick', $deferred = true);
                                                                                                                                                              +  $repository->where('ID', 2389)->set('title', 'The call of the wild', $deferred = false);
                                                                                                                                                              +  $this->assertQueriesCountByStatement(1, 'INSERT', 'Deferred write should happen on __destruct');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByStatementAndAction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made as a consequence of the specified action containing the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_action( 'edit_post', function($postId){
                                                                                                                                                              +  $count = get_option('acme_title_updates_count');
                                                                                                                                                              +  update_option('acme_title_updates_count', ++$count);
                                                                                                                                                              +  } );
                                                                                                                                                              +  wp_delete_post($bookOneId);
                                                                                                                                                              +  wp_delete_post($bookTwoId);
                                                                                                                                                              +  wp_update_post(['ID' => $bookThreeId, 'post_title' => 'New']);
                                                                                                                                                              +  $this->assertQueriesCountByStatementAndAction(2, 'DELETE', 'delete_post');
                                                                                                                                                              +  $this->assertQueriesCountByStatementAndAction(1, 'INSERT', 'edit_post');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $action - The action name, e.g. 'init'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByStatementAndFilter

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made as a consequence of the specified filter containing the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              add_filter('the_title', function($title, $postId){
                                                                                                                                                              +  $post = get_post($postId);
                                                                                                                                                              +  if($post->post_type !== 'book'){
                                                                                                                                                              +  return $title;
                                                                                                                                                              +  }
                                                                                                                                                              +  $new = get_option('acme_new_prefix');
                                                                                                                                                              +  return "{$new} - " . $title;
                                                                                                                                                              +  });
                                                                                                                                                              +  // Warm up the cache.
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookOneId)->post_title, $bookOneId);
                                                                                                                                                              +  // Cache is warmed up now.
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookTwoId)->post_title, $bookTwoId);
                                                                                                                                                              +  $title = apply_filters('the_title', get_post($bookThreeId)->post_title, $bookThreeId);
                                                                                                                                                              +  $this->assertQueriesCountByStatementAndFilter(1, 'SELECT', 'the_title');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $filter - The filter name, e.g. 'posts_where'.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByStatementAndFunction

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made by the specified function starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              wp_insert_post(['post_type' => 'book', 'post_title' => 'The Call of the Wild']);
                                                                                                                                                              +  wp_insert_post(['post_type' => 'book', 'post_title' => 'Alice in Wonderland']);
                                                                                                                                                              +  wp_insert_post(['post_type' => 'book', 'post_title' => 'The Chocolate Factory']);
                                                                                                                                                              +  $this->assertQueriesCountByStatementAndFunction(3, 'INSERT', 'wp_insert_post');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $function - The fully-qualified function name.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              assertQueriesCountByStatementAndMethod

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Asserts that n queries were made by the specified class method starting with the specified SQL statement. Queries generated by setUp, tearDown and factory methods are excluded by default.

                                                                                                                                                              +
                                                                                                                                                              Acme\BookRepository::new(['title' => 'Alice in Wonderland'])->commit();
                                                                                                                                                              +  Acme\BookRepository::new(['title' => 'Moby-Dick'])->commit();
                                                                                                                                                              +  Acme\BookRepository::new(['title' => 'The Call of the Wild'])->commit();
                                                                                                                                                              +  $this->assertQueriesCountByStatementAndMethod(3, 'INSERT', Acme\BookRepository::class, 'commit');
                                                                                                                                                              +  Regular expressions must contain delimiters.
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $n - The expected number of queries.
                                                                                                                                                              • +
                                                                                                                                                              • string $statement - A simple string the statement should start with or a valid regular expression.
                                                                                                                                                              • +
                                                                                                                                                              • string $class - The fully qualified name of the class to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $method - The name of the method to check.
                                                                                                                                                              • +
                                                                                                                                                              • string $message - An optional message to override the default one.
                                                                                                                                                              + +

                                                                                                                                                              countQueries

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the current number of queries. Set-up and tear-down queries performed by the test case are filtered out.

                                                                                                                                                              +
                                                                                                                                                              // In a WPTestCase, using the global $wpdb object.
                                                                                                                                                              +  $queriesCount = $this->queries()->countQueries();
                                                                                                                                                              +  // In a WPTestCase, using a custom $wpdb object.
                                                                                                                                                              +  $queriesCount = $this->queries()->countQueries($customWdbb);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • \wpdb/null $wpdb - A specific instance of the wpdb class or null to use the global one.
                                                                                                                                                              + +

                                                                                                                                                              getQueries

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the queries currently performed by the global database object or the specified one. Set-up and tear-down queries performed by the test case are filtered out.

                                                                                                                                                              +
                                                                                                                                                              // In a WPTestCase, using the global $wpdb object.
                                                                                                                                                              +  $queries = $this->queries()->getQueries();
                                                                                                                                                              +  // In a WPTestCase, using a custom $wpdb object.
                                                                                                                                                              +  $queries = $this->queries()->getQueries($customWdbb);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • null/\wpdb $wpdb - A specific instance of the wpdb class or null to use the global one.
                                                                                                                                                              + +

                                                                                                                                                              This class extends \Codeception\Module

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WPWebDriver/index.html b/v3/modules/WPWebDriver/index.html new file mode 100644 index 000000000..20e1056d0 --- /dev/null +++ b/v3/modules/WPWebDriver/index.html @@ -0,0 +1,4021 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WPWebDriver - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WpWebDriver module

                                                                                                                                                              +

                                                                                                                                                              This module should be used in acceptance tests, see levels of testing for more information.

                                                                                                                                                              +

                                                                                                                                                              This module extends the WebDriver module adding WordPress-specific configuration parameters and methods.

                                                                                                                                                              +

                                                                                                                                                              The module simulates a user interaction with the site with Javascript support; if you don't need to test your project with Javascript support use the WPBrowser module.

                                                                                                                                                              +

                                                                                                                                                              Module requirements for Codeception 4.0+

                                                                                                                                                              +

                                                                                                                                                              This module requires the codeception/module-webdriver Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                              +

                                                                                                                                                              To install the package run:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev codeception/module-webdriver:^1.0
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +

                                                                                                                                                              Due to the combination of possible browsers, capabilities and configurations, it's not possible to provide an exhaustive coverage of all the possible configuration parameteters here.

                                                                                                                                                              +

                                                                                                                                                              Please refer to WebDriver documentation for more information.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • url required - Start URL of your WordPress project, e.g. http://wp.test.
                                                                                                                                                              • +
                                                                                                                                                              • adminUsername required - This is the login name, not the "nice" name, of the administrator user of the WordPress test site. This will be used to fill the username field in WordPress login page.
                                                                                                                                                              • +
                                                                                                                                                              • adminPassword required - This is the the password of the administrator use of the WordPress test site. This will be used to fill the password in WordPress login page.
                                                                                                                                                              • +
                                                                                                                                                              • adminPath required - The path, relative to the WordPress test site home URL, to the administration area, usually /wp-admin.
                                                                                                                                                              • +
                                                                                                                                                              • browser - The browser to use for the tests, e.g. chrome or firefox.
                                                                                                                                                              • +
                                                                                                                                                              • capabilities - Depending on the browser set in browser this is a list of browser-specific capabilities.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                              modules:
                                                                                                                                                              +  enabled:
                                                                                                                                                              +    - WPWebDriver
                                                                                                                                                              +  config:
                                                                                                                                                              +    WPWebDriver:
                                                                                                                                                              +      url: 'http://wp.test'
                                                                                                                                                              +      adminUsername: 'admin'
                                                                                                                                                              +      adminPassword: 'password'
                                                                                                                                                              +      adminPath: '/wp-admin'
                                                                                                                                                              +      browser: chrome
                                                                                                                                                              +      host: localhost
                                                                                                                                                              +      port: 4444
                                                                                                                                                              +      window_size: false #disabled for Chrome driver
                                                                                                                                                              +      capabilities:
                                                                                                                                                              +        "goog:chromeOptions":
                                                                                                                                                              +          args:
                                                                                                                                                              +            - "--headless"
                                                                                                                                                              +            - "--disable-gpu"
                                                                                                                                                              +            - "--disable-dev-shm-usage"
                                                                                                                                                              +            - "--proxy-server='direct://'"
                                                                                                                                                              +            - "--proxy-bypass-list=*"
                                                                                                                                                              +            - "--no-sandbox"
                                                                                                                                                              +
                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                acceptPopup() : void
                                                                                                                                                                + Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt. + Don't confuse popups with modal windows, + as created by various libraries.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                activatePlugin($pluginSlug) : void
                                                                                                                                                                + In the plugin administration screen activates one or more plugins clicking the "Activate" link.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugins administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • activateTheme($slug) : void
                                                                                                                                                                + Activates a theme.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amEditingPostWithId($id) : void
                                                                                                                                                                + Go to the admin page to edit the post with the specified ID.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication the admin area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amEditingUserWithId($id) : void
                                                                                                                                                                + Go to the admin page to edit the user with the specified ID.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication the admin area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amOnAdminAjaxPage([$queryVars]) : void
                                                                                                                                                                + Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication, nonces or authorization.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amOnAdminPage($page) : void
                                                                                                                                                                + Go to a page in the admininstration area of the site.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              This method will not handle authentication to the administration area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                amOnCronPage([$queryVars]) : void
                                                                                                                                                                + Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnPage($page) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnPagesPage() : void
                                                                                                                                                                + Go the "Pages" administration screen.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • amOnPluginsPage() : void
                                                                                                                                                                + Go to the plugins administration screen.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                amOnSubdomain($subdomain) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnThemesPage() : void
                                                                                                                                                                + Moves to the themes administration page.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                amOnUrl($url) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                appendField($field, $value) : void
                                                                                                                                                                + Append the given text to the given element. + Can also add a selection to a select box.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->appendField('#mySelectbox', 'SelectValue');
                                                                                                                                                              +$I->appendField('#myTextField', 'appended');
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                attachFile($field, $filename) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                cancelPopup() : void
                                                                                                                                                                + Dismisses the active JavaScript popup, as created by window.alert, window.confirm, or window.prompt.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                checkOption($option) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                clearField($field) : void
                                                                                                                                                                + Clears given field which isn't empty.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->clearField('#username');
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                click($link, [$context]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                clickWithLeftButton([$cssOrXPath], [$offsetX], [$offsetY]) : void
                                                                                                                                                                + Performs click with the left mouse button on an element. + If the first parameter null then the offset is relative to the actual mouse position. + If the second and third parameters are given, + then the mouse is moved to an offset of the element's top-left corner. + Otherwise, the mouse is moved to the center of the element.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->clickWithLeftButton(['css' => '.checkout']);
                                                                                                                                                              +$I->clickWithLeftButton(null, 20, 50);
                                                                                                                                                              +$I->clickWithLeftButton(['css' => '.checkout'], 20, 50);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • clickWithRightButton([$cssOrXPath], [$offsetX], [$offsetY]) : void
                                                                                                                                                                + Performs contextual click with the right mouse button on an element. + If the first parameter null then the offset is relative to the actual mouse position. + If the second and third parameters are given, + then the mouse is moved to an offset of the element's top-left corner. + Otherwise, the mouse is moved to the center of the element.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->clickWithRightButton(['css' => '.checkout']);
                                                                                                                                                              +$I->clickWithRightButton(null, 20, 50);
                                                                                                                                                              +$I->clickWithRightButton(['css' => '.checkout'], 20, 50);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • closeTab() : void
                                                                                                                                                                + Closes current browser tab and switches to previous active tab.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->closeTab();
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • deactivatePlugin($pluginSlug) : void
                                                                                                                                                                + In the plugin administration screen deactivate a plugin clicking the "Deactivate" link.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugins administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                debugWebDriverLogs([?Codeception\TestInterface $test]) : void
                                                                                                                                                                + Print out latest Selenium Logs in debug mode

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                deleteSessionSnapshot($name) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSee($text, [$selector]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCheckboxIsChecked($checkbox) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCurrentUrlEquals($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeCurrentUrlMatches($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeElement($selector, [$attributes]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeElementInDOM($selector, [$attributes]) : void
                                                                                                                                                                + Opposite of seeElementInDOM.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInCurrentUrl($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInField($field, $value) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInFormFields($formSelector, array $params) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInPageSource($text) : void
                                                                                                                                                                + Checks that the page source doesn't contain the given string.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInPopup($text) : void
                                                                                                                                                                + Checks that the active JavaScript popup, + as created by window.alert|window.confirm|window.prompt, does NOT contain the given string.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInSource($raw) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeInTitle($title) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeLink($text, [$url]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeeOptionIsSelected($selector, $optionText) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dontSeePluginInstalled($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is not installed in the plugins administration screen.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                doubleClick($cssOrXPath) : void
                                                                                                                                                                + Performs a double-click on an element matched by CSS or XPath.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                dragAndDrop($source, $target) : void
                                                                                                                                                                + Performs a simple mouse drag-and-drop operation.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->dragAndDrop('#drag', '#drop');
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • executeAsyncJS($script, [array $arguments]) : void
                                                                                                                                                                + Executes asynchronous JavaScript. + A callback should be executed by JavaScript to exit from a script. + Callback is passed as a last element in arguments array. + Additional arguments can be passed as array in second parameter.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              // wait for 1200 milliseconds my running `setTimeout`
                                                                                                                                                              +* $I->executeAsyncJS('setTimeout(arguments[0], 1200)');
                                                                                                                                                              +
                                                                                                                                                              +$seconds = 1200; // or seconds are passed as argument
                                                                                                                                                              +$I->executeAsyncJS('setTimeout(arguments[1], arguments[0])', [$seconds]);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • executeInSelenium(Closure $function) : void
                                                                                                                                                                + Low-level API method. + If Codeception commands are not enough, this allows you to use Selenium WebDriver methods directly:
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              $I->executeInSelenium(function(\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
                                                                                                                                                              +  $webdriver->get('http://google.com');
                                                                                                                                                              +});
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This runs in the context of the + RemoteWebDriver class. + Try not to use this command on a regular basis. + If Codeception lacks a feature you need, please implement it and submit a patch.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • executeJS($script, [array $arguments]) : void
                                                                                                                                                                + Executes custom JavaScript.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              This example uses jQuery to get a value and assigns that value to a PHP variable:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$myVar = $I->executeJS('return $("#myField").val()');
                                                                                                                                                              +
                                                                                                                                                              +// additional arguments can be passed as array
                                                                                                                                                              +// Example shows `Hello World` alert:
                                                                                                                                                              +$I->executeJS("window.alert(arguments[0])", ['Hello world']);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                fillField($field, $value) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabActiveTheme() : void
                                                                                                                                                                + Returns the slug of the currently active themes.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                grabAttributeFrom($cssOrXpath, $attribute) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabAvailableThemes([$classes]) : void
                                                                                                                                                                + Returns the list of available themes.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                grabCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabCookiesWithPattern($cookiePattern) : void
                                                                                                                                                                + Returns all the cookies whose name matches a regex pattern.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabFromCurrentUrl([$uri]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabFullUrl() : void
                                                                                                                                                                + Grabs the current page full URL including the query vars.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabMultiple($cssOrXpath, [$attribute]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabPageSource() : void
                                                                                                                                                                + Grabs current page source code.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabTextFrom($cssOrXPathOrRegex) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabValueFrom($field) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                grabWordPressTestCookie([$name]) : void
                                                                                                                                                                + Returns WordPress default test cookie object if present.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                loadSessionSnapshot($name) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                logOut([$redirectTo]) : void
                                                                                                                                                                + Navigate to the default WordPress logout page and click the logout link.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                loginAs($username, $password, [$timeout], [$maxAttempts]) : void
                                                                                                                                                                + Login as the specified user.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not follow redirection, after the login, to any page. + Depending on the driven browser the login might be "too fast" and the server might have not + replied with valid cookies yet; in that case the method will re-attempt the login to obtain + the cookies.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • loginAsAdmin([$timeout], [$maxAttempts]) : void
                                                                                                                                                                + Login as the administrator user using the credentials specified in the module configuration.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not follow redirection, after the login, to any page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • makeElementScreenshot($selector, [$name]) : void
                                                                                                                                                                + Takes a screenshot of an element of the current window and saves it to tests/_output/debug.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->amOnPage('/user/edit');
                                                                                                                                                              +$I->makeElementScreenshot('#dialog', 'edit_page');
                                                                                                                                                              +// saved to: tests/_output/debug/edit_page.png
                                                                                                                                                              +$I->makeElementScreenshot('#dialog');
                                                                                                                                                              +// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                makeHtmlSnapshot([$name]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                makeScreenshot([$name]) : void
                                                                                                                                                                + Takes a screenshot of the current window and saves it to tests/_output/debug.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->amOnPage('/user/edit');
                                                                                                                                                              +$I->makeScreenshot('edit_page');
                                                                                                                                                              +// saved to: tests/_output/debug/edit_page.png
                                                                                                                                                              +$I->makeScreenshot();
                                                                                                                                                              +// saved to: tests/_output/debug/2017-05-26_14-24-11_4b3403665fea6.png
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                maximizeWindow() : void
                                                                                                                                                                + Maximizes the current window.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                moveBack() : void
                                                                                                                                                                + Moves back in history.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                moveForward() : void
                                                                                                                                                                + Moves forward in history.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                moveMouseOver([$cssOrXPath], [$offsetX], [$offsetY]) : void
                                                                                                                                                                + Move mouse over the first element matched by the given locator. + If the first parameter null then the page is used. + If the second and third parameters are given, + then the mouse is moved to an offset of the element's top-left corner. + Otherwise, the mouse is moved to the center of the element.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->moveMouseOver(['css' => '.checkout']);
                                                                                                                                                              +$I->moveMouseOver(null, 20, 50);
                                                                                                                                                              +$I->moveMouseOver(['css' => '.checkout'], 20, 50);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • openNewTab() : void
                                                                                                                                                                + Opens a new browser tab and switches to it.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              <?php
                                                                                                                                                              +$I->openNewTab();
                                                                                                                                                              +
                                                                                                                                                              + The tab is opened with JavaScript's window.open(), which means: + * Some adblockers might restrict it. + * The sessionStorage is copied to the new tab (contrary to a tab that was manually opened by the user)

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • performOn($element, $actions, [$timeout]) : void
                                                                                                                                                                + Waits for element and runs a sequence of actions inside its context. + Actions can be defined with array, callback, or Codeception\Util\ActionSequence instance.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Actions as array are recommended for simple to combine "waitForElement" with assertions; + waitForElement($el) and see('text', $el) can be simplified to:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->performOn($el, ['see' => 'text']);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              List of actions can be pragmatically build using Codeception\Util\ActionSequence:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->performOn('.model', ActionSequence::build()
                                                                                                                                                              +    ->see('Warning')
                                                                                                                                                              +    ->see('Are you sure you want to delete this?')
                                                                                                                                                              +    ->click('Yes')
                                                                                                                                                              +);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Actions executed from array or ActionSequence will print debug output for actions, and adds an action name to + exception on failure.

                                                                                                                                                              +

                                                                                                                                                              Whenever you need to define more actions a callback can be used. A WebDriver module is passed for argument:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->performOn('.rememberMe', function (WebDriver $I) {
                                                                                                                                                              +     $I->see('Remember me next time');
                                                                                                                                                              +     $I->seeElement('#LoginForm_rememberMe');
                                                                                                                                                              +     $I->dontSee('Login');
                                                                                                                                                              +});
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              In 3rd argument you can set number a seconds to wait for element to appear

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • pressKey($element, $char) : void
                                                                                                                                                                + Presses the given key on the given element. + To specify a character and modifier (e.g. Ctrl, Alt, Shift, Meta), pass an array for $char with + the modifier as the first element and the character as the second. + For special keys, use the constants from Facebook\WebDriver\WebDriverKeys.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// <input id="page" value="old" />
                                                                                                                                                              +$I->pressKey('#page','a'); // => olda
                                                                                                                                                              +$I->pressKey('#page',array('ctrl','a'),'new'); //=> new
                                                                                                                                                              +$I->pressKey('#page',array('shift','111'),'1','x'); //=> old!!!1x
                                                                                                                                                              +$I->pressKey('descendant-or-self::*[@id='page']','u'); //=> oldu
                                                                                                                                                              +$I->pressKey('#name', array('ctrl', 'a'), \Facebook\WebDriver\WebDriverKeys::DELETE); //=>''
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                reloadPage() : void
                                                                                                                                                                + Reloads the current page.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                resetCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                resizeWindow($width, $height) : void
                                                                                                                                                                + Resize the current window.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->resizeWindow(800, 600);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                saveSessionSnapshot($name) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                scrollTo($selector, [$offsetX], [$offsetY]) : void
                                                                                                                                                                + Move to the middle of the given element matched by the given locator. + Extra shift, calculated from the top-left corner of the element, + can be set by passing $offsetX and $offsetY parameters.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->scrollTo(['css' => '.checkout'], 20, 50);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                see($text, [$selector]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCheckboxIsChecked($checkbox) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCookie($cookie, [array $params]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCurrentUrlEquals($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeCurrentUrlMatches($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeElement($selector, [$attributes]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeElementInDOM($selector, [$attributes]) : void
                                                                                                                                                                + Checks that the given element exists on the page, even it is invisible.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->seeElementInDOM('//form/input[type=hidden]');
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seeErrorMessage([$classes]) : void
                                                                                                                                                                + In an administration screen look for an error admin notice.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The check is class-based to decouple from internationalization. + The method will not handle authentication and navigation the administration area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeInCurrentUrl($uri) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInField($field, $value) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInFormFields($formSelector, array $params) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInPageSource($text) : void
                                                                                                                                                                + Checks that the page source contains the given string.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->seeInPageSource('<link rel="apple-touch-icon"');
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeInPopup($text) : void
                                                                                                                                                                + Checks that the active JavaScript popup, + as created by window.alert|window.confirm|window.prompt, contains the given string.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInSource($raw) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeInTitle($title) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeLink($text, [$url]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeMessage([$classes]) : void
                                                                                                                                                                + In an administration screen look for an admin notice.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The check is class-based to decouple from internationalization. + The method will not handle authentication and navigation the administration area.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeNumberOfElements($selector, $expected) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeNumberOfElementsInDOM($selector, $expected) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seeNumberOfTabs($number) : void
                                                                                                                                                                + Checks current number of opened tabs

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->seeNumberOfTabs(2);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                seeOptionIsSelected($selector, $optionText) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                seePluginActivated($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is activated in the plugin administration screen.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seePluginDeactivated($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is not activated in the plugins administration screen.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seePluginInstalled($pluginSlug) : void
                                                                                                                                                                + Assert a plugin is installed, no matter its activation status, in the plugin administration screen.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seeThemeActivated($slug) : void
                                                                                                                                                                + Verifies that a theme is active.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will not handle authentication and navigation to the themes administration page.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • seeWpDiePage() : void
                                                                                                                                                                + Checks that the current page is one generated by the wp_die function.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The method will try to identify the page based on the default WordPress die page HTML attributes.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                selectOption($select, $option) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                setCookie($cookie, $value, [array $params], [$showDebug]) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                submitForm($selector, array $params, [$button]) : void
                                                                                                                                                                + Submits the given form on the page, optionally with the given form + values. Give the form fields values as an array. Note that hidden fields + can't be accessed.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Skipped fields will be filled by their values from the page. + You don't need to click the 'Submit' button afterwards. + This command itself triggers the request to form's action.

                                                                                                                                                              +

                                                                                                                                                              You can optionally specify what button's value to include + in the request with the last parameter as an alternative to + explicitly setting its value in the second parameter, as + button values are not otherwise included in the request.

                                                                                                                                                              +

                                                                                                                                                              Examples:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->submitForm('#login', [
                                                                                                                                                              +    'login' => 'davert',
                                                                                                                                                              +    'password' => '123456'
                                                                                                                                                              +]);
                                                                                                                                                              +// or
                                                                                                                                                              +$I->submitForm('#login', [
                                                                                                                                                              +    'login' => 'davert',
                                                                                                                                                              +    'password' => '123456'
                                                                                                                                                              +], 'submitButtonName');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              For example, given this sample "Sign Up" form:

                                                                                                                                                              +
                                                                                                                                                              <form action="/sign_up">
                                                                                                                                                              +    Login:
                                                                                                                                                              +    <input type="text" name="user[login]" /><br/>
                                                                                                                                                              +    Password:
                                                                                                                                                              +    <input type="password" name="user[password]" /><br/>
                                                                                                                                                              +    Do you agree to our terms?
                                                                                                                                                              +    <input type="checkbox" name="user[agree]" /><br/>
                                                                                                                                                              +    Select pricing plan:
                                                                                                                                                              +    <select name="plan">
                                                                                                                                                              +        <option value="1">Free</option>
                                                                                                                                                              +        <option value="2" selected="selected">Paid</option>
                                                                                                                                                              +    </select>
                                                                                                                                                              +    <input type="submit" name="submitButton" value="Submit" />
                                                                                                                                                              +</form>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You could write the following to submit it:

                                                                                                                                                              +

                                                                                                                                                              <?php
                                                                                                                                                              +$I->submitForm(
                                                                                                                                                              +    '#userForm',
                                                                                                                                                              +    [
                                                                                                                                                              +        'user[login]' => 'Davert',
                                                                                                                                                              +        'user[password]' => '123456',
                                                                                                                                                              +        'user[agree]' => true
                                                                                                                                                              +    ],
                                                                                                                                                              +    'submitButton'
                                                                                                                                                              +);
                                                                                                                                                              +
                                                                                                                                                              + Note that "2" will be the submitted value for the "plan" field, as it is + the selected option.

                                                                                                                                                              +

                                                                                                                                                              Also note that this differs from PhpBrowser, in that + 'user' => [ 'login' => 'Davert' ] is not supported at the moment. + Named array keys must be included in the name as above.

                                                                                                                                                              +

                                                                                                                                                              Pair this with seeInFormFields for quick testing magic.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$form = [
                                                                                                                                                              +     'field1' => 'value',
                                                                                                                                                              +     'field2' => 'another value',
                                                                                                                                                              +     'checkbox1' => true,
                                                                                                                                                              +     // ...
                                                                                                                                                              +];
                                                                                                                                                              +$I->submitForm('//form[@id=my-form]', $form, 'submitButton');
                                                                                                                                                              +// $I->amOnPage('/path/to/form-page') may be needed
                                                                                                                                                              +$I->seeInFormFields('//form[@id=my-form]', $form);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameter values must be set to arrays for multiple input fields + of the same name, or multi-select combo boxes. For checkboxes, + either the string value can be used, or boolean values which will + be replaced by the checkbox's value in the DOM.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->submitForm('#my-form', [
                                                                                                                                                              +     'field1' => 'value',
                                                                                                                                                              +     'checkbox' => [
                                                                                                                                                              +         'value of first checkbox',
                                                                                                                                                              +         'value of second checkbox',
                                                                                                                                                              +     ],
                                                                                                                                                              +     'otherCheckboxes' => [
                                                                                                                                                              +         true,
                                                                                                                                                              +         false,
                                                                                                                                                              +         false,
                                                                                                                                                              +     ],
                                                                                                                                                              +     'multiselect' => [
                                                                                                                                                              +         'first option value',
                                                                                                                                                              +         'second option value',
                                                                                                                                                              +     ]
                                                                                                                                                              +]);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Mixing string and boolean values for a checkbox's value is not supported + and may produce unexpected results.

                                                                                                                                                              +

                                                                                                                                                              Field names ending in "[]" must be passed without the trailing square + bracket characters, and must contain an array for its value. This allows + submitting multiple values with the same name, consider:

                                                                                                                                                              +
                                                                                                                                                              $I->submitForm('#my-form', [
                                                                                                                                                              +    'field[]' => 'value',
                                                                                                                                                              +    'field[]' => 'another value', // 'field[]' is already a defined key
                                                                                                                                                              +]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The solution is to pass an array value:

                                                                                                                                                              +
                                                                                                                                                              // this way both values are submitted
                                                                                                                                                              +$I->submitForm('#my-form', [
                                                                                                                                                              +    'field' => [
                                                                                                                                                              +        'value',
                                                                                                                                                              +        'another value',
                                                                                                                                                              +    ]
                                                                                                                                                              +]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The $button parameter can be either a string, an array or an instance + of Facebook\WebDriver\WebDriverBy. When it is a string, the + button will be found by its "name" attribute. If $button is an + array then it will be treated as a strict selector and a WebDriverBy + will be used verbatim.

                                                                                                                                                              +

                                                                                                                                                              For example, given the following HTML:

                                                                                                                                                              +
                                                                                                                                                              <input type="submit" name="submitButton" value="Submit" />
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              $button could be any one of the following: + - 'submitButton' + - ['name' => 'submitButton'] + - WebDriverBy::name('submitButton')

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • switchToFrame([$locator]) : void
                                                                                                                                                                + Switch to another frame on the page.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example: +

                                                                                                                                                              <frame name="another_frame" id="fr1" src="http://example.com">
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +# switch to frame by name
                                                                                                                                                              +$I->switchToFrame("another_frame");
                                                                                                                                                              +# switch to frame by CSS or XPath
                                                                                                                                                              +$I->switchToFrame("#fr1");
                                                                                                                                                              +# switch to parent page
                                                                                                                                                              +$I->switchToFrame();
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • switchToIFrame([$locator]) : void
                                                                                                                                                                + Switch to another iframe on the page.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example: +

                                                                                                                                                              <iframe name="another_frame" id="fr1" src="http://example.com">
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +# switch to iframe by name
                                                                                                                                                              +$I->switchToIFrame("another_frame");
                                                                                                                                                              +# switch to iframe by CSS or XPath
                                                                                                                                                              +$I->switchToIFrame("#fr1");
                                                                                                                                                              +# switch to parent page
                                                                                                                                                              +$I->switchToIFrame();
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • switchToNextTab([$offset]) : void
                                                                                                                                                                + Switches to next browser tab. + An offset can be specified.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// switch to next tab
                                                                                                                                                              +$I->switchToNextTab();
                                                                                                                                                              +// switch to 2nd next tab
                                                                                                                                                              +$I->switchToNextTab(2);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • switchToPreviousTab([$offset]) : void
                                                                                                                                                                + Switches to previous browser tab. + An offset can be specified.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// switch to previous tab
                                                                                                                                                              +$I->switchToPreviousTab();
                                                                                                                                                              +// switch to 2nd previous tab
                                                                                                                                                              +$I->switchToPreviousTab(2);
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • switchToWindow([$name]) : void
                                                                                                                                                                + Switch to another window identified by name.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              The window can only be identified by name. If the $name parameter is blank, the parent window will be used.

                                                                                                                                                              +

                                                                                                                                                              Example: +

                                                                                                                                                              <input type="button" value="Open window" onclick="window.open('http://example.com', 'another_window')">
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->click("Open window");
                                                                                                                                                              +# switch to another window
                                                                                                                                                              +$I->switchToWindow("another_window");
                                                                                                                                                              +# switch to parent window
                                                                                                                                                              +$I->switchToWindow();
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If the window has no name, match it by switching to next active tab using switchToNextTab method.

                                                                                                                                                              +

                                                                                                                                                              Or use native Selenium functions to get access to all opened windows:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->executeInSelenium(function (\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
                                                                                                                                                              +     $handles=$webdriver->getWindowHandles();
                                                                                                                                                              +     $last_window = end($handles);
                                                                                                                                                              +     $webdriver->switchTo()->window($last_window);
                                                                                                                                                              +});
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • type($text, [$delay]) : void
                                                                                                                                                                + Type in characters on active element. + With a second parameter you can specify delay between key presses.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +// activate input element
                                                                                                                                                              +$I->click('#input');
                                                                                                                                                              +
                                                                                                                                                              +// type text in active element
                                                                                                                                                              +$I->type('Hello world');
                                                                                                                                                              +
                                                                                                                                                              +// type text with a 1sec delay between chars
                                                                                                                                                              +$I->type('Hello World', 1);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This might be useful when you an input reacts to typing and you need to slow it down to emulate human behavior. + For instance, this is how Credit Card fields can be filled in.

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                typeInPopup($keys) : void
                                                                                                                                                                + Enters text into a native JavaScript prompt popup, as created by window.prompt.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                uncheckOption($option) : void

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                unselectOption($select, $option) : void
                                                                                                                                                                + Unselect an option in the given select box.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                wait($timeout) : void
                                                                                                                                                                + Wait for $timeout seconds.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                waitForElement($element, [$timeout]) : void
                                                                                                                                                                + Waits up to $timeout seconds for an element to appear on the page. + If the element doesn't appear, a timeout exception is thrown.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->waitForElement('#agree_button', 30); // secs
                                                                                                                                                              +$I->click('#agree_button');
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • waitForElementChange($element, Closure $callback, [$timeout]) : void
                                                                                                                                                                + Waits up to $timeout seconds for the given element to change. + Element "change" is determined by a callback function which is called repeatedly + until the return value evaluates to true.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +use \Facebook\WebDriver\WebDriverElement
                                                                                                                                                              +$I->waitForElementChange('#menu', function(WebDriverElement $el) {
                                                                                                                                                              +    return $el->isDisplayed();
                                                                                                                                                              +}, 100);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • waitForElementClickable($element, [$timeout]) : void
                                                                                                                                                                + Waits up to $timeout seconds for the given element to be clickable. + If element doesn't become clickable, a timeout exception is thrown.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->waitForElementClickable('#agree_button', 30); // secs
                                                                                                                                                              +$I->click('#agree_button');
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • waitForElementNotVisible($element, [$timeout]) : void
                                                                                                                                                                + Waits up to $timeout seconds for the given element to become invisible. + If element stays visible, a timeout exception is thrown.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->waitForElementNotVisible('#agree_button', 30); // secs
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • waitForElementVisible($element, [$timeout]) : void
                                                                                                                                                                + Waits up to $timeout seconds for the given element to be visible on the page. + If element doesn't appear, a timeout exception is thrown.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->waitForElementVisible('#agree_button', 30); // secs
                                                                                                                                                              +$I->click('#agree_button');
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • waitForJS($script, [$timeout]) : void
                                                                                                                                                                + Executes JavaScript and waits up to $timeout seconds for it to return true.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              In this example we will wait up to 60 seconds for all jQuery AJAX requests to finish.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->waitForJS("return $.active == 0;", 60);
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • +

                                                                                                                                                                waitForJqueryAjax([$time]) : void
                                                                                                                                                                + Waits for any jQuery triggered AJAX request to be resolved.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • +

                                                                                                                                                                waitForText($text, [$timeout], [$selector]) : void
                                                                                                                                                                + Waits up to $timeout seconds for the given string to appear on the page.

                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Can also be passed a selector to search in, be as specific as possible when using selectors. + waitForText() will only watch the first instance of the matching selector / text provided. + If the given text doesn't appear, a timeout exception is thrown.

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +$I->waitForText('foo', 30); // secs
                                                                                                                                                              +$I->waitForText('foo', 30, '.title'); // secs
                                                                                                                                                              +?>
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This class extends \Codeception\Module\WebDriver

                                                                                                                                                              +

                                                                                                                                                              This class implements \Codeception\Lib\Interfaces\RequiresPackage, \Codeception\Lib\Interfaces\ConflictsWithModule, \Codeception\Lib\Interfaces\ElementLocator, \Codeception\Lib\Interfaces\PageSourceSaver, \Codeception\Lib\Interfaces\ScreenshotSaver, \Codeception\Lib\Interfaces\SessionSnapshot, \Codeception\Lib\Interfaces\MultiSession, \Codeception\Lib\Interfaces\Remote, \Codeception\Lib\Interfaces\Web

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/modules/WordPress/index.html b/v3/modules/WordPress/index.html new file mode 100644 index 000000000..78ef462ee --- /dev/null +++ b/v3/modules/WordPress/index.html @@ -0,0 +1,3335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + WordPress - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              WordPress module

                                                                                                                                                              +

                                                                                                                                                              This module requires good knowledge and attention to be used effectively; you can replace it with a combination of the WPBrowser module together with the WPLoader module in loadOnly mode. +This module should be used in functional tests, see levels of testing for more information.
                                                                                                                                                              +This module provides a middle-ground, in terms of testing and effects, between the fully isolated approach of the WPBrowser module and the fully integrated approach of the WPLoader module with loadOnly set to false.
                                                                                                                                                              +It allows to interact with WordPress on a very high level, using methods like $I->loginAs() or $I->amOnPage() as you could do with the WPBrowser module while also loading WordPress in the same variable scope as the tests as the WPLoader module would. +Due to WordPress reliance on constants, globals and side-effects this module will make requests to WordPress in an insulated manner and reproduce WordPress environment (globals and super-globals) after each response in the tests variable scope. +The module simulates a user interaction with the site without Javascript support, use the WPWebDriver module for any kind of testing that requires Javascript-based interaction with the site.

                                                                                                                                                              +

                                                                                                                                                              Module requirements for Codeception 4.0+

                                                                                                                                                              +

                                                                                                                                                              This module requires the codeception/lib-innerbrowser Composer package to work when wp-browser is used with Codeception 4.0.

                                                                                                                                                              +

                                                                                                                                                              To install the package run:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev codeception/lib-innerbrowser:^1.0
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Detecting requests coming from this module

                                                                                                                                                              +

                                                                                                                                                              When it runs this module will set the WPBROWSER_HOST_REQUEST environment variable.
                                                                                                                                                              +You can detect and use that information to, as an example, use the correct database in your test site wp-config.php file: +

                                                                                                                                                              <?php
                                                                                                                                                              +if ( 
                                                                                                                                                              +    // Custom header.
                                                                                                                                                              +    isset( $_SERVER['HTTP_X_TESTING'] )
                                                                                                                                                              +    // Custom user agent.
                                                                                                                                                              +    || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )
                                                                                                                                                              +    // The env var set by the WPClIr or WordPress modules.
                                                                                                                                                              +    || getenv( 'WPBROWSER_HOST_REQUEST' )
                                                                                                                                                              +) {
                                                                                                                                                              +    // Use the test database if the request comes from a test.
                                                                                                                                                              +    define( 'DB_NAME', 'wordpress_test' );
                                                                                                                                                              +} else {
                                                                                                                                                              +    // Else use the default one.
                                                                                                                                                              +    define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              +}
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Configuration

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • wpRootFolder required The absolute, or relative to the project root folder, path to the root WordPress installation folder. The WordPress installation root folder is the one that contains the wp-load.php file.
                                                                                                                                                              • +
                                                                                                                                                              • adminUsername required - This is the login name, not the "nice" name, of the administrator user of the WordPress test site. This will be used to fill the username field in WordPress login page.
                                                                                                                                                              • +
                                                                                                                                                              • adminPassword required - This is the the password of the administrator use of the WordPress test site. This will be used to fill the password in WordPress login page.
                                                                                                                                                              • +
                                                                                                                                                              • adminPath required - The path, relative to the WordPress test site home URL, to the administration area, usually /wp-admin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Example configuration

                                                                                                                                                              +
                                                                                                                                                                modules:
                                                                                                                                                              +      enabled:
                                                                                                                                                              +          - WordPress
                                                                                                                                                              +      config:
                                                                                                                                                              +          WordPress:
                                                                                                                                                              +              wpRootFolder: "/var/www/wordpress"
                                                                                                                                                              +              adminUsername: 'admin'
                                                                                                                                                              +              adminPassword: 'password'
                                                                                                                                                              +              adminPath: '/wp-admin'
                                                                                                                                                              +
                                                                                                                                                              + + +

                                                                                                                                                              Public API

                                                                                                                                                              + + +

                                                                                                                                                              amEditingPostWithId

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go to the admin page to edit the post with the specified ID. The method will not handle authentication the admin area.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $postId = $I->havePostInDatabase();
                                                                                                                                                              +  $I->amEditingPostWithId($postId);
                                                                                                                                                              +  $I->fillField('post_title', 'Post title');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • int $id - The post ID.
                                                                                                                                                              + +

                                                                                                                                                              amOnAdminAjaxPage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go to the admin-ajax.php page to start a synchronous, and blocking, GET AJAX request. The method will not handle authentication, nonces or authorization.

                                                                                                                                                              +
                                                                                                                                                              $I->amOnAdminAjaxPage(['action' => 'my-action', 'data' => ['id' => 23], 'nonce' => $nonce]);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/\Codeception\Module\array $queryVars - A string or array of query variables to append to the AJAX path.
                                                                                                                                                              + +

                                                                                                                                                              amOnAdminPage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go to a page in the admininstration area of the site.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAs('user', 'password');
                                                                                                                                                              +  // Go to the plugins management screen.
                                                                                                                                                              +  $I->amOnAdminPage('/plugins.php');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $page - The path, relative to the admin area URL, to the page.
                                                                                                                                                              + +

                                                                                                                                                              amOnCronPage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go to the cron page to start a synchronous, and blocking, GET request to the cron script.

                                                                                                                                                              +
                                                                                                                                                              // Triggers the cron job with an optional query argument.
                                                                                                                                                              +  $I->amOnCronPage('/?some-query-var=some-value');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/\Codeception\Module\array $queryVars - A string or array of query variables to append to the AJAX path.
                                                                                                                                                              + +

                                                                                                                                                              amOnPage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go to a page on the site. The module will try to reach the page, relative to the URL specified in the module configuration, without applying any permalink resolution.

                                                                                                                                                              +
                                                                                                                                                              // Go the the homepage.
                                                                                                                                                              +  $I->amOnPage('/');
                                                                                                                                                              +  // Go to the single page of post with ID 23.
                                                                                                                                                              +  $I->amOnPage('/?p=23');
                                                                                                                                                              +  // Go to search page for the string "foo".
                                                                                                                                                              +  $I->amOnPage('/?s=foo');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $page - The path to the page, relative to the the root URL.
                                                                                                                                                              + +

                                                                                                                                                              amOnPagesPage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go the "Pages" administration screen. The method will not handle authentication.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnPagesPage();
                                                                                                                                                              +  $I->see('Add New');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              amOnPluginsPage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Go to the plugins administration screen. The method will not handle authentication.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnPluginsPage();
                                                                                                                                                              +  $I->activatePlugin('hello-dolly');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              dontSeePluginInstalled

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Assert a plugin is not installed in the plugins administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnPluginsPage();
                                                                                                                                                              +  $I->dontSeePluginInstalled('my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $pluginSlug - The plugin slug, like "hello-dolly".
                                                                                                                                                              + +

                                                                                                                                                              extractCookie

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Grab a cookie value from the current session, sets it in the $_COOKIE array and returns its value. This method utility is to get, in the scope of test code, the value of a cookie set during the tests.

                                                                                                                                                              +
                                                                                                                                                              $id = $I->haveUserInDatabase('user', 'subscriber', ['user_pass' => 'pass']);
                                                                                                                                                              +  $I->loginAs('user', 'pass');
                                                                                                                                                              +  // The cookie is now set in the `$_COOKIE` super-global.
                                                                                                                                                              +  $I->extractCookie(LOGGED_IN_COOKIE);
                                                                                                                                                              +  // Generate a nonce using WordPress methods (see WPLoader in loadOnly mode) with correctly set context.
                                                                                                                                                              +  wp_set_current_user($id);
                                                                                                                                                              +  $nonce = wp_create_nonce('wp_rest');
                                                                                                                                                              +  // Use the generated nonce to make a request to the the REST API.
                                                                                                                                                              +  $I->haveHttpHeader('X-WP-Nonce', $nonce);
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $cookie - The cookie name.
                                                                                                                                                              • +
                                                                                                                                                              • array/\Codeception\Module\array/array $params - Parameters to filter the cookie value.
                                                                                                                                                              + +

                                                                                                                                                              getResponseContent

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns content of the last response. This method exposes an underlying API for custom assertions.

                                                                                                                                                              +
                                                                                                                                                              // In test class.
                                                                                                                                                              +  $this->assertContains($text, $this->getResponseContent(), "foo-bar");
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              getWpRootFolder

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns the absolute path to the WordPress root folder.

                                                                                                                                                              +
                                                                                                                                                              $root = $I->getWpRootFolder();
                                                                                                                                                              +  $this->assertFileExists($root . '/someFile.txt');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              grabWordPressTestCookie

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Returns WordPress default test cookie object if present.

                                                                                                                                                              +
                                                                                                                                                              // Grab the default WordPress test cookie.
                                                                                                                                                              +  $wpTestCookie = $I->grabWordPressTestCookie();
                                                                                                                                                              +  // Grab a customized version of the test cookie.
                                                                                                                                                              +  $myTestCookie = $I->grabWordPressTestCookie('my_test_cookie');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $name - Optional, overrides the default cookie name.
                                                                                                                                                              + +

                                                                                                                                                              logOut

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Navigate to the default WordPress logout page and click the logout link.

                                                                                                                                                              +
                                                                                                                                                              // Log out using the `wp-login.php` form and return to the current page.
                                                                                                                                                              +  $I->logOut(true);
                                                                                                                                                              +  // Log out using the `wp-login.php` form and remain there.
                                                                                                                                                              +  $I->logOut(false);
                                                                                                                                                              +  // Log out using the `wp-login.php` form and move to another page.
                                                                                                                                                              +  $I->logOut('/some-other-page');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • bool/bool/string $redirectTo - Whether to redirect to another (optionally specified) page after the logout.
                                                                                                                                                              + +

                                                                                                                                                              loginAs

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Login as the specified user. The method will not follow redirection, after the login, to any page.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAs('user', 'password');
                                                                                                                                                              +  $I->amOnAdminPage('/');
                                                                                                                                                              +  $I->seeElement('.admin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $username - The user login name.
                                                                                                                                                              • +
                                                                                                                                                              • string $password - The user password in plain text.
                                                                                                                                                              + +

                                                                                                                                                              loginAsAdmin

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Login as the administrator user using the credentials specified in the module configuration. The method will not follow redirection, after the login, to any page.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnAdminPage('/');
                                                                                                                                                              +  $I->see('Dashboard');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              seeErrorMessage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              In an administration screen look for an error admin notice. The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area. .notice.notice-error ones.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin()
                                                                                                                                                              +  $I->amOnAdminPage('/');
                                                                                                                                                              +  $I->seeErrorMessage('.my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/string/\Codeception\Module\array $classes - A list of classes the notice should have other than the
                                                                                                                                                              + +

                                                                                                                                                              seeMessage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              In an administration screen look for an admin notice. The check is class-based to decouple from internationalization. The method will not handle authentication and navigation the administration area.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin()
                                                                                                                                                              +  $I->amOnAdminPage('/');
                                                                                                                                                              +  $I->seeMessage('.missing-api-token.my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string/\Codeception\Module\array/string $classes - A list of classes the message should have in addition to the .notice one.
                                                                                                                                                              + +

                                                                                                                                                              seePluginActivated

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Assert a plugin is activated in the plugin administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnPluginsPage();
                                                                                                                                                              +  $I->seePluginActivated('my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $pluginSlug - The plugin slug, like "hello-dolly".
                                                                                                                                                              + +

                                                                                                                                                              seePluginDeactivated

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Assert a plugin is not activated in the plugins administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnPluginsPage();
                                                                                                                                                              +  $I->seePluginDeactivated('my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $pluginSlug - The plugin slug, like "hello-dolly".
                                                                                                                                                              + +

                                                                                                                                                              seePluginInstalled

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Assert a plugin is installed, no matter its activation status, in the plugin administration screen. The method will not handle authentication and navigation to the plugin administration screen.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAsAdmin();
                                                                                                                                                              +  $I->amOnPluginsPage();
                                                                                                                                                              +  $I->seePluginInstalled('my-plugin');
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • string $pluginSlug - The plugin slug, like "hello-dolly".
                                                                                                                                                              + +

                                                                                                                                                              seeWpDiePage

                                                                                                                                                              + +
                                                                                                                                                              + +

                                                                                                                                                              Checks that the current page is one generated by the wp_die function. The method will try to identify the page based on the default WordPress die page HTML attributes.

                                                                                                                                                              +
                                                                                                                                                              $I->loginAs('user', 'password');
                                                                                                                                                              +  $I->amOnAdminPage('/forbidden');
                                                                                                                                                              +  $I->seeWpDiePage();
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This class extends \Codeception\Lib\Framework

                                                                                                                                                              +

                                                                                                                                                              This class implements \Codeception\Lib\Interfaces\Web, \Codeception\Lib\Interfaces\PageSourceSaver, \Codeception\Lib\Interfaces\ElementLocator, \Codeception\Lib\Interfaces\ConflictsWithModule, \Codeception\Lib\Interfaces\DependsOnModule

                                                                                                                                                              + + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/requirements/index.html b/v3/requirements/index.html new file mode 100644 index 000000000..3922b9795 --- /dev/null +++ b/v3/requirements/index.html @@ -0,0 +1,3074 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Requirements - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Requirements

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Requirements

                                                                                                                                                              +

                                                                                                                                                              wp-browser has some requirements your development environment will need to fulfill for it to work correctly.

                                                                                                                                                              +

                                                                                                                                                              PHP

                                                                                                                                                              +

                                                                                                                                                              The minimum supported version of PHP supported by wp-browser is 5.6.

                                                                                                                                                              +

                                                                                                                                                              This requirement does not reflect on the minimum PHP version your plugin might require; see the FAQs for more information.

                                                                                                                                                              +

                                                                                                                                                              Composer

                                                                                                                                                              +

                                                                                                                                                              There is no phar version of wp-browser and it can only be installed using Composer.

                                                                                                                                                              +

                                                                                                                                                              See Composer installation guide for more information.

                                                                                                                                                              +

                                                                                                                                                              WordPress, MySQL, Apache/Nginx

                                                                                                                                                              +

                                                                                                                                                              wp-browser will not download, install and configure WordPress for you.

                                                                                                                                                              +

                                                                                                                                                              It will also not download, install and setup MySQL, Apache, Nginx or any other technology required by a fully functional WordPress installation for you.

                                                                                                                                                              +

                                                                                                                                                              You need to set up a local WordPress installation on your own; you can use your preferred solution to do it.

                                                                                                                                                              +

                                                                                                                                                              In the documentation I will show automated ways to do this but, for most projects, that's not the best solution.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/setting-up-minimum-wordpress-installation/index.html b/v3/setting-up-minimum-wordpress-installation/index.html new file mode 100644 index 000000000..25ae89477 --- /dev/null +++ b/v3/setting-up-minimum-wordpress-installation/index.html @@ -0,0 +1,3017 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting up a minimum WordPress installation - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Setting up a minimum WordPress installation

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up a minimum WordPress installation

                                                                                                                                                              +

                                                                                                                                                              As mentioned in Installation section wp-browser will not download, configure and install WordPress for you.

                                                                                                                                                              +

                                                                                                                                                              On a high level, once WordPress is installed and configured, whatever local development environment solution you've used, there are some information you'll need to gather before moving into wp-browser configuration.

                                                                                                                                                              +

                                                                                                                                                              While there will be a section dedicated to different environments and setups I will outline below the example setup I will use, in the next section, to configure wp-browser:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • WordPress is installed, on my machine, at /Users/luca/Sites/wordpress.
                                                                                                                                                              • +
                                                                                                                                                              • I'm running MySQL server locally; I can connect to the MySQL server with the command mysql -u root -h 127.0.0.1 -P 3306; there is no password.
                                                                                                                                                              • +
                                                                                                                                                              • I've created two databases, wordpress and tests, with the command: +
                                                                                                                                                                mysql -u root -h 127.0.0.1 -P 3306 -e "create database if not exists wordpress; create database if not exists tests"
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • I've configured the /Users/luca/Sites/wordpress/wp-config.php file like below (redacted for brevity): +
                                                                                                                                                                <?php
                                                                                                                                                                +define( 'DB_NAME', 'wordpress' );
                                                                                                                                                                +define( 'DB_USER', 'root' );
                                                                                                                                                                +define( 'DB_PASSWORD', '' );
                                                                                                                                                                +define( 'DB_HOST', '127.0.0.1' );
                                                                                                                                                                +define( 'DB_CHARSET', 'utf8' );
                                                                                                                                                                +define( 'DB_COLLATE', '' );
                                                                                                                                                                +
                                                                                                                                                                +$table_prefix = 'wp_';
                                                                                                                                                                +
                                                                                                                                                                +if ( ! defined( 'ABSPATH' ) )
                                                                                                                                                                +    define( 'ABSPATH', dirname( __FILE__ ) . '/' );
                                                                                                                                                                +
                                                                                                                                                                +require_once ABSPATH . 'wp-settings.php';
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • To serve the site I'm using PHP built-in server with the command: +
                                                                                                                                                                (cd /Users/luca/Sites/wordpress; php -S localhost:8080)
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              • I can access the WordPress homepage at http://localhost:8080 and the administration area at http://localhost:8080/wp-admin.
                                                                                                                                                              • +
                                                                                                                                                              • I've installed WordPress via its UI (http://localhost:8080/wp-admin), the administrator username is admin, the administrator password is password.
                                                                                                                                                              • +
                                                                                                                                                              • I'm testing a plugin and that plugin is in the folder, relative to the WordPress root folder, wp-content/plugins/acme-plugin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              With all the steps above done I can now move into the actual wp-browser configuration phase.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/tutorials/automatically-change-db-in-tests/index.html b/v3/tutorials/automatically-change-db-in-tests/index.html new file mode 100644 index 000000000..8ae446a95 --- /dev/null +++ b/v3/tutorials/automatically-change-db-in-tests/index.html @@ -0,0 +1,3072 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Automatically change database during acceptance and functional tests - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Automatically change database during acceptance and functional tests

                                                                                                                                                              +

                                                                                                                                                              You should always back up any site you run tests on if you care about the site content.

                                                                                                                                                              +

                                                                                                                                                              Now this disclaimer has been made ad nauseam; there's a simple way to use a different database when during tests.

                                                                                                                                                              +

                                                                                                                                                              Identifying requests

                                                                                                                                                              +

                                                                                                                                                              The first component of this solution is identifying the source of the current HTTP request.
                                                                                                                                                              +WordPress makes this identification before deciding which database to use.

                                                                                                                                                              +

                                                                                                                                                              To provide the WordPress installation with this information, you can set the headers entry of the WPBrowser or WPWebDriver module in the suite configuration file.

                                                                                                                                                              +

                                                                                                                                                              As an example here is an acceptance suite configuration file setting two custom headers, X_WPBROWSER_REQUEST and X_TEST_REQUEST, on each request sent by the WPWebDriver module:

                                                                                                                                                              +
                                                                                                                                                              actor: AcceptanceTester
                                                                                                                                                              +modules:
                                                                                                                                                              +    enabled:
                                                                                                                                                              +        - WPDb
                                                                                                                                                              +        - WPBrowser
                                                                                                                                                              +        - \Helper\Acceptance
                                                                                                                                                              +    config:
                                                                                                                                                              +        WPDb:
                                                                                                                                                              +            dsn: 'mysql:host=localhost;dbname=tests'
                                                                                                                                                              +            user: 'root'
                                                                                                                                                              +            password: 'root'
                                                                                                                                                              +            dump: 'tests/_data/dump.sql'
                                                                                                                                                              +            populate: true
                                                                                                                                                              +            cleanup: true
                                                                                                                                                              +            waitlock: 10
                                                                                                                                                              +            url: 'http://wp.test'
                                                                                                                                                              +            urlReplacement: true
                                                                                                                                                              +            tablePrefix: 'wp_'
                                                                                                                                                              +        WPBrowser:
                                                                                                                                                              +            url: 'http://wp.test'
                                                                                                                                                              +            adminUsername: 'admin'
                                                                                                                                                              +            adminPassword: 'admin'
                                                                                                                                                              +            adminPath: '/wp-admin'
                                                                                                                                                              +            headers:
                                                                                                                                                              +                X_WPBROWSER_REQUEST: 1
                                                                                                                                                              +                X_TEST_REQUEST: 1
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The two headers are sent on each HTTP request type, not just on GET type requests.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Using a different database to handle test requests

                                                                                                                                                              +

                                                                                                                                                              Now that each request made by the WPWebDriver module contains those two headers, it's time for WordPress to check those and change the database to use accordingly.

                                                                                                                                                              +

                                                                                                                                                              The database to use is set by the DB_NAME constant that is, in turn, set in the wp-config.php file.
                                                                                                                                                              +Different setups could involve more complex configurations for the wp-config.php file but, for the sake of simplicity, I assume the default WordPress wp-config.php file structure.
                                                                                                                                                              +In the example below, the default database name is wordpress, while the name of the test database is tests.

                                                                                                                                                              +
                                                                                                                                                              - define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              ++ if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {
                                                                                                                                                              ++     define( 'DB_NAME', 'tests' );
                                                                                                                                                              ++ } else {
                                                                                                                                                              ++     define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              ++ }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The diff shows the replacement done in the WordPress installation wp-config.php file.

                                                                                                                                                              +

                                                                                                                                                              For copy-and-paste pleasure, replace the line starting with:

                                                                                                                                                              +
                                                                                                                                                              define( 'DB_NAME', 'default_db_name' );
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              With this snippet:

                                                                                                                                                              +
                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {
                                                                                                                                                              +      define( 'DB_NAME', 'test_db_name' );
                                                                                                                                                              +} else {
                                                                                                                                                              +      define( 'DB_NAME', 'default_db_name' );
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Where default_db_name is the name of the database your test WordPress installation normally uses.

                                                                                                                                                              +

                                                                                                                                                              Happy, and safer, testing.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/tutorials/images/local-flywheel-adminer.png b/v3/tutorials/images/local-flywheel-adminer.png new file mode 100644 index 000000000..1fe9c4b4f Binary files /dev/null and b/v3/tutorials/images/local-flywheel-adminer.png differ diff --git a/v3/tutorials/images/local-flywheel-codecept-version.png b/v3/tutorials/images/local-flywheel-codecept-version.png new file mode 100644 index 000000000..e64d3e568 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-codecept-version.png differ diff --git a/v3/tutorials/images/local-flywheel-composer-init.png b/v3/tutorials/images/local-flywheel-composer-init.png new file mode 100644 index 000000000..0e78b8370 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-composer-init.png differ diff --git a/v3/tutorials/images/local-flywheel-create-database.png b/v3/tutorials/images/local-flywheel-create-database.png new file mode 100644 index 000000000..294662bd7 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-create-database.png differ diff --git a/v3/tutorials/images/local-flywheel-db-export.png b/v3/tutorials/images/local-flywheel-db-export.png new file mode 100644 index 000000000..451bebd8d Binary files /dev/null and b/v3/tutorials/images/local-flywheel-db-export.png differ diff --git a/v3/tutorials/images/local-flywheel-db-import.png b/v3/tutorials/images/local-flywheel-db-import.png new file mode 100644 index 000000000..2f6255db3 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-db-import.png differ diff --git a/v3/tutorials/images/local-flywheel-mac-db-creds.png b/v3/tutorials/images/local-flywheel-mac-db-creds.png new file mode 100644 index 000000000..a70952bfb Binary files /dev/null and b/v3/tutorials/images/local-flywheel-mac-db-creds.png differ diff --git a/v3/tutorials/images/local-flywheel-mac-wpbrowser-init-1.png b/v3/tutorials/images/local-flywheel-mac-wpbrowser-init-1.png new file mode 100644 index 000000000..9cad5f58b Binary files /dev/null and b/v3/tutorials/images/local-flywheel-mac-wpbrowser-init-1.png differ diff --git a/v3/tutorials/images/local-flywheel-mac-wpbrowser-init-2.png b/v3/tutorials/images/local-flywheel-mac-wpbrowser-init-2.png new file mode 100644 index 000000000..a5266c418 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-mac-wpbrowser-init-2.png differ diff --git a/v3/tutorials/images/local-flywheel-sites-path.png b/v3/tutorials/images/local-flywheel-sites-path.png new file mode 100644 index 000000000..ffbad733b Binary files /dev/null and b/v3/tutorials/images/local-flywheel-sites-path.png differ diff --git a/v3/tutorials/images/local-flywheel-win-db-creds.png b/v3/tutorials/images/local-flywheel-win-db-creds.png new file mode 100644 index 000000000..3af8637f0 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-win-db-creds.png differ diff --git a/v3/tutorials/images/local-flywheel-win-wpbrowser-init-1.png b/v3/tutorials/images/local-flywheel-win-wpbrowser-init-1.png new file mode 100644 index 000000000..34b219621 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-win-wpbrowser-init-1.png differ diff --git a/v3/tutorials/images/local-flywheel-win-wpbrowser-init-2.png b/v3/tutorials/images/local-flywheel-win-wpbrowser-init-2.png new file mode 100644 index 000000000..b97785f36 Binary files /dev/null and b/v3/tutorials/images/local-flywheel-win-wpbrowser-init-2.png differ diff --git a/v3/tutorials/images/local-lite-mac-db-creds.png b/v3/tutorials/images/local-lite-mac-db-creds.png new file mode 100644 index 000000000..3119940ad Binary files /dev/null and b/v3/tutorials/images/local-lite-mac-db-creds.png differ diff --git a/v3/tutorials/images/local-my-plugin-shows.png b/v3/tutorials/images/local-my-plugin-shows.png new file mode 100644 index 000000000..fd3f72741 Binary files /dev/null and b/v3/tutorials/images/local-my-plugin-shows.png differ diff --git a/v3/tutorials/images/mac-codecept-version.png b/v3/tutorials/images/mac-codecept-version.png new file mode 100644 index 000000000..51cc2e099 Binary files /dev/null and b/v3/tutorials/images/mac-codecept-version.png differ diff --git a/v3/tutorials/images/mac-composer-init.png b/v3/tutorials/images/mac-composer-init.png new file mode 100644 index 000000000..f77117f86 Binary files /dev/null and b/v3/tutorials/images/mac-composer-init.png differ diff --git a/v3/tutorials/images/mamp-create-db.png b/v3/tutorials/images/mamp-create-db.png new file mode 100644 index 000000000..1f18693cd Binary files /dev/null and b/v3/tutorials/images/mamp-create-db.png differ diff --git a/v3/tutorials/images/mamp-db-export.png b/v3/tutorials/images/mamp-db-export.png new file mode 100644 index 000000000..57c1ebdc8 Binary files /dev/null and b/v3/tutorials/images/mamp-db-export.png differ diff --git a/v3/tutorials/images/mamp-db-import.png b/v3/tutorials/images/mamp-db-import.png new file mode 100644 index 000000000..bcf2df2a5 Binary files /dev/null and b/v3/tutorials/images/mamp-db-import.png differ diff --git a/v3/tutorials/images/mamp-mac-dirs.png b/v3/tutorials/images/mamp-mac-dirs.png new file mode 100644 index 000000000..cede1dccb Binary files /dev/null and b/v3/tutorials/images/mamp-mac-dirs.png differ diff --git a/v3/tutorials/images/mamp-mac-ports.png b/v3/tutorials/images/mamp-mac-ports.png new file mode 100644 index 000000000..486768b7d Binary files /dev/null and b/v3/tutorials/images/mamp-mac-ports.png differ diff --git a/v3/tutorials/images/mamp-my-plugin-shows.png b/v3/tutorials/images/mamp-my-plugin-shows.png new file mode 100644 index 000000000..8f9133fb0 Binary files /dev/null and b/v3/tutorials/images/mamp-my-plugin-shows.png differ diff --git a/v3/tutorials/images/mamp-wp-installation-1.png b/v3/tutorials/images/mamp-wp-installation-1.png new file mode 100644 index 000000000..ce5543a9a Binary files /dev/null and b/v3/tutorials/images/mamp-wp-installation-1.png differ diff --git a/v3/tutorials/images/mamp-wpbrowser-init-1.png b/v3/tutorials/images/mamp-wpbrowser-init-1.png new file mode 100644 index 000000000..7598ffb37 Binary files /dev/null and b/v3/tutorials/images/mamp-wpbrowser-init-1.png differ diff --git a/v3/tutorials/images/mamp-wpbrowser-init-2.png b/v3/tutorials/images/mamp-wpbrowser-init-2.png new file mode 100644 index 000000000..b886d043f Binary files /dev/null and b/v3/tutorials/images/mamp-wpbrowser-init-2.png differ diff --git a/v3/tutorials/images/vvv-codecept-version.png b/v3/tutorials/images/vvv-codecept-version.png new file mode 100644 index 000000000..40dde49a0 Binary files /dev/null and b/v3/tutorials/images/vvv-codecept-version.png differ diff --git a/v3/tutorials/images/vvv-my-plugin-composer-init.png b/v3/tutorials/images/vvv-my-plugin-composer-init.png new file mode 100644 index 000000000..ba4991489 Binary files /dev/null and b/v3/tutorials/images/vvv-my-plugin-composer-init.png differ diff --git a/v3/tutorials/images/vvv-my-plugin-shows.png b/v3/tutorials/images/vvv-my-plugin-shows.png new file mode 100644 index 000000000..feb2bee49 Binary files /dev/null and b/v3/tutorials/images/vvv-my-plugin-shows.png differ diff --git a/v3/tutorials/images/vvv-ssh.png b/v3/tutorials/images/vvv-ssh.png new file mode 100644 index 000000000..4d8ae948d Binary files /dev/null and b/v3/tutorials/images/vvv-ssh.png differ diff --git a/v3/tutorials/images/vvv-up.png b/v3/tutorials/images/vvv-up.png new file mode 100644 index 000000000..25f513b55 Binary files /dev/null and b/v3/tutorials/images/vvv-up.png differ diff --git a/v3/tutorials/images/vvv-wp-browser-init-1.png b/v3/tutorials/images/vvv-wp-browser-init-1.png new file mode 100644 index 000000000..c4bbf5490 Binary files /dev/null and b/v3/tutorials/images/vvv-wp-browser-init-1.png differ diff --git a/v3/tutorials/images/vvv-wp-browser-init-2.png b/v3/tutorials/images/vvv-wp-browser-init-2.png new file mode 100644 index 000000000..e9a08fe68 Binary files /dev/null and b/v3/tutorials/images/vvv-wp-browser-init-2.png differ diff --git a/v3/tutorials/images/vvv-wp-db-backup.png b/v3/tutorials/images/vvv-wp-db-backup.png new file mode 100644 index 000000000..1d77634ba Binary files /dev/null and b/v3/tutorials/images/vvv-wp-db-backup.png differ diff --git a/v3/tutorials/images/wamp-codecept-version.png b/v3/tutorials/images/wamp-codecept-version.png new file mode 100644 index 000000000..758724c22 Binary files /dev/null and b/v3/tutorials/images/wamp-codecept-version.png differ diff --git a/v3/tutorials/images/wamp-composer-init.png b/v3/tutorials/images/wamp-composer-init.png new file mode 100644 index 000000000..fbfb7ac04 Binary files /dev/null and b/v3/tutorials/images/wamp-composer-init.png differ diff --git a/v3/tutorials/images/wamp-create-db.png b/v3/tutorials/images/wamp-create-db.png new file mode 100644 index 000000000..b657d8075 Binary files /dev/null and b/v3/tutorials/images/wamp-create-db.png differ diff --git a/v3/tutorials/images/wamp-db-export.png b/v3/tutorials/images/wamp-db-export.png new file mode 100644 index 000000000..61dd287cd Binary files /dev/null and b/v3/tutorials/images/wamp-db-export.png differ diff --git a/v3/tutorials/images/wamp-db-import.png b/v3/tutorials/images/wamp-db-import.png new file mode 100644 index 000000000..4ec724a35 Binary files /dev/null and b/v3/tutorials/images/wamp-db-import.png differ diff --git a/v3/tutorials/images/wamp-my-plugin-shows.png b/v3/tutorials/images/wamp-my-plugin-shows.png new file mode 100644 index 000000000..bd032656b Binary files /dev/null and b/v3/tutorials/images/wamp-my-plugin-shows.png differ diff --git a/v3/tutorials/images/wamp-virtualhost-creation-1.png b/v3/tutorials/images/wamp-virtualhost-creation-1.png new file mode 100644 index 000000000..44d0a7df3 Binary files /dev/null and b/v3/tutorials/images/wamp-virtualhost-creation-1.png differ diff --git a/v3/tutorials/images/wamp-virtualhost-creation-2.png b/v3/tutorials/images/wamp-virtualhost-creation-2.png new file mode 100644 index 000000000..64fddda4d Binary files /dev/null and b/v3/tutorials/images/wamp-virtualhost-creation-2.png differ diff --git a/v3/tutorials/images/wamp-wp-installation-1.png b/v3/tutorials/images/wamp-wp-installation-1.png new file mode 100644 index 000000000..ad206a953 Binary files /dev/null and b/v3/tutorials/images/wamp-wp-installation-1.png differ diff --git a/v3/tutorials/images/wamp-wpbrowser-init-1.png b/v3/tutorials/images/wamp-wpbrowser-init-1.png new file mode 100644 index 000000000..fbad77c2e Binary files /dev/null and b/v3/tutorials/images/wamp-wpbrowser-init-1.png differ diff --git a/v3/tutorials/images/wamp-wpbrowser-init-2.png b/v3/tutorials/images/wamp-wpbrowser-init-2.png new file mode 100644 index 000000000..867e228c5 Binary files /dev/null and b/v3/tutorials/images/wamp-wpbrowser-init-2.png differ diff --git a/v3/tutorials/images/wp-installation-2.png b/v3/tutorials/images/wp-installation-2.png new file mode 100644 index 000000000..736e8c3e4 Binary files /dev/null and b/v3/tutorials/images/wp-installation-2.png differ diff --git a/v3/tutorials/local-flywheel-setup/index.html b/v3/tutorials/local-flywheel-setup/index.html new file mode 100644 index 000000000..2dcf0c66f --- /dev/null +++ b/v3/tutorials/local-flywheel-setup/index.html @@ -0,0 +1,3475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting up wp-browser on Local by Flywheel to test a plugin - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Setting up wp-browser on Local by Flywheel to test a plugin

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser with Local by Flywheel to test a plugin

                                                                                                                                                              +

                                                                                                                                                              Note: the original version of this guide used, on Mac, the version of Local by Flywheel based on VirtualBox and Docker containers. That version has been replaced by a new one that will not use any virtualization layer. The UI is almost the same but, for back-compatibility purposes, I've not removed the references to the previous version; I have, instead, pointed out where the set up values and procedures might differ due to the changes.

                                                                                                                                                              +

                                                                                                                                                              Requirements

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A Mac or Windows machine
                                                                                                                                                              • +
                                                                                                                                                              • A working installation of Local By Flywheel.
                                                                                                                                                              • +
                                                                                                                                                              • You should be able to create sites and visit them from your browser without issues.
                                                                                                                                                              • +
                                                                                                                                                              • Composer installed and working on your terminal PATH, you should be able to run composer --version at the terminal and see the version correctly.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Install Local by Flywheel

                                                                                                                                                              +

                                                                                                                                                              This walk-through starts after Local by Flywheel has been installed and is correctly running on your machine; you can download Local from the site and follow the installation instructions.

                                                                                                                                                              +

                                                                                                                                                              In the context of this guide I'm assuming the sites directory is ~/Local Sites, the default "Sites Path" in Local preferences.

                                                                                                                                                              +

                                                                                                                                                              If your document root lies elsewhere, replace the ~/Local Sites path with the actual directory in each command.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Creating the databases and installing WordPress

                                                                                                                                                              +

                                                                                                                                                              Using Local UI create a new site:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • The site name is myplugin.
                                                                                                                                                              • +
                                                                                                                                                              • The site administrator user name is admin.
                                                                                                                                                              • +
                                                                                                                                                              • The site administrator password is password.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Once Local provisioned and installed the new site, open the "Database" administration tab and, depending on your OS, start a database administration UI or website. +In the image below I'm using Adminer:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Create a database called tests:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Make sure you can visit the WordPress installation at http://myplugin.local and that you can correctly access the administration area at http://myplugin.local/wp-admin.

                                                                                                                                                              +

                                                                                                                                                              Scaffolding the project folder

                                                                                                                                                              +

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              +

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins.
                                                                                                                                                              +Create the main plugin file in the WordPress installation plugins directory, in the ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin/my-plugin.php file:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +/**
                                                                                                                                                              + * Plugin Name: My plugin
                                                                                                                                                              + */ 
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the WordPress installation at http://myplugin.local/wp-admin/plugins.php.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Installing wp-browser

                                                                                                                                                              +

                                                                                                                                                              Open a terminal window and navigate to the plugin directory and initialize the Composer project:

                                                                                                                                                              +
                                                                                                                                                              cd ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin
                                                                                                                                                              +composer init
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. +Here is the composer.json file generated by the above answers:

                                                                                                                                                              +
                                                                                                                                                              {
                                                                                                                                                              +    "name": "local/my-plugin",
                                                                                                                                                              +    "type": "wordpress-plugin",
                                                                                                                                                              +    "require": {}
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev lucatume/wp-browser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder.
                                                                                                                                                              +To check Codeception is correctly installed run this command:

                                                                                                                                                              +
                                                                                                                                                              vendor/bin/codecept --version
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser

                                                                                                                                                              +

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              +

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the WordPress site "normal" database: this is the database that stores the data of the site I would see when visiting the local installation URL at http://myplugin.local.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the database dedicated to the integration and "WordPress unit" tests: this database will be used to install WordPress during integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that your first step should be to backup the site database.

                                                                                                                                                              +

                                                                                                                                                              You can create a backup of the current site database contents using whatever tool the version of Local you're using provides.
                                                                                                                                                              +In this example I'm using Adminer:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              At any moment you can re-import the site database dump using, again, phpMyAdmin, under the "Import" tab:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Bootstrapping and configuring wp-browser

                                                                                                                                                              +

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              +
                                                                                                                                                              cd ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin
                                                                                                                                                              +vendor/bin/codecept init wpbrowser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The initialization guide will ask a number of questions.

                                                                                                                                                              +

                                                                                                                                                              Windows configuration

                                                                                                                                                              +

                                                                                                                                                              In the screenshots below are the answers I used to configure wp-browser on Windows.

                                                                                                                                                              +

                                                                                                                                                              Note that I've set up the database host using the values provided by Local UI, yours might differ depending on the version of Local you're using:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • +
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • +
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • +
                                                                                                                                                              • What is the path of the WordPress root directory? ~/Local Sites/myplugin/app/public
                                                                                                                                                              • +
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database used by the test site? localhost:10003
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost:10003
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the URL the test site? http://myplugin.local
                                                                                                                                                              • +
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@myplugin.local
                                                                                                                                                              • +
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • +
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • +
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • +
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • +
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              +

                                                                                                                                                              Mac configuration

                                                                                                                                                              +

                                                                                                                                                              In the screenshots below are the answers I used to configure wp-browser on Mac.

                                                                                                                                                              +

                                                                                                                                                              Note that I've set up the database host using the values provided by Local UI, yours might differ.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              This screenshot is from the previous version of Local, the one based on VirtualBox and Docker:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • +
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • +
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • +
                                                                                                                                                              • What is the path of the WordPress root directory? ~/Local Sites/myplugin/app/public
                                                                                                                                                              • +
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database used by the test site? /Users/lucatume/Library/Application Support/Local/run/FjKWfVMGd/mysql/mysqld.sock ( or 192.168.95.100:4055 on an older version of Local)
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database WPLoader should use? /Users/lucatume/Library/Application Support/Local/run/FjKWfVMGd/mysql/mysqld.sock (or 192.168.95.100:4055 on an older version of Local)
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the URL the test site? http://myplugin.local
                                                                                                                                                              • +
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@myplugin.local
                                                                                                                                                              • +
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • +
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • +
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • +
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • +
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              +

                                                                                                                                                              Setting up the starting database fixture

                                                                                                                                                              +

                                                                                                                                                              A "fixture", in testing terms, is a minimal, starting environment shared by all tests.
                                                                                                                                                              +In BDD it's the Background any scenario will share. +In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • +
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • +
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              You should set up this fixture "manually", using the site administration UI at http://myplugin.local/wp-admin.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              When you're done setting up the initial database fixture, export it using the "Export" tab of your database tool of choice, and move the file to the ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin/tests/_data/dump.sql directory.

                                                                                                                                                              +

                                                                                                                                                              There is one last step left to complete the setup.

                                                                                                                                                              +

                                                                                                                                                              Using the tests database in acceptance and functional tests

                                                                                                                                                              +

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              +

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              +

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the ~/Local Sites/myplugin/app/public/wp-config.php file, the DB_NAME constant is set to local.

                                                                                                                                                              +

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • If the request is a normal one, use the local database.
                                                                                                                                                              • +
                                                                                                                                                              • If the request comes from a test, use the tests database.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              In your IDE/text-editor of choice edit the ~/Local Sites/myplugin/app/public/wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              +
                                                                                                                                                              - define( 'DB_NAME', 'local' );
                                                                                                                                                              ++ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { 
                                                                                                                                                              ++    define( 'DB_NAME', 'tests' );
                                                                                                                                                              ++ } else {
                                                                                                                                                              ++    define( 'DB_NAME', 'local' );
                                                                                                                                                              ++ }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              +
                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {
                                                                                                                                                              +        define( 'DB_NAME', 'tests' );
                                                                                                                                                              +} else {
                                                                                                                                                              +        define( 'DB_NAME', 'local' );
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              +
                                                                                                                                                              headers:
                                                                                                                                                              +    X_TEST_REQUEST: 1
                                                                                                                                                              +    X_WPBROWSER_REQUEST: 1
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers.
                                                                                                                                                              +Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              +

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              +

                                                                                                                                                              Sanity check

                                                                                                                                                              +

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              +

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              +

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works.
                                                                                                                                                              +Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              +
                                                                                                                                                              cd ~/Local Sites/myplugin/app/public/wp-content/plugins/my-plugin 
                                                                                                                                                              +vendor/bin/codecept run acceptance
                                                                                                                                                              +vendor/bin/codecept run functional
                                                                                                                                                              +vendor/bin/codecept run wpunit
                                                                                                                                                              +vendor/bin/codecept run unit
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept to see a list of the available commands.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/tutorials/mamp-mac-setup/index.html b/v3/tutorials/mamp-mac-setup/index.html new file mode 100644 index 000000000..45561eb5d --- /dev/null +++ b/v3/tutorials/mamp-mac-setup/index.html @@ -0,0 +1,3385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting up wp-browser on MAMP for Mac to test a plugin - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Setting up wp-browser on MAMP for Mac to test a plugin

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser with MAMP on Mac to test a plugin

                                                                                                                                                              +

                                                                                                                                                              Requirements

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A Mac machine
                                                                                                                                                              • +
                                                                                                                                                              • A working installation of MAMP.
                                                                                                                                                              • +
                                                                                                                                                              • You should be able to create sites and visit them from your browser without issues.
                                                                                                                                                              • +
                                                                                                                                                              • Composer installed and working on your terminal PATH, you should be able to run composer --version at the terminal and see the version correctly.
                                                                                                                                                              • +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The version of MAMP used in this tutorial is the free, non PRO, one. MAMP PRO provides more features, but the setup instructions should remain valid.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Install and configure MAMP

                                                                                                                                                              +

                                                                                                                                                              This walk-through starts after MAMP has been installed and is correctly running on the host machine; you can download MAMP from the site and follow the installation instructions.
                                                                                                                                                              +In the context of this guide I'm assuming the "Document Root" directory is the default one, in the /Applications/MAMP/htdocs directory.
                                                                                                                                                              +If your document root lies elsewhere, replace the /Applications/MAMP/htdocs path with the actual directory in each command.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Creating the databases and installing WordPress

                                                                                                                                                              +

                                                                                                                                                              Go to the http://localhost/phpMyAdmin/ page and create two new databases:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • wordpress is the database you will use for WordPress
                                                                                                                                                              • +
                                                                                                                                                              • tests is the database you will use for the tests
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Unzip the the WordPress files into the /Applications/MAMP/htdocs and head over to http://localhost to install WordPress.

                                                                                                                                                              +

                                                                                                                                                              The database credentials for the installation are:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Database name: wordpress
                                                                                                                                                              • +
                                                                                                                                                              • Database user: root
                                                                                                                                                              • +
                                                                                                                                                              • Database password: root
                                                                                                                                                              • +
                                                                                                                                                              • Database host: localhost
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Use admin as administrator user name and password as password for the administrator user.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Make sure you can visit the WordPress installation at http://localhost and that you can correctly access the administration area at http://localhost/wp-admin.

                                                                                                                                                              +

                                                                                                                                                              Scaffolding the project folder

                                                                                                                                                              +

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              +

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins.
                                                                                                                                                              +Create the main plugin file in the WordPress installation plugins directory, in the /Applications/MAMP/htdocs/wp-content/plugins/my-plugin/my-plugin.php file:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +/**
                                                                                                                                                              + * Plugin Name: My plugin
                                                                                                                                                              + */ 
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the WordPress installation at http://localhost/wp-admin/plugins.php.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Installing wp-browser

                                                                                                                                                              +

                                                                                                                                                              Open a terminal window and navigate to the plugin directory and initialize the Composer project:

                                                                                                                                                              +
                                                                                                                                                              cd /Applications/MAMP/htdocs/wp-content/plugins/my-plugin
                                                                                                                                                              +composer init
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. +Here is the composer.json file generated by the above answers:

                                                                                                                                                              +
                                                                                                                                                              {
                                                                                                                                                              +    "name": "mamp/my-plugin",
                                                                                                                                                              +    "type": "wordpress-plugin",
                                                                                                                                                              +    "require": {}
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev lucatume/wp-browser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder.
                                                                                                                                                              +To check Codeception is correctly installed run this command:

                                                                                                                                                              +
                                                                                                                                                              vendor/bin/codecept --version
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser

                                                                                                                                                              +

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              +

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the WordPress site "normal" database: this is the database that stores the data of the site I would see when visiting the local installation URL at http://localhost.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the database dedicated to the integration and "WordPress unit" tests: this database will be used to install WordPress during integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that your first step should be to backup the site database.

                                                                                                                                                              +

                                                                                                                                                              You can create a backup of the current site database contents using phpMyAdmin, at http://localhost/phpMyAdmin/, under the "Export" tab:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              At any moment you can re-import the site database dump using, again, phpMyAdmin, under the "Import" tab:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Bootstrapping and configuring wp-browser

                                                                                                                                                              +

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              +
                                                                                                                                                              cd /Applications/MAMP/htdocs/wp-content/plugins/my-plugin
                                                                                                                                                              +vendor/bin/codecept init wpbrowser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The initialization guide will ask a number of questions.
                                                                                                                                                              +In the screenshots below are the answers I used to configure wp-browser.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • +
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • +
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • +
                                                                                                                                                              • What is the path of the WordPress root directory? /Applications/MAMP/htdocs
                                                                                                                                                              • +
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database used by the test site? localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the URL the test site? http://localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@wp.test
                                                                                                                                                              • +
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • +
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • +
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • +
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • +
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              +

                                                                                                                                                              Setting up the starting database fixture

                                                                                                                                                              +

                                                                                                                                                              A "fixture", in testing terms, is a minimal, starting environment shared by all tests.
                                                                                                                                                              +In BDD it's the Background any scenario will share. +In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • +
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • +
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              You should set up this fixture "manually", using the site administration UI at http://localhost/wp-admin.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              When you're done setting up the initial database fixture, export it using the "Export" tab of phpMyAdmin, at http://localhost/phpMyAdmin/ and move the file to the /Applications/MAMP/htdocs/wp-content/plugins/my-plugin/tests/_data/dump.sql directory.

                                                                                                                                                              +

                                                                                                                                                              There is one last step left to complete the setup.

                                                                                                                                                              +

                                                                                                                                                              Using the tests database in acceptance and functional tests

                                                                                                                                                              +

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              +

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              +

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the /Applications/MAMP/htdocs/wp-config.php file, the DB_NAME constant is set to wordpress.

                                                                                                                                                              +

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • If the request is a normal one, use the wordpress database.
                                                                                                                                                              • +
                                                                                                                                                              • If the request comes from a test, use the tests database.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              In your IDE/text-editor of choice edit the /Applications/MAMP/htdocs/wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              +
                                                                                                                                                              - define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              ++ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { 
                                                                                                                                                              ++    define( 'DB_NAME', 'tests' );
                                                                                                                                                              ++ } else {
                                                                                                                                                              ++    define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              ++ }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              +
                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {
                                                                                                                                                              +        define( 'DB_NAME', 'tests' );
                                                                                                                                                              +} else {
                                                                                                                                                              +        define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              +
                                                                                                                                                              headers:
                                                                                                                                                              +    X_TEST_REQUEST: 1
                                                                                                                                                              +    X_WPBROWSER_REQUEST: 1
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers.
                                                                                                                                                              +Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              +

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              +

                                                                                                                                                              Sanity check

                                                                                                                                                              +

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              +

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              +

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works.
                                                                                                                                                              +Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              +
                                                                                                                                                              cd /Applications/MAMP/htdocs/wp-content/plugins/my-plugin 
                                                                                                                                                              +vendor/bin/codecept run acceptance
                                                                                                                                                              +vendor/bin/codecept run functional
                                                                                                                                                              +vendor/bin/codecept run wpunit
                                                                                                                                                              +vendor/bin/codecept run unit
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept to see a list of the available commands.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/tutorials/vvv-setup/index.html b/v3/tutorials/vvv-setup/index.html new file mode 100644 index 000000000..cf4e89687 --- /dev/null +++ b/v3/tutorials/vvv-setup/index.html @@ -0,0 +1,3473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting up wp-browser on VVV to test a plugin - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Setting up wp-browser on VVV to test a plugin

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser on VVV to test a plugin

                                                                                                                                                              +

                                                                                                                                                              Requirements

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A Windows, Linux or Mac machine (I'll call this the "host machine" or just "host").
                                                                                                                                                              • +
                                                                                                                                                              • A working installation of VVV; you should be able to navigate to VVV root directory, run the vagrant up command, and have VVV up and running.
                                                                                                                                                              • +
                                                                                                                                                              • On the VVV installation you should be able to visit the two default sites URLs without issues; the two default sites addresses are:
                                                                                                                                                                  +
                                                                                                                                                                • http://one.wordpress.test
                                                                                                                                                                • +
                                                                                                                                                                • http://two.wordpress.test
                                                                                                                                                                • +
                                                                                                                                                                +
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Why VVV?

                                                                                                                                                              +

                                                                                                                                                              The VVV project provides a "a Vagrant configuration for developing with WordPress" and is an excellent, no-frills, starting point to develop WordPress projects (themes, plugins and whole sites.
                                                                                                                                                              +Based on Vagrant and Virtual Box, VVV removes the differences between systems by providing a uniform, Ubuntu Linux based, virtual machine that will bahave the same on Windows, Linux and Mac. +Configuring it to run WordPress tests is easy: let's get started.

                                                                                                                                                              +

                                                                                                                                                              Check VVV works correctly

                                                                                                                                                              +

                                                                                                                                                              This walk-through starts after VVV has been installed and is running on the host machine; the installation guide is clear and simple to follow and I'm not duplicating it here.
                                                                                                                                                              +In the context of this guide I'm assuming VVV lives in the ~/Repos/VVV directory, that we are working on the my-plugin project and that the plugin is being developed in the default (wordpress-one) WordPress installation provided by the box.
                                                                                                                                                              +If your VVV installation lies elsewhere, replace the ~/Repos/VVV with the actual directory in each command.

                                                                                                                                                              +

                                                                                                                                                              After completing the installation of VVV navigate to VVV root folder and run the vagrant up command:

                                                                                                                                                              +
                                                                                                                                                              cd ~/Repos/VVV
                                                                                                                                                              +vagrant up
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              vagrant up command result

                                                                                                                                                              +

                                                                                                                                                              After the automatic bootstrap and initialization process completed, VVV makes two WordPress sites available:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • http://one.wordpress.test/ is the first default site address.
                                                                                                                                                              • +
                                                                                                                                                              • http://two.wordpress.test/ is the second default site address.
                                                                                                                                                              • +
                                                                                                                                                              • http://vvv.test/ is VVV dashboard address.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              You should be able to reach each one of the URLs above without issues, should this not be the case something during VVV setup did not go according to the plan and you should fix it before moving on.

                                                                                                                                                              +

                                                                                                                                                              If the sanity check above is complete it's time to move to the following part specific to Codeception and wp-browser setup.

                                                                                                                                                              +

                                                                                                                                                              In and out, host and guest

                                                                                                                                                              +

                                                                                                                                                              The Vagrant box provided by VVV goes beyond a simple MySQL, PHP and Ngnix server stack and provides a complete WordPress development environment; tools like Composer, [grunt-cli][4992-0003], and [wp-cli][4992-0006] are ready to use.

                                                                                                                                                              +

                                                                                                                                                              This allows the entire development, when it comes to the CLI tools, to happen in the virtual machine and not outside of it.

                                                                                                                                                              +

                                                                                                                                                              "Inside the virtual machine" means the first CLI instruction to run from the ~/Repos/VVV folder (assuming that is the folder where VVV was installed) is this:

                                                                                                                                                              +
                                                                                                                                                              cd ~/Repos/VVV
                                                                                                                                                              +vagrant ssh
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              vagrant ssh command result

                                                                                                                                                              +

                                                                                                                                                              This will connect, via SSH, to the virtual machine as the vagrant user.
                                                                                                                                                              +To exit from the SSH session inside the box, just type exit and return.

                                                                                                                                                              +

                                                                                                                                                              Note: any further instruction I'm showing here, beside the code editing that will happen in a dedicated PHP IDE like [PHPStorm][4992-0004] or [Sublime Text][4992-0005] on the host machine, will happen "inside the virtual machine".

                                                                                                                                                              +

                                                                                                                                                              When I say "host machine" I mean your laptop, desktop or whatever computer you're working on; when I say "guest machine" I mean VVV virtual machine; this is usually the case for any virtual-ish setup (Vagrant, Docker and the like).

                                                                                                                                                              +

                                                                                                                                                              Scaffolding the project folder

                                                                                                                                                              +

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              +

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins.
                                                                                                                                                              +Create the main plugin file in the http://one.wordpress.test installation plugins directory, in the ~/Repos/VVV/www/wordpress-one/public_html/wp-content/plugins/my-plugin/my-plugin.php file:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +/**
                                                                                                                                                              + * Plugin Name: My plugin
                                                                                                                                                              + */ 
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the VVV default WordPress installation at http://one.wordpress.test/wp-admin/plugins.php.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              By default, VVV administrator user name is admin and password is password.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Installing wp-browser

                                                                                                                                                              +

                                                                                                                                                              Since Composer is provided from VVV, installing wp-browser requires entering the virtual machine (if you did not already):

                                                                                                                                                              +
                                                                                                                                                              cd ~/Repos/VVV
                                                                                                                                                              +vagrant ssh
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Once inside navigate to the plugins folder.
                                                                                                                                                              +The path is now relative to VVV filesystem structure so it won't be the same as the one used above that was, instead, in the context of the "host machine":

                                                                                                                                                              +
                                                                                                                                                              cd /srv/www/wordpress-one/public_html/wp-content/plugins/my-plugin 
                                                                                                                                                              +composer init
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. +Here is the composer.json file generated by the above answers:

                                                                                                                                                              +
                                                                                                                                                              {
                                                                                                                                                              +    "name": "vagrant/my-plugin",
                                                                                                                                                              +    "type": "wordpress-plugin",
                                                                                                                                                              +    "require": {}
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev lucatume/wp-browser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder.
                                                                                                                                                              +To check Codeception is correctly installed run this command:

                                                                                                                                                              +
                                                                                                                                                              vendor/bin/codecept --version
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser

                                                                                                                                                              +

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              +

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the WordPress site "normal" database: this is the database that stores the data of the site I would see when visiting the local installation URL (http://one.wordpress.test in the case of the VVV default installation).
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the database dedicated to the integration and "WordPress unit" tests: this database will be used to install WordPress during integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that if I am using VVV for my day to day WordPress development my first step should be to backup the site database.

                                                                                                                                                              +

                                                                                                                                                              You can create a backup of the current site database contents using wp-cli from within the virtual machine:

                                                                                                                                                              +
                                                                                                                                                              cd /srv/www/wordpress-one/public_html
                                                                                                                                                              +wp db export wordpress-one-backup.sql
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              At any moment you can re-import the site database dump using this command, the site database will be reset to the state it was when you created the database dump:

                                                                                                                                                              +
                                                                                                                                                              cd /srv/www/wordpress-one/public_html
                                                                                                                                                              +wp db import wordpress-one-backup.sql
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Creating the database dedicated to the tests

                                                                                                                                                              +

                                                                                                                                                              wp-browser will use the databases it works on in a destructive way: between tests the data will be lost.

                                                                                                                                                              +

                                                                                                                                                              After the backup you should have done in the previous step, the next step is creating a database dedicated to the test.

                                                                                                                                                              +

                                                                                                                                                              At the VVV box command line run:

                                                                                                                                                              +
                                                                                                                                                              mysql -u root -p -e "CREATE DATABASE if not exists tests"
                                                                                                                                                              +mysql -u root -p -e "GRANT ALL PRIVILEGES ON tests.* TO 'wp'@'localhost';"
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              When prompted for the password enter root. +The first command creates the tests database, if it does not exist; the second command grants the wp user all privileges on it.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              In VVV the root database user name is root and the password is root.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Check the database was correctly created running this command:

                                                                                                                                                              +
                                                                                                                                                              mysql -u root -p -e "SHOW DATABASES"
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The tests database should be present in the list.

                                                                                                                                                              +

                                                                                                                                                              Bootstrapping and configuring wp-browser

                                                                                                                                                              +

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              +
                                                                                                                                                              cd /srv/www/wordpress-one/public_html/wp-content/plugins/my-plugin
                                                                                                                                                              +vendor/bin/codecept init wpbrowser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The initialization guide will ask a number of questions.
                                                                                                                                                              +In the screenshots below are the answers I used to configure wp-browser.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • +
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • +
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • +
                                                                                                                                                              • What is the path of the WordPress root directory? /srv/www/wordpress-one/public_html
                                                                                                                                                              • +
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database used by the test site? localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the URL the test site? http://one.wordpress.test
                                                                                                                                                              • +
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@one.wordpress.test
                                                                                                                                                              • +
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • +
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • +
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • +
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • +
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              +

                                                                                                                                                              Setting up the starting database fixture

                                                                                                                                                              +

                                                                                                                                                              A "fixture", in testing terms, is a minimal, starting environment shared by all tests.
                                                                                                                                                              +In BDD it's the Background any scenario will share. +In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • +
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • +
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              You can set up this fixture "manually", using the site administration UI at http://one.wordpress.test/wp-admin, or use wp-cli and save precious time.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              As it's been the case so far, I'm running the following command from within the VVV box (use vagrant ssh to log in):

                                                                                                                                                              +
                                                                                                                                                              cd /srv/www/wordpress-one/public_html
                                                                                                                                                              +wp site empty --yes --uploads
                                                                                                                                                              +wp plugin deactivate --all
                                                                                                                                                              +wp plugin activate my-plugin
                                                                                                                                                              +wp db export wp-content/plugins/my-plugin/tests/_data/dump.sql
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The initial database fixture has been created, now there's one last step to complete.

                                                                                                                                                              +

                                                                                                                                                              Using the tests database in acceptance and functional tests

                                                                                                                                                              +

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              +

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              +

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the /srv/www/wordpress-one/public_html/wp-config.php file, the DB_NAME constant is set to wordpress-one.

                                                                                                                                                              +

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • If the request is a normal one, use the wordpress-one database.
                                                                                                                                                              • +
                                                                                                                                                              • If the request comes from a test, use the tests database.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              In your IDE/text-editor of choice edit the ~/Repos/VVV/www/wordpress-one/public_html/wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              +
                                                                                                                                                              - define( 'DB_NAME', 'wordpress-one' );
                                                                                                                                                              ++ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { 
                                                                                                                                                              ++    define( 'DB_NAME', 'tests' );
                                                                                                                                                              ++ } else {
                                                                                                                                                              ++    define( 'DB_NAME', 'wordpress-one' );
                                                                                                                                                              ++ }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              +
                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {
                                                                                                                                                              +        define( 'DB_NAME', 'tests' );
                                                                                                                                                              +} else {
                                                                                                                                                              +        define( 'DB_NAME', 'wordpress-one' );
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              +
                                                                                                                                                              headers:
                                                                                                                                                              +    X_TEST_REQUEST: 1
                                                                                                                                                              +    X_WPBROWSER_REQUEST: 1
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers.
                                                                                                                                                              +Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              +

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              +

                                                                                                                                                              Sanity check

                                                                                                                                                              +

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              +

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              +

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works.
                                                                                                                                                              +Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              +
                                                                                                                                                              cd /srv/www/wordpress-one/public_html/wp-content/plugins/my-plugin 
                                                                                                                                                              +vendor/bin/codecept run acceptance
                                                                                                                                                              +vendor/bin/codecept run functional
                                                                                                                                                              +vendor/bin/codecept run wpunit
                                                                                                                                                              +vendor/bin/codecept run unit
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept to see a list of the available commands.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file diff --git a/v3/tutorials/wamp-setup/index.html b/v3/tutorials/wamp-setup/index.html new file mode 100644 index 000000000..1a613e795 --- /dev/null +++ b/v3/tutorials/wamp-setup/index.html @@ -0,0 +1,3387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting up wp-browser on WAMP for Windows to test a plugin - wp-browser docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + +
                                                                                                                                                              + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + +
                                                                                                                                                              + +
                                                                                                                                                              + + + + + + + + +

                                                                                                                                                              Setting up wp-browser on WAMP for Windows to test a plugin

                                                                                                                                                              + +
                                                                                                                                                              +

                                                                                                                                                              This is the documentation for version 3 of the project. +The current version is version 4 and the documentation can be found here.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser with WAMP on Windows to test a plugin

                                                                                                                                                              +

                                                                                                                                                              Requirements

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A Windows machine
                                                                                                                                                              • +
                                                                                                                                                              • A working installation of WAMP.
                                                                                                                                                              • +
                                                                                                                                                              • You should be able to create sites and visit them from your browser without issues.
                                                                                                                                                              • +
                                                                                                                                                              • Composer installed and working on your terminal PATH, you should be able to run composer --version at the terminal and see the version correctly.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Install and configure WAMP

                                                                                                                                                              +

                                                                                                                                                              This walk-through starts after WAMP has been installed and is correctly running on the host machine; you can download WAMP from the site and follow the installation instructions.
                                                                                                                                                              +In the context of this guide I'm installing the test WordPress installation in the C:\wamp64\www\wp directory. +If your installation lies elsewhere, replace the C:\wamp64\www\wp path with the actual directory in each command.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Creating the databases and installing WordPress

                                                                                                                                                              +

                                                                                                                                                              Go to the http://localhost/phpmyadmin/index.php page and create two new databases:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • wordpress is the database you will use for WordPress
                                                                                                                                                              • +
                                                                                                                                                              • tests is the database you will use for the tests
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The default database user is root, the default password is empty.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Unzip the the WordPress files into the C:\wamp64\www\wp and head over to http://localhost/wp to install WordPress.
                                                                                                                                                              +The database credentials for the installation are:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Database name: wordpress
                                                                                                                                                              • +
                                                                                                                                                              • Database user: root
                                                                                                                                                              • +
                                                                                                                                                              • Database password is empty
                                                                                                                                                              • +
                                                                                                                                                              • Database host: localhost
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Use admin as administrator user name and password as password for the administrator user.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Make sure you can visit the WordPress installation at http://localhost/wp and that you can correctly access the administration area at http://localhost/wp/wp-admin.

                                                                                                                                                              +

                                                                                                                                                              Scaffolding the project folder

                                                                                                                                                              +

                                                                                                                                                              I'm assuming the scope of the development is to test the my-plugin plugin.

                                                                                                                                                              +

                                                                                                                                                              The first step is to create the bare minimum code required to make the plugin show up among the available WordPress plugins.
                                                                                                                                                              +Create the main plugin file in the WordPress installation plugins directory, in the C:\wamp64\www\wp\wp-content\plugins\my-plugin\my-plugin.php file:

                                                                                                                                                              +
                                                                                                                                                              <?php
                                                                                                                                                              +/**
                                                                                                                                                              + * Plugin Name: My plugin
                                                                                                                                                              + */ 
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The plugin should now show up, activate and deactivate correctly, among the plugins listed in the WordPress installation at http://localhost/wp/wp-admin/plugins.php.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Installing wp-browser

                                                                                                                                                              +

                                                                                                                                                              Open a terminal window and navigate to the plugin directory and initialize the Composer project.
                                                                                                                                                              +I'm using Cmder as terminal emulator on Windows, but you can use the default one.

                                                                                                                                                              +
                                                                                                                                                              cd C:\wamp64\www\wp\wp-content\plugins\my-plugin
                                                                                                                                                              +composer init
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Composer will ask some questions to initialize the project, for the sake of this small guide the answers are not relevant. +Here is the composer.json file generated by the above answers:

                                                                                                                                                              +
                                                                                                                                                              {
                                                                                                                                                              +    "name": "wamp/my-plugin",
                                                                                                                                                              +    "type": "wordpress-plugin",
                                                                                                                                                              +    "require": {}
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Next require lucatume/wp-browser as a development dependency:

                                                                                                                                                              +
                                                                                                                                                              composer require --dev lucatume/wp-browser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Composer installs any dependency binary file, an executable file, in the project vendor/bin folder.
                                                                                                                                                              +To check Codeception is correctly installed run this command:

                                                                                                                                                              +
                                                                                                                                                              vendor\bin\codecept.bat --version
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Since wp-browser requires Codeception, there is no need to require Codeception explicitly as a development dependency.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Setting up wp-browser

                                                                                                                                                              +

                                                                                                                                                              For those that might get lost while trying to set up wp-browser for the first time the VVV context provides an excellent base to understand the process.

                                                                                                                                                              +

                                                                                                                                                              wp-browser needs to know:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • Where the WordPress installation files are located: they will be loaded in integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the WordPress site "normal" database: this is the database that stores the data of the site I would see when visiting the local installation URL at http://localhost/wp.
                                                                                                                                                              • +
                                                                                                                                                              • How to connect to the database dedicated to the integration and "WordPress unit" tests: this database will be used to install WordPress during integration and "WordPress unit" tests.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Any test suite using a database should never run on a database containing data of any value; this means that your first step should be to backup the site database.

                                                                                                                                                              +

                                                                                                                                                              You can create a backup of the current site database contents using phpMyAdmin, at http://localhost/phpmyadmin/, under the "Export" tab:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              At any moment you can re-import the site database dump using, again, phpMyAdmin, under the "Import" tab:

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Bootstrapping and configuring wp-browser

                                                                                                                                                              +

                                                                                                                                                              After the backup is done it's time to bootstrap wp-browser using its interactive mode:

                                                                                                                                                              +
                                                                                                                                                              cd C:\wamp64\www\wp\wp-content\plugins\my-plugin
                                                                                                                                                              +vendor/bin/codecept.bat init wpbrowser
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The initialization guide will ask a number of questions.
                                                                                                                                                              +In the screenshots below are the answers I used to configure wp-browser.

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              Below a complete list of each answer:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • I acknowledge wp-browser should run on development servers... y
                                                                                                                                                              • +
                                                                                                                                                              • Would you like to set up the suites interactively now? y
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the acceptance suite to be called? acceptance
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the functional suite to be called? functional
                                                                                                                                                              • +
                                                                                                                                                              • How would you like the WordPress unit and integration suite to be called? wpunit
                                                                                                                                                              • +
                                                                                                                                                              • How would you like to call the env configuration file? .env.testing
                                                                                                                                                              • +
                                                                                                                                                              • What is the path of the WordPress root directory? C:/wamp64/www/wp
                                                                                                                                                              • +
                                                                                                                                                              • What is the path, relative to WordPress root URL, of the admin area of the test site? /wp-admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database used by the test site? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database used by the test site? localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database used by the test site? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database used by the test site? ``
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database used by the test site? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the name of the test database WPLoader should use? tests
                                                                                                                                                              • +
                                                                                                                                                              • What is the host of the test database WPLoader should use? localhost
                                                                                                                                                              • +
                                                                                                                                                              • What is the user of the test database WPLoader should use? root
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the test database WPLoader should use? ``
                                                                                                                                                              • +
                                                                                                                                                              • What is the table prefix of the test database WPLoader should use? wp_
                                                                                                                                                              • +
                                                                                                                                                              • What is the URL the test site? http://localhost/wp
                                                                                                                                                              • +
                                                                                                                                                              • What is the email of the test site WordPress administrator? admin@wp.test
                                                                                                                                                              • +
                                                                                                                                                              • What is the title of the test site? My Plugin Test
                                                                                                                                                              • +
                                                                                                                                                              • What is the login of the administrator user of the test site? admin
                                                                                                                                                              • +
                                                                                                                                                              • What is the password of the administrator user of the test site? password
                                                                                                                                                              • +
                                                                                                                                                              • Are you testing a plugin, a theme or a combination of both (both)? plugin
                                                                                                                                                              • +
                                                                                                                                                              • What is the folder/plugin.php name of the plugin? my-plugin/my-plugin.php
                                                                                                                                                              • +
                                                                                                                                                              • Does your project needs additional plugins to be activated to work? no
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              Codeception will build the suites for the first time and should be ready to go.

                                                                                                                                                              +

                                                                                                                                                              Setting up the starting database fixture

                                                                                                                                                              +

                                                                                                                                                              A "fixture", in testing terms, is a minimal, starting environment shared by all tests.
                                                                                                                                                              +In BDD it's the Background any scenario will share. +In the case of a plugin the minimal, starting environment is the following:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • A fresh WordPress installation empty of any content.
                                                                                                                                                              • +
                                                                                                                                                              • WordPress using its default theme.
                                                                                                                                                              • +
                                                                                                                                                              • The only active plugin is the one you're testing, in this example: my-plugin.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              You should set up this fixture "manually", using the site administration UI at http://localhost/wp/wp-admin.

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              The following command will empty the site, backup any content you care about first!

                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              When you're done setting up the initial database fixture, export it using the "Export" tab of phpMyAdmin, at http://localhost/phpmyadmin/ and move the file to the C:\wamp64\www\wp\wp-content\plugins\my-plugin\tests\_data\dump.sql directory.

                                                                                                                                                              +

                                                                                                                                                              There is one last step left to complete the setup.

                                                                                                                                                              +

                                                                                                                                                              Using the tests database in acceptance and functional tests

                                                                                                                                                              +

                                                                                                                                                              Acceptance and functional tests will act as users, navigating to the site pages and making requests as a user would.

                                                                                                                                                              +

                                                                                                                                                              This means that WordPress will load, and with it its wp-config.php file, to handle the requests made by the tests.

                                                                                                                                                              +

                                                                                                                                                              During the setup phase I've specified the database to be used for acceptance and functional tests as tests but, looking at the contents of the C:\wamp64\www\wp\wp-config.php file, the DB_NAME constant is set to wordpress.

                                                                                                                                                              +

                                                                                                                                                              What we'll do now means:

                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                              • If the request is a normal one, use the wordpress database.
                                                                                                                                                              • +
                                                                                                                                                              • If the request comes from a test, use the tests database.
                                                                                                                                                              • +
                                                                                                                                                              +

                                                                                                                                                              In your IDE/text-editor of choice edit the C:\wamp64\www\wp\wp-config.php and replace the line defining the DB_NAME constant like this:

                                                                                                                                                              +
                                                                                                                                                              - define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              ++ if( isset( $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) && $_SERVER['HTTP_X_WPBROWSER_REQUEST'] ) { 
                                                                                                                                                              ++    define( 'DB_NAME', 'tests' );
                                                                                                                                                              ++ } else {
                                                                                                                                                              ++    define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              ++ }
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Here's the copy-and-paste friendly version:

                                                                                                                                                              +
                                                                                                                                                              if( isset( $_SERVER['HTTP_X_TEST_REQUEST'] ) && $_SERVER['HTTP_X_TEST_REQUEST'] ) {
                                                                                                                                                              +        define( 'DB_NAME', 'tests' );
                                                                                                                                                              +} else {
                                                                                                                                                              +        define( 'DB_NAME', 'wordpress' );
                                                                                                                                                              +}
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              If you look at the tests/acceptance.suite.yml and tests/functional.suite.yml files, respectively the acceptance and functional suite configuration files, you will see these entries in the WPBrowser module configuration:

                                                                                                                                                              +
                                                                                                                                                              headers:
                                                                                                                                                              +    X_TEST_REQUEST: 1
                                                                                                                                                              +    X_WPBROWSER_REQUEST: 1
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              This means that, with each HTTP request done during tests, the module will send the two headers.
                                                                                                                                                              +Those headers are read, on the WordPress side, using the $_SERVER['HTTP_X_TEST_REQUEST'] and $_SERVER['X_WPBROWSER_REQUEST'] variables.

                                                                                                                                                              +

                                                                                                                                                              Codeception and wp-browser are ready to run and the test-drive development can start.

                                                                                                                                                              +

                                                                                                                                                              Sanity check

                                                                                                                                                              +

                                                                                                                                                              Before starting to write tests, take a moment to run each suite separately and make sure all is set up correctly.

                                                                                                                                                              +

                                                                                                                                                              If you run into issues, there's a chance you forgot something along the way, please take the time to read this tutorial a second time before opening an issue.

                                                                                                                                                              +

                                                                                                                                                              You have created 4 suites, each suite has at least one example test to make sure all works.
                                                                                                                                                              +Run each suite and make sure all tests succeed, from within the box run:

                                                                                                                                                              +
                                                                                                                                                              cd C:\wamp64\www\wp\wp-content\plugins\my-plugin 
                                                                                                                                                              +vendor/bin/codecept run acceptance
                                                                                                                                                              +vendor/bin/codecept run functional
                                                                                                                                                              +vendor/bin/codecept run wpunit
                                                                                                                                                              +vendor/bin/codecept run unit
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              You're now run to customize the suites to your liking or start writing tests, run vendor/bin/codecept.bat to see a list of the available commands.

                                                                                                                                                              + + + + + + + + + + + + + +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + + + + + + \ No newline at end of file