From c7f140b38a3bb42da10b6b103a4d26c2c4e85b97 Mon Sep 17 00:00:00 2001 From: Nikolay Beketov Date: Thu, 5 Jun 2025 14:48:46 +0300 Subject: [PATCH 1/6] Added .DS_Store to .gitignore and updated module.json with release settings for publishing and changelog. --- .github/workflows/build.yml | 15 +++++++++++++++ .gitignore | 1 + module.json | 5 +++++ 3 files changed, 21 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1c1da71 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,15 @@ +name: Build and Publish + +on: + push: + branches: + - master + - develop + workflow_dispatch: + +jobs: + build: + uses: mikopbx/.github-workflows/.github/workflows/extension-publish.yml@master + with: + initial_version: "1.18" + secrets: inherit \ No newline at end of file diff --git a/.gitignore b/.gitignore index f7206fa..27a60ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea /.idea/ +.DS_Store diff --git a/module.json b/module.json index 04c70ea..a0b9c54 100644 --- a/module.json +++ b/module.json @@ -7,5 +7,10 @@ "wiki_links": { "ru": {"https://wiki.mikopbx.com/module-get-ssl": "https://docs.mikopbx.com/mikopbx/modules/miko/module-get-ssl-lets-encrypt"}, "en": {"https://wiki.mikopbx.com/module-get-ssl": "https://docs.mikopbx.com/mikopbx/v/english/modules/miko/module-get-ssl-lets-encrypt"} + }, + "release_settings": { + "publish_release": true, + "changelog_enabled": true, + "create_github_release": true } } \ No newline at end of file From 20b753577ec76b2d01e113d73eb5697edae4d045 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 29 Sep 2025 09:00:23 +0300 Subject: [PATCH 2/6] Added translation using Weblate (Hebrew) --- Messages/he.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Messages/he.php diff --git a/Messages/he.php b/Messages/he.php new file mode 100644 index 0000000..b547ddb --- /dev/null +++ b/Messages/he.php @@ -0,0 +1,33 @@ +. + */ + 'repModuleGetSsl' => '', + 'mo_ModuleModuleGetSsl' => '', + 'BreadcrumbModuleGetSsl' => '', + 'SubHeaderModuleGetSsl' => '', + 'module_getssl_DomainNameLabel' => '', + 'module_getssl_autoUpdateLabel' => '', + 'module_getssl_getUpdateSSLButton' => '', + 'module_getssl_getUpdateLogHeader' => '', + 'module_getssl_DomainNameEmpty' => '', + 'module_getssl_ConfigStartsGenerating' => '', + 'module_getssl_ConfigGenerated' => '', + 'module_getssl_GetSSLProcessing' => '', + 'module_getssl_GetSSLProcessingTimeout' => '', +]; From ea1a7127a14ff92530e83ff97a2ed58b11c2837b Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 30 Sep 2025 04:50:36 +0300 Subject: [PATCH 3/6] Added translation using Weblate (Persian) --- Messages/fa.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Messages/fa.php diff --git a/Messages/fa.php b/Messages/fa.php new file mode 100644 index 0000000..b547ddb --- /dev/null +++ b/Messages/fa.php @@ -0,0 +1,33 @@ +. + */ + 'repModuleGetSsl' => '', + 'mo_ModuleModuleGetSsl' => '', + 'BreadcrumbModuleGetSsl' => '', + 'SubHeaderModuleGetSsl' => '', + 'module_getssl_DomainNameLabel' => '', + 'module_getssl_autoUpdateLabel' => '', + 'module_getssl_getUpdateSSLButton' => '', + 'module_getssl_getUpdateLogHeader' => '', + 'module_getssl_DomainNameEmpty' => '', + 'module_getssl_ConfigStartsGenerating' => '', + 'module_getssl_ConfigGenerated' => '', + 'module_getssl_GetSSLProcessing' => '', + 'module_getssl_GetSSLProcessingTimeout' => '', +]; From 87fbb069af5372e47c3003806d5fee747766280a Mon Sep 17 00:00:00 2001 From: Nikolay Beketov Date: Tue, 17 Feb 2026 11:53:03 +0700 Subject: [PATCH 4/6] docs: add README in English and Russian, add CLAUDE.md Replace template readme with module description for sysadmins. Add English README.md with cross-link to Russian version. Add CLAUDE.md with architecture and build instructions for Claude Code. --- CLAUDE.md | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 35 +++++++++++++++++++++++ readme.ru.md | 35 +++++++++++++++++++---- 3 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 CLAUDE.md create mode 100644 README.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a6398c5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,80 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +MikoPBX extension module for automated SSL certificate management via Let's Encrypt (ACME v2). Uses the `getssl` bash script as the ACME client, supports 40+ DNS providers for DNS-01 validation, and provides real-time certificate request progress via nchan Pub/Sub or polling fallback. + +## Build Commands + +### JavaScript Compilation +Source files live in `public/assets/js/src/`, compiled output goes to `public/assets/js/`: +```bash +/Users/nb/PhpstormProjects/mikopbx/MikoPBXUtils/node_modules/.bin/babel \ + "public/assets/js/src/module-get-ssl-index.js" \ + --out-dir "public/assets/js/" \ + --source-maps inline \ + --presets airbnb +``` +Repeat for each source file (`module-get-ssl-index.js`, `module-get-ssl-status-worker.js`). + +### PHP Static Analysis +```bash +phpstan analyse +``` + +## Architecture + +### Module Lifecycle +1. **Installation** (`Setup/PbxExtensionSetup.php`): Creates DB table `m_ModuleGetSsl`, sets defaults, detects domain from internet interface +2. **Runtime** (`Lib/GetSslConf.php`): Registers REST API callbacks, cron tasks, reacts to model changes and PBX lifecycle events +3. **Certificate Request** (`Lib/GetSslMain.php`): Generates getssl config, launches async certificate request, streams progress to browser +4. **Uninstall**: Removes symlinks from `/usr/bin/getssl`, `/usr/share/getssl`, `/usr/www/sites/.well-known` + +### Key Classes + +- **`Lib/GetSslConf.php`** — Module configuration hook. Handles REST API routing (`GET-CERT`, `CHECK-RESULT`), cron task registration (1st/15th at 01:00), and PBX lifecycle events (`onAfterPbxStarted`, `onAfterModuleEnable`) +- **`Lib/GetSslMain.php`** — Core orchestrator. Manages directories, generates getssl config file, launches certificate requests, monitors process completion (120s timeout), pushes real-time updates via nchan, updates SSL keys in PbxSettings DB +- **`Lib/MikoPBXVersion.php`** — Compatibility layer for Phalcon 4 vs 5 class names. Version cutoff at PBX 2024.2.30 +- **`Models/ModuleGetSsl.php`** — Phalcon ORM model for `m_ModuleGetSsl` table (fields: `id`, `domainName`, `autoUpdate`) +- **`App/Controllers/ModuleGetSslController.php`** — Web UI controller: renders form, handles save, triggers certificate request on save +- **`App/Forms/ModuleGetSslForm.php`** — Phalcon form definition with Semantic UI integration + +### Frontend (ES6 → Babel → ES5) + +- **`public/assets/js/src/module-get-ssl-index.js`** — Form controller: validation, module status toggle, triggers API call to start certificate request, handles async response channel +- **`public/assets/js/src/module-get-ssl-status-worker.js`** — Real-time progress: EventSource (PBX ≥2024.2.30) or polling fallback, Ace editor for log display, 4-stage processing pipeline (STAGE_1–4) + +### REST API + +- `POST /pbxcore/api/modules/ModuleGetSsl/get-cert` — Start certificate request. Supports async via `X-Async-Response-Channel-Id` header +- `GET /pbxcore/api/modules/ModuleGetSsl/check-result` — Poll log file contents (fallback for older PBX versions) + +### Real-time Updates + +Pub/Sub channel `module-get-ssl-pub` pushes JSON messages with `moduleUniqueId`, `stage`, `stageDetails`, `pid`. Browser subscribes via EventSource on PBX ≥2024.2.30, falls back to polling `check-result` endpoint on older versions. + +### Symlinks Created at Runtime +- `/usr/bin/getssl` → `{moduleDir}/bin/getssl` +- `/usr/share/getssl` → `{moduleDir}/bin/utils` +- `/usr/www/sites/.well-known` → `{moduleDir}/db/getssl/.well-known` +- `/usr/bin/nslookup` → busybox + +### Cron Auto-Renewal +Runs `getssl -a -U -q -w {confDir}` on 1st and 15th of each month at 01:00. Cron is reloaded whenever module settings change. + +## Phalcon Version Compatibility + +Always use `MikoPBXVersion` for version-dependent class imports (Di, Validation, Uniqueness, Text, Logger). PBX versions ≥2024.2.30 use Phalcon 5; older versions use Phalcon 4. Do not hardcode Phalcon namespace paths. + +## Internationalization + +31 language files in `Messages/`. Translation keys prefixed with `module_getssl_`. English (`en.php`) is the reference file. + +## Dependencies + +- PHP 7.4+ / 8.0+, Phalcon 4 or 5 +- MikoPBX Core framework (`MikoPBX\Common`, `MikoPBX\Core`, `MikoPBX\Modules`, `MikoPBX\AdminCabinet`) +- jQuery, Semantic UI, Ace Editor (from MikoPBX core frontend) +- `getssl` ACME client (`bin/getssl`, embedded 142KB bash script) diff --git a/README.md b/README.md new file mode 100644 index 0000000..831ecce --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# ModuleGetSsl — Free SSL Certificates for MikoPBX + +[Русская версия](readme.ru.md) + +## What It Does + +This module automates obtaining and renewing free SSL certificates from [Let's Encrypt](https://letsencrypt.org/) for your MikoPBX web interface. After setup, the HTTPS certificate is issued automatically and renewed on schedule — no manual steps required. + +## How It Works + +1. You install the module from the MikoPBX module marketplace +2. Enter your domain name in the module settings and click save +3. The module requests a certificate from Let's Encrypt, and the progress is shown in real time +4. Once issued, the certificate is automatically applied to the MikoPBX web interface + +Auto-renewal runs on the 1st and 15th of each month. If the certificate is due for renewal, it will be updated automatically. + +## Requirements + +- MikoPBX **2024.1.114** or newer +- A domain name pointing to your PBX public IP address (A record) +- Port **80** accessible from the internet (required for Let's Encrypt HTTP-01 validation) + +## Documentation + +- [English documentation](https://docs.mikopbx.com/mikopbx/v/english/modules/miko/module-get-ssl-lets-encrypt) +- [Документация на русском](https://docs.mikopbx.com/mikopbx/modules/miko/module-get-ssl-lets-encrypt) + +## Support + +For questions and issues — [help@miko.ru](mailto:help@miko.ru) or the developer channel in Telegram: [@mikopbx_dev](https://t.me/joinchat/AAPn5xSqZIpQnNnCAa3bBw) + +## License + +GPL-3.0-or-later diff --git a/readme.ru.md b/readme.ru.md index 3e2892c..ebd9214 100644 --- a/readme.ru.md +++ b/readme.ru.md @@ -1,12 +1,35 @@ -# Шаблон модуля расширения для MikoPBX +# ModuleGetSsl — Бесплатные SSL-сертификаты для MikoPBX -_Read this in other languages:_ [_English_](./)_,_ [_Русский_](readme.ru.md)_._ +[English version](README.md) -## Описание модуля расширения +## Что делает модуль -Документацию по разработке и установке собственного модуля можно найти по ссылке [https://docs.mikopbx.com](https://docs.mikopbx.com/mikopbx-development/) +Модуль автоматически получает и обновляет бесплатные SSL-сертификаты от [Let's Encrypt](https://letsencrypt.org/) для веб-интерфейса MikoPBX. После настройки HTTPS-сертификат выпускается автоматически и продлевается по расписанию — никаких ручных действий не требуется. -### Вопросы +## Как это работает -Подключайтесь к каналу для разрабочиков в telegram [@mikopbx\_dev](https://t.me/joinchat/AAPn5xSqZIpQnNnCAa3bBw) +1. Установите модуль из маркетплейса модулей MikoPBX +2. Укажите доменное имя в настройках модуля и нажмите сохранить +3. Модуль запросит сертификат у Let's Encrypt, прогресс отображается в реальном времени +4. После выпуска сертификат автоматически применяется к веб-интерфейсу MikoPBX +Автоматическое продление запускается 1-го и 15-го числа каждого месяца. Если сертификат подлежит обновлению, он будет продлён автоматически. + +## Требования + +- MikoPBX версии **2024.1.114** или новее +- Доменное имя, указывающее на публичный IP-адрес АТС (A-запись) +- Порт **80**, доступный из интернета (необходим для HTTP-01 валидации Let's Encrypt) + +## Документация + +- [Документация на русском](https://docs.mikopbx.com/mikopbx/modules/miko/module-get-ssl-lets-encrypt) +- [English documentation](https://docs.mikopbx.com/mikopbx/v/english/modules/miko/module-get-ssl-lets-encrypt) + +## Поддержка + +По вопросам и проблемам — [help@miko.ru](mailto:help@miko.ru) или канал разработчиков в Telegram: [@mikopbx_dev](https://t.me/joinchat/AAPn5xSqZIpQnNnCAa3bBw) + +## Лицензия + +GPL-3.0-or-later From f17b5b099ef8c7a3ee47fb210c5189a44bccc2bf Mon Sep 17 00:00:00 2001 From: Nikolay Beketov Date: Tue, 17 Feb 2026 16:05:24 +0700 Subject: [PATCH 5/6] feat: temporarily open port 80 for ACME HTTP-01 validation Add AcmeHttpPort class that creates a dedicated nginx server block on port 80 serving only /.well-known/acme-challenge/ (returns 444 for everything else) and adds iptables rules when firewall is managed. Port 80 is opened before certificate request and guaranteed closed after via try/finally in all code paths: REST API GET-CERT handler, updateCert.php, and new cronRenewCert.php wrapper for cron renewal. Safety mechanisms: - Lock file with PID+timestamp in /var/run (tmpfs, survives no crash) - Watchdog cron (every minute) cleans up stale state after 5min/dead PID - Cleanup on PBX startup via onAfterPbxStarted Also adds timestamp wrapper for getssl output (ISO format matching syslog) and phpstan.neon config for the module. --- Lib/AcmeHttpPort.php | 241 ++++++++++++++++++++++++++++++++++++++++ Lib/GetSslConf.php | 22 +++- Lib/GetSslMain.php | 12 +- bin/cleanupPort80.php | 26 +++++ bin/cronRenewCert.php | 44 ++++++++ bin/timestampWrapper.sh | 5 + bin/updateCert.php | 14 ++- phpstan.neon | 26 +++++ 8 files changed, 376 insertions(+), 14 deletions(-) create mode 100644 Lib/AcmeHttpPort.php create mode 100644 bin/cleanupPort80.php create mode 100644 bin/cronRenewCert.php create mode 100644 bin/timestampWrapper.sh create mode 100644 phpstan.neon diff --git a/Lib/AcmeHttpPort.php b/Lib/AcmeHttpPort.php new file mode 100644 index 0000000..bfd3002 --- /dev/null +++ b/Lib/AcmeHttpPort.php @@ -0,0 +1,241 @@ +. + */ + +namespace Modules\ModuleGetSsl\Lib; + +use MikoPBX\Common\Models\PbxSettings; +use MikoPBX\Core\System\Processes; +use MikoPBX\Core\System\System; +use MikoPBX\Core\System\Util; +use Modules\ModuleGetSsl\Models\ModuleGetSsl; + +/** + * Manages temporary port 80 opening for ACME HTTP-01 validation. + * + * Creates a dedicated nginx server block on port 80 serving only + * /.well-known/acme-challenge/ and adds iptables rules when firewall is active. + */ +class AcmeHttpPort +{ + private const LOCK_FILE = '/var/run/custom_modules/ModuleGetSsl/acme_port80.lock'; + private const NGINX_ACME_CONF = '/etc/nginx/mikopbx/modules_servers/ModuleGetSsl_acme80.conf'; + private const MAX_OPEN_SECONDS = 300; + + /** + * Opens port 80 for ACME HTTP-01 validation. + * + * Creates a dedicated nginx server block and adds firewall rules if needed. + * + * @return bool true on success or if port is already open + */ + public function openPort(): bool + { + if ($this->isAlreadyOpen()) { + return true; + } + + $lockDir = dirname(self::LOCK_FILE); + Util::mwMkdir($lockDir); + $lockData = json_encode(['pid' => getmypid(), 'time' => time()]); + file_put_contents(self::LOCK_FILE, $lockData); + + $domainName = $this->getDomainName(); + if (empty($domainName)) { + unlink(self::LOCK_FILE); + return false; + } + + $this->createNginxConf($domainName); + $this->reloadNginx(); + $this->addFirewallRules(); + + return true; + } + + /** + * Closes port 80 after ACME validation completes. + * + * Removes the nginx config, reloads nginx, removes firewall rules, and cleans up the lock file. + */ + public function closePort(): void + { + if (file_exists(self::NGINX_ACME_CONF)) { + unlink(self::NGINX_ACME_CONF); + } + $this->reloadNginx(); + $this->removeFirewallRules(); + + if (file_exists(self::LOCK_FILE)) { + unlink(self::LOCK_FILE); + } + } + + /** + * Cleans up stale port 80 state from a previous crash or timeout. + */ + public static function cleanupStale(): void + { + if (!file_exists(self::LOCK_FILE)) { + return; + } + + $lockContent = file_get_contents(self::LOCK_FILE); + $lockData = json_decode($lockContent, true); + if (!is_array($lockData)) { + // Corrupted lock file, clean up + $instance = new self(); + $instance->closePort(); + Util::sysLogMsg(__CLASS__, 'Cleaned up corrupted ACME port 80 lock file'); + return; + } + + $pid = $lockData['pid'] ?? 0; + $lockTime = $lockData['time'] ?? 0; + $elapsed = time() - $lockTime; + $pidDead = ($pid > 0) ? !file_exists("/proc/$pid") : true; + + if ($elapsed > self::MAX_OPEN_SECONDS || $pidDead) { + $instance = new self(); + $instance->closePort(); + Util::sysLogMsg( + __CLASS__, + "Cleaned up stale ACME port 80 (elapsed: {$elapsed}s, pid: $pid, dead: " . ($pidDead ? 'yes' : 'no') . ')' + ); + } + } + + /** + * Checks if port 80 is already open by this module. + */ + private function isAlreadyOpen(): bool + { + if (!file_exists(self::LOCK_FILE)) { + return false; + } + + $lockContent = file_get_contents(self::LOCK_FILE); + $lockData = json_decode($lockContent, true); + if (!is_array($lockData)) { + return false; + } + + $pid = $lockData['pid'] ?? 0; + if ($pid > 0 && file_exists("/proc/$pid")) { + return true; + } + + return false; + } + + /** + * Gets domain name from module settings. + */ + private function getDomainName(): string + { + $settings = ModuleGetSsl::findFirst(); + if ($settings === null) { + return ''; + } + return $settings->domainName ?? ''; + } + + /** + * Creates a dedicated nginx server block for ACME validation on port 80. + */ + private function createNginxConf(string $domainName): void + { + $confDir = dirname(self::NGINX_ACME_CONF); + Util::mwMkdir($confDir); + + $conf = <<isFirewallManaged()) { + return; + } + + $iptablesPath = Util::which('iptables'); + Processes::mwExec("$iptablesPath -I INPUT -p tcp --dport 80 -j ACCEPT"); + + $ip6tablesPath = Util::which('ip6tables'); + Processes::mwExec("$ip6tablesPath -I INPUT -p tcp --dport 80 -j ACCEPT"); + } + + /** + * Removes iptables rules for port 80. + */ + private function removeFirewallRules(): void + { + if (!$this->isFirewallManaged()) { + return; + } + + $iptablesPath = Util::which('iptables'); + Processes::mwExec("$iptablesPath -D INPUT -p tcp --dport 80 -j ACCEPT"); + + $ip6tablesPath = Util::which('ip6tables'); + Processes::mwExec("$ip6tablesPath -D INPUT -p tcp --dport 80 -j ACCEPT"); + } + + /** + * Checks whether firewall rules need to be managed. + * + * Returns true only when PBX firewall is enabled AND system can manage iptables. + */ + private function isFirewallManaged(): bool + { + $firewallEnabled = PbxSettings::getValueByKey(PbxSettings::PBX_FIREWALL_ENABLED); + if ($firewallEnabled !== '1') { + return false; + } + return System::canManageFirewall(); + } +} diff --git a/Lib/GetSslConf.php b/Lib/GetSslConf.php index 945d46c..36e390e 100644 --- a/Lib/GetSslConf.php +++ b/Lib/GetSslConf.php @@ -25,6 +25,7 @@ use MikoPBX\Core\System\Util; use MikoPBX\Modules\Config\ConfigClass; use MikoPBX\PBXCoreREST\Lib\PBXApiResult; +use Modules\ModuleGetSsl\Lib\AcmeHttpPort; use Modules\ModuleGetSsl\Models\ModuleGetSsl; class GetSslConf extends ConfigClass @@ -65,11 +66,17 @@ public function moduleRestAPICallback(array $request): PBXApiResult } switch ($action) { case 'GET-CERT': - $moduleMain = new GetSslMain($asyncChannelId); - $moduleMain->createAclConf(); - $res = $moduleMain->startGetCertSsl(); - if (!empty($asyncChannelId)) { - $res = $moduleMain->checkResultAsync(); + $portManager = new AcmeHttpPort(); + $portManager->openPort(); + try { + $moduleMain = new GetSslMain($asyncChannelId); + $moduleMain->createAclConf(); + $res = $moduleMain->startGetCertSsl(); + if (!empty($asyncChannelId)) { + $res = $moduleMain->checkResultAsync(); + } + } finally { + $portManager->closePort(); } break; case 'CHECK-RESULT': @@ -92,6 +99,7 @@ public function moduleRestAPICallback(array $request): PBXApiResult */ public function onAfterPbxStarted(): void { + AcmeHttpPort::cleanupStale(); $moduleMain = new GetSslMain(); $moduleMain->createAclConf(); } @@ -123,5 +131,9 @@ public function createCronTasks(array &$tasks): void if (!empty($task)) { $tasks[] = $task; } + + // Watchdog: check every minute for stale port 80 state + $phpPath = Util::which('php'); + $tasks[] = "* * * * * $phpPath -f $this->moduleDir/bin/cleanupPort80.php > /dev/null 2>&1" . PHP_EOL; } } diff --git a/Lib/GetSslMain.php b/Lib/GetSslMain.php index b386e7f..d6d9f00 100644 --- a/Lib/GetSslMain.php +++ b/Lib/GetSslMain.php @@ -298,13 +298,15 @@ public function startGetCertSsl(bool $asynchronously = true): PBXApiResult $pid = Processes::getPidOfProcess("$getSsl $extHostname"); if ($pid === '') { $confDir = $this->dirs['confDir']; + $shPath = Util::which('sh'); + $tsWrapper = $this->dirs['binDir'] . '/timestampWrapper.sh'; if($asynchronously){ - Processes::mwExecBg("$getSsl $extHostname -w '$confDir'", $this->logFile); + Processes::mwExecBg("$shPath $tsWrapper $getSsl $extHostname -w '$confDir'", $this->logFile); $pid = Processes::getPidOfProcess("$getSsl $extHostname"); }else{ echo('starting'.PHP_EOL); passthru("cat '$confDir/getssl.cfg' "); - passthru("$getSsl $extHostname -w '$confDir'", $this->logFile); + passthru("$shPath $tsWrapper $getSsl $extHostname -w '$confDir'", $this->logFile); } } $result->data['result'] = $this->translation->_('module_getssl_GetSSLProcessing'); @@ -400,9 +402,9 @@ public function getCronTask(): string && intval($this->module_settings['autoUpdate']) === 1 && !empty($this->module_settings['domainName']) ) { - $workerPath = $this->dirs['moduleDir']. '/db/getssl'; - $getSslPath = $this->dirs['getSslPath']; - return "0 1 1,15 * * $getSslPath -a -U -q -w '$workerPath' > /dev/null 2> /dev/null" . PHP_EOL; + $phpPath = Util::which('php'); + $cronScript = $this->dirs['moduleDir'] . '/bin/cronRenewCert.php'; + return "0 1 1,15 * * $phpPath -f $cronScript > /dev/null 2>&1" . PHP_EOL; } return ''; } diff --git a/bin/cleanupPort80.php b/bin/cleanupPort80.php new file mode 100644 index 0000000..58d4127 --- /dev/null +++ b/bin/cleanupPort80.php @@ -0,0 +1,26 @@ +#!/usr/bin/php +. + */ + +use Modules\ModuleGetSsl\Lib\AcmeHttpPort; + +require_once('Globals.php'); + +AcmeHttpPort::cleanupStale(); diff --git a/bin/cronRenewCert.php b/bin/cronRenewCert.php new file mode 100644 index 0000000..a2ba18e --- /dev/null +++ b/bin/cronRenewCert.php @@ -0,0 +1,44 @@ +#!/usr/bin/php +. + */ + +use MikoPBX\Core\System\Processes; +use MikoPBX\Core\System\Util; +use Modules\ModuleGetSsl\Lib\AcmeHttpPort; +use Modules\ModuleGetSsl\Lib\GetSslMain; + +require_once('Globals.php'); + +$portManager = new AcmeHttpPort(); +$portManager->openPort(); +try { + $moduleMain = new GetSslMain(); + $moduleMain->createAclConf(); + + $getSslPath = $moduleMain->dirs['getSslPath']; + $confDir = $moduleMain->dirs['confDir']; + $shPath = Util::which('sh'); + $tsWrapper = $moduleMain->dirs['binDir'] . '/timestampWrapper.sh'; + Processes::mwExec("$shPath $tsWrapper $getSslPath -a -U -q -w '$confDir'"); + + $moduleMain->run(); +} finally { + $portManager->closePort(); +} diff --git a/bin/timestampWrapper.sh b/bin/timestampWrapper.sh new file mode 100644 index 0000000..80ae902 --- /dev/null +++ b/bin/timestampWrapper.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# Wraps a command's output with ISO timestamps on each line +"$@" 2>&1 | while IFS= read -r line; do + printf "[%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$line" +done diff --git a/bin/updateCert.php b/bin/updateCert.php index f51c4da..2a5c6e5 100644 --- a/bin/updateCert.php +++ b/bin/updateCert.php @@ -19,11 +19,17 @@ * If not, see . */ -use MikoPBX\Core\System\Configs\NginxConf; +use Modules\ModuleGetSsl\Lib\AcmeHttpPort; use Modules\ModuleGetSsl\Lib\GetSslMain; require_once('Globals.php'); -$moduleMain = new GetSslMain(); -$moduleMain->createAclConf(); -$res = $moduleMain->startGetCertSsl(false); \ No newline at end of file +$portManager = new AcmeHttpPort(); +$portManager->openPort(); +try { + $moduleMain = new GetSslMain(); + $moduleMain->createAclConf(); + $res = $moduleMain->startGetCertSsl(false); +} finally { + $portManager->closePort(); +} \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..c7702cd --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,26 @@ +parameters: + level: 0 + paths: + - Lib + - Models + - bin + - App + - Setup + scanDirectories: + - ../../Core/src + parallel: + jobSize: 20 + processTimeout: 300.0 + tmpDir: /tmp/phpstan-ModuleGetSsl + reportUnmatchedIgnoredErrors: false + ignoreErrors: + - + message: '#unknown class Phalcon\\Di#' + - + message: '#Class Phalcon\\Validation not found#' + - + message: '#Class Phalcon\\Validation\\Validator\\Uniqueness not found#' + - + message: '#Class Phalcon\\Text not found#' + - + message: '#Class Phalcon\\Logger not found#' From f8359c067ccd971f26e157966d84ff48f4f71b94 Mon Sep 17 00:00:00 2001 From: Nikolay Beketov Date: Wed, 18 Feb 2026 11:17:48 +0700 Subject: [PATCH 6/6] fix: button loading state, cert install from disk, log improvements - Disable submit button and show ACE editor immediately on cert request - Re-enable button on success/failure - Call run() after cert process to install existing cert files into PbxSettings (fixes case when cert exists on disk but was cleared from system settings) - Load last log into ACE editor on page open - Add link to system diagnostic for full log - Add timestamped logging for port 80 open/close and cert installation - Add translation keys for log link (en, ru) --- App/Views/ModuleGetSsl/index.volt | 3 ++ Lib/AcmeHttpPort.php | 31 ++++++++++++++++++- Lib/GetSslConf.php | 3 ++ Lib/GetSslMain.php | 12 +++++++ Messages/en.php | 1 + Messages/ru.php | 1 + public/assets/js/module-get-ssl-index.js | 11 +++++-- .../assets/js/module-get-ssl-status-worker.js | 23 +++++++++++++- public/assets/js/src/module-get-ssl-index.js | 9 ++++-- .../js/src/module-get-ssl-status-worker.js | 22 +++++++++++++ 10 files changed, 109 insertions(+), 7 deletions(-) diff --git a/App/Views/ModuleGetSsl/index.volt b/App/Views/ModuleGetSsl/index.volt index be257e3..71f0fe0 100644 --- a/App/Views/ModuleGetSsl/index.volt +++ b/App/Views/ModuleGetSsl/index.volt @@ -18,6 +18,9 @@ {{ partial("partials/submitbutton",['submitBtnIconClass':'exchange icon', 'submitBtnText': t._('module_getssl_getUpdateSSLButton')]) }} diff --git a/Lib/AcmeHttpPort.php b/Lib/AcmeHttpPort.php index bfd3002..76e6474 100644 --- a/Lib/AcmeHttpPort.php +++ b/Lib/AcmeHttpPort.php @@ -21,6 +21,7 @@ namespace Modules\ModuleGetSsl\Lib; use MikoPBX\Common\Models\PbxSettings; +use MikoPBX\Core\System\Directories; use MikoPBX\Core\System\Processes; use MikoPBX\Core\System\System; use MikoPBX\Core\System\Util; @@ -38,6 +39,14 @@ class AcmeHttpPort private const NGINX_ACME_CONF = '/etc/nginx/mikopbx/modules_servers/ModuleGetSsl_acme80.conf'; private const MAX_OPEN_SECONDS = 300; + private string $logFile; + + public function __construct() + { + $logDir = Directories::getDir(Directories::CORE_LOGS_DIR); + $this->logFile = "$logDir/ModuleGetSsl/last-result.log"; + } + /** * Opens port 80 for ACME HTTP-01 validation. * @@ -48,6 +57,7 @@ class AcmeHttpPort public function openPort(): bool { if ($this->isAlreadyOpen()) { + $this->log('Port 80 already open, skipping'); return true; } @@ -59,12 +69,20 @@ public function openPort(): bool $domainName = $this->getDomainName(); if (empty($domainName)) { unlink(self::LOCK_FILE); + $this->log('Port 80 open skipped: domain name is empty'); return false; } $this->createNginxConf($domainName); $this->reloadNginx(); - $this->addFirewallRules(); + + $firewallManaged = $this->isFirewallManaged(); + if ($firewallManaged) { + $this->addFirewallRules(); + $this->log("Port 80 opened for $domainName (nginx + iptables)"); + } else { + $this->log("Port 80 opened for $domainName (nginx only, firewall not managed)"); + } return true; } @@ -85,6 +103,8 @@ public function closePort(): void if (file_exists(self::LOCK_FILE)) { unlink(self::LOCK_FILE); } + + $this->log('Port 80 closed'); } /** @@ -238,4 +258,13 @@ private function isFirewallManaged(): bool } return System::canManageFirewall(); } + + /** + * Appends a timestamped message to the module log file. + */ + private function log(string $message): void + { + $timestamp = date('Y-m-d H:i:s'); + file_put_contents($this->logFile, "[$timestamp] $message" . PHP_EOL, FILE_APPEND); + } } diff --git a/Lib/GetSslConf.php b/Lib/GetSslConf.php index 36e390e..d958327 100644 --- a/Lib/GetSslConf.php +++ b/Lib/GetSslConf.php @@ -75,6 +75,9 @@ public function moduleRestAPICallback(array $request): PBXApiResult if (!empty($asyncChannelId)) { $res = $moduleMain->checkResultAsync(); } + // Install existing cert files into PbxSettings + // (handles case when cert exists on disk but was cleared from settings) + $moduleMain->run(); } finally { $portManager->closePort(); } diff --git a/Lib/GetSslMain.php b/Lib/GetSslMain.php index d6d9f00..137800e 100644 --- a/Lib/GetSslMain.php +++ b/Lib/GetSslMain.php @@ -341,6 +341,9 @@ public function run(): void if (file_exists($privateKeyPath) && file_exists($certPath)) { $this->updateKey('WEBHTTPSPublicKey', $certPath); $this->updateKey('WEBHTTPSPrivateKey', $privateKeyPath); + $this->appendLog('SSL certificate installed into PbxSettings'); + } else { + $this->appendLog('Certificate files not found, skipping PbxSettings update'); } } @@ -385,6 +388,15 @@ private function updateKey(string $name, string $path): void } } + /** + * Appends a timestamped message to the module log file. + */ + private function appendLog(string $message): void + { + $timestamp = date('Y-m-d H:i:s'); + file_put_contents($this->logFile, "[$timestamp] $message" . PHP_EOL, FILE_APPEND); + } + /** * Generates a cron task string for automatically updating SSL certificates. * diff --git a/Messages/en.php b/Messages/en.php index d854b3f..b0d826b 100644 --- a/Messages/en.php +++ b/Messages/en.php @@ -20,4 +20,5 @@ 'module_getssl_ConfigGenerated' => 'Configuration files created...', 'module_getssl_GetSSLProcessing' => 'Requesting data from Lets Encrypt...', 'module_getssl_GetSSLProcessingTimeout' => 'Error, Lets Encrypt service did not return a response within 2 minutes', + 'module_getssl_ViewFullLogLink' => 'View full log in system diagnostic', ]; diff --git a/Messages/ru.php b/Messages/ru.php index ad7f839..7ab2ee4 100644 --- a/Messages/ru.php +++ b/Messages/ru.php @@ -31,4 +31,5 @@ 'module_getssl_ConfigGenerated' => 'Конфигурационные файлы созданы...', 'module_getssl_GetSSLProcessing' => 'Выполняется запрос данных в Lets Encrypt...', 'module_getssl_GetSSLProcessingTimeout' => 'Ошибка, сервис Lets Encrypt не вернул ответа в течение 2 минут', + 'module_getssl_ViewFullLogLink' => 'Смотреть полный лог в системной диагностике', ]; diff --git a/public/assets/js/module-get-ssl-index.js b/public/assets/js/module-get-ssl-index.js index 7e7fae4..4f76ba4 100644 --- a/public/assets/js/module-get-ssl-index.js +++ b/public/assets/js/module-get-ssl-index.js @@ -15,6 +15,7 @@ var ModuleGetSsl = { $checkBoxes: $('#' + idForm + ' .ui.checkbox'), $disabilityFields: $('#' + idForm + ' .disability'), $statusToggle: $('#module-status-toggle'), + $submitButton: $('#submitbutton'), $moduleStatus: $('#status'), $intervalId: undefined, // To manage the interval for SSL status check @@ -59,6 +60,9 @@ var ModuleGetSsl = { return xhr; }, beforeSend: function beforeSend(settings) { + ModuleGetSsl.$submitButton.addClass('loading disabled'); + moduleGetSSLStatusLoopWorker.$resultBlock.show(); + moduleGetSSLStatusLoopWorker.editor.getSession().setValue(''); return settings; }, successTest: PbxApi.successTest, @@ -68,14 +72,15 @@ var ModuleGetSsl = { * @param {object} response - The response object. */ onSuccess: function onSuccess(response) { - moduleGetSSLStatusLoopWorker.editor.getSession().setValue(''); + ModuleGetSsl.$submitButton.removeClass('loading disabled'); }, /** - * Handles the failure response of the 'get-available-ldap-users' API request. + * Handles the failure response of the 'get-cert' API request. * @param {object} response - The response object. */ onFailure: function onFailure(response) { + ModuleGetSsl.$submitButton.removeClass('loading disabled'); UserMessage.showMultiString(response.message); moduleGetSSLStatusLoopWorker.$resultBlock.hide(); } @@ -138,4 +143,4 @@ var ModuleGetSsl = { $(document).ready(function () { ModuleGetSsl.initialize(); }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtZ2V0LXNzbC1pbmRleC5qcyJdLCJuYW1lcyI6WyJpZFVybCIsImlkRm9ybSIsImNsYXNzTmFtZSIsIk1vZHVsZUdldFNzbCIsIiRmb3JtT2JqIiwiJCIsIiRjaGVja0JveGVzIiwiJGRpc2FiaWxpdHlGaWVsZHMiLCIkc3RhdHVzVG9nZ2xlIiwiJG1vZHVsZVN0YXR1cyIsIiRpbnRlcnZhbElkIiwidW5kZWZpbmVkIiwidmFsaWRhdGVSdWxlcyIsImRvbWFpbk5hbWUiLCJpZGVudGlmaWVyIiwicnVsZXMiLCJ0eXBlIiwicHJvbXB0IiwiZ2xvYmFsVHJhbnNsYXRlIiwibW9kdWxlX2dldHNzbF9Eb21haW5OYW1lRW1wdHkiLCJpbml0aWFsaXplIiwiY2hlY2tib3giLCJjaGVja1N0YXR1c1RvZ2dsZSIsIndpbmRvdyIsImFkZEV2ZW50TGlzdGVuZXIiLCJpbml0aWFsaXplRm9ybSIsIm1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIiLCIkcmVzdWx0QmxvY2siLCJoaWRlIiwiZ2V0U3NsIiwiYXBpIiwidXJsIiwiQ29uZmlnIiwicGJ4VXJsIiwib24iLCJtZXRob2QiLCJiZWZvcmVYSFIiLCJ4aHIiLCJzZXRSZXF1ZXN0SGVhZGVyIiwiY2hhbm5lbElkIiwiYmVmb3JlU2VuZCIsInNldHRpbmdzIiwic3VjY2Vzc1Rlc3QiLCJQYnhBcGkiLCJvblN1Y2Nlc3MiLCJyZXNwb25zZSIsImVkaXRvciIsImdldFNlc3Npb24iLCJzZXRWYWx1ZSIsIm9uRmFpbHVyZSIsIlVzZXJNZXNzYWdlIiwic2hvd011bHRpU3RyaW5nIiwibWVzc2FnZSIsInJlbW92ZUNsYXNzIiwic2hvdyIsImFkZENsYXNzIiwiY2JCZWZvcmVTZW5kRm9ybSIsInJlc3VsdCIsImRhdGEiLCJmb3JtIiwiY2JBZnRlclNlbmRGb3JtIiwiRm9ybSIsImNoZWNrU3VjY2VzcyIsImdsb2JhbFJvb3RVcmwiLCJlbmFibGVEaXJyaXR5IiwiZG9jdW1lbnQiLCJyZWFkeSJdLCJt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QUNHLGFBQUwsR0FBcUIsS0FBckI7QUFDQUgsSUFBQUEsSUFBSSxDQUFDRCxlQUFMLEdBQXVCekQsWUFBWSxDQUFDeUQsZUFBcEM7QUFDQUMsSUFBQUEsSUFBSSxDQUFDTCxnQkFBTCxHQUF3QnJELFlBQVksQ0FBQ3FELGdCQUFyQyxDQVBnQixDQVFoQjs7QUFDQUssSUFBQUEsSUFBSSxDQUFDekMsVUFBTDtBQUNBO0FBL0htQixDQUFyQixDLENBa0lBOztBQUNBZixDQUFDLENBQUM0RCxRQUFELENBQUQsQ0FBWUMsS0FBWixDQUFrQixZQUFNO0FBQ3ZCL0QsRUFBQUEsWUFBWSxDQUFDaUIsVUFBYjtBQUNBLENBRkQiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBnbG9iYWwgZ2xvYmFsUm9vdFVybCwgZ2xvYmFsVHJhbnNsYXRlLCBGb3JtLCBDb25maWcsIFBieEFwaSAqL1xuXG4vLyBDb25zdGFudHMgcmVsYXRlZCB0byB0aGUgZm9ybSBhbmQgbW9kdWxlXG5jb25zdCBpZFVybCAgICAgPSAnbW9kdWxlLWdldC1zc2wnOyAgICAgICAgICAgICAgLy8gQVBJIGVuZHBvaW50IGZvciBTU0wgbW9kdWxlXG5jb25zdCBpZEZvcm0gICAgPSAnbW9kdWxlLWdldC1zc2wtZm9ybSc7ICAgICAgICAgLy8gRm9ybSBlbGVtZW50IElEIGZvciBTU0wgbW9kdWxlXG5jb25zdCBjbGFzc05hbWUgPSAnTW9kdWxlR2V0U3NsJzsgICAgICAgICAgICAgICAgLy8gQ2xhc3MgbmFtZSBmb3IgdGhpcyBtb2R1bGVcblxuLy8gTWFpbiBNb2R1bGVHZXRTc2wgY2xhc3MgZGVmaW5pdGlvblxuY29uc3QgTW9kdWxlR2V0U3NsID0ge1xuXHQvLyBDYWNoZSBjb21tb25seSB1c2VkIGpRdWVyeSBvYmplY3RzXG5cdCRmb3JtT2JqOiAkKCcjJyArIGlkRm9ybSksXG5cdCRjaGVja0JveGVzOiAkKCcjJyArIGlkRm9ybSArICcgLnVpLmNoZWNrYm94JyksXG5cdCRkaXNhYmlsaXR5RmllbGRzOiAkKCcjJyArIGlkRm9ybSArICcgLmRpc2FiaWxpdHknKSxcblx0JHN0YXR1c1RvZ2dsZTogJCgnI21vZHVsZS1zdGF0dXMtdG9nZ2xlJyksXG5cdCRtb2R1bGVTdGF0dXM6ICQoJyNzdGF0dXMnKSxcblx0JGludGVydmFsSWQ6IHVuZGVmaW5lZCwgLy8gVG8gbWFuYWdlIHRoZSBpbnRlcnZhbCBmb3IgU1NMIHN0YXR1cyBjaGVja1xuXG5cdC8vIFZhbGlkYXRpb24gcnVsZXMgZm9yIHRoZSBmb3JtXG5cdHZhbGlkYXRlUnVsZXM6IHtcblx0XHRkb21haW5OYW1lOiB7XG5cdFx0XHRpZGVudGlmaWVyOiAnZG9tYWluTmFtZScsXG5cdFx0XHRydWxlczogW1xuXHRcdFx0XHR7XG5cdFx0XHRcdFx0dHlwZTogJ2VtcHR5Jyxcblx0XHRcdFx0XHRwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5tb2R1bGVfZ2V0c3NsX0RvbWFpbk5hbWVFbXB0eSxcblx0XHRcdFx0fSxcblx0XHRcdF0sXG5cdFx0fSxcblx0fSxcblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSB0aGUgbW9kdWxlLCBiaW5kIGV2ZW50IGxpc3RlbmVycywgYW5kIHNldHVwIHRoZSBmb3JtLlxuXHQgKiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aGVuIHRoZSBkb2N1bWVudCBpcyByZWFkeS5cblx0ICovXG5cdGluaXRpYWxpemUoKSB7XG5cdFx0Ly8gSW5pdGlhbGl6ZSBTZW1hbnRpYyBVSSBjaGVja2JveGVzXG5cdFx0dGhpcy4kY2hlY2tCb3hlcy5jaGVja2JveCgpO1xuXG5cdFx0Ly8gQ2hlY2sgYW5kIHNldCBtb2R1bGUgc3RhdHVzIG9uIGxvYWQgYW5kIHdoZW4gdGhlIHN0YXR1cyBjaGFuZ2VzXG5cdFx0dGhpcy5jaGVja1N0YXR1c1RvZ2dsZSgpO1xuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdNb2R1bGVTdGF0dXNDaGFuZ2VkJywgdGhpcy5jaGVja1N0YXR1c1RvZ2dsZSk7XG5cblx0XHQvLyBJbml0aWFsaXplIGZvcm0gd2l0aCB2YWxpZGF0aW9uIGFuZCBzdWJtaXQgaGFuZGxlcnNcblx0XHR0aGlzLmluaXRpYWxpemVGb3JtKCk7XG5cblx0XHRtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5oaWRlKCk7XG5cdH0sXG5cblx0LyoqXG5cdCAqIFJlcXVlc3QgYW4gU1NMIGNlcnRpZmljYXRlIGJ5IGNhbGxpbmcgdGhlIHNlcnZlci1zaWRlIEFQSS5cblx0ICogVGhpcyBtZXRob2Qgc2VuZHMgYSBHRVQgcmVxdWVzdCB0byBpbml0aWF0ZSB0aGUgU1NMIHByb2Nlc3MuXG5cdCAqL1xuXHRnZXRTc2woKSB7XG5cdFx0JC5hcGkoe1xuXHRcdFx0dXJsOiBgJHtDb25maWcucGJ4VXJsfS9wYnhjb3JlL2FwaS9tb2R1bGVzLyR7Y2xhc3NOYW1lfS9nZXQtY2VydGAsXG5cdFx0XHRvbjogJ25vdycsXG5cdFx0XHRtZXRob2Q6ICdQT1NUJyxcblx0XHRcdGJlZm9yZVhIUih4aHIpIHtcblx0XHRcdFx0eGhyLnNldFJlcXVlc3RIZWFkZXIgKCdYLUFzeW5jLVJlc3BvbnNlLUNoYW5uZWwtSWQnLCBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmNoYW5uZWxJZCk7XG5cdFx0XHRcdHhoci5zZXRSZXF1ZXN0SGVhZGVyICgnWC1Qcm9jZXNzb3ItVGltZW91dCcsICcxMjAnKTtcblx0XHRcdFx0cmV0dXJuIHhocjtcblx0XHRcdH0sXG5cdFx0XHRiZWZvcmVTZW5kKHNldHRpbmdzKSB7XG5cdFx0XHRcdHJldHVybiBzZXR0aW5ncztcblx0XHRcdH0sXG5cdFx0XHRzdWNjZXNzVGVzdDogUGJ4QXBpLnN1Y2Nlc3NUZXN0LFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBIYW5kbGVzIHRoZSBzdWNjZXNzZnVsIHJlc3BvbnNlIG9mIHRoZSAnZ2V0LWNlcnQnIEFQSSByZXF1ZXN0LlxuXHRcdFx0ICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIG9iamVjdC5cblx0XHRcdCAqL1xuXHRcdFx0b25TdWNjZXNzOiBmdW5jdGlvbiAocmVzcG9uc2UpIHtcblx0XHRcdFx0bW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IuZ2V0U2Vzc2lvbigpLnNldFZhbHVlKCcnKTtcblx0XHRcdH0sXG5cdFx0XHQvKipcblx0XHRcdCAqIEhhbmRsZXMgdGhlIGZhaWx1cmUgcmVzcG9uc2Ugb2YgdGhlICdnZXQtYXZhaWxhYmxlLWxkYXAtdXNlcnMnIEFQSSByZXF1ZXN0LlxuXHRcdFx0ICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIG9iamVjdC5cblx0XHRcdCAqL1xuXHRcdFx0b25GYWlsdXJlOiBmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRVc2VyTWVzc2FnZS5zaG93TXVsdGlTdHJpbmcocmVzcG9uc2UubWVzc2FnZSk7XG5cdFx0XHRcdG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuJHJlc3VsdEJsb2NrLmhpZGUoKTtcblx0XHRcdH0sXG5cdFx0fSlcblx0fSxcblxuXHQvKipcblx0ICogVG9nZ2xlcyB0aGUgZm9ybSBmaWVsZHMgYW5kIHN0YXR1cyB2aXNpYmlsaXR5IGJhc2VkIG9uIHRoZSBtb2R1bGUncyBzdGF0dXMuXG5cdCAqIEVuYWJsZXMgb3IgZGlzYWJsZXMgZm9ybSBmaWVsZHMgZGVwZW5kaW5nIG9uIHdoZXRoZXIgdGhlIG1vZHVsZSBpcyBhY3RpdmUuXG5cdCAqL1xuXHRjaGVja1N0YXR1c1RvZ2dsZSgpIHtcblx0XHQvLyBJZiB0aGUgbW9kdWxlIHN0YXR1cyBpcyBhY3RpdmUsIGVuYWJsZSBmb3JtIGZpZWxkcyBhbmQgc2hvdyBzdGF0dXNcblx0XHRpZiAoTW9kdWxlR2V0U3NsLiRzdGF0dXNUb2dnbGUuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuXHRcdFx0TW9kdWxlR2V0U3NsLiRkaXNhYmlsaXR5RmllbGRzLnJlbW92ZUNsYXNzKCdkaXNhYmxlZCcpO1xuXHRcdFx0TW9kdWxlR2V0U3NsLiRtb2R1bGVTdGF0dXMuc2hvdygpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBJZiB0aGUgbW9kdWxlIHN0YXR1cyBpcyBpbmFjdGl2ZSwgZGlzYWJsZSBmb3JtIGZpZWxkcyBhbmQgaGlkZSBzdGF0dXNcblx0XHRcdE1vZHVsZUdldFNzbC4kZGlzYWJpbGl0eUZpZWxkcy5hZGRDbGFzcygnZGlzYWJsZWQnKTtcblx0XHRcdE1vZHVsZUdldFNzbC4kbW9kdWxlU3RhdHVzLmhpZGUoKTtcblx0XHR9XG5cdH0sXG5cblx0LyoqXG5cdCAqIENhbGxiYWNrIGJlZm9yZSBzZW5kaW5nIHRoZSBmb3JtLlxuXHQgKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBBamF4IHJlcXVlc3Qgc2V0dGluZ3MuXG5cdCAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBtb2RpZmllZCBBamF4IHJlcXVlc3Qgc2V0dGluZ3MuXG5cdCAqL1xuXHRjYkJlZm9yZVNlbmRGb3JtKHNldHRpbmdzKSB7XG5cdFx0Y29uc3QgcmVzdWx0ID0gc2V0dGluZ3M7XG5cdFx0cmVzdWx0LmRhdGEgPSBNb2R1bGVHZXRTc2wuJGZvcm1PYmouZm9ybSgnZ2V0IHZhbHVlcycpO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdH0sXG5cblx0LyoqXG5cdCAqIENhbGxiYWNrIGZ1bmN0aW9uIGFmdGVyIHNlbmRpbmcgdGhlIGZvcm0uXG5cdCAqL1xuXHRjYkFmdGVyU2VuZEZvcm0ocmVzcG9uc2UpIHtcblx0XHRpZiAoRm9ybS5jaGVja1N1Y2Nlc3MocmVzcG9uc2UpKXtcblx0XHRcdE1vZHVsZUdldFNzbC5nZXRTc2woKTtcblx0XHR9XG5cdH0sXG5cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZXMgdGhlIGZvcm0gdmFsaWRhdGlvbiBhbmQgc3VibWlzc2lvbiBsb2dpYy5cblx0ICogU2V0cyB1cCBjYWxsYmFja3MgYW5kIHZhbGlkYXRpb24gcnVsZXMgZm9yIHRoZSBmb3JtLlxuXHQgKi9cblx0aW5pdGlhbGl6ZUZvcm0oKSB7XG5cdFx0Ly8gQXNzaWduIGZvcm0tcmVsYXRlZCBzZXR0aW5ncyB0byB0aGUgRm9ybSBvYmplY3Rcblx0XHRGb3JtLiRmb3JtT2JqID0gTW9kdWxlR2V0U3NsLiRmb3JtT2JqO1xuXHRcdEZvcm0udXJsID0gYCR7Z2xvYmFsUm9vdFVybH0ke2lkVXJsfS8ke2lkVXJsfS9zYXZlYDtcblx0XHRGb3JtLnZhbGlkYXRlUnVsZXMgPSBNb2R1bGVHZXRTc2wudmFsaWRhdGVSdWxlcztcblx0XHRGb3JtLmVuYWJsZURpcnJpdHkgPSBmYWxzZTtcblx0XHRGb3JtLmNiQWZ0ZXJTZW5kRm9ybSA9IE1vZHVsZUdldFNzbC5jYkFmdGVyU2VuZEZvcm07XG5cdFx0Rm9ybS5jYkJlZm9yZVNlbmRGb3JtID0gTW9kdWxlR2V0U3NsLmNiQmVmb3JlU2VuZEZvcm07XG5cdFx0Ly8gSW5pdGlhbGl6ZSB0aGUgZm9ybSB3aXRoIHRoZSBzcGVjaWZpZWQgcGFyYW1ldGVyc1xuXHRcdEZvcm0uaW5pdGlhbGl6ZSgpO1xuXHR9LFxufTtcblxuLy8gSW5pdGlhbGl6ZSB0aGUgTW9kdWxlR2V0U3NsIGNsYXNzIHdoZW4gdGhlIGRvY3VtZW50IGlzIHJlYWR5XG4kKGRvY3VtZW50KS5yZWFkeSgoKSA9PiB7XG5cdE1vZHVsZUdldFNzbC5pbml0aWFsaXplKCk7XG59KTsiXX0= \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtZ2V0LXNzbC1pbmRleC5qcyJdLCJuYW1lcyI6WyJpZFVybCIsImlkRm9ybSIsImNsYXNzTmFtZSIsIk1vZHVsZUdldFNzbCIsIiRmb3JtT2JqIiwiJCIsIiRjaGVja0JveGVzIiwiJGRpc2FiaWxpdHlGaWVsZHMiLCIkc3RhdHVzVG9nZ2xlIiwiJHN1Ym1pdEJ1dHRvbiIsIiRtb2R1bGVTdGF0dXMiLCIkaW50ZXJ2YWxJZCIsInVuZGVmaW5lZCIsInZhbGlkYXRlUnVsZXMiLCJkb21haW5OYW1lIiwiaWRlbnRpZmllciIsInJ1bGVzIiwidHlwZSIsInByb21wdCIsImdsb2JhbFRyYW5zbGF0ZSIsIm1vZHVsZV9nZXRzc2xfRG9tYWluTmFtZUVtcHR5IiwiaW5pdGlhbGl6ZSIsImNoZWNrYm94IiwiY2hlY2tTdGF0dXNUb2dnbGUiLCJ3aW5kb3ciLCJhZGRFdmVudExpc3RlbmVyIiwiaW5pdGlhbGl6ZUZvcm0iLCJtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyIiwiJHJlc3VsdEJsb2NrIiwiaGlkZSIsImdldFNzbCIsImFwaSIsInVybCIsIkNvbmZpZyIsInBieFVybCIsIm9uIiwibWV0aG9kIiwiYmVmb3JlWEhSIiwieGhyIiwic2V0UmVxdWVzdEhlYWRlciIsImNoYW5uZWxJZCIsImJlZm9yZVNlbmQiLCJzZXR0aW5ncyIsImFkZENsYXNzIiwic2hvdyIsImVkaXRvciIsImdldFNlc3Npb24iLCJzZXRWYWx1ZSIsInN1Y2Nlc3NUZXN0IiwiUGJ4QXBpIiwib25TdWNjZXNzIiwicmVzcG9uc2UiLCJyZW1vdmVDbGFzcyIsIm9uRmFpbHVyZSIsIlVzZXJNZXNzYWdlIiwic2hvd011bHRpU3RyaW5nIiwibWVzc2FnZSIsImNiQmVmb3JlU2VuZEZvcm0iLCJyZXN1bHQiLCJkYXRhIiwiZm9ybSIsImNiQWZ0ZXJTZW5kRm9ybSIsIkZvcm0iLCJjaGVja1N1Y2Nlc3MiLCJnbG9iYWxSb290VXJsIiwiZW5hYmxlRGlycml0eSIsImRvY3Vt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TUFBYjtBQUNBO0FBQ0QsR0FuSG1COztBQXNIcEI7QUFDRDtBQUNBO0FBQ0E7QUFDQ0osRUFBQUEsY0ExSG9CLDRCQTBISDtBQUNoQjtBQUNBb0MsSUFBQUEsSUFBSSxDQUFDMUQsUUFBTCxHQUFnQkQsWUFBWSxDQUFDQyxRQUE3QjtBQUNBMEQsSUFBQUEsSUFBSSxDQUFDOUIsR0FBTCxhQUFjZ0MsYUFBZCxTQUE4QmhFLEtBQTlCLGNBQXVDQSxLQUF2QztBQUNBOEQsSUFBQUEsSUFBSSxDQUFDakQsYUFBTCxHQUFxQlYsWUFBWSxDQUFDVSxhQUFsQztBQUNBaUQsSUFBQUEsSUFBSSxDQUFDRyxhQUFMLEdBQXFCLEtBQXJCO0FBQ0FILElBQUFBLElBQUksQ0FBQ0QsZUFBTCxHQUF1QjFELFlBQVksQ0FBQzBELGVBQXBDO0FBQ0FDLElBQUFBLElBQUksQ0FBQ0wsZ0JBQUwsR0FBd0J0RCxZQUFZLENBQUNzRCxnQkFBckMsQ0FQZ0IsQ0FRaEI7O0FBQ0FLLElBQUFBLElBQUksQ0FBQ3pDLFVBQUw7QUFDQTtBQXBJbUIsQ0FBckIsQyxDQXVJQTs7QUFDQWhCLENBQUMsQ0FBQzZELFFBQUQsQ0FBRCxDQUFZQyxLQUFaLENBQWtCLFlBQU07QUFDdkJoRSxFQUFBQSxZQUFZLENBQUNrQixVQUFiO0FBQ0EsQ0FGRCIsInNvdXJjZXNDb250ZW50IjpbIi8qIGdsb2JhbCBnbG9iYWxSb290VXJsLCBnbG9iYWxUcmFuc2xhdGUsIEZvcm0sIENvbmZpZywgUGJ4QXBpICovXG5cbi8vIENvbnN0YW50cyByZWxhdGVkIHRvIHRoZSBmb3JtIGFuZCBtb2R1bGVcbmNvbnN0IGlkVXJsICAgICA9ICdtb2R1bGUtZ2V0LXNzbCc7ICAgICAgICAgICAgICAvLyBBUEkgZW5kcG9pbnQgZm9yIFNTTCBtb2R1bGVcbmNvbnN0IGlkRm9ybSAgICA9ICdtb2R1bGUtZ2V0LXNzbC1mb3JtJzsgICAgICAgICAvLyBGb3JtIGVsZW1lbnQgSUQgZm9yIFNTTCBtb2R1bGVcbmNvbnN0IGNsYXNzTmFtZSA9ICdNb2R1bGVHZXRTc2wnOyAgICAgICAgICAgICAgICAvLyBDbGFzcyBuYW1lIGZvciB0aGlzIG1vZHVsZVxuXG4vLyBNYWluIE1vZHVsZUdldFNzbCBjbGFzcyBkZWZpbml0aW9uXG5jb25zdCBNb2R1bGVHZXRTc2wgPSB7XG5cdC8vIENhY2hlIGNvbW1vbmx5IHVzZWQgalF1ZXJ5IG9iamVjdHNcblx0JGZvcm1PYmo6ICQoJyMnICsgaWRGb3JtKSxcblx0JGNoZWNrQm94ZXM6ICQoJyMnICsgaWRGb3JtICsgJyAudWkuY2hlY2tib3gnKSxcblx0JGRpc2FiaWxpdHlGaWVsZHM6ICQoJyMnICsgaWRGb3JtICsgJyAuZGlzYWJpbGl0eScpLFxuXHQkc3RhdHVzVG9nZ2xlOiAkKCcjbW9kdWxlLXN0YXR1cy10b2dnbGUnKSxcblx0JHN1Ym1pdEJ1dHRvbjogJCgnI3N1Ym1pdGJ1dHRvbicpLFxuXHQkbW9kdWxlU3RhdHVzOiAkKCcjc3RhdHVzJyksXG5cdCRpbnRlcnZhbElkOiB1bmRlZmluZWQsIC8vIFRvIG1hbmFnZSB0aGUgaW50ZXJ2YWwgZm9yIFNTTCBzdGF0dXMgY2hlY2tcblxuXHQvLyBWYWxpZGF0aW9uIHJ1bGVzIGZvciB0aGUgZm9ybVxuXHR2YWxpZGF0ZVJ1bGVzOiB7XG5cdFx0ZG9tYWluTmFtZToge1xuXHRcdFx0aWRlbnRpZmllcjogJ2RvbWFpbk5hbWUnLFxuXHRcdFx0cnVsZXM6IFtcblx0XHRcdFx0e1xuXHRcdFx0XHRcdHR5cGU6ICdlbXB0eScsXG5cdFx0XHRcdFx0cHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUubW9kdWxlX2dldHNzbF9Eb21haW5OYW1lRW1wdHksXG5cdFx0XHRcdH0sXG5cdFx0XHRdLFxuXHRcdH0sXG5cdH0sXG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgdGhlIG1vZHVsZSwgYmluZCBldmVudCBsaXN0ZW5lcnMsIGFuZCBzZXR1cCB0aGUgZm9ybS5cblx0ICogVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgd2hlbiB0aGUgZG9jdW1lbnQgaXMgcmVhZHkuXG5cdCAqL1xuXHRpbml0aWFsaXplKCkge1xuXHRcdC8vIEluaXRpYWxpemUgU2VtYW50aWMgVUkgY2hlY2tib3hlc1xuXHRcdHRoaXMuJGNoZWNrQm94ZXMuY2hlY2tib3goKTtcblxuXHRcdC8vIENoZWNrIGFuZCBzZXQgbW9kdWxlIHN0YXR1cyBvbiBsb2FkIGFuZCB3aGVuIHRoZSBzdGF0dXMgY2hhbmdlc1xuXHRcdHRoaXMuY2hlY2tTdGF0dXNUb2dnbGUoKTtcblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignTW9kdWxlU3RhdHVzQ2hhbmdlZCcsIHRoaXMuY2hlY2tTdGF0dXNUb2dnbGUpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBmb3JtIHdpdGggdmFsaWRhdGlvbiBhbmQgc3VibWl0IGhhbmRsZXJzXG5cdFx0dGhpcy5pbml0aWFsaXplRm9ybSgpO1xuXG5cdFx0bW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci4kcmVzdWx0QmxvY2suaGlkZSgpO1xuXHR9LFxuXG5cdC8qKlxuXHQgKiBSZXF1ZXN0IGFuIFNTTCBjZXJ0aWZpY2F0ZSBieSBjYWxsaW5nIHRoZSBzZXJ2ZXItc2lkZSBBUEkuXG5cdCAqIFRoaXMgbWV0aG9kIHNlbmRzIGEgR0VUIHJlcXVlc3QgdG8gaW5pdGlhdGUgdGhlIFNTTCBwcm9jZXNzLlxuXHQgKi9cblx0Z2V0U3NsKCkge1xuXHRcdCQuYXBpKHtcblx0XHRcdHVybDogYCR7Q29uZmlnLnBieFVybH0vcGJ4Y29yZS9hcGkvbW9kdWxlcy8ke2NsYXNzTmFtZX0vZ2V0LWNlcnRgLFxuXHRcdFx0b246ICdub3cnLFxuXHRcdFx0bWV0aG9kOiAnUE9TVCcsXG5cdFx0XHRiZWZvcmVYSFIoeGhyKSB7XG5cdFx0XHRcdHhoci5zZXRSZXF1ZXN0SGVhZGVyICgnWC1Bc3luYy1SZXNwb25zZS1DaGFubmVsLUlkJywgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5jaGFubmVsSWQpO1xuXHRcdFx0XHR4aHIuc2V0UmVxdWVzdEhlYWRlciAoJ1gtUHJvY2Vzc29yLVRpbWVvdXQnLCAnMTIwJyk7XG5cdFx0XHRcdHJldHVybiB4aHI7XG5cdFx0XHR9LFxuXHRcdFx0YmVmb3JlU2VuZChzZXR0aW5ncykge1xuXHRcdFx0XHRNb2R1bGVHZXRTc2wuJHN1Ym1pdEJ1dHRvbi5hZGRDbGFzcygnbG9hZGluZyBkaXNhYmxlZCcpO1xuXHRcdFx0XHRtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5zaG93KCk7XG5cdFx0XHRcdG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZWRpdG9yLmdldFNlc3Npb24oKS5zZXRWYWx1ZSgnJyk7XG5cdFx0XHRcdHJldHVybiBzZXR0aW5ncztcblx0XHRcdH0sXG5cdFx0XHRzdWNjZXNzVGVzdDogUGJ4QXBpLnN1Y2Nlc3NUZXN0LFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBIYW5kbGVzIHRoZSBzdWNjZXNzZnVsIHJlc3BvbnNlIG9mIHRoZSAnZ2V0LWNlcnQnIEFQSSByZXF1ZXN0LlxuXHRcdFx0ICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIG9iamVjdC5cblx0XHRcdCAqL1xuXHRcdFx0b25TdWNjZXNzOiBmdW5jdGlvbiAocmVzcG9uc2UpIHtcblx0XHRcdFx0TW9kdWxlR2V0U3NsLiRzdWJtaXRCdXR0b24ucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcgZGlzYWJsZWQnKTtcblx0XHRcdH0sXG5cdFx0XHQvKipcblx0XHRcdCAqIEhhbmRsZXMgdGhlIGZhaWx1cmUgcmVzcG9uc2Ugb2YgdGhlICdnZXQtY2VydCcgQVBJIHJlcXVlc3QuXG5cdFx0XHQgKiBAcGFyYW0ge29iamVjdH0gcmVzcG9uc2UgLSBUaGUgcmVzcG9uc2Ugb2JqZWN0LlxuXHRcdFx0ICovXG5cdFx0XHRvbkZhaWx1cmU6IGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG5cdFx0XHRcdE1vZHVsZUdldFNzbC4kc3VibWl0QnV0dG9uLnJlbW92ZUNsYXNzKCdsb2FkaW5nIGRpc2FibGVkJyk7XG5cdFx0XHRcdFVzZXJNZXNzYWdlLnNob3dNdWx0aVN0cmluZyhyZXNwb25zZS5tZXNzYWdlKTtcblx0XHRcdFx0bW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci4kcmVzdWx0QmxvY2suaGlkZSgpO1xuXHRcdFx0fSxcblx0XHR9KVxuXHR9LFxuXG5cdC8qKlxuXHQgKiBUb2dnbGVzIHRoZSBmb3JtIGZpZWxkcyBhbmQgc3RhdHVzIHZpc2liaWxpdHkgYmFzZWQgb24gdGhlIG1vZHVsZSdzIHN0YXR1cy5cblx0ICogRW5hYmxlcyBvciBkaXNhYmxlcyBmb3JtIGZpZWxkcyBkZXBlbmRpbmcgb24gd2hldGhlciB0aGUgbW9kdWxlIGlzIGFjdGl2ZS5cblx0ICovXG5cdGNoZWNrU3RhdHVzVG9nZ2xlKCkge1xuXHRcdC8vIElmIHRoZSBtb2R1bGUgc3RhdHVzIGlzIGFjdGl2ZSwgZW5hYmxlIGZvcm0gZmllbGRzIGFuZCBzaG93IHN0YXR1c1xuXHRcdGlmIChNb2R1bGVHZXRTc2wuJHN0YXR1c1RvZ2dsZS5jaGVja2JveCgnaXMgY2hlY2tlZCcpKSB7XG5cdFx0XHRNb2R1bGVHZXRTc2wuJGRpc2FiaWxpdHlGaWVsZHMucmVtb3ZlQ2xhc3MoJ2Rpc2FibGVkJyk7XG5cdFx0XHRNb2R1bGVHZXRTc2wuJG1vZHVsZVN0YXR1cy5zaG93KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIElmIHRoZSBtb2R1bGUgc3RhdHVzIGlzIGluYWN0aXZlLCBkaXNhYmxlIGZvcm0gZmllbGRzIGFuZCBoaWRlIHN0YXR1c1xuXHRcdFx0TW9kdWxlR2V0U3NsLiRkaXNhYmlsaXR5RmllbGRzLmFkZENsYXNzKCdkaXNhYmxlZCcpO1xuXHRcdFx0TW9kdWxlR2V0U3NsLiRtb2R1bGVTdGF0dXMuaGlkZSgpO1xuXHRcdH1cblx0fSxcblxuXHQvKipcblx0ICogQ2FsbGJhY2sgYmVmb3JlIHNlbmRpbmcgdGhlIGZvcm0uXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIEFqYXggcmVxdWVzdCBzZXR0aW5ncy5cblx0ICogQHJldHVybnMge09iamVjdH0gVGhlIG1vZGlmaWVkIEFqYXggcmVxdWVzdCBzZXR0aW5ncy5cblx0ICovXG5cdGNiQmVmb3JlU2VuZEZvcm0oc2V0dGluZ3MpIHtcblx0XHRjb25zdCByZXN1bHQgPSBzZXR0aW5ncztcblx0XHRyZXN1bHQuZGF0YSA9IE1vZHVsZUdldFNzbC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWVzJyk7XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHQvKipcblx0ICogQ2FsbGJhY2sgZnVuY3Rpb24gYWZ0ZXIgc2VuZGluZyB0aGUgZm9ybS5cblx0ICovXG5cdGNiQWZ0ZXJTZW5kRm9ybShyZXNwb25zZSkge1xuXHRcdGlmIChGb3JtLmNoZWNrU3VjY2VzcyhyZXNwb25zZSkpe1xuXHRcdFx0TW9kdWxlR2V0U3NsLmdldFNzbCgpO1xuXHRcdH1cblx0fSxcblxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplcyB0aGUgZm9ybSB2YWxpZGF0aW9uIGFuZCBzdWJtaXNzaW9uIGxvZ2ljLlxuXHQgKiBTZXRzIHVwIGNhbGxiYWNrcyBhbmQgdmFsaWRhdGlvbiBydWxlcyBmb3IgdGhlIGZvcm0uXG5cdCAqL1xuXHRpbml0aWFsaXplRm9ybSgpIHtcblx0XHQvLyBBc3NpZ24gZm9ybS1yZWxhdGVkIHNldHRpbmdzIHRvIHRoZSBGb3JtIG9iamVjdFxuXHRcdEZvcm0uJGZvcm1PYmogPSBNb2R1bGVHZXRTc2wuJGZvcm1PYmo7XG5cdFx0Rm9ybS51cmwgPSBgJHtnbG9iYWxSb290VXJsfSR7aWRVcmx9LyR7aWRVcmx9L3NhdmVgO1xuXHRcdEZvcm0udmFsaWRhdGVSdWxlcyA9IE1vZHVsZUdldFNzbC52YWxpZGF0ZVJ1bGVzO1xuXHRcdEZvcm0uZW5hYmxlRGlycml0eSA9IGZhbHNlO1xuXHRcdEZvcm0uY2JBZnRlclNlbmRGb3JtID0gTW9kdWxlR2V0U3NsLmNiQWZ0ZXJTZW5kRm9ybTtcblx0XHRGb3JtLmNiQmVmb3JlU2VuZEZvcm0gPSBNb2R1bGVHZXRTc2wuY2JCZWZvcmVTZW5kRm9ybTtcblx0XHQvLyBJbml0aWFsaXplIHRoZSBmb3JtIHdpdGggdGhlIHNwZWNpZmllZCBwYXJhbWV0ZXJzXG5cdFx0Rm9ybS5pbml0aWFsaXplKCk7XG5cdH0sXG59O1xuXG4vLyBJbml0aWFsaXplIHRoZSBNb2R1bGVHZXRTc2wgY2xhc3Mgd2hlbiB0aGUgZG9jdW1lbnQgaXMgcmVhZHlcbiQoZG9jdW1lbnQpLnJlYWR5KCgpID0+IHtcblx0TW9kdWxlR2V0U3NsLmluaXRpYWxpemUoKTtcbn0pOyJdfQ== \ No newline at end of file diff --git a/public/assets/js/module-get-ssl-status-worker.js b/public/assets/js/module-get-ssl-status-worker.js index 488a87d..1bec09b 100644 --- a/public/assets/js/module-get-ssl-status-worker.js +++ b/public/assets/js/module-get-ssl-status-worker.js @@ -59,6 +59,7 @@ var moduleGetSSLStatusLoopWorker = { */ initialize: function initialize() { moduleGetSSLStatusLoopWorker.initializeAce(); + moduleGetSSLStatusLoopWorker.loadLastLog(); if (moduleGetSSLStatusLoopWorker.versionCompare(globalPBXVersion, '2024.2.30') > 0) { moduleGetSSLStatusLoopWorker.startListenPushNotifications(); @@ -67,6 +68,26 @@ var moduleGetSSLStatusLoopWorker = { } }, + /** + * Loads the last log file content into the ACE editor on page load. + */ + loadLastLog: function loadLastLog() { + $.api({ + url: "".concat(Config.pbxUrl, "/pbxcore/api/modules/ModuleGetSsl/check-result"), + on: 'now', + method: 'GET', + successTest: PbxApi.successTest, + onSuccess: function onSuccess(response) { + if (response.data.result && response.data.result.length > 0) { + moduleGetSSLStatusLoopWorker.$resultBlock.show(); + moduleGetSSLStatusLoopWorker.editor.getSession().setValue(response.data.result); + } + }, + onFailure: function onFailure() {// Silently ignore - no log to show + } + }); + }, + /** * Restarts the moduleGetSSLStatus worker. */ @@ -243,4 +264,4 @@ var moduleGetSSLStatusLoopWorker = { $(document).ready(function () { moduleGetSSLStatusLoopWorker.initialize(); }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtZ2V0LXNzbC1zdGF0dXMtd29ya2VyLmpzIl0sIm5hbWVzIjpbIm1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIiLCJ0aW1lT3V0IiwidGltZU91dEhhbmRsZSIsImV2ZW50U291cmNlIiwiY2hhbm5lbElkIiwiJHJlc3VsdEJsb2NrIiwiJCIsImluaXRpYWxpemUiLCJpbml0aWFsaXplQWNlIiwidmVyc2lvbkNvbXBhcmUiLCJnbG9iYWxQQlhWZXJzaW9uIiwic3RhcnRMaXN0ZW5QdXNoTm90aWZpY2F0aW9ucyIsInJlc3RhcnRXb3JrZXIiLCJ3aW5kb3ciLCJjbGVhclRpbWVvdXQiLCJ0aW1lb3V0SGFuZGxlIiwid29ya2VyIiwiYXBpIiwidXJsIiwiQ29uZmlnIiwicGJ4VXJsIiwib24iLCJtZXRob2QiLCJzdWNjZXNzVGVzdCIsIlBieEFwaSIsIm9uU3VjY2VzcyIsInJlc3BvbnNlIiwiZGF0YSIsInJlc3VsdCIsImxlbmd0aCIsInNob3ciLCJlZGl0b3IiLCJnZXRTZXNzaW9uIiwic2V0VmFsdWUiLCJzZXRUaW1lb3V0Iiwib25GYWlsdXJlIiwiVXNlck1lc3NhZ2UiLCJzaG93TXVsdGlTdHJpbmciLCJtZXNzYWdlIiwiaGlkZSIsImFjZUhlaWdodCIsImlubmVySGVpZ2h0Iiwicm93c0NvdW50IiwiTWF0aCIsInJvdW5kIiwibG9hZCIsImNzcyIsImFjZSIsImVkaXQiLCJOZXdNb2RlIiwicmVxdWlyZSIsIk1vZGUiLCJzZXNzaW9uIiwic2V0TW9kZSIsInNldFRoZW1lIiwicmVzaXplIiwiRm9ybSIsImRhdGFDaGFuZ2VkIiwic2V0T3B0aW9ucyIsIm1heExpbmVzIiwic2hvd1ByaW50TWFyZ2luIiwic2hvd0xpbmVOdW1iZXJzIiwibGFzdEV2ZW50SWRLZXkiLCJsYXN0RXZlbnRJZCIsImxvY2FsU3RvcmFnZSIsImdldEl0ZW0iLCJzdWJQYXRoIiwiRXZlbnRTb3VyY2UiLCJhZGRFdmVudExpc3RlbmVyIiwiZSIsIkpTT04iLCJwYXJzZSIsImNvbnNvbGUiLCJkZWJ1ZyIsInByb2Nlc3NTdGF0dXNNZXNzYWdlIiwic2V0SXRlbSIsInN0YWdlRGV0YWlscyIsInJlc3VsdFRleHQiLCJnZXRWYWx1ZSIsInN0YWdlIiwibWVzc2FnZXMiLCJ2MSIsInYyIiwib3B0aW9ucyIsImxleGljb2dyYXBoaWNhbCIsInplcm9FeHRlbmQiLCJ2MXBhcnRzIiwiU3RyaW5nIiwic3BsaXQiLCJ2MnBhcnRzIiwiaXNWYWxpZFBhcnQiLCJ4IiwidGVzdCIsImV2ZXJ5IiwiTmFOIiwicHVzaCIsIm1hcCIsIk51bWJlciIsImkiLCJkb2N1bWVudCIsInJlYWR5Il0sIm1hcHBpbmdzIjoiOztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBTUEsNEJBQTRCLEdBQUc7QUFFakM7QUFDSjtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsT0FBTyxFQUFFLEtBTndCOztBQVFqQztBQUNKO0FBQ0E7QUFDQTtBQUNJQyxFQUFBQSxhQUFhLEVBQUUsQ0Faa0I7O0FBZWpDO0FBQ0o7QUFDQTtBQUNJQyxFQUFBQSxXQUFXLEVBQUUsSUFsQm9COztBQW9CakM7QUFDSjtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsU0FBUyxFQUFFLG9CQXhCc0I7O0FBMEJqQztBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0lDLEVBQUFBLFlBQVksRUFBRUMsQ0FBQyxDQUFDLGFBQUQsQ0EvQmtCOztBQWlDakM7QUFDSjtBQUNBO0FBQ0lDLEVBQUFBLFVBcENpQyx3QkFvQ3JCO0FBQ1JQLElBQUFBLDRCQUE0QixDQUFDUSxhQUE3Qjs7QUFDQSxRQUFJUiw0QkFBNEIsQ0FBQ1MsY0FBN0IsQ0FBNENDLGdCQUE1QyxFQUE2RCxXQUE3RCxJQUEwRSxDQUE5RSxFQUFnRjtBQUM1RVYsTUFBQUEsNEJBQTRCLENBQUNXLDRCQUE3QjtBQUNILEtBRkQsTUFFTztBQUNIWCxNQUFBQSw0QkFBNEIsQ0FBQ1ksYUFBN0I7QUFDSDtBQUNKLEdBM0NnQzs7QUE2Q2pDO0FBQ0o7QUFDQTtBQUNJQSxFQUFBQSxhQWhEaUMsMkJBZ0RqQjtBQUNaQyxJQUFBQSxNQUFNLENBQUNDLFlBQVAsQ0FBb0JkLDRCQUE0QixDQUFDZSxhQUFqRDtBQUNBZixJQUFBQSw0QkFBNEIsQ0FBQ2dCLE1BQTdCO0FBQ0gsR0FuRGdDOztBQXFEakM7QUFDSjtBQUNBO0FBQ0lBLEVBQUFBLE1BeERpQyxvQkF3RHhCO0FBQ0xWLElBQUFBLENBQUMsQ0FBQ1csR0FBRixDQUFNO0FBQ0ZDLE1BQUFBLEdBQUcsWUFBS0MsTUFBTSxDQUFDQyxNQUFaLG1EQUREO0FBRUZDLE1BQUFBLEVBQUUsRUFBRSxLQUZGO0FBR0ZDLE1BQUFBLE1BQU0sRUFBRSxLQUhOO0FBSUZDLE1BQUFBLFdBQVcsRUFBRUMsTUFBTSxDQUFDRCxXQUpsQjs7QUFLRjtBQUNaO0FBQ0E7QUFDQTtBQUNZRSxNQUFBQSxTQUFTLEVBQUUsbUJBQVVDLFFBQVYsRUFBb0I7QUFDM0IsWUFBSUEsUUFBUSxDQUFDQyxJQUFULENBQWNDLE1BQWQsQ0FBcUJDLE1BQXJCLEdBQThCLENBQWxDLEVBQXFDO0FBQ2pDN0IsVUFBQUEsNEJBQTRCLENBQUNLLFlBQTdCLENBQTBDeUIsSUFBMUM7QUFDQTlCLFVBQUFBLDRCQUE0QixDQUFDK0IsTUFBN0IsQ0FBb0NDLFVBQXBDLEdBQWlEQyxRQUFqRCxDQUEwRFAsUUFBUSxDQUFDQyxJQUFULENBQWNDLE1BQXhFO0FBQ0g7O0FBQ0Q1QixRQUFBQSw0QkFBNEIsQ0FBQ2UsYUFBN0IsR0FBNkNGLE1BQU0sQ0FBQ3FCLFVBQVAsQ0FDekNsQyw0QkFBNEIsQ0FBQ2dCLE1BRFksRUFFekNoQiw0QkFBNEIsQ0FBQ0MsT0FGWSxDQUE3QztBQUlILE9BbEJDOztBQW1CRjtBQUNaO0FBQ0E7QUFDQTtBQUNZa0MsTUFBQUEsU0FBUyxFQUFFLG1CQUFTVCxRQUFULEVBQW1CO0FBQzFCVSxRQUFBQSxXQUFXLENBQUNDLGVBQVosQ0FBNEJYLFFBQVEsQ0FBQ1ksT0FBckM7QUFDQXRDLFFBQUFBLDRCQUE0QixDQUFDSyxZQUE3QixDQUEwQ2tDLElBQTFDO0FBQ0g7QUExQkMsS0FBTjtBQTRCSCxHQXJGZ0M7O0FBdUZqQztBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0kvQixFQUFBQSxhQTVGaUMsMkJBNEZqQjtBQUNaLFFBQU1nQyxTQUFTLEdBQUczQixNQUFNLENBQUM0QixXQUFQLEdBQXFCLEdBQXZDO0FBQ0EsUUFBTUMsU0FBUyxHQUFHQyxJQUFJLENBQUNDLEtBQUwsQ0FBV0osU0FBUyxHQUFHLElBQXZCLENBQWxCO0FBQ0FsQyxJQUFBQSxDQUFDLENBQUNPLE1BQUQsQ0FBRCxDQUFVZ0MsSUFBVixDQUFlLFlBQVk7QUFDdkJ2QyxNQUFBQSxDQUFDLENBQUMsbUJBQUQsQ0FBRCxDQUF1QndDLEdBQXZCLENBQTJCLFlBQTNCLFlBQTRDTixTQUE1QztBQUNILEtBRkQ7QUFHQXhDLElBQUFBLDRCQUE0QixDQUFDK0IsTUFBN0IsR0FBc0NnQixHQUFHLENBQUNDLElBQUosQ0FBUyxrQkFBVCxDQUF0Qzs7QUFDQSxRQUFJQyxPQUFPLEdBQUdGLEdBQUcsQ0FBQ0csT0FBSixDQUFZLGdCQUFaLEVBQThCQyxJQUE1Qzs7QUFDQW5ELElBQUFBLDRCQUE0QixDQUFDK0IsTUFBN0IsQ0FBb0NxQixPQUFwQyxDQUE0Q0MsT0FBNUMsQ0FBb0QsSUFBSUosT0FBSixFQUFwRDtBQUNBakQsSUFBQUEsNEJBQTRCLENBQUMrQixNQUE3QixDQUFvQ3VCLFFBQXBDLENBQTZDLG1CQUE3QztBQUNBdEQsSUFBQUEsNEJBQTRCLENBQUMrQixNQUE3QixDQUFvQ3dCLE1BQXBDO0FBQ0F2RCxJQUFBQSw0QkFBNEIsQ0FBQytCLE1BQTdCLENBQW9DQyxVQUFwQyxHQUFpRFgsRUFBakQsQ0FBb0QsUUFBcEQsRUFBOEQsWUFBTTtBQUNoRTtBQUNBbUMsTUFBQUEsSUFBSSxDQUFDQyxXQUFMO0FBQ0gsS0FIRDtBQUtBekQsSUFBQUEsNEJBQTRCLENBQUMrQixNQUE3QixDQUFvQzJCLFVBQXBDLENBQStDO0FBQzNDQyxNQUFBQSxRQUFRLEVBQUVqQixTQURpQztBQUUzQ2tCLE1BQUFBLGVBQWUsRUFBRSxLQUYwQjtBQUczQ0MsTUFBQUEsZUFBZSxFQUFFO0FBSDBCLEtBQS9DO0FBS0gsR0FqSGdDOztBQWtIakM7QUFDSjtBQUNBO0FBQ0E7QUFDSWxELEVBQUFBLDRCQXRIaUMsMENBc0hGO0FBQzNCLFFBQU1tRCxjQUFjLGFBQU05RCw0QkFBNEIsQ0FBQ0ksU0FBbkMsaUJBQXBCO0FBQ0EsUUFBSTJELFdBQVcsR0FBR0MsWUFBWSxDQUFDQyxPQUFiLENBQXFCSCxjQUFyQixDQUFsQjtBQUNBLFFBQU1JLE9BQU8sR0FBR0gsV0FBVyxvQ0FBNkIvRCw0QkFBNEIsQ0FBQ0ksU0FBMUQsNEJBQXFGMkQsV0FBckYscUNBQStIL0QsNEJBQTRCLENBQUNJLFNBQTVKLENBQTNCO0FBQ0FKLElBQUFBLDRCQUE0QixDQUFDRyxXQUE3QixHQUEyQyxJQUFJZ0UsV0FBSixDQUFnQkQsT0FBaEIsQ0FBM0M7QUFFQWxFLElBQUFBLDRCQUE0QixDQUFDRyxXQUE3QixDQUF5Q2lFLGdCQUF6QyxDQUEwRCxTQUExRCxFQUFxRSxVQUFBQyxDQUFDLEVBQUk7QUFDdEUsVUFBTTNDLFFBQVEsR0FBRzRDLElBQUksQ0FBQ0MsS0FBTCxDQUFXRixDQUFDLENBQUMxQyxJQUFiLENBQWpCO0FBQ0E2QyxNQUFBQSxPQUFPLENBQUNDLEtBQVIsQ0FBYy9DLFFBQWQ7QUFDQTFCLE1BQUFBLDRCQUE0QixDQUFDMEUsb0JBQTdCLENBQWtEaEQsUUFBbEQ7QUFDQXNDLE1BQUFBLFlBQVksQ0FBQ1csT0FBYixDQUFxQmIsY0FBckIsRUFBcUNPLENBQUMsQ0FBQ04sV0FBdkM7QUFDSCxLQUxEO0FBTUgsR0FsSWdDOztBQW9JakM7QUFDSjtBQUNBO0FBQ0E7QUFDSVcsRUFBQUEsb0JBeElpQyxnQ0F3SVpoRCxRQXhJWSxFQXdJSDtBQUMxQixRQUFJQSxRQUFRLENBQUNrRCxZQUFULENBQXNCaEQsTUFBMUIsRUFBaUM7QUFDN0I1QixNQUFBQSw0QkFBNEIsQ0FBQ0ssWUFBN0IsQ0FBMEN5QixJQUExQztBQUNBLFVBQUkrQyxVQUFVLEdBQUc3RSw0QkFBNEIsQ0FBQytCLE1BQTdCLENBQW9DQyxVQUFwQyxHQUFpRDhDLFFBQWpELEVBQWpCOztBQUNBLFVBQUlwRCxRQUFRLENBQUNxRCxLQUFULEtBQW1CLHlCQUF2QixFQUFpRDtBQUM3Q0YsUUFBQUEsVUFBVSxJQUFJLE9BQU9uRCxRQUFRLENBQUNrRCxZQUFULENBQXNCakQsSUFBdEIsQ0FBMkJDLE1BQWhEO0FBQ0gsT0FGRCxNQUVPLElBQUdGLFFBQVEsQ0FBQ3FELEtBQVQsS0FBbUIsc0JBQXRCLEVBQThDO0FBQ2pERixRQUFBQSxVQUFVLElBQUksT0FBT25ELFFBQVEsQ0FBQ2tELFlBQVQsQ0FBc0JqRCxJQUF0QixDQUEyQkMsTUFBaEQ7QUFDSCxPQUZNLE1BRUEsSUFBR0YsUUFBUSxDQUFDcUQsS0FBVCxLQUFtQix3QkFBbkIsSUFBK0NyRCxRQUFRLENBQUNrRCxZQUFULENBQXNCakQsSUFBdEIsQ0FBMkJDLE1BQTNCLENBQWtDQyxNQUFsQyxHQUEyQyxDQUE3RixFQUFnRztBQUNuR2dELFFBQUFBLFVBQVUsR0FBR25ELFFBQVEsQ0FBQ2tELFlBQVQsQ0FBc0JqRCxJQUF0QixDQUEyQkMsTUFBeEM7QUFDSCxPQUZNLE1BRUEsSUFBR0YsUUFBUSxDQUFDcUQsS0FBVCxLQUFtQixzQkFBbkIsSUFBNkNyRCxRQUFRLENBQUNrRCxZQUFULENBQXNCakQsSUFBdEIsQ0FBMkJDLE1BQTNCLENBQWtDQyxNQUFsQyxHQUEyQyxDQUEzRixFQUErRjtBQUNsR2dELFFBQUFBLFVBQVUsR0FBR25ELFFBQVEsQ0FBQ2tELFlBQVQsQ0FBc0JqRCxJQUF0QixDQUEyQkMsTUFBeEM7QUFDSDs7QUFDRDVCLE1BQUFBLDRCQUE0QixDQUFDK0IsTUFBN0IsQ0FBb0NDLFVBQXBDLEdBQWlEQyxRQUFqRCxDQUEwRDRDLFVBQTFEO0FBQ0gsS0FiRCxNQWFPO0FBQ0h6QyxNQUFBQSxXQUFXLENBQUNDLGVBQVosQ0FBNEJYLFFBQVEsQ0FBQ2tELFlBQVQsQ0FBc0JJLFFBQWxEO0FBQ0FoRixNQUFBQSw0QkFBNEIsQ0FBQ0ssWUFBN0IsQ0FBMENrQyxJQUExQztBQUNIO0FBQ0osR0ExSmdDOztBQTRKakM7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0k5QixFQUFBQSxjQXJLaUMsMEJBcUtsQndFLEVBcktrQixFQXFLZEMsRUFyS2MsRUFxS1ZDLE9BcktVLEVBcUtEO0FBQzVCLFFBQU1DLGVBQWUsR0FBR0QsT0FBTyxJQUFJQSxPQUFPLENBQUNDLGVBQTNDO0FBQ0EsUUFBTUMsVUFBVSxHQUFHRixPQUFPLElBQUlBLE9BQU8sQ0FBQ0UsVUFBdEM7QUFDQSxRQUFJQyxPQUFPLEdBQUdDLE1BQU0sQ0FBQ04sRUFBRCxDQUFOLENBQVdPLEtBQVgsQ0FBaUIsR0FBakIsQ0FBZDtBQUNBLFFBQUlDLE9BQU8sR0FBR0YsTUFBTSxDQUFDTCxFQUFELENBQU4sQ0FBV00sS0FBWCxDQUFpQixHQUFqQixDQUFkOztBQUVBLGFBQVNFLFdBQVQsQ0FBcUJDLENBQXJCLEVBQXdCO0FBQ3BCLGFBQU8sQ0FBQ1AsZUFBZSxHQUFHLGdCQUFILEdBQXNCLE9BQXRDLEVBQStDUSxJQUEvQyxDQUFvREQsQ0FBcEQsQ0FBUDtBQUNIOztBQUVELFFBQUksQ0FBQ0wsT0FBTyxDQUFDTyxLQUFSLENBQWNILFdBQWQsQ0FBRCxJQUErQixDQUFDRCxPQUFPLENBQUNJLEtBQVIsQ0FBY0gsV0FBZCxDQUFwQyxFQUFnRTtBQUM1RCxhQUFPSSxHQUFQO0FBQ0g7O0FBRUQsUUFBSVQsVUFBSixFQUFnQjtBQUNaLGFBQU9DLE9BQU8sQ0FBQ3pELE1BQVIsR0FBaUI0RCxPQUFPLENBQUM1RCxNQUFoQztBQUF3Q3lELFFBQUFBLE9BQU8sQ0FBQ1MsSUFBUixDQUFhLEdBQWI7QUFBeEM7O0FBQ0EsYUFBT04sT0FBTyxDQUFDNUQsTUFBUixHQUFpQnlELE9BQU8sQ0FBQ3pELE1BQWhDO0FBQXdDNEQsUUFBQUEsT0FBTyxDQUFDTSxJQUFSLENBQWEsR0FBYjtBQUF4QztBQUNIOztBQUVELFFBQUksQ0FBQ1gsZUFBTCxFQUFzQjtBQUNsQkUsTUFBQUEsT0FBTyxHQUFHQSxPQUFPLENBQUNVLEdBQVIsQ0FBWUMsTUFBWixDQUFWO0FBQ0FSLE1BQUFBLE9BQU8sR0FBR0EsT0FBTyxDQUFDTyxHQUFSLENBQVlDLE1BQVosQ0FBVjtBQUNIOztBQUVELFNBQUssSUFBSUMsQ0FBQyxHQUFHLENBQWIsRUFBZ0JBLENBQUMsR0FBR1osT0FBTyxDQUFDekQsTUFBNUIsRUFBb0NxRSxDQUFDLElBQUksQ0FBekMsRUFBNEM7QUFDeEMsVUFBSVQsT0FBTyxDQUFDNUQsTUFBUixLQUFtQnFFLENBQXZCLEVBQTBCO0FBQ3RCLGVBQU8sQ0FBUDtBQUNIOztBQUNELFVBQUlaLE9BQU8sQ0FBQ1ksQ0FBRCxDQUFQLEtBQWVULE9BQU8sQ0FBQ1MsQ0FBRCxDQUExQixFQUErQixDQUMzQjtBQUNILE9BRkQsTUFFTyxJQUFJWixPQUFPLENBQUNZLENBQUQsQ0FBUCxHQUFhVCxPQUFPLENBQUNTLENBQUQsQ0FBeEIsRUFBNkI7QUFDaEMsZUFBTyxDQUFQO0FBQ0gsT0FGTSxNQUVBO0FBQ0gsZUFBTyxDQUFDLENBQVI7QUFDSDtBQUNKOztBQUVELFFBQUlaLE9BQU8sQ0FBQ3pELE1BQVIsS0FBbUI0RCxPQUFPLENBQUM1RCxNQUEvQixFQUF1QztBQUNuQyxhQUFPLENBQUMsQ0FBUjtBQUNIOztBQUVELFdBQU8sQ0FBUDtBQUNIO0FBL01nQyxDQUFyQyxDLENBbU5BOztBQUNBdkIsQ0FBQyxDQUFDNkYsUUFBRCxDQUFELENBQVlDLEtBQVosQ0FBa0IsWUFBTTtBQUNwQnBHLEVBQUFBLDRCQUE0QixDQUFDTyxVQUE3QjtBQUNILENBRkQiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogTWlrb1BCWCAtIGZyZWUgcGhvbmUgc3lzdGVtIGZvciBzbWFsbCBidXNpbmVzc1xuICogQ29weXJpZ2h0IMKpIDIwMTctMjAyMyBBbGV4ZXkgUG9ydG5vdiBhbmQgTmlrb2xheSBCZWtldG92XG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICogKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLlxuICogSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiAqL1xuXG4vKiBnbG9iYWwgZ2xvYmFsUm9vdFVybCwgUGJ4QXBpLCBnbG9iYWxUcmFuc2xhdGUsIFVzZXJNZXNzYWdlICovXG5cbi8qKlxuICogQG1vZHVsZSBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyXG4gKi9cbmNvbnN0IG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIgPSB7XG5cbiAgICAvKipcbiAgICAgKiBUaW1lIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgZmV0Y2hpbmcgbmV3IHN0YXR1cy5cbiAgICAgKiBAdHlwZSB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRpbWVPdXQ6IDEwMDAwLFxuXG4gICAgLyoqXG4gICAgICogVGhlIGlkIG9mIHRoZSB0aW1lciBmdW5jdGlvbiBmb3Igc3RhdHVzIHdvcmtlci5cbiAgICAgKiBAdHlwZSB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRpbWVPdXRIYW5kbGU6IDAsXG5cblxuICAgIC8qKi5cbiAgICAgKiBAdHlwZSB7RXZlbnRTb3VyY2V9XG4gICAgICovXG4gICAgZXZlbnRTb3VyY2U6IG51bGwsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgaWRlbnRpZmllciBmb3IgdGhlIFBVQi9TVUIgY2hhbm5lbCB1c2VkIHRvIHN1YnNjcmliZSB0byBtb2R1bGUgc3RhdHVzIHVwZGF0ZXMuXG4gICAgICogVGhpcyBlbnN1cmVzIHRoYXQgdGhlIGNsaWVudCBpcyBsaXN0ZW5pbmcgb24gdGhlIGNvcnJlY3QgY2hhbm5lbCBmb3IgcmVsZXZhbnQgZXZlbnRzLlxuICAgICAqL1xuICAgIGNoYW5uZWxJZDogJ21vZHVsZS1nZXQtc3NsLXB1YicsXG5cbiAgICAvKipcbiAgICAgKiBqUXVlcnkgc2VsZWN0b3IgZm9yIHRoZSByZXN1bHQgbWVzc2FnZSBlbGVtZW50LlxuICAgICAqXG4gICAgICogVGhpcyBwcm9wZXJ0eSBzdG9yZXMgYSByZWZlcmVuY2UgdG8gdGhlIERPTSBlbGVtZW50IHdpdGggdGhlIElEICdkaXYtcmVzdWx0JyB1c2luZyBqUXVlcnkuXG4gICAgICovXG4gICAgJHJlc3VsdEJsb2NrOiAkKCcjZGl2LXJlc3VsdCcpLFxuXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgdGhlIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIgbW9kdWxlIGJ5IHNldHRpbmcgdXAgdGhlIGNvbm5lY3Rpb24gdG8gcmVjZWl2ZSBzZXJ2ZXItc2VudCBldmVudHMuXG4gICAgICovXG4gICAgaW5pdGlhbGl6ZSgpe1xuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmluaXRpYWxpemVBY2UoKTtcbiAgICAgICAgaWYgKG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIudmVyc2lvbkNvbXBhcmUoZ2xvYmFsUEJYVmVyc2lvbiwnMjAyNC4yLjMwJyk+MCl7XG4gICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLnN0YXJ0TGlzdGVuUHVzaE5vdGlmaWNhdGlvbnMoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIucmVzdGFydFdvcmtlcigpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlc3RhcnRzIHRoZSBtb2R1bGVHZXRTU0xTdGF0dXMgd29ya2VyLlxuICAgICAqL1xuICAgIHJlc3RhcnRXb3JrZXIoKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQobW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci50aW1lb3V0SGFuZGxlKTtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci53b3JrZXIoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogV29ya2VyIGZ1bmN0aW9uIGZvciBmZXRjaGluZyBzdGF0dXMuXG4gICAgICovXG4gICAgd29ya2VyKCkge1xuICAgICAgICAkLmFwaSh7XG4gICAgICAgICAgICB1cmw6IGAke0NvbmZpZy5wYnhVcmx9L3BieGNvcmUvYXBpL21vZHVsZXMvTW9kdWxlR2V0U3NsL2NoZWNrLXJlc3VsdGAsXG4gICAgICAgICAgICBvbjogJ25vdycsXG4gICAgICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICAgICAgc3VjY2Vzc1Rlc3Q6IFBieEFwaS5zdWNjZXNzVGVzdCxcbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogSGFuZGxlcyB0aGUgc3VjY2Vzc2Z1bCByZXNwb25zZSBvZiB0aGUgJ2NoZWNrLXJlc3VsdCcgQVBJIHJlcXVlc3QuXG4gICAgICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcmVzcG9uc2UgLSBUaGUgcmVzcG9uc2Ugb2JqZWN0LlxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBvblN1Y2Nlc3M6IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5kYXRhLnJlc3VsdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuJHJlc3VsdEJsb2NrLnNob3coKTtcbiAgICAgICAgICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IuZ2V0U2Vzc2lvbigpLnNldFZhbHVlKHJlc3BvbnNlLmRhdGEucmVzdWx0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci50aW1lb3V0SGFuZGxlID0gd2luZG93LnNldFRpbWVvdXQoXG4gICAgICAgICAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIud29ya2VyLFxuICAgICAgICAgICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLnRpbWVPdXQsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIEhhbmRsZXMgdGhlIGZhaWx1cmUgcmVzcG9uc2Ugb2YgdGhlICdnZXQtYXZhaWxhYmxlLWxkYXAtdXNlcnMnIEFQSSByZXF1ZXN0LlxuICAgICAgICAgICAgICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIG9iamVjdC5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgb25GYWlsdXJlOiBmdW5jdGlvbihyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIFVzZXJNZXNzYWdlLnNob3dNdWx0aVN0cmluZyhyZXNwb25zZS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5oaWRlKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgQWNlIGVkaXRvciBpbnN0YW5jZS5cbiAgICAgKiBTZXRzIHVwIEFjZSBlZGl0b3Igd2l0aCBhIG1vbm9rYWkgdGhlbWUgYW5kIGN1c3RvbSBvcHRpb25zLlxuICAgICAqIEF0dGFjaGVzIGNoYW5nZSBoYW5kbGVyIHRvIHRoZSBlZGl0b3Igc2Vzc2lvbi5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplQWNlKCkge1xuICAgICAgICBjb25zdCBhY2VIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQgLSA0ODA7XG4gICAgICAgIGNvbnN0IHJvd3NDb3VudCA9IE1hdGgucm91bmQoYWNlSGVpZ2h0IC8gMTYuMyk7XG4gICAgICAgICQod2luZG93KS5sb2FkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQoJy5hcHBsaWNhdGlvbi1jb2RlJykuY3NzKCdtaW4taGVpZ2h0JywgYCR7YWNlSGVpZ2h0fXB4YCk7XG4gICAgICAgIH0pO1xuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmVkaXRvciA9IGFjZS5lZGl0KCd1c2VyLWVkaXQtY29uZmlnJyk7XG4gICAgICAgIGxldCBOZXdNb2RlID0gYWNlLnJlcXVpcmUoJ2FjZS9tb2RlL2p1bGlhJykuTW9kZTtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3Iuc2Vzc2lvbi5zZXRNb2RlKG5ldyBOZXdNb2RlKCkpO1xuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmVkaXRvci5zZXRUaGVtZSgnYWNlL3RoZW1lL21vbm9rYWknKTtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IucmVzaXplKCk7XG4gICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZWRpdG9yLmdldFNlc3Npb24oKS5vbignY2hhbmdlJywgKCkgPT4ge1xuICAgICAgICAgICAgLy8gVHJpZ2dlciBjaGFuZ2UgZXZlbnQgdG8gYWNrbm93bGVkZ2UgdGhlIG1vZGlmaWNhdGlvblxuICAgICAgICAgICAgRm9ybS5kYXRhQ2hhbmdlZCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmVkaXRvci5zZXRPcHRpb25zKHtcbiAgICAgICAgICAgIG1heExpbmVzOiByb3dzQ291bnQsXG4gICAgICAgICAgICBzaG93UHJpbnRNYXJnaW46IGZhbHNlLFxuICAgICAgICAgICAgc2hvd0xpbmVOdW1iZXJzOiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBFc3RhYmxpc2hlcyBhIGNvbm5lY3Rpb24gdG8gdGhlIHNlcnZlciB0byBzdGFydCByZWNlaXZpbmcgcmVhbC10aW1lIHVwZGF0ZXMgb24gbW9kdWxlIGluc3RhbGxhdGlvbiBwcm9ncmVzcy5cbiAgICAgKiBVdGlsaXplcyB0aGUgRXZlbnRTb3VyY2UgQVBJIHRvIGxpc3RlbiBmb3IgbWVzc2FnZXMgb24gYSBzcGVjaWZpZWQgY2hhbm5lbC5cbiAgICAgKi9cbiAgICBzdGFydExpc3RlblB1c2hOb3RpZmljYXRpb25zKCkge1xuICAgICAgICBjb25zdCBsYXN0RXZlbnRJZEtleSA9IGAke21vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuY2hhbm5lbElkfS1sYXN0RXZlbnRJZGA7XG4gICAgICAgIGxldCBsYXN0RXZlbnRJZCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKGxhc3RFdmVudElkS2V5KTtcbiAgICAgICAgY29uc3Qgc3ViUGF0aCA9IGxhc3RFdmVudElkID8gYC9wYnhjb3JlL2FwaS9uY2hhbi9zdWIvJHttb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmNoYW5uZWxJZH0/bGFzdF9ldmVudF9pZD0ke2xhc3RFdmVudElkfWAgOiBgL3BieGNvcmUvYXBpL25jaGFuL3N1Yi8ke21vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuY2hhbm5lbElkfWA7XG4gICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZXZlbnRTb3VyY2UgPSBuZXcgRXZlbnRTb3VyY2Uoc3ViUGF0aCk7XG5cbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5ldmVudFNvdXJjZS5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgZSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IEpTT04ucGFyc2UoZS5kYXRhKTtcbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcocmVzcG9uc2UpO1xuICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5wcm9jZXNzU3RhdHVzTWVzc2FnZShyZXNwb25zZSk7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShsYXN0RXZlbnRJZEtleSwgZS5sYXN0RXZlbnRJZCk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSByZXNwb25zZSAtIFRoZSBkYXRhIHBheWxvYWQgb2YgdGhlIHNlcnZlci1zZW50IGV2ZW50LCBjb250YWluaW5nIGRldGFpbHMgYWJvdXQgdGhlIGluc3RhbGxhdGlvbiBzdGFnZSBhbmQgcHJvZ3Jlc3MuXG4gICAgICovXG4gICAgcHJvY2Vzc1N0YXR1c01lc3NhZ2UocmVzcG9uc2Upe1xuICAgICAgICBpZiAocmVzcG9uc2Uuc3RhZ2VEZXRhaWxzLnJlc3VsdCl7XG4gICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5zaG93KCk7XG4gICAgICAgICAgICBsZXQgcmVzdWx0VGV4dCA9IG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZWRpdG9yLmdldFNlc3Npb24oKS5nZXRWYWx1ZSgpO1xuICAgICAgICAgICAgaWYgKHJlc3BvbnNlLnN0YWdlID09PSAnU1RBR0VfMV9HRU5FUkFURV9DT05GSUcnKXtcbiAgICAgICAgICAgICAgICByZXN1bHRUZXh0ICs9ICdcXG4nICsgcmVzcG9uc2Uuc3RhZ2VEZXRhaWxzLmRhdGEucmVzdWx0O1xuICAgICAgICAgICAgfSBlbHNlIGlmKHJlc3BvbnNlLnN0YWdlID09PSAnU1RBR0VfMl9SRVFVRVNUX0NFUlQnKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0VGV4dCArPSAnXFxuJyArIHJlc3BvbnNlLnN0YWdlRGV0YWlscy5kYXRhLnJlc3VsdDtcbiAgICAgICAgICAgIH0gZWxzZSBpZihyZXNwb25zZS5zdGFnZSA9PT0gJ1NUQUdFXzNfUEFSU0VfUkVTUE9OU0UnICYmIHJlc3BvbnNlLnN0YWdlRGV0YWlscy5kYXRhLnJlc3VsdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0VGV4dCA9IHJlc3BvbnNlLnN0YWdlRGV0YWlscy5kYXRhLnJlc3VsdDtcbiAgICAgICAgICAgIH0gZWxzZSBpZihyZXNwb25zZS5zdGFnZSA9PT0gJ1NUQUdFXzRfRklOQUxfUkVTVUxUJyAmJiByZXNwb25zZS5zdGFnZURldGFpbHMuZGF0YS5yZXN1bHQubGVuZ3RoID4gMCApIHtcbiAgICAgICAgICAgICAgICByZXN1bHRUZXh0ID0gcmVzcG9uc2Uuc3RhZ2VEZXRhaWxzLmRhdGEucmVzdWx0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IuZ2V0U2Vzc2lvbigpLnNldFZhbHVlKHJlc3VsdFRleHQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd011bHRpU3RyaW5nKHJlc3BvbnNlLnN0YWdlRGV0YWlscy5tZXNzYWdlcyk7XG4gICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5oaWRlKCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ29tcGFyZSB2ZXJzaW9ucyBvZiBtb2R1bGVzLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2MSAtIFRoZSBmaXJzdCB2ZXJzaW9uIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHYyIC0gVGhlIHNlY29uZCB2ZXJzaW9uIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXSAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxleGljb2dyYXBoaWNhbF0gLSBXaGV0aGVyIHRvIHBlcmZvcm0gbGV4aWNvZ3JhcGhpY2FsIGNvbXBhcmlzb24gKGRlZmF1bHQ6IGZhbHNlKS5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnplcm9FeHRlbmRdIC0gV2VhdGhlciB0byB6ZXJvLWV4dGVuZCB0aGUgc2hvcnRlciB2ZXJzaW9uIChkZWZhdWx0OiBmYWxzZSkuXG4gICAgICogQHJldHVybnMge251bWJlcn0gLSBBIG51bWJlciBpbmRpY2F0aW5nIHRoZSBjb21wYXJpc29uIHJlc3VsdDogMCBpZiB2ZXJzaW9ucyBhcmUgZXF1YWwsIDEgaWYgdjEgaXMgZ3JlYXRlciwgLTEgaWYgdjIgaXMgZ3JlYXRlciwgb3IgTmFOIGlmIHRoZSB2ZXJzaW9ucyBhcmUgaW52YWxpZC5cbiAgICAgKi9cbiAgICB2ZXJzaW9uQ29tcGFyZSh2MSwgdjIsIG9wdGlvbnMpIHtcbiAgICAgICAgY29uc3QgbGV4aWNvZ3JhcGhpY2FsID0gb3B0aW9ucyAmJiBvcHRpb25zLmxleGljb2dyYXBoaWNhbDtcbiAgICAgICAgY29uc3QgemVyb0V4dGVuZCA9IG9wdGlvbnMgJiYgb3B0aW9ucy56ZXJvRXh0ZW5kO1xuICAgICAgICBsZXQgdjFwYXJ0cyA9IFN0cmluZyh2MSkuc3BsaXQoJy4nKTtcbiAgICAgICAgbGV0IHYycGFydHMgPSBTdHJpbmcodjIpLnNwbGl0KCcuJyk7XG5cbiAgICAgICAgZnVuY3Rpb24gaXNWYWxpZFBhcnQoeCkge1xuICAgICAgICAgICAgcmV0dXJuIChsZXhpY29ncmFwaGljYWwgPyAvXlxcZCtbQS1aYS16XSokLyA6IC9eXFxkKyQvKS50ZXN0KHgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF2MXBhcnRzLmV2ZXJ5KGlzVmFsaWRQYXJ0KSB8fCAhdjJwYXJ0cy5ldmVyeShpc1ZhbGlkUGFydCkpIHtcbiAgICAgICAgICAgIHJldHVybiBOYU47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoemVyb0V4dGVuZCkge1xuICAgICAgICAgICAgd2hpbGUgKHYxcGFydHMubGVuZ3RoIDwgdjJwYXJ0cy5sZW5ndGgpIHYxcGFydHMucHVzaCgnMCcpO1xuICAgICAgICAgICAgd2hpbGUgKHYycGFydHMubGVuZ3RoIDwgdjFwYXJ0cy5sZW5ndGgpIHYycGFydHMucHVzaCgnMCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFsZXhpY29ncmFwaGljYWwpIHtcbiAgICAgICAgICAgIHYxcGFydHMgPSB2MXBhcnRzLm1hcChOdW1iZXIpO1xuICAgICAgICAgICAgdjJwYXJ0cyA9IHYycGFydHMubWFwKE51bWJlcik7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHYxcGFydHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGlmICh2MnBhcnRzLmxlbmd0aCA9PT0gaSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHYxcGFydHNbaV0gPT09IHYycGFydHNbaV0pIHtcbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgfSBlbHNlIGlmICh2MXBhcnRzW2ldID4gdjJwYXJ0c1tpXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodjFwYXJ0cy5sZW5ndGggIT09IHYycGFydHMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gMDtcbiAgICB9LFxuXG59O1xuXG4vLyBJbml0aWFsaXplcyB0aGUgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlciBtb2R1bGUgd2hlbiB0aGUgRE9NIGlzIGZ1bGx5IGxvYWRlZC5cbiQoZG9jdW1lbnQpLnJlYWR5KCgpID0+IHtcbiAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmluaXRpYWxpemUoKTtcbn0pOyJdfQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtZ2V0LXNzbC1zdGF0dXMtd29ya2VyLmpzIl0sIm5hbWVzIjpbIm1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIiLCJ0aW1lT3V0IiwidGltZU91dEhhbmRsZSIsImV2ZW50U291cmNlIiwiY2hhbm5lbElkIiwiJHJlc3VsdEJsb2NrIiwiJCIsImluaXRpYWxpemUiLCJpbml0aWFsaXplQWNlIiwibG9hZExhc3RMb2ciLCJ2ZXJzaW9uQ29tcGFyZSIsImdsb2JhbFBCWFZlcnNpb24iLCJzdGFydExpc3RlblB1c2hOb3RpZmljYXRpb25zIiwicmVzdGFydFdvcmtlciIsImFwaSIsInVybCIsIkNvbmZpZyIsInBieFVybCIsIm9uIiwibWV0aG9kIiwic3VjY2Vzc1Rlc3QiLCJQYnhBcGkiLCJvblN1Y2Nlc3MiLCJyZXNwb25zZSIsImRhdGEiLCJyZXN1bHQiLCJsZW5ndGgiLCJzaG93IiwiZWRpdG9yIiwiZ2V0U2Vzc2lvbiIsInNldFZhbHVlIiwib25GYWlsdXJlIiwid2luZG93IiwiY2xlYXJUaW1lb3V0IiwidGltZW91dEhhbmRsZSIsIndvcmtlciIsInNldFRpbWVvdXQiLCJVc2VyTWVzc2FnZSIsInNob3dNdWx0aVN0cmluZyIsIm1lc3NhZ2UiLCJoaWRlIiwiYWNlSGVpZ2h0IiwiaW5uZXJIZWlnaHQiLCJyb3dzQ291bnQiLCJNYXRoIiwicm91bmQiLCJsb2FkIiwiY3NzIiwiYWNlIiwiZWRpdCIsIk5ld01vZGUiLCJyZXF1aXJlIiwiTW9kZSIsInNlc3Npb24iLCJzZXRNb2RlIiwic2V0VGhlbWUiLCJyZXNpemUiLCJGb3JtIiwiZGF0YUNoYW5nZWQiLCJzZXRPcHRpb25zIiwibWF4TGluZXMiLCJzaG93UHJpbnRNYXJnaW4iLCJzaG93TGluZU51bWJlcnMiLCJsYXN0RXZlbnRJZEtleSIsImxhc3RFdmVudElkIiwibG9jYWxTdG9yYWdlIiwiZ2V0SXRlbSIsInN1YlBhdGgiLCJFdmVudFNvdXJjZSIsImFkZEV2ZW50TGlzdGVuZXIiLCJlIiwiSlNPTiIsInBhcnNlIiwiY29uc29sZSIsImRlYnVnIiwicHJvY2Vzc1N0YXR1c01lc3NhZ2UiLCJzZXRJdGVtIiwic3RhZ2VEZXRhaWxzIiwicmVzdWx0VGV4dCIsImdldFZhbHVlIiwic3RhZ2UiLCJtZXNzYWdlcyIsInYxIiwidjIiLCJvcHRpb25zIiwibGV4aWNvZ3JhcGhpY2FsIiwiemVyb0V4dGVuZCIsInYxcGFydHMiLCJTdHJpbmciLCJzcGxpdCIsInYycGFydHMiLCJpc1ZhbGlkUGFydCIsIngiLCJ0ZXN0IiwiZXZlcnkiLCJOYU4iLCJwdXNoIiwibWFwIiwiTnVtYmVyIiwiaSIsImRvY3VtZW50IiwicmVhZHkiXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFNQSw0QkFBNEIsR0FBRztBQUVqQztBQUNKO0FBQ0E7QUFDQTtBQUNJQyxFQUFBQSxPQUFPLEVBQUUsS0FOd0I7O0FBUWpDO0FBQ0o7QUFDQTtBQUNBO0FBQ0lDLEVBQUFBLGFBQWEsRUFBRSxDQVprQjs7QUFlakM7QUFDSjtBQUNBO0FBQ0lDLEVBQUFBLFdBQVcsRUFBRSxJQWxCb0I7O0FBb0JqQztBQUNKO0FBQ0E7QUFDQTtBQUNJQyxFQUFBQSxTQUFTLEVBQUUsb0JBeEJzQjs7QUEwQmpDO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsWUFBWSxFQUFFQyxDQUFDLENBQUMsYUFBRCxDQS9Ca0I7O0FBaUNqQztBQUNKO0FBQ0E7QUFDSUMsRUFBQUEsVUFwQ2lDLHdCQW9DckI7QUFDUlAsSUFBQUEsNEJBQTRCLENBQUNRLGFBQTdCO0FBQ0FSLElBQUFBLDRCQUE0QixDQUFDUyxXQUE3Qjs7QUFDQSxRQUFJVCw0QkFBNEIsQ0FBQ1UsY0FBN0IsQ0FBNENDLGdCQUE1QyxFQUE2RCxXQUE3RCxJQUEwRSxDQUE5RSxFQUFnRjtBQUM1RVgsTUFBQUEsNEJBQTRCLENBQUNZLDRCQUE3QjtBQUNILEtBRkQsTUFFTztBQUNIWixNQUFBQSw0QkFBNEIsQ0FBQ2EsYUFBN0I7QUFDSDtBQUNKLEdBNUNnQzs7QUE4Q2pDO0FBQ0o7QUFDQTtBQUNJSixFQUFBQSxXQWpEaUMseUJBaURuQjtBQUNWSCxJQUFBQSxDQUFDLENBQUNRLEdBQUYsQ0FBTTtBQUNGQyxNQUFBQSxHQUFHLFlBQUtDLE1BQU0sQ0FBQ0MsTUFBWixtREFERDtBQUVGQyxNQUFBQSxFQUFFLEVBQUUsS0FGRjtBQUdGQyxNQUFBQSxNQUFNLEVBQUUsS0FITjtBQUlGQyxNQUFBQSxXQUFXLEVBQUVDLE1BQU0sQ0FBQ0QsV0FKbEI7QUFLRkUsTUFBQUEsU0FBUyxFQUFFLG1CQUFVQyxRQUFWLEVBQW9CO0FBQzNCLFlBQUlBLFFBQVEsQ0FBQ0MsSUFBVCxDQUFjQyxNQUFkLElBQXdCRixRQUFRLENBQUNDLElBQVQsQ0FBY0MsTUFBZCxDQUFxQkMsTUFBckIsR0FBOEIsQ0FBMUQsRUFBNkQ7QUFDekQxQixVQUFBQSw0QkFBNEIsQ0FBQ0ssWUFBN0IsQ0FBMENzQixJQUExQztBQUNBM0IsVUFBQUEsNEJBQTRCLENBQUM0QixNQUE3QixDQUFvQ0MsVUFBcEMsR0FBaURDLFFBQWpELENBQTBEUCxRQUFRLENBQUNDLElBQVQsQ0FBY0MsTUFBeEU7QUFDSDtBQUNKLE9BVkM7QUFXRk0sTUFBQUEsU0FBUyxFQUFFLHFCQUFXLENBQ2xCO0FBQ0g7QUFiQyxLQUFOO0FBZUgsR0FqRWdDOztBQW1FakM7QUFDSjtBQUNBO0FBQ0lsQixFQUFBQSxhQXRFaUMsMkJBc0VqQjtBQUNabUIsSUFBQUEsTUFBTSxDQUFDQyxZQUFQLENBQW9CakMsNEJBQTRCLENBQUNrQyxhQUFqRDtBQUNBbEMsSUFBQUEsNEJBQTRCLENBQUNtQyxNQUE3QjtBQUNILEdBekVnQzs7QUEyRWpDO0FBQ0o7QUFDQTtBQUNJQSxFQUFBQSxNQTlFaUMsb0JBOEV4QjtBQUNMN0IsSUFBQUEsQ0FBQyxDQUFDUSxHQUFGLENBQU07QUFDRkMsTUFBQUEsR0FBRyxZQUFLQyxNQUFNLENBQUNDLE1BQVosbURBREQ7QUFFRkMsTUFBQUEsRUFBRSxFQUFFLEtBRkY7QUFHRkMsTUFBQUEsTUFBTSxFQUFFLEtBSE47QUFJRkMsTUFBQUEsV0FBVyxFQUFFQyxNQUFNLENBQUNELFdBSmxCOztBQUtGO0FBQ1o7QUFDQTtBQUNBO0FBQ1lFLE1BQUFBLFNBQVMsRUFBRSxtQkFBVUMsUUFBVixFQUFvQjtBQUMzQixZQUFJQSxRQUFRLENBQUNDLElBQVQsQ0FBY0MsTUFBZCxDQUFxQkMsTUFBckIsR0FBOEIsQ0FBbEMsRUFBcUM7QUFDakMxQixVQUFBQSw0QkFBNEIsQ0FBQ0ssWUFBN0IsQ0FBMENzQixJQUExQztBQUNBM0IsVUFBQUEsNEJBQTRCLENBQUM0QixNQUE3QixDQUFvQ0MsVUFBcEMsR0FBaURDLFFBQWpELENBQTBEUCxRQUFRLENBQUNDLElBQVQsQ0FBY0MsTUFBeEU7QUFDSDs7QUFDRHpCLFFBQUFBLDRCQUE0QixDQUFDa0MsYUFBN0IsR0FBNkNGLE1BQU0sQ0FBQ0ksVUFBUCxDQUN6Q3BDLDRCQUE0QixDQUFDbUMsTUFEWSxFQUV6Q25DLDRCQUE0QixDQUFDQyxPQUZZLENBQTdDO0FBSUgsT0FsQkM7O0FBbUJGO0FBQ1o7QUFDQTtBQUNBO0FBQ1k4QixNQUFBQSxTQUFTLEVBQUUsbUJBQVNSLFFBQVQsRUFBbUI7QUFDMUJjLFFBQUFBLFdBQVcsQ0FBQ0MsZUFBWixDQUE0QmYsUUFBUSxDQUFDZ0IsT0FBckM7QUFDQXZDLFFBQUFBLDRCQUE0QixDQUFDSyxZQUE3QixDQUEwQ21DLElBQTFDO0FBQ0g7QUExQkMsS0FBTjtBQTRCSCxHQTNHZ0M7O0FBNkdqQztBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0loQyxFQUFBQSxhQWxIaUMsMkJBa0hqQjtBQUNaLFFBQU1pQyxTQUFTLEdBQUdULE1BQU0sQ0FBQ1UsV0FBUCxHQUFxQixHQUF2QztBQUNBLFFBQU1DLFNBQVMsR0FBR0MsSUFBSSxDQUFDQyxLQUFMLENBQVdKLFNBQVMsR0FBRyxJQUF2QixDQUFsQjtBQUNBbkMsSUFBQUEsQ0FBQyxDQUFDMEIsTUFBRCxDQUFELENBQVVjLElBQVYsQ0FBZSxZQUFZO0FBQ3ZCeEMsTUFBQUEsQ0FBQyxDQUFDLG1CQUFELENBQUQsQ0FBdUJ5QyxHQUF2QixDQUEyQixZQUEzQixZQUE0Q04sU0FBNUM7QUFDSCxLQUZEO0FBR0F6QyxJQUFBQSw0QkFBNEIsQ0FBQzRCLE1BQTdCLEdBQXNDb0IsR0FBRyxDQUFDQyxJQUFKLENBQVMsa0JBQVQsQ0FBdEM7O0FBQ0EsUUFBSUMsT0FBTyxHQUFHRixHQUFHLENBQUNHLE9BQUosQ0FBWSxnQkFBWixFQUE4QkMsSUFBNUM7O0FBQ0FwRCxJQUFBQSw0QkFBNEIsQ0FBQzRCLE1BQTdCLENBQW9DeUIsT0FBcEMsQ0FBNENDLE9BQTVDLENBQW9ELElBQUlKLE9BQUosRUFBcEQ7QUFDQWxELElBQUFBLDRCQUE0QixDQUFDNEIsTUFBN0IsQ0FBb0MyQixRQUFwQyxDQUE2QyxtQkFBN0M7QUFDQXZELElBQUFBLDRCQUE0QixDQUFDNEIsTUFBN0IsQ0FBb0M0QixNQUFwQztBQUNBeEQsSUFBQUEsNEJBQTRCLENBQUM0QixNQUE3QixDQUFvQ0MsVUFBcEMsR0FBaURYLEVBQWpELENBQW9ELFFBQXBELEVBQThELFlBQU07QUFDaEU7QUFDQXVDLE1BQUFBLElBQUksQ0FBQ0MsV0FBTDtBQUNILEtBSEQ7QUFLQTFELElBQUFBLDRCQUE0QixDQUFDNEIsTUFBN0IsQ0FBb0MrQixVQUFwQyxDQUErQztBQUMzQ0MsTUFBQUEsUUFBUSxFQUFFakIsU0FEaUM7QUFFM0NrQixNQUFBQSxlQUFlLEVBQUUsS0FGMEI7QUFHM0NDLE1BQUFBLGVBQWUsRUFBRTtBQUgwQixLQUEvQztBQUtILEdBdklnQzs7QUF3SWpDO0FBQ0o7QUFDQTtBQUNBO0FBQ0lsRCxFQUFBQSw0QkE1SWlDLDBDQTRJRjtBQUMzQixRQUFNbUQsY0FBYyxhQUFNL0QsNEJBQTRCLENBQUNJLFNBQW5DLGlCQUFwQjtBQUNBLFFBQUk0RCxXQUFXLEdBQUdDLFlBQVksQ0FBQ0MsT0FBYixDQUFxQkgsY0FBckIsQ0FBbEI7QUFDQSxRQUFNSSxPQUFPLEdBQUdILFdBQVcsb0NBQTZCaEUsNEJBQTRCLENBQUNJLFNBQTFELDRCQUFxRjRELFdBQXJGLHFDQUErSGhFLDRCQUE0QixDQUFDSSxTQUE1SixDQUEzQjtBQUNBSixJQUFBQSw0QkFBNEIsQ0FBQ0csV0FBN0IsR0FBMkMsSUFBSWlFLFdBQUosQ0FBZ0JELE9BQWhCLENBQTNDO0FBRUFuRSxJQUFBQSw0QkFBNEIsQ0FBQ0csV0FBN0IsQ0FBeUNrRSxnQkFBekMsQ0FBMEQsU0FBMUQsRUFBcUUsVUFBQUMsQ0FBQyxFQUFJO0FBQ3RFLFVBQU0vQyxRQUFRLEdBQUdnRCxJQUFJLENBQUNDLEtBQUwsQ0FBV0YsQ0FBQyxDQUFDOUMsSUFBYixDQUFqQjtBQUNBaUQsTUFBQUEsT0FBTyxDQUFDQyxLQUFSLENBQWNuRCxRQUFkO0FBQ0F2QixNQUFBQSw0QkFBNEIsQ0FBQzJFLG9CQUE3QixDQUFrRHBELFFBQWxEO0FBQ0EwQyxNQUFBQSxZQUFZLENBQUNXLE9BQWIsQ0FBcUJiLGNBQXJCLEVBQXFDTyxDQUFDLENBQUNOLFdBQXZDO0FBQ0gsS0FMRDtBQU1ILEdBeEpnQzs7QUEwSmpDO0FBQ0o7QUFDQTtBQUNBO0FBQ0lXLEVBQUFBLG9CQTlKaUMsZ0NBOEpacEQsUUE5SlksRUE4Skg7QUFDMUIsUUFBSUEsUUFBUSxDQUFDc0QsWUFBVCxDQUFzQnBELE1BQTFCLEVBQWlDO0FBQzdCekIsTUFBQUEsNEJBQTRCLENBQUNLLFlBQTdCLENBQTBDc0IsSUFBMUM7QUFDQSxVQUFJbUQsVUFBVSxHQUFHOUUsNEJBQTRCLENBQUM0QixNQUE3QixDQUFvQ0MsVUFBcEMsR0FBaURrRCxRQUFqRCxFQUFqQjs7QUFDQSxVQUFJeEQsUUFBUSxDQUFDeUQsS0FBVCxLQUFtQix5QkFBdkIsRUFBaUQ7QUFDN0NGLFFBQUFBLFVBQVUsSUFBSSxPQUFPdkQsUUFBUSxDQUFDc0QsWUFBVCxDQUFzQnJELElBQXRCLENBQTJCQyxNQUFoRDtBQUNILE9BRkQsTUFFTyxJQUFHRixRQUFRLENBQUN5RCxLQUFULEtBQW1CLHNCQUF0QixFQUE4QztBQUNqREYsUUFBQUEsVUFBVSxJQUFJLE9BQU92RCxRQUFRLENBQUNzRCxZQUFULENBQXNCckQsSUFBdEIsQ0FBMkJDLE1BQWhEO0FBQ0gsT0FGTSxNQUVBLElBQUdGLFFBQVEsQ0FBQ3lELEtBQVQsS0FBbUIsd0JBQW5CLElBQStDekQsUUFBUSxDQUFDc0QsWUFBVCxDQUFzQnJELElBQXRCLENBQTJCQyxNQUEzQixDQUFrQ0MsTUFBbEMsR0FBMkMsQ0FBN0YsRUFBZ0c7QUFDbkdvRCxRQUFBQSxVQUFVLEdBQUd2RCxRQUFRLENBQUNzRCxZQUFULENBQXNCckQsSUFBdEIsQ0FBMkJDLE1BQXhDO0FBQ0gsT0FGTSxNQUVBLElBQUdGLFFBQVEsQ0FBQ3lELEtBQVQsS0FBbUIsc0JBQW5CLElBQTZDekQsUUFBUSxDQUFDc0QsWUFBVCxDQUFzQnJELElBQXRCLENBQTJCQyxNQUEzQixDQUFrQ0MsTUFBbEMsR0FBMkMsQ0FBM0YsRUFBK0Y7QUFDbEdvRCxRQUFBQSxVQUFVLEdBQUd2RCxRQUFRLENBQUNzRCxZQUFULENBQXNCckQsSUFBdEIsQ0FBMkJDLE1BQXhDO0FBQ0g7O0FBQ0R6QixNQUFBQSw0QkFBNEIsQ0FBQzRCLE1BQTdCLENBQW9DQyxVQUFwQyxHQUFpREMsUUFBakQsQ0FBMERnRCxVQUExRDtBQUNILEtBYkQsTUFhTztBQUNIekMsTUFBQUEsV0FBVyxDQUFDQyxlQUFaLENBQTRCZixRQUFRLENBQUNzRCxZQUFULENBQXNCSSxRQUFsRDtBQUNBakYsTUFBQUEsNEJBQTRCLENBQUNLLFlBQTdCLENBQTBDbUMsSUFBMUM7QUFDSDtBQUNKLEdBaExnQzs7QUFrTGpDO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNJOUIsRUFBQUEsY0EzTGlDLDBCQTJMbEJ3RSxFQTNMa0IsRUEyTGRDLEVBM0xjLEVBMkxWQyxPQTNMVSxFQTJMRDtBQUM1QixRQUFNQyxlQUFlLEdBQUdELE9BQU8sSUFBSUEsT0FBTyxDQUFDQyxlQUEzQztBQUNBLFFBQU1DLFVBQVUsR0FBR0YsT0FBTyxJQUFJQSxPQUFPLENBQUNFLFVBQXRDO0FBQ0EsUUFBSUMsT0FBTyxHQUFHQyxNQUFNLENBQUNOLEVBQUQsQ0FBTixDQUFXTyxLQUFYLENBQWlCLEdBQWpCLENBQWQ7QUFDQSxRQUFJQyxPQUFPLEdBQUdGLE1BQU0sQ0FBQ0wsRUFBRCxDQUFOLENBQVdNLEtBQVgsQ0FBaUIsR0FBakIsQ0FBZDs7QUFFQSxhQUFTRSxXQUFULENBQXFCQyxDQUFyQixFQUF3QjtBQUNwQixhQUFPLENBQUNQLGVBQWUsR0FBRyxnQkFBSCxHQUFzQixPQUF0QyxFQUErQ1EsSUFBL0MsQ0FBb0RELENBQXBELENBQVA7QUFDSDs7QUFFRCxRQUFJLENBQUNMLE9BQU8sQ0FBQ08sS0FBUixDQUFjSCxXQUFkLENBQUQsSUFBK0IsQ0FBQ0QsT0FBTyxDQUFDSSxLQUFSLENBQWNILFdBQWQsQ0FBcEMsRUFBZ0U7QUFDNUQsYUFBT0ksR0FBUDtBQUNIOztBQUVELFFBQUlULFVBQUosRUFBZ0I7QUFDWixhQUFPQyxPQUFPLENBQUM3RCxNQUFSLEdBQWlCZ0UsT0FBTyxDQUFDaEUsTUFBaEM7QUFBd0M2RCxRQUFBQSxPQUFPLENBQUNTLElBQVIsQ0FBYSxHQUFiO0FBQXhDOztBQUNBLGFBQU9OLE9BQU8sQ0FBQ2hFLE1BQVIsR0FBaUI2RCxPQUFPLENBQUM3RCxNQUFoQztBQUF3Q2dFLFFBQUFBLE9BQU8sQ0FBQ00sSUFBUixDQUFhLEdBQWI7QUFBeEM7QUFDSDs7QUFFRCxRQUFJLENBQUNYLGVBQUwsRUFBc0I7QUFDbEJFLE1BQUFBLE9BQU8sR0FBR0EsT0FBTyxDQUFDVSxHQUFSLENBQVlDLE1BQVosQ0FBVjtBQUNBUixNQUFBQSxPQUFPLEdBQUdBLE9BQU8sQ0FBQ08sR0FBUixDQUFZQyxNQUFaLENBQVY7QUFDSDs7QUFFRCxTQUFLLElBQUlDLENBQUMsR0FBRyxDQUFiLEVBQWdCQSxDQUFDLEdBQUdaLE9BQU8sQ0FBQzdELE1BQTVCLEVBQW9DeUUsQ0FBQyxJQUFJLENBQXpDLEVBQTRDO0FBQ3hDLFVBQUlULE9BQU8sQ0FBQ2hFLE1BQVIsS0FBbUJ5RSxDQUF2QixFQUEwQjtBQUN0QixlQUFPLENBQVA7QUFDSDs7QUFDRCxVQUFJWixPQUFPLENBQUNZLENBQUQsQ0FBUCxLQUFlVCxPQUFPLENBQUNTLENBQUQsQ0FBMUIsRUFBK0IsQ0FDM0I7QUFDSCxPQUZELE1BRU8sSUFBSVosT0FBTyxDQUFDWSxDQUFELENBQVAsR0FBYVQsT0FBTyxDQUFDUyxDQUFELENBQXhCLEVBQTZCO0FBQ2hDLGVBQU8sQ0FBUDtBQUNILE9BRk0sTUFFQTtBQUNILGVBQU8sQ0FBQyxDQUFSO0FBQ0g7QUFDSjs7QUFFRCxRQUFJWixPQUFPLENBQUM3RCxNQUFSLEtBQW1CZ0UsT0FBTyxDQUFDaEUsTUFBL0IsRUFBdUM7QUFDbkMsYUFBTyxDQUFDLENBQVI7QUFDSDs7QUFFRCxXQUFPLENBQVA7QUFDSDtBQXJPZ0MsQ0FBckMsQyxDQXlPQTs7QUFDQXBCLENBQUMsQ0FBQzhGLFFBQUQsQ0FBRCxDQUFZQyxLQUFaLENBQWtCLFlBQU07QUFDcEJyRyxFQUFBQSw0QkFBNEIsQ0FBQ08sVUFBN0I7QUFDSCxDQUZEIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pa29QQlggLSBmcmVlIHBob25lIHN5c3RlbSBmb3Igc21hbGwgYnVzaW5lc3NcbiAqIENvcHlyaWdodCDCqSAyMDE3LTIwMjMgQWxleGV5IFBvcnRub3YgYW5kIE5pa29sYXkgQmVrZXRvdlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAqIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbiAqXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS5cbiAqIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gKi9cblxuLyogZ2xvYmFsIGdsb2JhbFJvb3RVcmwsIFBieEFwaSwgZ2xvYmFsVHJhbnNsYXRlLCBVc2VyTWVzc2FnZSAqL1xuXG4vKipcbiAqIEBtb2R1bGUgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlclxuICovXG5jb25zdCBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyID0ge1xuXG4gICAgLyoqXG4gICAgICogVGltZSBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIGZldGNoaW5nIG5ldyBzdGF0dXMuXG4gICAgICogQHR5cGUge251bWJlcn1cbiAgICAgKi9cbiAgICB0aW1lT3V0OiAxMDAwMCxcblxuICAgIC8qKlxuICAgICAqIFRoZSBpZCBvZiB0aGUgdGltZXIgZnVuY3Rpb24gZm9yIHN0YXR1cyB3b3JrZXIuXG4gICAgICogQHR5cGUge251bWJlcn1cbiAgICAgKi9cbiAgICB0aW1lT3V0SGFuZGxlOiAwLFxuXG5cbiAgICAvKiouXG4gICAgICogQHR5cGUge0V2ZW50U291cmNlfVxuICAgICAqL1xuICAgIGV2ZW50U291cmNlOiBudWxsLFxuXG4gICAgLyoqXG4gICAgICogVGhlIGlkZW50aWZpZXIgZm9yIHRoZSBQVUIvU1VCIGNoYW5uZWwgdXNlZCB0byBzdWJzY3JpYmUgdG8gbW9kdWxlIHN0YXR1cyB1cGRhdGVzLlxuICAgICAqIFRoaXMgZW5zdXJlcyB0aGF0IHRoZSBjbGllbnQgaXMgbGlzdGVuaW5nIG9uIHRoZSBjb3JyZWN0IGNoYW5uZWwgZm9yIHJlbGV2YW50IGV2ZW50cy5cbiAgICAgKi9cbiAgICBjaGFubmVsSWQ6ICdtb2R1bGUtZ2V0LXNzbC1wdWInLFxuXG4gICAgLyoqXG4gICAgICogalF1ZXJ5IHNlbGVjdG9yIGZvciB0aGUgcmVzdWx0IG1lc3NhZ2UgZWxlbWVudC5cbiAgICAgKlxuICAgICAqIFRoaXMgcHJvcGVydHkgc3RvcmVzIGEgcmVmZXJlbmNlIHRvIHRoZSBET00gZWxlbWVudCB3aXRoIHRoZSBJRCAnZGl2LXJlc3VsdCcgdXNpbmcgalF1ZXJ5LlxuICAgICAqL1xuICAgICRyZXN1bHRCbG9jazogJCgnI2Rpdi1yZXN1bHQnKSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemVzIHRoZSBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyIG1vZHVsZSBieSBzZXR0aW5nIHVwIHRoZSBjb25uZWN0aW9uIHRvIHJlY2VpdmUgc2VydmVyLXNlbnQgZXZlbnRzLlxuICAgICAqL1xuICAgIGluaXRpYWxpemUoKXtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5pbml0aWFsaXplQWNlKCk7XG4gICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIubG9hZExhc3RMb2coKTtcbiAgICAgICAgaWYgKG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIudmVyc2lvbkNvbXBhcmUoZ2xvYmFsUEJYVmVyc2lvbiwnMjAyNC4yLjMwJyk+MCl7XG4gICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLnN0YXJ0TGlzdGVuUHVzaE5vdGlmaWNhdGlvbnMoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIucmVzdGFydFdvcmtlcigpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIExvYWRzIHRoZSBsYXN0IGxvZyBmaWxlIGNvbnRlbnQgaW50byB0aGUgQUNFIGVkaXRvciBvbiBwYWdlIGxvYWQuXG4gICAgICovXG4gICAgbG9hZExhc3RMb2coKSB7XG4gICAgICAgICQuYXBpKHtcbiAgICAgICAgICAgIHVybDogYCR7Q29uZmlnLnBieFVybH0vcGJ4Y29yZS9hcGkvbW9kdWxlcy9Nb2R1bGVHZXRTc2wvY2hlY2stcmVzdWx0YCxcbiAgICAgICAgICAgIG9uOiAnbm93JyxcbiAgICAgICAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICAgICAgICBzdWNjZXNzVGVzdDogUGJ4QXBpLnN1Y2Nlc3NUZXN0LFxuICAgICAgICAgICAgb25TdWNjZXNzOiBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2UuZGF0YS5yZXN1bHQgJiYgcmVzcG9uc2UuZGF0YS5yZXN1bHQubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5zaG93KCk7XG4gICAgICAgICAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZWRpdG9yLmdldFNlc3Npb24oKS5zZXRWYWx1ZShyZXNwb25zZS5kYXRhLnJlc3VsdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uRmFpbHVyZTogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgLy8gU2lsZW50bHkgaWdub3JlIC0gbm8gbG9nIHRvIHNob3dcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0pXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlc3RhcnRzIHRoZSBtb2R1bGVHZXRTU0xTdGF0dXMgd29ya2VyLlxuICAgICAqL1xuICAgIHJlc3RhcnRXb3JrZXIoKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQobW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci50aW1lb3V0SGFuZGxlKTtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci53b3JrZXIoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogV29ya2VyIGZ1bmN0aW9uIGZvciBmZXRjaGluZyBzdGF0dXMuXG4gICAgICovXG4gICAgd29ya2VyKCkge1xuICAgICAgICAkLmFwaSh7XG4gICAgICAgICAgICB1cmw6IGAke0NvbmZpZy5wYnhVcmx9L3BieGNvcmUvYXBpL21vZHVsZXMvTW9kdWxlR2V0U3NsL2NoZWNrLXJlc3VsdGAsXG4gICAgICAgICAgICBvbjogJ25vdycsXG4gICAgICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICAgICAgc3VjY2Vzc1Rlc3Q6IFBieEFwaS5zdWNjZXNzVGVzdCxcbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogSGFuZGxlcyB0aGUgc3VjY2Vzc2Z1bCByZXNwb25zZSBvZiB0aGUgJ2NoZWNrLXJlc3VsdCcgQVBJIHJlcXVlc3QuXG4gICAgICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcmVzcG9uc2UgLSBUaGUgcmVzcG9uc2Ugb2JqZWN0LlxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBvblN1Y2Nlc3M6IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5kYXRhLnJlc3VsdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuJHJlc3VsdEJsb2NrLnNob3coKTtcbiAgICAgICAgICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IuZ2V0U2Vzc2lvbigpLnNldFZhbHVlKHJlc3BvbnNlLmRhdGEucmVzdWx0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci50aW1lb3V0SGFuZGxlID0gd2luZG93LnNldFRpbWVvdXQoXG4gICAgICAgICAgICAgICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIud29ya2VyLFxuICAgICAgICAgICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLnRpbWVPdXQsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIEhhbmRsZXMgdGhlIGZhaWx1cmUgcmVzcG9uc2Ugb2YgdGhlICdnZXQtYXZhaWxhYmxlLWxkYXAtdXNlcnMnIEFQSSByZXF1ZXN0LlxuICAgICAgICAgICAgICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIG9iamVjdC5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgb25GYWlsdXJlOiBmdW5jdGlvbihyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIFVzZXJNZXNzYWdlLnNob3dNdWx0aVN0cmluZyhyZXNwb25zZS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5oaWRlKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgQWNlIGVkaXRvciBpbnN0YW5jZS5cbiAgICAgKiBTZXRzIHVwIEFjZSBlZGl0b3Igd2l0aCBhIG1vbm9rYWkgdGhlbWUgYW5kIGN1c3RvbSBvcHRpb25zLlxuICAgICAqIEF0dGFjaGVzIGNoYW5nZSBoYW5kbGVyIHRvIHRoZSBlZGl0b3Igc2Vzc2lvbi5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplQWNlKCkge1xuICAgICAgICBjb25zdCBhY2VIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQgLSA0ODA7XG4gICAgICAgIGNvbnN0IHJvd3NDb3VudCA9IE1hdGgucm91bmQoYWNlSGVpZ2h0IC8gMTYuMyk7XG4gICAgICAgICQod2luZG93KS5sb2FkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQoJy5hcHBsaWNhdGlvbi1jb2RlJykuY3NzKCdtaW4taGVpZ2h0JywgYCR7YWNlSGVpZ2h0fXB4YCk7XG4gICAgICAgIH0pO1xuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmVkaXRvciA9IGFjZS5lZGl0KCd1c2VyLWVkaXQtY29uZmlnJyk7XG4gICAgICAgIGxldCBOZXdNb2RlID0gYWNlLnJlcXVpcmUoJ2FjZS9tb2RlL2p1bGlhJykuTW9kZTtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3Iuc2Vzc2lvbi5zZXRNb2RlKG5ldyBOZXdNb2RlKCkpO1xuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmVkaXRvci5zZXRUaGVtZSgnYWNlL3RoZW1lL21vbm9rYWknKTtcbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IucmVzaXplKCk7XG4gICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZWRpdG9yLmdldFNlc3Npb24oKS5vbignY2hhbmdlJywgKCkgPT4ge1xuICAgICAgICAgICAgLy8gVHJpZ2dlciBjaGFuZ2UgZXZlbnQgdG8gYWNrbm93bGVkZ2UgdGhlIG1vZGlmaWNhdGlvblxuICAgICAgICAgICAgRm9ybS5kYXRhQ2hhbmdlZCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmVkaXRvci5zZXRPcHRpb25zKHtcbiAgICAgICAgICAgIG1heExpbmVzOiByb3dzQ291bnQsXG4gICAgICAgICAgICBzaG93UHJpbnRNYXJnaW46IGZhbHNlLFxuICAgICAgICAgICAgc2hvd0xpbmVOdW1iZXJzOiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBFc3RhYmxpc2hlcyBhIGNvbm5lY3Rpb24gdG8gdGhlIHNlcnZlciB0byBzdGFydCByZWNlaXZpbmcgcmVhbC10aW1lIHVwZGF0ZXMgb24gbW9kdWxlIGluc3RhbGxhdGlvbiBwcm9ncmVzcy5cbiAgICAgKiBVdGlsaXplcyB0aGUgRXZlbnRTb3VyY2UgQVBJIHRvIGxpc3RlbiBmb3IgbWVzc2FnZXMgb24gYSBzcGVjaWZpZWQgY2hhbm5lbC5cbiAgICAgKi9cbiAgICBzdGFydExpc3RlblB1c2hOb3RpZmljYXRpb25zKCkge1xuICAgICAgICBjb25zdCBsYXN0RXZlbnRJZEtleSA9IGAke21vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuY2hhbm5lbElkfS1sYXN0RXZlbnRJZGA7XG4gICAgICAgIGxldCBsYXN0RXZlbnRJZCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKGxhc3RFdmVudElkS2V5KTtcbiAgICAgICAgY29uc3Qgc3ViUGF0aCA9IGxhc3RFdmVudElkID8gYC9wYnhjb3JlL2FwaS9uY2hhbi9zdWIvJHttb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmNoYW5uZWxJZH0/bGFzdF9ldmVudF9pZD0ke2xhc3RFdmVudElkfWAgOiBgL3BieGNvcmUvYXBpL25jaGFuL3N1Yi8ke21vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuY2hhbm5lbElkfWA7XG4gICAgICAgIG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZXZlbnRTb3VyY2UgPSBuZXcgRXZlbnRTb3VyY2Uoc3ViUGF0aCk7XG5cbiAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5ldmVudFNvdXJjZS5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgZSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IEpTT04ucGFyc2UoZS5kYXRhKTtcbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcocmVzcG9uc2UpO1xuICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5wcm9jZXNzU3RhdHVzTWVzc2FnZShyZXNwb25zZSk7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShsYXN0RXZlbnRJZEtleSwgZS5sYXN0RXZlbnRJZCk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSByZXNwb25zZSAtIFRoZSBkYXRhIHBheWxvYWQgb2YgdGhlIHNlcnZlci1zZW50IGV2ZW50LCBjb250YWluaW5nIGRldGFpbHMgYWJvdXQgdGhlIGluc3RhbGxhdGlvbiBzdGFnZSBhbmQgcHJvZ3Jlc3MuXG4gICAgICovXG4gICAgcHJvY2Vzc1N0YXR1c01lc3NhZ2UocmVzcG9uc2Upe1xuICAgICAgICBpZiAocmVzcG9uc2Uuc3RhZ2VEZXRhaWxzLnJlc3VsdCl7XG4gICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5zaG93KCk7XG4gICAgICAgICAgICBsZXQgcmVzdWx0VGV4dCA9IG1vZHVsZUdldFNTTFN0YXR1c0xvb3BXb3JrZXIuZWRpdG9yLmdldFNlc3Npb24oKS5nZXRWYWx1ZSgpO1xuICAgICAgICAgICAgaWYgKHJlc3BvbnNlLnN0YWdlID09PSAnU1RBR0VfMV9HRU5FUkFURV9DT05GSUcnKXtcbiAgICAgICAgICAgICAgICByZXN1bHRUZXh0ICs9ICdcXG4nICsgcmVzcG9uc2Uuc3RhZ2VEZXRhaWxzLmRhdGEucmVzdWx0O1xuICAgICAgICAgICAgfSBlbHNlIGlmKHJlc3BvbnNlLnN0YWdlID09PSAnU1RBR0VfMl9SRVFVRVNUX0NFUlQnKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0VGV4dCArPSAnXFxuJyArIHJlc3BvbnNlLnN0YWdlRGV0YWlscy5kYXRhLnJlc3VsdDtcbiAgICAgICAgICAgIH0gZWxzZSBpZihyZXNwb25zZS5zdGFnZSA9PT0gJ1NUQUdFXzNfUEFSU0VfUkVTUE9OU0UnICYmIHJlc3BvbnNlLnN0YWdlRGV0YWlscy5kYXRhLnJlc3VsdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0VGV4dCA9IHJlc3BvbnNlLnN0YWdlRGV0YWlscy5kYXRhLnJlc3VsdDtcbiAgICAgICAgICAgIH0gZWxzZSBpZihyZXNwb25zZS5zdGFnZSA9PT0gJ1NUQUdFXzRfRklOQUxfUkVTVUxUJyAmJiByZXNwb25zZS5zdGFnZURldGFpbHMuZGF0YS5yZXN1bHQubGVuZ3RoID4gMCApIHtcbiAgICAgICAgICAgICAgICByZXN1bHRUZXh0ID0gcmVzcG9uc2Uuc3RhZ2VEZXRhaWxzLmRhdGEucmVzdWx0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlci5lZGl0b3IuZ2V0U2Vzc2lvbigpLnNldFZhbHVlKHJlc3VsdFRleHQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd011bHRpU3RyaW5nKHJlc3BvbnNlLnN0YWdlRGV0YWlscy5tZXNzYWdlcyk7XG4gICAgICAgICAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLiRyZXN1bHRCbG9jay5oaWRlKCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ29tcGFyZSB2ZXJzaW9ucyBvZiBtb2R1bGVzLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2MSAtIFRoZSBmaXJzdCB2ZXJzaW9uIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHYyIC0gVGhlIHNlY29uZCB2ZXJzaW9uIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXSAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxleGljb2dyYXBoaWNhbF0gLSBXaGV0aGVyIHRvIHBlcmZvcm0gbGV4aWNvZ3JhcGhpY2FsIGNvbXBhcmlzb24gKGRlZmF1bHQ6IGZhbHNlKS5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnplcm9FeHRlbmRdIC0gV2VhdGhlciB0byB6ZXJvLWV4dGVuZCB0aGUgc2hvcnRlciB2ZXJzaW9uIChkZWZhdWx0OiBmYWxzZSkuXG4gICAgICogQHJldHVybnMge251bWJlcn0gLSBBIG51bWJlciBpbmRpY2F0aW5nIHRoZSBjb21wYXJpc29uIHJlc3VsdDogMCBpZiB2ZXJzaW9ucyBhcmUgZXF1YWwsIDEgaWYgdjEgaXMgZ3JlYXRlciwgLTEgaWYgdjIgaXMgZ3JlYXRlciwgb3IgTmFOIGlmIHRoZSB2ZXJzaW9ucyBhcmUgaW52YWxpZC5cbiAgICAgKi9cbiAgICB2ZXJzaW9uQ29tcGFyZSh2MSwgdjIsIG9wdGlvbnMpIHtcbiAgICAgICAgY29uc3QgbGV4aWNvZ3JhcGhpY2FsID0gb3B0aW9ucyAmJiBvcHRpb25zLmxleGljb2dyYXBoaWNhbDtcbiAgICAgICAgY29uc3QgemVyb0V4dGVuZCA9IG9wdGlvbnMgJiYgb3B0aW9ucy56ZXJvRXh0ZW5kO1xuICAgICAgICBsZXQgdjFwYXJ0cyA9IFN0cmluZyh2MSkuc3BsaXQoJy4nKTtcbiAgICAgICAgbGV0IHYycGFydHMgPSBTdHJpbmcodjIpLnNwbGl0KCcuJyk7XG5cbiAgICAgICAgZnVuY3Rpb24gaXNWYWxpZFBhcnQoeCkge1xuICAgICAgICAgICAgcmV0dXJuIChsZXhpY29ncmFwaGljYWwgPyAvXlxcZCtbQS1aYS16XSokLyA6IC9eXFxkKyQvKS50ZXN0KHgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF2MXBhcnRzLmV2ZXJ5KGlzVmFsaWRQYXJ0KSB8fCAhdjJwYXJ0cy5ldmVyeShpc1ZhbGlkUGFydCkpIHtcbiAgICAgICAgICAgIHJldHVybiBOYU47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoemVyb0V4dGVuZCkge1xuICAgICAgICAgICAgd2hpbGUgKHYxcGFydHMubGVuZ3RoIDwgdjJwYXJ0cy5sZW5ndGgpIHYxcGFydHMucHVzaCgnMCcpO1xuICAgICAgICAgICAgd2hpbGUgKHYycGFydHMubGVuZ3RoIDwgdjFwYXJ0cy5sZW5ndGgpIHYycGFydHMucHVzaCgnMCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFsZXhpY29ncmFwaGljYWwpIHtcbiAgICAgICAgICAgIHYxcGFydHMgPSB2MXBhcnRzLm1hcChOdW1iZXIpO1xuICAgICAgICAgICAgdjJwYXJ0cyA9IHYycGFydHMubWFwKE51bWJlcik7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHYxcGFydHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGlmICh2MnBhcnRzLmxlbmd0aCA9PT0gaSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHYxcGFydHNbaV0gPT09IHYycGFydHNbaV0pIHtcbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgfSBlbHNlIGlmICh2MXBhcnRzW2ldID4gdjJwYXJ0c1tpXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodjFwYXJ0cy5sZW5ndGggIT09IHYycGFydHMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gMDtcbiAgICB9LFxuXG59O1xuXG4vLyBJbml0aWFsaXplcyB0aGUgbW9kdWxlR2V0U1NMU3RhdHVzTG9vcFdvcmtlciBtb2R1bGUgd2hlbiB0aGUgRE9NIGlzIGZ1bGx5IGxvYWRlZC5cbiQoZG9jdW1lbnQpLnJlYWR5KCgpID0+IHtcbiAgICBtb2R1bGVHZXRTU0xTdGF0dXNMb29wV29ya2VyLmluaXRpYWxpemUoKTtcbn0pOyJdfQ== \ No newline at end of file diff --git a/public/assets/js/src/module-get-ssl-index.js b/public/assets/js/src/module-get-ssl-index.js index 72c6b17..cb9b556 100644 --- a/public/assets/js/src/module-get-ssl-index.js +++ b/public/assets/js/src/module-get-ssl-index.js @@ -12,6 +12,7 @@ const ModuleGetSsl = { $checkBoxes: $('#' + idForm + ' .ui.checkbox'), $disabilityFields: $('#' + idForm + ' .disability'), $statusToggle: $('#module-status-toggle'), + $submitButton: $('#submitbutton'), $moduleStatus: $('#status'), $intervalId: undefined, // To manage the interval for SSL status check @@ -61,6 +62,9 @@ const ModuleGetSsl = { return xhr; }, beforeSend(settings) { + ModuleGetSsl.$submitButton.addClass('loading disabled'); + moduleGetSSLStatusLoopWorker.$resultBlock.show(); + moduleGetSSLStatusLoopWorker.editor.getSession().setValue(''); return settings; }, successTest: PbxApi.successTest, @@ -69,13 +73,14 @@ const ModuleGetSsl = { * @param {object} response - The response object. */ onSuccess: function (response) { - moduleGetSSLStatusLoopWorker.editor.getSession().setValue(''); + ModuleGetSsl.$submitButton.removeClass('loading disabled'); }, /** - * Handles the failure response of the 'get-available-ldap-users' API request. + * Handles the failure response of the 'get-cert' API request. * @param {object} response - The response object. */ onFailure: function(response) { + ModuleGetSsl.$submitButton.removeClass('loading disabled'); UserMessage.showMultiString(response.message); moduleGetSSLStatusLoopWorker.$resultBlock.hide(); }, diff --git a/public/assets/js/src/module-get-ssl-status-worker.js b/public/assets/js/src/module-get-ssl-status-worker.js index ed08463..9ef7a3a 100644 --- a/public/assets/js/src/module-get-ssl-status-worker.js +++ b/public/assets/js/src/module-get-ssl-status-worker.js @@ -59,6 +59,7 @@ const moduleGetSSLStatusLoopWorker = { */ initialize(){ moduleGetSSLStatusLoopWorker.initializeAce(); + moduleGetSSLStatusLoopWorker.loadLastLog(); if (moduleGetSSLStatusLoopWorker.versionCompare(globalPBXVersion,'2024.2.30')>0){ moduleGetSSLStatusLoopWorker.startListenPushNotifications(); } else { @@ -66,6 +67,27 @@ const moduleGetSSLStatusLoopWorker = { } }, + /** + * Loads the last log file content into the ACE editor on page load. + */ + loadLastLog() { + $.api({ + url: `${Config.pbxUrl}/pbxcore/api/modules/ModuleGetSsl/check-result`, + on: 'now', + method: 'GET', + successTest: PbxApi.successTest, + onSuccess: function (response) { + if (response.data.result && response.data.result.length > 0) { + moduleGetSSLStatusLoopWorker.$resultBlock.show(); + moduleGetSSLStatusLoopWorker.editor.getSession().setValue(response.data.result); + } + }, + onFailure: function() { + // Silently ignore - no log to show + }, + }) + }, + /** * Restarts the moduleGetSSLStatus worker. */