diff --git a/App/Controllers/ModulePhoneBookController.php b/App/Controllers/ModulePhoneBookController.php index 58b6c2d..d9fc1da 100644 --- a/App/Controllers/ModulePhoneBookController.php +++ b/App/Controllers/ModulePhoneBookController.php @@ -123,6 +123,7 @@ public function getNewRecordsAction(): void $parameters['columns'] = [ 'call_id', 'number' => 'number_rep', + 'created' => 'created', 'DT_RowId' => 'id', ]; $parameters['order'] = ['call_id desc']; @@ -156,20 +157,18 @@ public function saveAction(): void $dataId = $this->request->getPost('id', ['string', 'trim']); $callId = $this->request->getPost('call_id', ['string', 'trim']); - $number = $this->request->getPost('number', ['alnum']); - $numberRep = $this->request->getPost('number_rep', ['string', 'trim'], $number); + $numberRep = $this->request->getPost('number_rep', ['string', 'trim']); + $number = PhoneBook::cleanPhoneNumber($numberRep, TRUE); if (empty($callId) || empty($number)) { return; } // If we are unable to change the primary field, delete the old record and recreate it - $oldId = null; $record = null; if (stripos($dataId, 'new') === false) { $record = PhoneBook::findFirstById($dataId); - if ($record->number !== $number) { - $oldId = $record->id; + if ($record !== null && $record->number !== $number) { $record->delete(); $record = null; } @@ -179,39 +178,17 @@ public function saveAction(): void $record = new PhoneBook(); } - foreach ($record as $key => $value) { - switch ($key) { - case 'id': - break; - case 'number': - $record->number = $number; - break; - case 'number_rep': - $record->number_rep = $numberRep; - break; - case 'call_id': - $record->call_id = $callId; - break; - case 'search_index': - // Collect data for the search index - $username = mb_strtolower($callId); - // Combine all fields into a single string - $record->search_index = $username . $number . $numberRep; - break; - default: - break; - } - } + $record->setPhonebookRecord($callId, $numberRep); if ($record->save() === false) { $errors = $record->getMessages(); $this->flash->error(implode('
', $errors)); $this->view->success = false; - + $this->response->setStatusCode(500); return; } - $this->view->data = ['oldId' => $oldId, 'newId' => $record->id]; + $this->view->data = ['oldId' => $dataId, 'newId' => $record->id]; $this->view->success = true; } @@ -236,22 +213,24 @@ public function deleteAction(?string $id = null): void */ public function deleteAllRecordsAction(): void { - $records = PhoneBook::find(); - foreach ($records as $record) { - if (!$record->delete()) { - $this->flash->error(implode('
', $record->getMessages())); - $this->view->result = false; - return; - } + $phoneBook = new PhoneBook(); + $connection = $phoneBook->getWriteConnection(); + $tableName = $phoneBook->getSource(); + + try { + $connection->execute("DELETE FROM {$tableName}"); + $this->view->result = true; + $this->view->reload = 'module-phone-book/module-phone-book/index'; + } catch (\Throwable $e) { + $this->flash->error($e->getMessage()); + $this->view->result = false; } - $this->view->result = true; - $this->view->reload = 'module-phone-book/module-phone-book/index'; } /** - * Toggle input mask feature. + * Save settings */ - public function toggleDisableInputMaskAction(): void + public function saveSettingsAction(): void { if (!$this->request->isPost()) { return; @@ -262,10 +241,19 @@ public function toggleDisableInputMaskAction(): void $settings = new Settings(); } - $settings->disableInputMask = $this->request->getPost('disableInputMask') === 'true' ? '1' : '0'; + if ($this->request->hasPost('disableInputMask')) { + $settings->disableInputMask = $this->request->getPost('disableInputMask') === 'true' ? '1' : '0'; + } + + if ($this->request->hasPost('phoneBookApiUrl')) { + $settings->phoneBookApiUrl = empty($this->request->getPost('phoneBookApiUrl')) ? NULL : $this->request->getPost('phoneBookApiUrl', 'trim'); + $settings->phoneBookLifeTime = empty($this->request->getPost('phoneBookLifeTime')) ? 0 : $this->request->getPost('phoneBookLifeTime', 'int!'); + } + if (!$settings->save()) { $this->flash->error(implode('
', $settings->getMessages())); $this->view->success = false; + $this->response->setStatusCode(500); return; } $this->view->success = true; diff --git a/App/Forms/ModuleConfigForm.php b/App/Forms/ModuleConfigForm.php index ea491e5..9220af7 100644 --- a/App/Forms/ModuleConfigForm.php +++ b/App/Forms/ModuleConfigForm.php @@ -21,6 +21,8 @@ namespace Modules\ModulePhoneBook\App\Forms; use MikoPBX\AdminCabinet\Forms\BaseForm; +use Phalcon\Forms\Element\Text; +use Phalcon\Forms\Element\Numeric; use Phalcon\Forms\Element\Check; use Phalcon\Forms\Element\File; @@ -31,6 +33,20 @@ public function initialize($entity = null, $options = null): void // DisableInputMask $this->addCheckBox('disableInputMask', intval($entity->disableInputMask) === 1); + // phoneBookApiUrl Text field + $this->add( + new Text('phoneBookApiUrl', [ + 'placeholder' => 'https://', + ]) + ); + + // phoneBookLifeTime Text field + $this->add( + new Numeric('phoneBookLifeTime', [ + 'min' => 0 + ]) + ); + // Excel file $excelFile = new File('excelFile'); $this->add($excelFile); @@ -49,7 +65,7 @@ public function addCheckBox(string $fieldName, bool $checked, string $checkedVal { $checkAr = ['value' => null]; if ($checked) { - $checkAr = ['checked' => $checkedValue,'value' => $checkedValue]; + $checkAr = ['checked' => $checkedValue, 'value' => $checkedValue]; } $this->add(new Check($fieldName, $checkAr)); } diff --git a/App/Views/ModulePhoneBook/Tabs/phonebookTab.volt b/App/Views/ModulePhoneBook/Tabs/phonebookTab.volt index aa8bfde..d01f378 100644 --- a/App/Views/ModulePhoneBook/Tabs/phonebookTab.volt +++ b/App/Views/ModulePhoneBook/Tabs/phonebookTab.volt @@ -8,7 +8,7 @@
+
+
+ + {{ form.render('phoneBookApiUrl') }} +
{{ t._('module_phnbk_ApiUrlDescription', {'repesent': '%number%'}) }}
+
+
+ + {{ form.render('phoneBookLifeTime') }} +
{{ t._('module_phnbk_CacheLifetimeDescription') }}
+
+
+
{{ t._('module_phnbk_SaveBtn') }}
+
+
{{ t._('module_phnbk_DeleteAllRecords') }}
diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..abbd62c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,85 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +ModulePhoneBook is a MikoPBX extension module that provides caller ID management and contact storage. It integrates with Asterisk PBX for real-time caller identification on inbound and outbound calls. + +## Build Commands + +### JavaScript Compilation +```bash +docker run --rm -v /Users/nb/PhpstormProjects/mikopbx:/workspace ghcr.io/mikopbx/babel-compiler:latest /workspace/Extensions/[module]/public/assets/js/src/[file] extension` +``` + +### PHP Syntax Check +```bash +php -l Lib/PhoneBookConf.php +``` + +### Code Quality (PHPStan) +Run phpstan after creating new PHP code to validate quality. + +### Dependencies +```bash +composer install +``` + +## Architecture + +### Directory Structure +- `App/Controllers/` - Phalcon MVC controllers (ModulePhoneBookController) +- `App/Forms/` - Phalcon form definitions +- `Lib/` - Core business logic + - `PhoneBookConf.php` - PBX integration, REST API callbacks, Asterisk dialplan generation + - `PhoneBookAgi.php` - Asterisk AGI handler for real-time caller ID lookup + - `PhoneBookImport.php` - Excel import processor using PhpSpreadsheet + - `MikoPBXVersion.php` - Version compatibility helpers +- `Models/` - Phalcon ORM models (PhoneBook, Settings) +- `Setup/` - Module installation logic (PbxExtensionSetup) +- `agi-bin/` - Asterisk AGI scripts +- `Messages/` - i18n translation files (26 languages) +- `public/assets/js/src/` - Source JavaScript files (ES6) +- `public/assets/js/` - Compiled JavaScript files + +### Data Flow +1. **Inbound calls**: Asterisk dialplan → `agi_phone_book.php` → `PhoneBookAgi::setCallerId('in')` → Sets CALLERID(name) +2. **Outbound calls**: CONNECTED_LINE_SEND_SUB → `PhoneBookAgi::setCallerId('out')` → Sets CONNECTEDLINE(name) +3. **Web UI**: DataTable with server-side processing via AJAX to `ModulePhoneBookController::getNewRecordsAction()` + +### Phone Number Storage Format +Numbers are normalized for consistent storage and fast lookups: +- Strip all non-digit characters +- Keep last 9 digits only +- Prepend "1" +- Example: `+7 (906) 555-43-43` → `1065554343` + +### Database +SQLite database at runtime: `/storage/usbdisk1/mikopbx/custom_modules/ModulePhoneBook/db/module.db` + +Tables: +- `m_PhoneBook` - contacts (id, number, number_rep, call_id, search_index) +- `m_ModulePhoneBook` - settings (disableInputMask) + +### Key Integration Points +- `PhoneBookConf::moduleRestAPICallback()` - REST API entry point for Excel import +- `PhoneBookConf::generateIncomingRoutBeforeDial()` - Injects AGI into inbound routes +- `PhoneBookConf::generateOutRoutContext()` - Injects connected line handling for outbound +- `PhoneBookConf::extensionGenContexts()` - Generates `[phone-book-out]` Asterisk context + +### Frontend +- Uses Semantic UI components and DataTables +- Input masking for phone numbers (toggleable via settings) +- State persistence in localStorage for page length and search +- Files in `public/assets/js/src/` must be compiled with Babel to `public/assets/js/` + +## Module Configuration + +`module.json` defines module metadata including: +- `moduleUniqueID`: "ModulePhoneBook" +- `min_pbx_version`: "2024.1.114" + +## CI/CD + +GitHub Actions workflow (`.github/workflows/build.yml`) uses shared MikoPBX workflow for building and publishing releases. diff --git a/Lib/MikoPBXVersion.php b/Lib/MikoPBXVersion.php index 7c25bc4..8207858 100644 --- a/Lib/MikoPBXVersion.php +++ b/Lib/MikoPBXVersion.php @@ -99,4 +99,17 @@ public static function getLoggerClass(): string return \Phalcon\Logger::class; } } + + /** + * Return validator Callback class for the current version of PBX + * @return class-string<\Phalcon\Filter\Validation\Validator\Callback>|class-string<\Phalcon\Validation\Validator\Callback> + */ + public static function getValidatorCallbackClass(): string + { + if (self::isPhalcon5Version()) { + return \Phalcon\Filter\Validation\Validator\Callback::class; + } else { + return \Phalcon\Validation\Validator\Callback::class; + } + } } diff --git a/Lib/PhoneBookAgi.php b/Lib/PhoneBookAgi.php index 4f1e982..0b8db13 100644 --- a/Lib/PhoneBookAgi.php +++ b/Lib/PhoneBookAgi.php @@ -23,6 +23,7 @@ use MikoPBX\Core\Asterisk\AGI; use MikoPBX\Core\System\Util; use Modules\ModulePhoneBook\Models\PhoneBook; +use Modules\ModulePhoneBook\Models\Settings; use Phalcon\Di\Injectable; /** @@ -48,15 +49,27 @@ public static function setCallerID(string $type): void } else { $number = $agi->request['agi_extension']; } - + $number_orig = $number; // Normalize the phone number to match the expected format (last 9 digits) - $number = '1' . substr($number, -9); + $number = PhoneBook::cleanPhoneNumber($number, TRUE); // Find the corresponding phonebook entry by the number $result = PhoneBook::findFirstByNumber($number); + $settings = Settings::findFirst(); + $lifeTime = ($settings !== null) ? ($settings->phoneBookLifeTime ?? 0) : 0; + $apiUrl = ($settings !== null) ? ($settings->phoneBookApiUrl ?? '') : ''; + + if ($result === null || empty($result->call_id) || ($lifeTime > 0 && $result->created > 0 && $result->created + $lifeTime < time())) { + // The record was not found or expired - search through the API if configured + if (!empty($apiUrl)) { + $searcher = new PhoneBookFind(); + $result = $searcher->findApiByNumber($number_orig, $result); + } + } + // If a matching record is found and the call_id is not empty, set the appropriate caller ID - if ($result !== null && !empty($result->call_id)) { + if ($result !== NULL && !empty($result->call_id)) { if ($type === 'in') { $agi->set_variable('CALLERID(name)', $result->call_id); } else { @@ -68,4 +81,4 @@ public static function setCallerID(string $type): void Util::sysLogMsg('PhoneBookAGI', $e->getMessage(), LOG_ERR); } } -} \ No newline at end of file +} diff --git a/Lib/PhoneBookFind.php b/Lib/PhoneBookFind.php new file mode 100644 index 0000000..bc6e8da --- /dev/null +++ b/Lib/PhoneBookFind.php @@ -0,0 +1,125 @@ +. + */ + +namespace Modules\ModulePhoneBook\Lib; + +use GuzzleHttp\Client; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Exception\GuzzleException; +use MikoPBX\Core\System\Util; +use Modules\ModulePhoneBook\Models\PhoneBook; +use Modules\ModulePhoneBook\Models\Settings; +use Phalcon\Di\Injectable; + +include_once __DIR__ . '/../vendor/autoload.php'; + +/** + * Class PhoneBookFind + * + */ +class PhoneBookFind extends Injectable +{ + /** + * Find CallerID from API + * + * @param string $number_search + * @param PhoneBook|null $oldPhoneBook + * @return PhoneBook|null + */ + public function findApiByNumber(string $number_search, ?PhoneBook $oldPhoneBook = NULL): ?PhoneBook + { + // Normalize the phone number to match the expected format (last 9 digits) + $number = PhoneBook::cleanPhoneNumber($number_search, TRUE); + + if (empty($number)) { + return NULL; + } + + $settings = Settings::findFirst(); + $apiUrl = ($settings !== null) ? ($settings->phoneBookApiUrl ?? '') : ''; + if (empty($apiUrl)) { + return null; + } + $url = str_replace('%number%', $number, $apiUrl); + $callerID = $this->getRequest($url); + + // Logging + Util::sysLogMsg( + 'PhoneBookAGI', + "Find CallerID from API: $number => " . (empty($callerID) ? 'NOT FOUND' : $callerID) + ); + + if ($callerID !== NULL) { + // Saving the number in the phonebook + $record = $oldPhoneBook !== NULL && $oldPhoneBook->number === $number ? $oldPhoneBook : PhoneBook::findFirstByNumber( + $number + ); + + if ($record == NULL) { + $record = new PhoneBook(); + } + + $record->setPhonebookRecord( + $callerID, + $number_search, + time() + ); + + if (!$record->save()) { + // Log the error message if an exception occurs + Util::sysLogMsg('PhoneBookAGI', implode(' | ', $record->getMessages()), LOG_ERR); + } else { + return $record; + } + } + + return NULL; + } + + /** + * Get the $url content with CURL + * + * @param string $url + * @return string|null + */ + private function getRequest(string $url): ?string + { + $callerId = NULL; + try { + $client = new Client([ + 'timeout' => 3, + 'connect_timeout' => 2 + ]); + $response = $client->get($url); + $status = $response->getStatusCode(); + if ($status === 200) { + // Just trim here, sanitization is done in PhoneBook::setPhonebookRecord() + $callerId = trim($response->getBody()->getContents()); + } + } catch (ClientException $e) { + // ClientException catches 4xx errors - not logging as these are expected + } catch (GuzzleException $e) { + // Log the error message if an exception occurs + Util::sysLogMsg('PhoneBookAGI', $e->getMessage(), LOG_ERR); + } + + return !empty($callerId) ? $callerId : NULL; + } +} diff --git a/Lib/PhoneBookImport.php b/Lib/PhoneBookImport.php index e5284b3..b513732 100644 --- a/Lib/PhoneBookImport.php +++ b/Lib/PhoneBookImport.php @@ -65,12 +65,15 @@ public function run(string $uploadedFilePath): PBXApiResult // Iterate over rows and process each record for ($row = 2; $row <= $highestRow; ++$row) { - $callId = $sheet->getCell([1, $row])->getValue(); - $numberRep = $sheet->getCell([2, $row])->getValue(); - $number = $this->cleanPhoneNumber($numberRep); - $number = '1' . substr($number, -9); // Add 1 to the beginning of the number + $callId = (string)($sheet->getCell([1, $row])->getValue() ?? ''); + $numberRep = (string)($sheet->getCell([2, $row])->getValue() ?? ''); - $res = $this->savePhonebookRecord($callId, $numberRep, $number); + // Skip empty rows + if (empty($callId) && empty($numberRep)) { + continue; + } + + $res = $this->savePhonebookRecord($callId, $numberRep); if (!$res->success) { $result->success = false; $result->messages['error'] = array_merge($result->messages['error']??[], $res->messages['error']??[]); @@ -111,21 +114,15 @@ private function validateExcelFile(string $filePath): bool * * @param string $callId The caller ID * @param string $numberRep The phone number in its original format (with special characters) - * @param string $number The cleaned phone number (digits only) * @return PBXApiResult The result of the save operation */ - private function savePhonebookRecord(string $callId, string $numberRep, string $number): PBXApiResult + private function savePhonebookRecord(string $callId, string $numberRep): PBXApiResult { $result = new PBXApiResult(); $record = new PhoneBook(); - $record->call_id = $callId; - $record->number_rep = $numberRep; - $record->number = $number; - // Collect data for the search index - $username = mb_strtolower($callId); - // Combine all fields into a single string - $record->search_index = $username . $number . $numberRep; + $record->setPhonebookRecord($callId, $numberRep); + if (!$record->save()) { $errors = implode('
', $record->getMessages()); $message = $this->translation->_("module_phnbk_ImportError"); @@ -136,16 +133,4 @@ private function savePhonebookRecord(string $callId, string $numberRep, string $ $result->success = true; return $result; } - - /** - * Clean phone number by removing non-numeric characters - * - * @param string $numberRep The original phone number (including special characters) - * @return string The cleaned phone number (digits only) - */ - private function cleanPhoneNumber(string $numberRep): string - { - // Remove all non-numeric characters - return preg_replace('/\D+/', '', $numberRep); - } } diff --git a/Messages/en.php b/Messages/en.php index 4473672..16168f6 100644 --- a/Messages/en.php +++ b/Messages/en.php @@ -1,12 +1,13 @@ 'Module phonebook - %repesent%', 'mo_ModuleModulePhoneBook' => 'Module phonebook', 'BreadcrumbModulePhoneBook' => 'Phonebook', @@ -45,4 +46,11 @@ 'module_phnbk_AllRecordsDeleted' => 'All entries have been deleted', 'module_phnbk_RecognitionOnProgress' => 'Parsing and loading data from a file', 'module_phnbk_RecognitionFinished' => 'Data loading completed', + 'module_phnbk_UrlNotValid' => 'Url not valid', + 'module_phnbk_IntegerPositiveOrZero' => 'A positive integer or zero', + 'module_phnbk_CacheLifetime' => 'Cache lifetime', + 'module_phnbk_CacheLifetimeDescription' => 'The number of seconds during which the cached record will be valid. 0 - forever.', + 'module_phnbk_SaveBtn' => 'Save', + 'module_phnbk_ApiUrl' => 'The URL to search for the CallerID', + 'module_phnbk_ApiUrlDescription' => '%repesent% in the line will be replaced with a phone number.' ]; diff --git a/Messages/fa.php b/Messages/fa.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/Messages/fa.php @@ -0,0 +1 @@ + '電話番号 - +7(926)123-45-67の形式。', 'module_phnbk_ExcelInstructionStep3' => '各行は電話帳のエントリを表します。', 'module_phnbk_ImportError' => 'エントリの保存中にエラーが発生しました', - 'module_phnbk_ExcelInstructionStep1' => 'ファイルの形式は .xls または .xlsx. である必要があります。', + 'module_phnbk_ExcelInstructionStep1' => 'ファイルの形式は .xls または .xlsx. である必要があります', 'module_phnbk_ExcelInstructionStep2' => 'ファイルには次の 2 つの列が含まれている必要があります。', 'module_phnbk_ExcelInstructionStep2_1' => 'CallerID - 加入者名 (例: Ivan Ivanov)。', 'module_phnbk_ExcelInstructionStep4' => 'アップロードする前に、ファイル内のデータが正しいことを確認してください。', diff --git a/Messages/ru.php b/Messages/ru.php index 04ab958..a922ff7 100644 --- a/Messages/ru.php +++ b/Messages/ru.php @@ -48,13 +48,20 @@ 'module_phnbk_NoFileUploaded' => 'Не загружен файл для импорта', 'module_phnbk_invalidFormat' => 'Ошибка формата файла', 'module_phnbk_DeleteAllTitle' => 'Внимание!', - 'module_phnbk_DeleteAllDescription' => 'Все записи телефонной книги будут безвозвратно удалены, если вам нужно удалить одну или запись, используйтесь кнопкой в таблице.', + 'module_phnbk_DeleteAllDescription' => 'Все записи телефонной книги будут безвозвратно удалены, если вам нужно удалить одну или несколько записей, используйтесь кнопкой в таблице.', 'module_phnbk_CancelBtn' => 'Отмена', 'module_phnbk_Approve' => 'Удалить все', 'module_phnbk_GeneraLFileUploadError' => 'Ошибка при загрузке файла', - 'module_phnbk_UploadError'=>'Ошибка загрузки файла', - 'module_phnbk_UploadInProgress'=>'Загрузки файла на сервер', - 'module_phnbk_AllRecordsDeleted'=>'Все записи удалены', - 'module_phnbk_RecognitionOnProgress'=>'Разбор и загрузка данных из файла', - 'module_phnbk_RecognitionFinished'=>'Загрузка данных выполнена' + 'module_phnbk_UploadError' => 'Ошибка загрузки файла', + 'module_phnbk_UploadInProgress' => 'Загрузки файла на сервер', + 'module_phnbk_AllRecordsDeleted' => 'Все записи удалены', + 'module_phnbk_RecognitionOnProgress' => 'Разбор и загрузка данных из файла', + 'module_phnbk_RecognitionFinished' => 'Загрузка данных выполнена', + 'module_phnbk_UrlNotValid' => 'Недопустимый URL-адрес', + 'module_phnbk_IntegerPositiveOrZero' => 'Целое положительное число или ноль', + 'module_phnbk_CacheLifetime' => 'Время жизни кеша', + 'module_phnbk_CacheLifetimeDescription' => 'Количество секунд, в течение которых кэшированная запись будет действительна. 0 - навсегда.', + 'module_phnbk_SaveBtn' => 'Сохранить', + 'module_phnbk_ApiUrl' => 'URL-адрес для поиска CallerID', + 'module_phnbk_ApiUrlDescription' => '%repesent% в строке будет заменен на номер телефона.' ]; diff --git a/Models/PhoneBook.php b/Models/PhoneBook.php index e5a6eba..ce42345 100644 --- a/Models/PhoneBook.php +++ b/Models/PhoneBook.php @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License along with this program. * If not, see . */ + namespace Modules\ModulePhoneBook\Models; use MikoPBX\Modules\Models\ModulesModelsBase; @@ -30,7 +31,8 @@ * @method static mixed findFirstByNumber(array|string|int $parameters = null) * @Indexes( * [name='number', columns=['number'], type=''], - * [name='CallerID', columns=['CallerID'], type=''] + * [name='CallerID', columns=['CallerID'], type=''], + * [name='Created', columns=['created'], type=''] * ) */ class PhoneBook extends ModulesModelsBase @@ -71,6 +73,13 @@ class PhoneBook extends ModulesModelsBase */ public ?string $search_index = ""; + /** + * Created - Created timestamp or 0 + * + * @Column(type="integer", nullable=false, default=0) + */ + public int $created = 0; + /** * Initializes the model by setting the source table, * calling the parent initializer, and enabling dynamic updates. @@ -107,4 +116,38 @@ public function validation(): bool return $this->validate($validation); } + + + /** + * + * @param string $callId + * @param string $numberRep + * @param int $created + * @return void + */ + public function setPhonebookRecord(string $callId, string $numberRep, int $created = 0): void + { + $this->call_id = trim(strip_tags(str_replace('"',"'", $callId))); + $this->number_rep = $numberRep; + $this->number = $this->cleanPhoneNumber($numberRep, TRUE); + $this->created = $created; + + // Combine all fields into a single string + $this->search_index = mb_strtolower($callId) . $this->number . $this->number_rep; + } + + /** + * Clean phone number by removing non-numeric characters + * + * @param string $numberRep The original phone number (including special characters) + * @param boolean $isNormalize Is Normalize number + * @return string The cleaned phone number (digits only) + */ + public static function cleanPhoneNumber(string $numberRep, bool $isNormalize = FALSE): string + { + // Remove all non-numeric characters + $numberRep = preg_replace('/\D+/', '', $numberRep); + // Normalize number + return $isNormalize ? '1' . substr($numberRep, -9) : $numberRep; + } } diff --git a/Models/Settings.php b/Models/Settings.php index f4eeaa1..f1b821e 100644 --- a/Models/Settings.php +++ b/Models/Settings.php @@ -1,20 +1,27 @@ . */ namespace Modules\ModulePhoneBook\Models; use MikoPBX\Modules\Models\ModulesModelsBase; +use Modules\ModulePhoneBook\Lib\MikoPBXVersion; class Settings extends ModulesModelsBase { @@ -32,10 +39,75 @@ class Settings extends ModulesModelsBase */ public $disableInputMask; + /** + * Url for CallerID search + * + * @Column(type="string", nullable=true) + */ + public $phoneBookApiUrl; + + /** + * Lifetime in seconds + * + * @Column(type="integer", default="0", nullable=false) + */ + public $phoneBookLifeTime; + public function initialize(): void { $this->setSource('m_ModulePhoneBook'); parent::initialize(); } + + /** + * Validates the settings before saving. + * + * @return bool Returns true if validation passes, otherwise false. + */ + public function validation(): bool + { + $validationClass = MikoPBXVersion::getValidationClass(); + $callbackClass = MikoPBXVersion::getValidatorCallbackClass(); + $validation = new $validationClass(); + + $validation->add( + 'phoneBookApiUrl', + new $callbackClass( + [ + 'callback' => function ($data) { + if (empty($data->phoneBookApiUrl)) { + return true; + } + // Check URL is valid + if (!filter_var($data->phoneBookApiUrl, FILTER_VALIDATE_URL)) { + return false; + } + // Check URL uses http/https scheme (SSRF protection) + $scheme = parse_url($data->phoneBookApiUrl, PHP_URL_SCHEME); + if (!in_array(strtolower($scheme), ['http', 'https'], true)) { + return false; + } + // Check URL contains %number% placeholder + return stripos($data->phoneBookApiUrl, '%number%') !== false; + }, + 'message' => $this->t('module_phnbk_UrlNotValid'), + ] + ) + ); + + $validation->add( + 'phoneBookLifeTime', + new $callbackClass( + [ + 'callback' => function ($data) { + return $data->phoneBookLifeTime >= 0; + }, + 'message' => $this->t('module_phnbk_CacheLifetime') . ' - ' . $this->t('module_phnbk_IntegerPositiveOrZero'), + ] + ) + ); + + return $this->validate($validation); + } } diff --git a/README.md b/README.md index 8aad34b..5e4a52c 100644 --- a/README.md +++ b/README.md @@ -1,172 +1,196 @@ -# Phone Book Module for MIKOPBX +# Phone Book Module for MikoPBX -A comprehensive phone book management module for MIKOPBX that provides caller ID management, contact storage, and integration with the PBX system's inbound and outbound calls. +[![GitHub release](https://img.shields.io/github/v/release/mikopbx/ModulePhoneBook)](https://github.com/mikopbx/ModulePhoneBook/releases) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) + +**[Русская версия](README.ru.md)** | **English** + +Contact management module for MikoPBX with real-time caller ID lookup on incoming and outgoing calls. ## Features -- Real-time caller ID lookup for inbound and outbound calls -- Contact management with formatted number display -- Excel file import support -- Full-text search capabilities -- Input mask toggling for phone number formatting -- Asterisk AGI integration for call processing -- DataTable-based web interface +- **Caller ID Lookup** — automatic name display for incoming and outgoing calls +- **External API Integration** — lookup caller ID from external services with caching +- **Excel Import** — bulk contact import from Excel files (.xlsx, .xls) +- **Web Interface** — contact management via DataTable with search and pagination +- **Input Masking** — automatic phone number formatting (optional) +- **Multi-language** — 26 languages supported -## System Requirements +## Requirements -- MIKOPBX version 2024.1.114 or higher -- Modern web browser with JavaScript enabled +- MikoPBX 2024.1.114 or higher -## Database Structure +## Installation -The module uses SQLite database located at: -`/storage/usbdisk1/mikopbx/custom_modules/ModulePhoneBook/db/module.db` +1. Go to **Modules** → **Marketplace** in MikoPBX admin panel +2. Find **Phone Book** module +3. Click **Install** -### Phone Book Table (m_PhoneBook) +Or install from GitHub release: +1. Download the latest `.zip` release +2. Go to **Modules** → **Module Installation** +3. Upload the archive -Main table storing contact information: +## Usage -```sql -CREATE TABLE m_PhoneBook ( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - number INTEGER, -- Normalized number (1 + last 9 digits) - number_rep VARCHAR(255), -- Display format (e.g., +7(906)555-43-43) - call_id VARCHAR(255), -- Caller ID display name - search_index TEXT -- Combined search field for full-text search -); +### Adding Contacts --- Indexes -CREATE INDEX number ON m_PhoneBook (number); -CREATE INDEX CallerID ON m_PhoneBook (call_id); -``` +1. Navigate to **Phone Book** module +2. Click **Add** button +3. Enter name and phone number +4. Press Enter or click outside the field to save -### Settings Table (m_ModulePhoneBook) +### Excel Import -Module configuration storage: +Prepare an Excel file with two columns: -```sql -CREATE TABLE m_ModulePhoneBook ( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - disableInputMask INTEGER DEFAULT 0 -- Toggle for input mask functionality -); -``` +| Name | Phone Number | +|------|--------------| +| John Doe | +1 555 123-4567 | +| ACME Corp | 18005551234 | -## Phone Number Format +1. Go to **Import** tab +2. Select Excel file +3. Click **Import** -The module uses a specific format for storing phone numbers: -1. Original number gets cleaned from any non-digit characters -2. Only the last 9 digits are kept -3. Digit "1" is added at the beginning -4. The result is stored in the 'number' field +Phone numbers are normalized automatically — any format is accepted. -Example: -``` -Original: +7 (906) 555-43-43 -Cleaned: 79065554343 -Last 9: 065554343 -Stored: 1065554343 -``` +### External API Lookup -This format ensures: -- Consistent number storage -- Quick lookups -- Independence from country codes -- Compatibility with various number formats +Configure external API for caller ID lookup: -## Core Components +1. Go to **Settings** tab +2. Enter API URL with `%number%` placeholder: + ``` + https://api.example.com/lookup?phone=%number% + ``` +3. Set cache lifetime (seconds, 0 = no cache) +4. Click **Save** -### Business Logic (Lib/) +The API should return plain text with the caller name. -1. **PhoneBookConf.php** - Core configuration and PBX integration: - - Manages Asterisk dialplan integration - - Processes incoming/outgoing call routing +#### Example API Request/Response -2. **PhoneBookAgi.php** - Asterisk AGI integration: - - Real-time caller ID lookup - - Handles both incoming and outgoing calls - - Sets caller ID display names +When a call comes from **+1 (555) 123-4567**, the module normalizes it to **1555123456** and makes an HTTP GET request: -3. **PhoneBookImport.php** - Data import functionality: - - Excel file processing - - Data validation and normalization - - Bulk contact import +**Request:** +```http +GET https://api.example.com/lookup?phone=1555123456 +``` -### Frontend Features +**Response (plain text):** +``` +John Doe +``` -The module includes several JavaScript components: +The name "John Doe" will be displayed as the caller ID on the phone. If the API returns an empty response or error, the module continues without displaying a name. -1. **DataTable Integration:** - - Server-side processing - - Real-time search - - Automatic page length calculation - - Saved state persistence +**Example with company name:** +```http +GET https://api.example.com/lookup?phone=1800555123 +``` -2. **Input Masking:** - - Dynamic phone number formatting - - Multiple format support - - Configurable masks - - Toggle functionality +**Response:** +``` +ACME Corporation +``` -3. **Excel Import:** - - File upload with progress tracking - - Background processing - - Error handling - - Automatic data normalization +The cache stores the response for the configured lifetime to reduce API calls for repeated numbers. -## Usage +## How It Works + +### Phone Number Normalization -### Managing Contacts +Numbers are normalized for consistent storage and fast lookups: -```php -// Example: Adding a new contact -$contact = new PhoneBook(); -$contact->number = '1065554343'; // Normalized format -$contact->number_rep = '+7(906)555-43-43'; // Display format -$contact->call_id = 'John Doe'; -$contact->search_index = 'johndoe1065554343+7(906)555-43-43'; -$contact->save(); ``` +Input: +7 (906) 555-43-43 +Step 1: 79065554343 (digits only) +Step 2: 065554343 (last 9 digits) +Step 3: 1065554343 (prefix "1" added) +``` + +This ensures matching works regardless of how numbers are dialed. -### Excel Import Format +### Call Flow -The module accepts Excel files with the following structure: +**Incoming calls:** ``` -| Name/Company | Phone Number | -|-----------------|-------------------| -| John Doe | +1 (555) 123-4567 | -| ACME Corp | +1-777-888-9999 | +Asterisk → AGI script → PhoneBook lookup → Set CALLERID(name) ``` -Phone numbers are automatically normalized during import. - -## Development +**Outgoing calls:** +``` +Asterisk → CONNECTED_LINE_SEND_SUB → PhoneBook lookup → Set CONNECTEDLINE(name) +``` -### Class Structure +## Architecture ``` ModulePhoneBook/ +├── agi-bin/ +│ └── agi_phone_book.php # Asterisk AGI entry point +├── App/ +│ ├── Controllers/ # Phalcon MVC controllers +│ ├── Forms/ # Form definitions +│ └── Views/ # Volt templates ├── Lib/ -│ ├── PhoneBookConf.php # PBX integration -│ ├── PhoneBookAgi.php # Asterisk AGI handler -│ └── PhoneBookImport.php # Import processor +│ ├── PhoneBookConf.php # Asterisk dialplan integration +│ ├── PhoneBookAgi.php # AGI caller ID handler +│ ├── PhoneBookFind.php # External API lookup +│ └── PhoneBookImport.php # Excel import processor ├── Models/ -│ ├── PhoneBook.php # Contact storage -│ └── Settings.php # Configuration -├── public/ - └── assets/ - └── js/ - └── src/ - ├── module-phonebook-datatable.js - ├── module-phonebook-import.js - └── module-phonebook-index.js +│ ├── PhoneBook.php # Contact model +│ └── Settings.php # Settings model +├── public/assets/ +│ ├── css/ # Module styles +│ └── js/ # JavaScript (ES6 source + compiled) +└── Messages/ # Translations (26 languages) ``` -## License +## Database + +SQLite database at `/storage/usbdisk1/mikopbx/custom_modules/ModulePhoneBook/db/module.db` + +**m_PhoneBook** — contacts: +- `id` — primary key +- `number` — normalized number for lookup +- `number_rep` — display format +- `call_id` — contact name +- `search_index` — full-text search field +- `created` — timestamp (for API cache expiration) + +**m_ModulePhoneBook** — settings: +- `disableInputMask` — toggle input masking +- `phoneBookApiUrl` — external API URL +- `phoneBookLifeTime` — cache lifetime in seconds + +## Development + +### Build JavaScript -GNU General Public License v3.0 - see LICENSE file for details. +```bash +# Compile ES6 to ES5 with Babel +docker run --rm -v ~/mikopbx:/workspace ghcr.io/mikopbx/babel-compiler:latest /workspace/Extensions/[module]/public/assets/js/src/[file] extension` +``` + +### PHP Syntax Check + +```bash +php -l Lib/PhoneBookConf.php +``` + +## Links + +- [Documentation (EN)](https://docs.mikopbx.com/mikopbx/english/modules/miko/module-phone-book) +- [Documentation (RU)](https://docs.mikopbx.com/mikopbx/modules/miko/phone-book) +- [MikoPBX Website](https://mikopbx.com) ## Support -- Documentation: [https://docs.mikopbx.com/mikopbx/modules/miko/phone-book](https://docs.mikopbx.com/mikopbx/modules/miko/phone-book) - Email: help@miko.ru -- Issues: GitHub issue tracker \ No newline at end of file +- Issues: [GitHub Issues](https://github.com/mikopbx/ModulePhoneBook/issues) + +## License + +GPL-3.0 — see [LICENSE](LICENSE) file. diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 0000000..a84b61e --- /dev/null +++ b/README.ru.md @@ -0,0 +1,196 @@ +# Модуль телефонной книги для MikoPBX + +[![GitHub release](https://img.shields.io/github/v/release/mikopbx/ModulePhoneBook)](https://github.com/mikopbx/ModulePhoneBook/releases) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) + +**Русская версия** | **[English](README.md)** + +Модуль управления контактами для MikoPBX с автоматическим определением имени звонящего на входящих и исходящих вызовах. + +## Возможности + +- **Определение имени звонящего** — автоматический показ имени при входящих и исходящих звонках +- **Интеграция с внешним API** — поиск имени через внешние сервисы с кэшированием +- **Импорт из Excel** — массовая загрузка контактов из файлов Excel (.xlsx, .xls) +- **Веб-интерфейс** — управление контактами через DataTable с поиском и пагинацией +- **Маска ввода** — автоматическое форматирование номеров телефонов (опционально) +- **Мультиязычность** — поддержка 26 языков + +## Требования + +- MikoPBX версии 2024.1.114 или выше + +## Установка + +1. Перейдите в **Модули** → **Маркетплейс** в панели администрирования MikoPBX +2. Найдите модуль **Телефонная книга** +3. Нажмите **Установить** + +Или установите из GitHub релиза: +1. Скачайте последний `.zip` релиз +2. Перейдите в **Модули** → **Установка модуля** +3. Загрузите архив + +## Использование + +### Добавление контактов + +1. Откройте модуль **Телефонная книга** +2. Нажмите кнопку **Добавить** +3. Введите имя и номер телефона +4. Нажмите Enter или кликните вне поля для сохранения + +### Импорт из Excel + +Подготовьте Excel файл с двумя колонками: + +| Имя | Номер телефона | +|-----|----------------| +| Иван Петров | +7 906 555-43-43 | +| ООО Компания | 84951234567 | + +1. Перейдите на вкладку **Импорт** +2. Выберите Excel файл +3. Нажмите **Импортировать** + +Номера телефонов нормализуются автоматически — принимается любой формат. + +### Поиск через внешний API + +Настройте внешний API для определения имени звонящего: + +1. Перейдите на вкладку **Настройки** +2. Введите URL API с плейсхолдером `%number%`: + ``` + https://api.example.com/lookup?phone=%number% + ``` +3. Установите время жизни кэша (в секундах, 0 = без кэша) +4. Нажмите **Сохранить** + +API должен возвращать текст с именем контакта. + +#### Пример запроса и ответа API + +При входящем звонке с номера **+7 (906) 555-43-43**, модуль нормализует его в **1065554343** и выполняет HTTP GET запрос: + +**Запрос:** +```http +GET https://api.example.com/lookup?phone=1065554343 +``` + +**Ответ (обычный текст):** +``` +Иван Петров +``` + +Имя "Иван Петров" будет отображаться как определитель номера на телефоне. Если API вернет пустой ответ или ошибку, модуль продолжит работу без отображения имени. + +**Пример с названием компании:** +```http +GET https://api.example.com/lookup?phone=1495123456 +``` + +**Ответ:** +``` +ООО Рога и Копыта +``` + +Кэш сохраняет ответ на настроенное время жизни, чтобы сократить количество запросов к API для повторяющихся номеров. + +## Как это работает + +### Нормализация номеров + +Номера нормализуются для единообразного хранения и быстрого поиска: + +``` +Ввод: +7 (906) 555-43-43 +Шаг 1: 79065554343 (только цифры) +Шаг 2: 065554343 (последние 9 цифр) +Шаг 3: 1065554343 (добавлен префикс "1") +``` + +Это обеспечивает корректное сопоставление независимо от формата набора номера. + +### Поток вызовов + +**Входящие звонки:** +``` +Asterisk → AGI скрипт → Поиск в PhoneBook → Установка CALLERID(name) +``` + +**Исходящие звонки:** +``` +Asterisk → CONNECTED_LINE_SEND_SUB → Поиск в PhoneBook → Установка CONNECTEDLINE(name) +``` + +## Архитектура + +``` +ModulePhoneBook/ +├── agi-bin/ +│ └── agi_phone_book.php # Точка входа AGI для Asterisk +├── App/ +│ ├── Controllers/ # Контроллеры Phalcon MVC +│ ├── Forms/ # Определения форм +│ └── Views/ # Шаблоны Volt +├── Lib/ +│ ├── PhoneBookConf.php # Интеграция с диалпланом Asterisk +│ ├── PhoneBookAgi.php # Обработчик AGI для Caller ID +│ ├── PhoneBookFind.php # Поиск через внешний API +│ └── PhoneBookImport.php # Обработчик импорта Excel +├── Models/ +│ ├── PhoneBook.php # Модель контакта +│ └── Settings.php # Модель настроек +├── public/assets/ +│ ├── css/ # Стили модуля +│ └── js/ # JavaScript (исходники ES6 + скомпилированные) +└── Messages/ # Переводы (26 языков) +``` + +## База данных + +SQLite база данных: `/storage/usbdisk1/mikopbx/custom_modules/ModulePhoneBook/db/module.db` + +**m_PhoneBook** — контакты: +- `id` — первичный ключ +- `number` — нормализованный номер для поиска +- `number_rep` — отображаемый формат +- `call_id` — имя контакта +- `search_index` — поле для полнотекстового поиска +- `created` — временная метка (для истечения кэша API) + +**m_ModulePhoneBook** — настройки: +- `disableInputMask` — переключатель маски ввода +- `phoneBookApiUrl` — URL внешнего API +- `phoneBookLifeTime` — время жизни кэша в секундах + +## Разработка + +### Сборка JavaScript + +```bash +# Компиляция ES6 в ES5 с помощью Babel +docker run --rm -v ~/mikopbx:/workspace ghcr.io/mikopbx/babel-compiler:latest /workspace/Extensions/[module]/public/assets/js/src/[file] extension` +``` + +### Проверка синтаксиса PHP + +```bash +php -l Lib/PhoneBookConf.php +``` + +## Ссылки + +- [Документация (RU)](https://docs.mikopbx.com/mikopbx/modules/miko/phone-book) +- [Документация (EN)](https://docs.mikopbx.com/mikopbx/english/modules/miko/module-phone-book) +- [Сайт MikoPBX](https://mikopbx.com) + +## Поддержка + +- Email: help@miko.ru +- Вопросы: [GitHub Issues](https://github.com/mikopbx/ModulePhoneBook/issues) + +## Лицензия + +GPL-3.0 — см. файл [LICENSE](LICENSE). diff --git a/Setup/PbxExtensionSetup.php b/Setup/PbxExtensionSetup.php index 8384519..1c6ea01 100644 --- a/Setup/PbxExtensionSetup.php +++ b/Setup/PbxExtensionSetup.php @@ -46,9 +46,8 @@ public function installDB(): bool $username = mb_strtolower($record->call_id); // Combine all fields into a single string $record->search_index = $username . $record->number . $record->number_rep; - $result = $record->save(); - if (!$result) { - SystemMessages::sysLogMsg(__METHOD__, implode(' ', $result->getMessages())); + if (!$record->save()) { + SystemMessages::sysLogMsg(__METHOD__, implode(' ', $record->getMessages())); return false; } } diff --git a/composer.json b/composer.json index 589bd97..596d987 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,8 @@ "description": "ModulePhoneBook", "require": { "php": "^7.4", - "maennchen/zipstream-php":"2.2.6", + "guzzlehttp/guzzle": "^7.10", + "maennchen/zipstream-php": "2.2.6", "phpoffice/phpspreadsheet": "1.29.2" }, "autoload": { diff --git a/composer.lock b/composer.lock index f37f043..62b9642 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e7b81910101d64d6e1fc21896d21e1ef", + "content-hash": "193b719b1c8fbb8d020bfbcbe0e5087b", "packages": [ { "name": "ezyang/htmlpurifier", @@ -67,6 +67,331 @@ }, "time": "2024-11-01T03:51:45+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "7.10.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-08-23T22:36:01+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-08-22T14:34:08+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "21dc724a0583619cd1652f673303492272778051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-08-23T21:21:41+00:00" + }, { "name": "maennchen/zipstream-php", "version": "2.2.6", @@ -631,6 +956,117 @@ }, "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, { "name": "symfony/polyfill-mbstring", "version": "v1.31.0", diff --git a/public/assets/js/module-phonebook-datatable.js b/public/assets/js/module-phonebook-datatable.js index 2cd08b0..c2e507b 100644 --- a/public/assets/js/module-phonebook-datatable.js +++ b/public/assets/js/module-phonebook-datatable.js @@ -92,18 +92,9 @@ var ModulePhoneBookDT = { /** * Initialize the search functionality. - * It listens for key events and applies a filter based on the user's input. + * Sets up the search input field ready for use. */ - initializeSearch: function initializeSearch() { - var _this = this; - - this.$globalSearch.on('keyup', function (e) { - var searchText = _this.$globalSearch.val().trim(); - - if (e.keyCode === 13 || e.keyCode === 8 || searchText.length === 0) { - _this.applyFilter(searchText); - } - }); + initializeSearch: function initializeSearch() {// Search handler is initialized in initializeDataTable() with debounce }, /** @@ -111,34 +102,34 @@ var ModulePhoneBookDT = { * Handles input focus, form submission, adding new rows, and delete actions. */ initializeEventListeners: function initializeEventListeners() { - var _this2 = this; + var _this = this; // Handle focus on input fields for editing this.$body.on('focusin', '.caller-id-input, .number-input', function (e) { - _this2.onFieldFocus($(e.target)); + _this.onFieldFocus($(e.target)); }); // Handle loss of focus on input fields and save changes this.$body.on('focusout', '.caller-id-input, .number-input', function () { - _this2.saveChangesForAllRows(); + _this.saveChangesForAllRows(); }); // Handle delete button click this.$body.on('click', 'a.delete', function (e) { e.preventDefault(); var id = $(e.target).closest('a').data('value'); - _this2.deleteRow($(e.target), id); + _this.deleteRow($(e.target), id); }); // Handle Enter or Tab key to trigger form submission $(document).on('keydown', function (e) { if (e.key === 'Enter' || e.key === 'Tab' && !$(':focus').hasClass('.number-input')) { - _this2.saveChangesForAllRows(); + _this.saveChangesForAllRows(); } }); // Handle adding a new row this.$addNewButton.on('click', function (e) { e.preventDefault(); - _this2.addNewRow(); + _this.addNewRow(); }); // Handle page length selection this.$pageLengthSelector.dropdown({ @@ -175,14 +166,14 @@ var ModulePhoneBookDT = { * It sends the changes for each modified row to the server. */ saveChangesForAllRows: function saveChangesForAllRows() { - var _this3 = this; + var _this2 = this; var $rows = $('.changed-field').closest('tr'); $rows.each(function (_, row) { var rowId = $(row).attr('id'); if (rowId !== undefined) { - _this3.sendChangesToServer(rowId); + _this2.sendChangesToServer(rowId); } }); }, @@ -208,7 +199,7 @@ var ModulePhoneBookDT = { * Initialize the DataTable instance with the required settings and options. */ initializeDataTable: function initializeDataTable() { - var _this4 = this; + var _this3 = this; // Get the user's saved value or use the automatically calculated value if none exists var savedPageLength = localStorage.getItem('phonebookTablePageLength'); @@ -239,10 +230,10 @@ var ModulePhoneBookDT = { sDom: 'rtip', ordering: false, createdRow: function createdRow(row, data) { - _this4.buildRowTemplate(row, data); + _this3.buildRowTemplate(row, data); }, drawCallback: function drawCallback() { - _this4.initializeInputmask($(_this4.inputNumberJQTPL)); + _this3.initializeInputmask($(_this3.inputNumberJQTPL)); }, language: SemanticLocalization.dataTableLocalisation }); @@ -259,11 +250,11 @@ var ModulePhoneBookDT = { clearTimeout(searchDebounceTimer); // Set a new timer for delayed execution searchDebounceTimer = setTimeout(function () { - var text = _this4.$globalSearch.val(); // Trigger the search if input is valid (Enter, Backspace, or more than 2 characters) + var text = _this3.$globalSearch.val(); // Trigger the search if input is valid (Enter, Backspace, or more than 2 characters) if (e.keyCode === 13 || e.keyCode === 8 || text.length >= 2) { - _this4.applyFilter(text); + _this3.applyFilter(text); } }, 500); // 500ms delay before executing the search }); // Restore the saved search phrase from DataTables state @@ -283,7 +274,7 @@ var ModulePhoneBookDT = { } this.dataTable.on('draw', function () { - _this4.$globalSearch.closest('div').removeClass('loading'); + _this3.$globalSearch.closest('div').removeClass('loading'); }); }, @@ -294,9 +285,9 @@ var ModulePhoneBookDT = { * @param {Object} data - The data object for the row. */ buildRowTemplate: function buildRowTemplate(row, data) { - var nameTemplate = "\n
\n \n
"); - var numberTemplate = "\n
\n \n
"); - var deleteButtonTemplate = "\n
\n \n \n \n
"); + var nameTemplate = "
\n \n
"); + var numberTemplate = "
\n \n
"); + var deleteButtonTemplate = ""); $('td', row).eq(0).html(''); $('td', row).eq(1).html(nameTemplate); $('td', row).eq(2).html(numberTemplate); @@ -356,17 +347,14 @@ var ModulePhoneBookDT = { * @param {string} recordId - The ID of the record to save. */ sendChangesToServer: function sendChangesToServer(recordId) { - var _this5 = this; + var _this4 = this; var callerId = $("tr#".concat(recordId, " .caller-id-input")).val(); var numberInputVal = $("tr#".concat(recordId, " .number-input")).val(); if (!callerId || !numberInputVal) return; - var number = numberInputVal.replace(/\D+/g, ''); - number = "1".concat(number.substr(number.length - 9)); var data = { call_id: callerId, number_rep: numberInputVal, - number: number, id: recordId }; this.displaySavingIcon(recordId); @@ -379,7 +367,7 @@ var ModulePhoneBookDT = { return response && response.success === true; }, onSuccess: function onSuccess(response) { - return _this5.onSaveSuccess(response, recordId); + return _this4.onSaveSuccess(response, recordId); }, onFailure: function onFailure(response) { return UserMessage.showMultiString(response.message); @@ -409,6 +397,7 @@ var ModulePhoneBookDT = { if (response.data) { var oldId = response.data.oldId || recordId; $("tr#".concat(oldId, " input")).attr('readonly', true); + $("tr#".concat(oldId, " a.delete.button")).attr('data-value', response.data.newId); $("tr#".concat(oldId, " div")).removeClass('changed-field loading').addClass('transparent'); $("tr#".concat(oldId, " .spinner.loading")).addClass('user circle').removeClass('spinner loading'); @@ -425,7 +414,7 @@ var ModulePhoneBookDT = { * @param {string} id - The ID of the record to delete. */ deleteRow: function deleteRow($target, id) { - var _this6 = this; + var _this5 = this; if (id === 'new') { $target.closest('tr').remove(); @@ -439,8 +428,8 @@ var ModulePhoneBookDT = { if (response.success) { $target.closest('tr').remove(); - if (_this6.$recordsTable.find('tbody > tr').length === 0) { - _this6.$recordsTable.find('tbody').append(''); + if (_this5.$recordsTable.find('tbody > tr').length === 0) { + _this5.$recordsTable.find('tbody').append(''); } } } @@ -487,4 +476,4 @@ var ModulePhoneBookDT = { $(document).ready(function () { ModulePhoneBookDT.initialize(); }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtcGhvbmVib29rLWRhdGF0YWJsZS5qcyJdLCJuYW1lcyI6WyJNb2R1bGVQaG9uZUJvb2tEVCIsIiRnbG9iYWxTZWFyY2giLCIkIiwiJHBhZ2VMZW5ndGhTZWxlY3RvciIsIiRzZWFyY2hFeHRlbnNpb25zSW5wdXQiLCJkYXRhVGFibGUiLCIkYm9keSIsIiRkaXNhYmxlSW5wdXRNYXNrVG9nZ2xlIiwiJHJlY29yZHNUYWJsZSIsIiRhZGROZXdCdXR0b24iLCJpbnB1dE51bWJlckpRVFBMIiwiJG1hc2tMaXN0IiwiZ2V0TmV3UmVjb3Jkc0FKQVhVcmwiLCJnbG9iYWxSb290VXJsIiwiZGVsZXRlUmVjb3JkQUpBWFVybCIsInNhdmVSZWNvcmRBSkFYVXJsIiwiaW5pdGlhbGl6ZSIsImluaXRpYWxpemVTZWFyY2giLCJpbml0aWFsaXplRGF0YVRhYmxlIiwiaW5pdGlhbGl6ZUV2ZW50TGlzdGVuZXJzIiwib24iLCJlIiwic2VhcmNoVGV4dCIsInZhbCIsInRyaW0iLCJrZXlDb2RlIiwibGVuZ3RoIiwiYXBwbHlGaWx0ZXIiLCJvbkZpZWxkRm9jdXMiLCJ0YXJnZXQiLCJzYXZlQ2hhbmdlc0ZvckFsbFJvd3MiLCJwcmV2ZW50RGVmYXVsdCIsImlkIiwiY2xvc2VzdCIsImRhdGEiLCJkZWxldGVSb3ciLCJkb2N1bWVudCIsImtleSIsImhhc0NsYXNzIiwiYWRkTmV3Um93IiwiZHJvcGRvd24iLCJvbkNoYW5nZSIsInBhZ2VMZW5ndGgiLCJjYWxjdWxhdGVQYWdlTGVuZ3RoIiwibG9jYWxTdG9yYWdlIiwicmVtb3ZlSXRlbSIsInNldEl0ZW0iLCJwYWdlIiwibGVuIiwiZHJhdyIsImV2ZW50Iiwic3RvcFByb3BhZ2F0aW9uIiwiJGlucHV0IiwidHJhbnNpdGlvbiIsInJlbW92ZUNsYXNzIiwiYWRkQ2xhc3MiLCJhdHRyIiwiJHJvd3MiLCJlYWNoIiwiXyIsInJvdyIsInJvd0lkIiwidW5kZWZpbmVkIiwic2VuZENoYW5nZXNUb1NlcnZlciIsIiRlbXB0eVJvdyIsInJlbW92ZSIsIm5ld0lkIiwiTWF0aCIsImZsb29yIiwicmFuZG9tIiwibmV3Um93VGVtcGxhdGUiLCJmaW5kIiwicHJlcGVuZCIsIiRuZXdSb3ciLCJmb2N1cyIsImluaXRpYWxpemVJbnB1dG1hc2siLCJzYXZlZFBhZ2VMZW5ndGgiLCJnZXRJdGVtIiwic2VhcmNoIiwic2VydmVyU2lkZSIsInByb2Nlc3NpbmciLCJhamF4IiwidXJsIiwidHlwZSIsImRhdGFTcmMiLCJjb2x1bW5zIiwicGFnaW5nIiwiZGVmZXJSZW5kZXIiLCJzRG9tIiwib3JkZXJpbmciLCJjcmVhdGVkUm93IiwiYnVpbGRSb3dUZW1wbGF0ZSIsImRyYXdDYWxsYmFjayIsImxhbmd1YWdlIiwiU2VtYW50aWNMb2NhbGl6YXRpb24iLCJkYXRhVGFibGVMb2NhbGlzYXRpb24iLCJEYXRhVGFibGUiLCJzZWFyY2hEZWJvdW5jZVRpbWVyIiwiY2xlYXJUaW1lb3V0Iiwic2V0VGltZW91dCIsInRleHQiLCJzdGF0ZSIsImxvYWRlZCIsInNlYXJjaFZhbHVlIiwiZ2V0UXVlcnlQYXJhbSIsIm5hbWVUZW1wbGF0ZSIsImNhbGxfaWQiLCJudW1iZXJUZW1wbGF0ZSIsIm51bWJlciIsImRlbGV0ZUJ1dHRvblRlbXBsYXRlIiwiRFRfUm93SWQiLCJlcSIsImh0bWwiLCIkY2hhbmdlZEZpZWxkcyIsIm9iaiIsIiRlbCIsImNoZWNrYm94IiwibWFza3NTb3J0IiwiSW5wdXRNYXNrUGF0dGVybnMiLCJpbnB1dG1hc2tzIiwiaW5wdXRtYXNrIiwiZGVmaW5pdGlvbnMiLCJ2YWxpZGF0b3IiLCJjYXJkaW5hbGl0eSIsInNob3dNYXNrT25Ib3ZlciIsIm9uQmVmb3JlUGFzdGUiLCJjYk9uTnVtYmVyQmVmb3JlUGFzdGUiLCJtYXRjaCIsInJlcGxhY2UiLCJsaXN0IiwibGlzdEtleSIsInJlY29yZElkIiwiY2FsbGVySWQiLCJudW1iZXJJbnB1dFZhbCIsInN1YnN0ciIsIm51bWJlcl9yZXAiLCJkaXNwbGF5U2F2aW5nSWNvbiIsImFwaSIsIm1ldGhvZCIsInN1Y2Nlc3NUZXN0IiwicmVzcG9uc2UiLCJzdWNjZXNzIiwib25TdWNjZXNzIiwib25TYXZlU3VjY2VzcyIsIm9uRmFpbHVyZSIsIlVzZXJNZXNzYWdlIiwic2hvd011bHRpU3RyaW5nIiwibWVzc2FnZSIsIm9uRXJyb3IiLCJlcnJvck1lc3NhZ2UiLCJlbGVtZW50IiwieGhyIiwic3RhdHVzIiwid2luZG93IiwibG9jYXRpb24iLCJvbGRJZCIsIiR0YXJnZXQiLCJhcHBlbmQiLCJwYXN0ZWRWYWx1ZSIsInJvd0hlaWdodCIsImZpcnN0Iiwib3V0ZXJIZWlnaHQiLCJ3aW5kb3dIZWlnaHQiLCJpbm5lckhlaWdodCIsImhlYWRlckZvb3RlckhlaWdodCIsIm1heCIsInBhcmFtIiwidXJsUGFyYW1zIiwiVVJMU2VhcmNoUGFyYW1zIiwiZ2V0IiwicmVhZHkiXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUVBLElBQU1BLGlCQUFpQixHQUFHO0FBRXRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lDLEVBQUFBLGFBQWEsRUFBRUMsQ0FBQyxDQUFDLGdCQUFELENBTk07O0FBUXRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lDLEVBQUFBLG1CQUFtQixFQUFDRCxDQUFDLENBQUMscUJBQUQsQ0FaQzs7QUFjdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUUsRUFBQUEsc0JBQXNCLEVBQUVGLENBQUMsQ0FBQywwQkFBRCxDQWxCSDs7QUFxQnRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lHLEVBQUFBLFNBQVMsRUFBRSxFQXpCVzs7QUEyQnRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lDLEVBQUFBLEtBQUssRUFBRUosQ0FBQyxDQUFDLE1BQUQsQ0EvQmM7QUFpQ3RCO0FBQ0FLLEVBQUFBLHVCQUF1QixFQUFFTCxDQUFDLENBQUMscUJBQUQsQ0FsQ0o7O0FBb0N0QjtBQUNKO0FBQ0E7QUFDQTtBQUNJTSxFQUFBQSxhQUFhLEVBQUVOLENBQUMsQ0FBQyxrQkFBRCxDQXhDTTs7QUEwQ3RCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lPLEVBQUFBLGFBQWEsRUFBRVAsQ0FBQyxDQUFDLGlCQUFELENBOUNNOztBQWdEdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSVEsRUFBQUEsZ0JBQWdCLEVBQUUsb0JBcERJOztBQXNEdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsU0FBUyxFQUFFLElBMURXO0FBNER0QjtBQUNBQyxFQUFBQSxvQkFBb0IsWUFBS0MsYUFBTCxvQ0E3REU7QUErRHRCQyxFQUFBQSxtQkFBbUIsWUFBS0QsYUFBTCw2QkEvREc7QUFpRXRCRSxFQUFBQSxpQkFBaUIsWUFBS0YsYUFBTCwyQkFqRUs7O0FBbUV0QjtBQUNKO0FBQ0E7QUFDQTtBQUNJRyxFQUFBQSxVQXZFc0Isd0JBdUVUO0FBQ1QsU0FBS0MsZ0JBQUw7QUFDQSxTQUFLQyxtQkFBTDtBQUNBLFNBQUtDLHdCQUFMO0FBQ0gsR0EzRXFCOztBQTZFdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUYsRUFBQUEsZ0JBakZzQiw4QkFpRkg7QUFBQTs7QUFDZixTQUFLaEIsYUFBTCxDQUFtQm1CLEVBQW5CLENBQXNCLE9BQXRCLEVBQStCLFVBQUNDLENBQUQsRUFBTztBQUNsQyxVQUFNQyxVQUFVLEdBQUcsS0FBSSxDQUFDckIsYUFBTCxDQUFtQnNCLEdBQW5CLEdBQXlCQyxJQUF6QixFQUFuQjs7QUFDQSxVQUFJSCxDQUFDLENBQUNJLE9BQUYsS0FBYyxFQUFkLElBQW9CSixDQUFDLENBQUNJLE9BQUYsS0FBYyxDQUFsQyxJQUF1Q0gsVUFBVSxDQUFDSSxNQUFYLEtBQXNCLENBQWpFLEVBQW9FO0FBQ2hFLFFBQUEsS0FBSSxDQUFDQyxXQUFMLENBQWlCTCxVQUFqQjtBQUNIO0FBQ0osS0FMRDtBQU1ILEdBeEZxQjs7QUEwRnRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lILEVBQUFBLHdCQTlGc0Isc0NBOEZLO0FBQUE7O0FBRXZCO0FBQ0EsU0FBS2IsS0FBTCxDQUFXYyxFQUFYLENBQWMsU0FBZCxFQUF5QixpQ0FBekIsRUFBNEQsVUFBQ0MsQ0FBRCxFQUFPO0FBQy9ELE1BQUEsTUFBSSxDQUFDTyxZQUFMLENBQWtCMUIsQ0FBQyxDQUFDbUIsQ0FBQyxDQUFDUSxNQUFILENBQW5CO0FBQ0gsS0FGRCxFQUh1QixDQU92Qjs7QUFDQSxTQUFLdkIsS0FBTCxDQUFXYyxFQUFYLENBQWMsVUFBZCxFQUEwQixpQ0FBMUIsRUFBNkQsWUFBTTtBQUMvRCxNQUFBLE1BQUksQ0FBQ1UscUJBQUw7QUFDSCxLQUZELEVBUnVCLENBWXZCOztBQUNBLFNBQUt4QixLQUFMLENBQVdjLEVBQVgsQ0FBYyxPQUFkLEVBQXVCLFVBQXZCLEVBQW1DLFVBQUNDLENBQUQsRUFBTztBQUN0Q0EsTUFBQUEsQ0FBQyxDQUFDVSxjQUFGO0FBQ0EsVUFBTUMsRUFBRSxHQUFHOUIsQ0FBQyxDQUFDbUIsQ0FBQyxDQUFDUSxNQUFILENBQUQsQ0FBWUksT0FBWixDQUFvQixHQUFwQixFQUF5QkMsSUFBekIsQ0FBOEIsT0FBOUIsQ0FBWDs7QUFDQSxNQUFBLE1BQUksQ0FBQ0MsU0FBTCxDQUFlakMsQ0FBQyxDQUFDbUIsQ0FBQyxDQUFDUSxNQUFILENBQWhCLEVBQTRCRyxFQUE1QjtBQUNILEtBSkQsRUFidUIsQ0FtQnZCOztBQUNBOUIsSUFBQUEsQ0FBQyxDQUFDa0MsUUFBRCxDQUFELENBQVloQixFQUFaLENBQWUsU0FBZixFQUEwQixVQUFDQyxDQUFELEVBQU87QUFDN0IsVUFBSUEsQ0FBQyxDQUFDZ0IsR0FBRixLQUFVLE9BQVYsSUFBc0JoQixDQUFDLENBQUNnQixHQUFGLEtBQVUsS0FBVixJQUFtQixDQUFDbkMsQ0FBQyxDQUFDLFFBQUQsQ0FBRCxDQUFZb0MsUUFBWixDQUFxQixlQUFyQixDQUE5QyxFQUFzRjtBQUNsRixRQUFBLE1BQUksQ0FBQ1IscUJBQUw7QUFDSDtBQUNKLEtBSkQsRUFwQnVCLENBMEJ2Qjs7QUFDQSxTQUFLckIsYUFBTCxDQUFtQlcsRUFBbkIsQ0FBc0IsT0FBdEIsRUFBK0IsVUFBQ0MsQ0FBRCxFQUFPO0FBQ2xDQSxNQUFBQSxDQUFDLENBQUNVLGNBQUY7O0FBQ0EsTUFBQSxNQUFJLENBQUNRLFNBQUw7QUFDSCxLQUhELEVBM0J1QixDQWdDdkI7O0FBQ0EsU0FBS3BDLG1CQUFMLENBQXlCcUMsUUFBekIsQ0FBa0M7QUFDOUJDLE1BQUFBLFFBRDhCLG9CQUNyQkMsVUFEcUIsRUFDVDtBQUNqQixZQUFJQSxVQUFVLEtBQUcsTUFBakIsRUFBd0I7QUFDcEJBLFVBQUFBLFVBQVUsR0FBRyxLQUFLQyxtQkFBTCxFQUFiO0FBQ0FDLFVBQUFBLFlBQVksQ0FBQ0MsVUFBYixDQUF3QiwwQkFBeEI7QUFDSCxTQUhELE1BR087QUFDSEQsVUFBQUEsWUFBWSxDQUFDRSxPQUFiLENBQXFCLDBCQUFyQixFQUFpREosVUFBakQ7QUFDSDs7QUFDRDFDLFFBQUFBLGlCQUFpQixDQUFDSyxTQUFsQixDQUE0QjBDLElBQTVCLENBQWlDQyxHQUFqQyxDQUFxQ04sVUFBckMsRUFBaURPLElBQWpEO0FBQ0g7QUFUNkIsS0FBbEMsRUFqQ3VCLENBNkN2Qjs7QUFDQSxTQUFLOUMsbUJBQUwsQ0FBeUJpQixFQUF6QixDQUE0QixPQUE1QixFQUFxQyxVQUFTOEIsS0FBVCxFQUFnQjtBQUNqREEsTUFBQUEsS0FBSyxDQUFDQyxlQUFOLEdBRGlELENBQ3hCO0FBQzVCLEtBRkQ7QUFHSCxHQS9JcUI7O0FBa0p0QjtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0l2QixFQUFBQSxZQXZKc0Isd0JBdUpUd0IsTUF2SlMsRUF1SkQ7QUFDakJBLElBQUFBLE1BQU0sQ0FBQ0MsVUFBUCxDQUFrQixNQUFsQjtBQUNBRCxJQUFBQSxNQUFNLENBQUNuQixPQUFQLENBQWUsS0FBZixFQUFzQnFCLFdBQXRCLENBQWtDLGFBQWxDLEVBQWlEQyxRQUFqRCxDQUEwRCxlQUExRDtBQUNBSCxJQUFBQSxNQUFNLENBQUNJLElBQVAsQ0FBWSxVQUFaLEVBQXdCLEtBQXhCO0FBQ0gsR0EzSnFCOztBQTZKdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSTFCLEVBQUFBLHFCQWpLc0IsbUNBaUtFO0FBQUE7O0FBQ3BCLFFBQU0yQixLQUFLLEdBQUd2RCxDQUFDLENBQUMsZ0JBQUQsQ0FBRCxDQUFvQitCLE9BQXBCLENBQTRCLElBQTVCLENBQWQ7QUFDQXdCLElBQUFBLEtBQUssQ0FBQ0MsSUFBTixDQUFXLFVBQUNDLENBQUQsRUFBSUMsR0FBSixFQUFZO0FBQ25CLFVBQU1DLEtBQUssR0FBRzNELENBQUMsQ0FBQzBELEdBQUQsQ0FBRCxDQUFPSixJQUFQLENBQVksSUFBWixDQUFkOztBQUNBLFVBQUlLLEtBQUssS0FBS0MsU0FBZCxFQUF5QjtBQUNyQixRQUFBLE1BQUksQ0FBQ0MsbUJBQUwsQ0FBeUJGLEtBQXpCO0FBQ0g7QUFDSixLQUxEO0FBTUgsR0F6S3FCOztBQTJLdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSXRCLEVBQUFBLFNBL0tzQix1QkErS1Y7QUFDUixRQUFNeUIsU0FBUyxHQUFHOUQsQ0FBQyxDQUFDLG1CQUFELENBQW5CO0FBQ0EsUUFBSThELFNBQVMsQ0FBQ3RDLE1BQWQsRUFBc0JzQyxTQUFTLENBQUNDLE1BQVY7QUFFdEIsU0FBS25DLHFCQUFMO0FBRUEsUUFBTW9DLEtBQUssZ0JBQVNDLElBQUksQ0FBQ0MsS0FBTCxDQUFXRCxJQUFJLENBQUNFLE1BQUwsS0FBZ0IsR0FBM0IsQ0FBVCxDQUFYO0FBQ0EsUUFBTUMsY0FBYyxvQ0FDTkosS0FETSxncEJBQXBCO0FBWUEsU0FBSzFELGFBQUwsQ0FBbUIrRCxJQUFuQixDQUF3QixPQUF4QixFQUFpQ0MsT0FBakMsQ0FBeUNGLGNBQXpDO0FBQ0EsUUFBTUcsT0FBTyxHQUFHdkUsQ0FBQyxZQUFLZ0UsS0FBTCxFQUFqQjtBQUNBTyxJQUFBQSxPQUFPLENBQUNGLElBQVIsQ0FBYSxPQUFiLEVBQXNCbEIsVUFBdEIsQ0FBaUMsTUFBakM7QUFDQW9CLElBQUFBLE9BQU8sQ0FBQ0YsSUFBUixDQUFhLGtCQUFiLEVBQWlDRyxLQUFqQztBQUNBLFNBQUtDLG1CQUFMLENBQXlCRixPQUFPLENBQUNGLElBQVIsQ0FBYSxlQUFiLENBQXpCO0FBQ0gsR0F2TXFCOztBQXlNdEI7QUFDSjtBQUNBO0FBQ0lyRCxFQUFBQSxtQkE1TXNCLGlDQTRNQTtBQUFBOztBQUVsQjtBQUNBLFFBQU0wRCxlQUFlLEdBQUdoQyxZQUFZLENBQUNpQyxPQUFiLENBQXFCLDBCQUFyQixDQUF4QjtBQUNBLFFBQU1uQyxVQUFVLEdBQUdrQyxlQUFlLEdBQUdBLGVBQUgsR0FBcUIsS0FBS2pDLG1CQUFMLEVBQXZEO0FBRUEsU0FBS25DLGFBQUwsQ0FBbUJILFNBQW5CLENBQTZCO0FBQ3pCeUUsTUFBQUEsTUFBTSxFQUFFO0FBQUVBLFFBQUFBLE1BQU0sRUFBRSxLQUFLN0UsYUFBTCxDQUFtQnNCLEdBQW5CO0FBQVYsT0FEaUI7QUFFekJ3RCxNQUFBQSxVQUFVLEVBQUUsSUFGYTtBQUd6QkMsTUFBQUEsVUFBVSxFQUFFLElBSGE7QUFJekJDLE1BQUFBLElBQUksRUFBRTtBQUNGQyxRQUFBQSxHQUFHLEVBQUUsS0FBS3RFLG9CQURSO0FBRUZ1RSxRQUFBQSxJQUFJLEVBQUUsTUFGSjtBQUdGQyxRQUFBQSxPQUFPLEVBQUU7QUFIUCxPQUptQjtBQVN6QkMsTUFBQUEsT0FBTyxFQUFFLENBQ0w7QUFBRW5ELFFBQUFBLElBQUksRUFBRTtBQUFSLE9BREssRUFFTDtBQUFFQSxRQUFBQSxJQUFJLEVBQUU7QUFBUixPQUZLLEVBR0w7QUFBRUEsUUFBQUEsSUFBSSxFQUFFO0FBQVIsT0FISyxFQUlMO0FBQUVBLFFBQUFBLElBQUksRUFBRTtBQUFSLE9BSkssQ0FUZ0I7QUFlekJvRCxNQUFBQSxNQUFNLEVBQUUsSUFmaUI7QUFnQnpCNUMsTUFBQUEsVUFBVSxFQUFFQSxVQWhCYTtBQWlCekI2QyxNQUFBQSxXQUFXLEVBQUUsSUFqQlk7QUFrQnpCQyxNQUFBQSxJQUFJLEVBQUUsTUFsQm1CO0FBbUJ6QkMsTUFBQUEsUUFBUSxFQUFFLEtBbkJlO0FBb0J6QkMsTUFBQUEsVUFBVSxFQUFFLG9CQUFDOUIsR0FBRCxFQUFNMUIsSUFBTixFQUFlO0FBQ3ZCLFFBQUEsTUFBSSxDQUFDeUQsZ0JBQUwsQ0FBc0IvQixHQUF0QixFQUEyQjFCLElBQTNCO0FBQ0gsT0F0QndCO0FBdUJ6QjBELE1BQUFBLFlBQVksRUFBRSx3QkFBTTtBQUNoQixRQUFBLE1BQUksQ0FBQ2pCLG1CQUFMLENBQXlCekUsQ0FBQyxDQUFDLE1BQUksQ0FBQ1EsZ0JBQU4sQ0FBMUI7QUFDSCxPQXpCd0I7QUEwQnpCbUYsTUFBQUEsUUFBUSxFQUFFQyxvQkFBb0IsQ0FBQ0M7QUExQk4sS0FBN0I7QUE2QkEsU0FBSzFGLFNBQUwsR0FBaUIsS0FBS0csYUFBTCxDQUFtQndGLFNBQW5CLEVBQWpCLENBbkNrQixDQXNDbEI7O0FBQ0EsUUFBSXBCLGVBQUosRUFBcUI7QUFDakIsV0FBS3pFLG1CQUFMLENBQXlCcUMsUUFBekIsQ0FBa0MsV0FBbEMsRUFBK0NvQyxlQUEvQztBQUNILEtBekNpQixDQTRDbEI7OztBQUNBLFFBQUlxQixtQkFBbUIsR0FBRyxJQUExQjtBQUVBLFNBQUtoRyxhQUFMLENBQW1CbUIsRUFBbkIsQ0FBc0IsT0FBdEIsRUFBK0IsVUFBQ0MsQ0FBRCxFQUFPO0FBQ2xDO0FBQ0E2RSxNQUFBQSxZQUFZLENBQUNELG1CQUFELENBQVosQ0FGa0MsQ0FJbEM7O0FBQ0FBLE1BQUFBLG1CQUFtQixHQUFHRSxVQUFVLENBQUMsWUFBTTtBQUNuQyxZQUFNQyxJQUFJLEdBQUcsTUFBSSxDQUFDbkcsYUFBTCxDQUFtQnNCLEdBQW5CLEVBQWIsQ0FEbUMsQ0FFbkM7OztBQUNBLFlBQUlGLENBQUMsQ0FBQ0ksT0FBRixLQUFjLEVBQWQsSUFBb0JKLENBQUMsQ0FBQ0ksT0FBRixLQUFjLENBQWxDLElBQXVDMkUsSUFBSSxDQUFDMUUsTUFBTCxJQUFlLENBQTFELEVBQTZEO0FBQ3pELFVBQUEsTUFBSSxDQUFDQyxXQUFMLENBQWlCeUUsSUFBakI7QUFDSDtBQUNKLE9BTitCLEVBTTdCLEdBTjZCLENBQWhDLENBTGtDLENBV3pCO0FBQ1osS0FaRCxFQS9Da0IsQ0E2RGxCOztBQUNBLFFBQU1DLEtBQUssR0FBRyxLQUFLaEcsU0FBTCxDQUFlZ0csS0FBZixDQUFxQkMsTUFBckIsRUFBZDs7QUFDQSxRQUFJRCxLQUFLLElBQUlBLEtBQUssQ0FBQ3ZCLE1BQW5CLEVBQTJCO0FBQ3ZCLFdBQUs3RSxhQUFMLENBQW1Cc0IsR0FBbkIsQ0FBdUI4RSxLQUFLLENBQUN2QixNQUFOLENBQWFBLE1BQXBDLEVBRHVCLENBQ3NCO0FBQ2hELEtBakVpQixDQW1FbEI7OztBQUNBLFFBQU15QixXQUFXLEdBQUcsS0FBS0MsYUFBTCxDQUFtQixRQUFuQixDQUFwQixDQXBFa0IsQ0FzRWxCOztBQUNBLFFBQUlELFdBQUosRUFBaUI7QUFDYixXQUFLdEcsYUFBTCxDQUFtQnNCLEdBQW5CLENBQXVCZ0YsV0FBdkI7QUFDQSxXQUFLNUUsV0FBTCxDQUFpQjRFLFdBQWpCO0FBQ0g7O0FBRUQsU0FBS2xHLFNBQUwsQ0FBZWUsRUFBZixDQUFrQixNQUFsQixFQUEwQixZQUFNO0FBQzVCLE1BQUEsTUFBSSxDQUFDbkIsYUFBTCxDQUFtQmdDLE9BQW5CLENBQTJCLEtBQTNCLEVBQWtDcUIsV0FBbEMsQ0FBOEMsU0FBOUM7QUFDSCxLQUZEO0FBR0gsR0EzUnFCOztBQTZSdEI7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0lxQyxFQUFBQSxnQkFuU3NCLDRCQW1TTC9CLEdBblNLLEVBbVNBMUIsSUFuU0EsRUFtU007QUFDeEIsUUFBTXVFLFlBQVksMEpBRTBDdkUsSUFBSSxDQUFDd0UsT0FGL0MsOEJBQWxCO0FBSUEsUUFBTUMsY0FBYyxpSkFFcUN6RSxJQUFJLENBQUMwRSxNQUYxQyw4QkFBcEI7QUFJQSxRQUFNQyxvQkFBb0IsaUlBRVEzRSxJQUFJLENBQUM0RSxRQUZiLG1JQUExQjtBQU9BNUcsSUFBQUEsQ0FBQyxDQUFDLElBQUQsRUFBTzBELEdBQVAsQ0FBRCxDQUFhbUQsRUFBYixDQUFnQixDQUFoQixFQUFtQkMsSUFBbkIsQ0FBd0IscUNBQXhCO0FBQ0E5RyxJQUFBQSxDQUFDLENBQUMsSUFBRCxFQUFPMEQsR0FBUCxDQUFELENBQWFtRCxFQUFiLENBQWdCLENBQWhCLEVBQW1CQyxJQUFuQixDQUF3QlAsWUFBeEI7QUFDQXZHLElBQUFBLENBQUMsQ0FBQyxJQUFELEVBQU8wRCxHQUFQLENBQUQsQ0FBYW1ELEVBQWIsQ0FBZ0IsQ0FBaEIsRUFBbUJDLElBQW5CLENBQXdCTCxjQUF4QjtBQUNBekcsSUFBQUEsQ0FBQyxDQUFDLElBQUQsRUFBTzBELEdBQVAsQ0FBRCxDQUFhbUQsRUFBYixDQUFnQixDQUFoQixFQUFtQkMsSUFBbkIsQ0FBd0JILG9CQUF4QjtBQUNILEdBdlRxQjs7QUF5VHRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDSWxGLEVBQUFBLFdBOVRzQix1QkE4VFZ5RSxJQTlUVSxFQThUSjtBQUNkLFFBQU1hLGNBQWMsR0FBRy9HLENBQUMsQ0FBQyxnQkFBRCxDQUF4QjtBQUNBK0csSUFBQUEsY0FBYyxDQUFDdkQsSUFBZixDQUFvQixVQUFDQyxDQUFELEVBQUl1RCxHQUFKLEVBQVk7QUFDNUIsVUFBTTlELE1BQU0sR0FBR2xELENBQUMsQ0FBQ2dILEdBQUQsQ0FBRCxDQUFPM0MsSUFBUCxDQUFZLE9BQVosQ0FBZjtBQUNBbkIsTUFBQUEsTUFBTSxDQUFDN0IsR0FBUCxDQUFXNkIsTUFBTSxDQUFDbEIsSUFBUCxDQUFZLE9BQVosQ0FBWDtBQUNBa0IsTUFBQUEsTUFBTSxDQUFDSSxJQUFQLENBQVksVUFBWixFQUF3QixJQUF4QjtBQUNBdEQsTUFBQUEsQ0FBQyxDQUFDZ0gsR0FBRCxDQUFELENBQU81RCxXQUFQLENBQW1CLGVBQW5CLEVBQW9DQyxRQUFwQyxDQUE2QyxhQUE3QztBQUNILEtBTEQ7QUFNQSxTQUFLbEQsU0FBTCxDQUFleUUsTUFBZixDQUFzQnNCLElBQXRCLEVBQTRCbkQsSUFBNUI7QUFDQSxTQUFLaEQsYUFBTCxDQUFtQmdDLE9BQW5CLENBQTJCLEtBQTNCLEVBQWtDc0IsUUFBbEMsQ0FBMkMsU0FBM0M7QUFDSCxHQXhVcUI7O0FBMFV0QjtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0lvQixFQUFBQSxtQkEvVXNCLCtCQStVRndDLEdBL1VFLEVBK1VHO0FBQ3JCLFFBQUksS0FBSzVHLHVCQUFMLENBQTZCNkcsUUFBN0IsQ0FBc0MsWUFBdEMsQ0FBSixFQUF5RDs7QUFFekQsUUFBSSxLQUFLekcsU0FBTCxLQUFtQixJQUF2QixFQUE2QjtBQUN6QixXQUFLQSxTQUFMLEdBQWlCVCxDQUFDLENBQUNtSCxTQUFGLENBQVlDLGlCQUFaLEVBQStCLENBQUMsR0FBRCxDQUEvQixFQUFzQyxTQUF0QyxFQUFpRCxNQUFqRCxDQUFqQjtBQUNIOztBQUVESCxJQUFBQSxHQUFHLENBQUNJLFVBQUosQ0FBZTtBQUNYQyxNQUFBQSxTQUFTLEVBQUU7QUFDUEMsUUFBQUEsV0FBVyxFQUFFO0FBQ1QsZUFBSztBQUFFQyxZQUFBQSxTQUFTLEVBQUUsT0FBYjtBQUFzQkMsWUFBQUEsV0FBVyxFQUFFO0FBQW5DO0FBREksU0FETjtBQUlQQyxRQUFBQSxlQUFlLEVBQUUsS0FKVjtBQUtQQyxRQUFBQSxhQUFhLEVBQUUsS0FBS0M7QUFMYixPQURBO0FBUVhDLE1BQUFBLEtBQUssRUFBRSxPQVJJO0FBU1hDLE1BQUFBLE9BQU8sRUFBRSxHQVRFO0FBVVhDLE1BQUFBLElBQUksRUFBRSxLQUFLdEgsU0FWQTtBQVdYdUgsTUFBQUEsT0FBTyxFQUFFO0FBWEUsS0FBZjtBQWFILEdBbldxQjs7QUFxV3RCO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDSW5FLEVBQUFBLG1CQTFXc0IsK0JBMFdGb0UsUUExV0UsRUEwV1E7QUFBQTs7QUFDMUIsUUFBTUMsUUFBUSxHQUFHbEksQ0FBQyxjQUFPaUksUUFBUCx1QkFBRCxDQUFxQzVHLEdBQXJDLEVBQWpCO0FBQ0EsUUFBTThHLGNBQWMsR0FBR25JLENBQUMsY0FBT2lJLFFBQVAsb0JBQUQsQ0FBa0M1RyxHQUFsQyxFQUF2QjtBQUVBLFFBQUksQ0FBQzZHLFFBQUQsSUFBYSxDQUFDQyxjQUFsQixFQUFrQztBQUVsQyxRQUFJekIsTUFBTSxHQUFHeUIsY0FBYyxDQUFDTCxPQUFmLENBQXVCLE1BQXZCLEVBQStCLEVBQS9CLENBQWI7QUFDQXBCLElBQUFBLE1BQU0sY0FBT0EsTUFBTSxDQUFDMEIsTUFBUCxDQUFjMUIsTUFBTSxDQUFDbEYsTUFBUCxHQUFnQixDQUE5QixDQUFQLENBQU47QUFFQSxRQUFNUSxJQUFJLEdBQUc7QUFDVHdFLE1BQUFBLE9BQU8sRUFBRTBCLFFBREE7QUFFVEcsTUFBQUEsVUFBVSxFQUFFRixjQUZIO0FBR1R6QixNQUFBQSxNQUFNLEVBQU5BLE1BSFM7QUFJVDVFLE1BQUFBLEVBQUUsRUFBRW1HO0FBSkssS0FBYjtBQU9BLFNBQUtLLGlCQUFMLENBQXVCTCxRQUF2QjtBQUVBakksSUFBQUEsQ0FBQyxDQUFDdUksR0FBRixDQUFNO0FBQ0Z2RCxNQUFBQSxHQUFHLEVBQUUsS0FBS25FLGlCQURSO0FBRUYySCxNQUFBQSxNQUFNLEVBQUUsTUFGTjtBQUdGdEgsTUFBQUEsRUFBRSxFQUFFLEtBSEY7QUFJRmMsTUFBQUEsSUFBSSxFQUFKQSxJQUpFO0FBS0Z5RyxNQUFBQSxXQUFXLEVBQUUscUJBQUNDLFFBQUQ7QUFBQSxlQUFjQSxRQUFRLElBQUlBLFFBQVEsQ0FBQ0MsT0FBVCxLQUFxQixJQUEvQztBQUFBLE9BTFg7QUFNRkMsTUFBQUEsU0FBUyxFQUFFLG1CQUFDRixRQUFEO0FBQUEsZUFBYyxNQUFJLENBQUNHLGFBQUwsQ0FBbUJILFFBQW5CLEVBQTZCVCxRQUE3QixDQUFkO0FBQUEsT0FOVDtBQU9GYSxNQUFBQSxTQUFTLEVBQUUsbUJBQUNKLFFBQUQ7QUFBQSxlQUFjSyxXQUFXLENBQUNDLGVBQVosQ0FBNEJOLFFBQVEsQ0FBQ08sT0FBckMsQ0FBZDtBQUFBLE9BUFQ7QUFRRkMsTUFBQUEsT0FBTyxFQUFFLGlCQUFDQyxZQUFELEVBQWVDLE9BQWYsRUFBd0JDLEdBQXhCLEVBQWdDO0FBQ3JDLFlBQUlBLEdBQUcsQ0FBQ0MsTUFBSixLQUFlLEdBQW5CLEVBQXdCQyxNQUFNLENBQUNDLFFBQVAsYUFBcUI3SSxhQUFyQjtBQUMzQjtBQVZDLEtBQU47QUFZSCxHQXhZcUI7O0FBMFl0QjtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0kySCxFQUFBQSxpQkEvWXNCLDZCQStZSkwsUUEvWUksRUErWU07QUFDeEJqSSxJQUFBQSxDQUFDLGNBQU9pSSxRQUFQLG1CQUFELENBQ0s3RSxXQURMLENBQ2lCLGFBRGpCLEVBRUtDLFFBRkwsQ0FFYyxpQkFGZDtBQUdILEdBblpxQjs7QUFxWnRCO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNJd0YsRUFBQUEsYUEzWnNCLHlCQTJaUkgsUUEzWlEsRUEyWkVULFFBM1pGLEVBMlpZO0FBQzlCLFFBQUlTLFFBQVEsQ0FBQzFHLElBQWIsRUFBbUI7QUFDZixVQUFJeUgsS0FBSyxHQUFHZixRQUFRLENBQUMxRyxJQUFULENBQWN5SCxLQUFkLElBQXVCeEIsUUFBbkM7QUFDQWpJLE1BQUFBLENBQUMsY0FBT3lKLEtBQVAsWUFBRCxDQUF1Qm5HLElBQXZCLENBQTRCLFVBQTVCLEVBQXdDLElBQXhDO0FBQ0F0RCxNQUFBQSxDQUFDLGNBQU95SixLQUFQLFVBQUQsQ0FBcUJyRyxXQUFyQixDQUFpQyx1QkFBakMsRUFBMERDLFFBQTFELENBQW1FLGFBQW5FO0FBQ0FyRCxNQUFBQSxDQUFDLGNBQU95SixLQUFQLHVCQUFELENBQWtDcEcsUUFBbEMsQ0FBMkMsYUFBM0MsRUFBMERELFdBQTFELENBQXNFLGlCQUF0RTs7QUFDQSxVQUFJcUcsS0FBSyxLQUFLZixRQUFRLENBQUMxRyxJQUFULENBQWNnQyxLQUE1QixFQUFtQztBQUMvQmhFLFFBQUFBLENBQUMsY0FBT3lKLEtBQVAsRUFBRCxDQUFpQm5HLElBQWpCLENBQXNCLElBQXRCLEVBQTRCb0YsUUFBUSxDQUFDMUcsSUFBVCxDQUFjZ0MsS0FBMUM7QUFDSDtBQUNKO0FBQ0osR0FyYXFCOztBQXVhdEI7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0kvQixFQUFBQSxTQTdhc0IscUJBNmFaeUgsT0E3YVksRUE2YUg1SCxFQTdhRyxFQTZhQztBQUFBOztBQUNuQixRQUFJQSxFQUFFLEtBQUssS0FBWCxFQUFrQjtBQUNkNEgsTUFBQUEsT0FBTyxDQUFDM0gsT0FBUixDQUFnQixJQUFoQixFQUFzQmdDLE1BQXRCO0FBQ0E7QUFDSDs7QUFFRC9ELElBQUFBLENBQUMsQ0FBQ3VJLEdBQUYsQ0FBTTtBQUNGdkQsTUFBQUEsR0FBRyxZQUFLLEtBQUtwRSxtQkFBVixjQUFpQ2tCLEVBQWpDLENBREQ7QUFFRlosTUFBQUEsRUFBRSxFQUFFLEtBRkY7QUFHRjBILE1BQUFBLFNBQVMsRUFBRSxtQkFBQ0YsUUFBRCxFQUFjO0FBQ3JCLFlBQUlBLFFBQVEsQ0FBQ0MsT0FBYixFQUFzQjtBQUNsQmUsVUFBQUEsT0FBTyxDQUFDM0gsT0FBUixDQUFnQixJQUFoQixFQUFzQmdDLE1BQXRCOztBQUNBLGNBQUksTUFBSSxDQUFDekQsYUFBTCxDQUFtQitELElBQW5CLENBQXdCLFlBQXhCLEVBQXNDN0MsTUFBdEMsS0FBaUQsQ0FBckQsRUFBd0Q7QUFDcEQsWUFBQSxNQUFJLENBQUNsQixhQUFMLENBQW1CK0QsSUFBbkIsQ0FBd0IsT0FBeEIsRUFBaUNzRixNQUFqQyxDQUF3Qyx1QkFBeEM7QUFDSDtBQUNKO0FBQ0o7QUFWQyxLQUFOO0FBWUgsR0EvYnFCOztBQWljdEI7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0kvQixFQUFBQSxxQkF2Y3NCLGlDQXVjQWdDLFdBdmNBLEVBdWNhO0FBQy9CLFdBQU9BLFdBQVcsQ0FBQzlCLE9BQVosQ0FBb0IsTUFBcEIsRUFBNEIsRUFBNUIsQ0FBUDtBQUNILEdBemNxQjs7QUEyY3RCO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDSXJGLEVBQUFBLG1CQWhkc0IsaUNBZ2RBO0FBQ2xCO0FBQ0EsUUFBSW9ILFNBQVMsR0FBRyxLQUFLdkosYUFBTCxDQUFtQitELElBQW5CLENBQXdCLElBQXhCLEVBQThCeUYsS0FBOUIsR0FBc0NDLFdBQXRDLEVBQWhCLENBRmtCLENBSWxCOztBQUNBLFFBQU1DLFlBQVksR0FBR1QsTUFBTSxDQUFDVSxXQUE1QjtBQUNBLFFBQU1DLGtCQUFrQixHQUFHLEdBQTNCLENBTmtCLENBTWM7QUFFaEM7O0FBQ0EsV0FBT2pHLElBQUksQ0FBQ2tHLEdBQUwsQ0FBU2xHLElBQUksQ0FBQ0MsS0FBTCxDQUFXLENBQUM4RixZQUFZLEdBQUdFLGtCQUFoQixJQUFzQ0wsU0FBakQsQ0FBVCxFQUFzRSxDQUF0RSxDQUFQO0FBQ0gsR0ExZHFCOztBQTRkdEI7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0l2RCxFQUFBQSxhQWxlc0IseUJBa2VSOEQsS0FsZVEsRUFrZUQ7QUFDakIsUUFBTUMsU0FBUyxHQUFHLElBQUlDLGVBQUosQ0FBb0JmLE1BQU0sQ0FBQ0MsUUFBUCxDQUFnQjVFLE1BQXBDLENBQWxCO0FBQ0EsV0FBT3lGLFNBQVMsQ0FBQ0UsR0FBVixDQUFjSCxLQUFkLENBQVA7QUFDSDtBQXJlcUIsQ0FBMUI7QUF3ZUFwSyxDQUFDLENBQUNrQyxRQUFELENBQUQsQ0FBWXNJLEtBQVosQ0FBa0IsWUFBTTtBQUNwQjFLLEVBQUFBLGlCQUFpQixDQUFDZ0IsVUFBbEI7QUFDSCxDQUZEIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pa29QQlggLSBmcmVlIHBob25lIHN5c3RlbSBmb3Igc21hbGwgYnVzaW5lc3NcbiAqIENvcHlyaWdodCDCqSAyMDE3LTIwMjQgQWxleGV5IFBvcnRub3YgYW5kIE5pa29sYXkgQmVrZXRvdlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAqIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbiAqXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS5cbiAqIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gKi9cblxuLyogZ2xvYmFsIGdsb2JhbFJvb3RVcmwsIGdsb2JhbFRyYW5zbGF0ZSwgU2VtYW50aWNMb2NhbGl6YXRpb24sIFVzZXJNZXNzYWdlLCBJbnB1dE1hc2tQYXR0ZXJucyAqL1xuXG5jb25zdCBNb2R1bGVQaG9uZUJvb2tEVCA9IHtcblxuICAgIC8qKlxuICAgICAqIFRoZSBnbG9iYWwgc2VhcmNoIGlucHV0IGVsZW1lbnQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkZ2xvYmFsU2VhcmNoOiAkKCcjZ2xvYmFsLXNlYXJjaCcpLFxuXG4gICAgLyoqXG4gICAgICogVGhlIHBhZ2UgbGVuZ3RoIHNlbGVjdG9yLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJHBhZ2VMZW5ndGhTZWxlY3RvcjokKCcjcGFnZS1sZW5ndGgtc2VsZWN0JyksXG5cbiAgICAvKipcbiAgICAgKiBUaGUgcGFnZSBsZW5ndGggc2VsZWN0b3IuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkc2VhcmNoRXh0ZW5zaW9uc0lucHV0OiAkKCcjc2VhcmNoLWV4dGVuc2lvbnMtaW5wdXQnKSxcblxuXG4gICAgLyoqXG4gICAgICogVGhlIGRhdGEgdGFibGUgb2JqZWN0LlxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgZGF0YVRhYmxlOiB7fSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBkb2N1bWVudCBib2R5LlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJGJvZHk6ICQoJ2JvZHknKSxcblxuICAgIC8vIENhY2hlZCBET00gZWxlbWVudHNcbiAgICAkZGlzYWJsZUlucHV0TWFza1RvZ2dsZTogJCgnI2Rpc2FibGUtaW5wdXQtbWFzaycpLFxuXG4gICAgLyoqXG4gICAgICogVGhlIGV4dGVuc2lvbnMgdGFibGUgZWxlbWVudC5cbiAgICAgKiBAdHlwZSB7alF1ZXJ5fVxuICAgICAqL1xuICAgICRyZWNvcmRzVGFibGU6ICQoJyNwaG9uZWJvb2stdGFibGUnKSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBhZGQgbmV3IGJ1dHRvbiBlbGVtZW50LlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJGFkZE5ld0J1dHRvbjogJCgnI2FkZC1uZXctYnV0dG9uJyksXG5cbiAgICAvKipcbiAgICAgKiBTZWxlY3RvciBmb3IgbnVtYmVyIGlucHV0IGZpZWxkcy5cbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIGlucHV0TnVtYmVySlFUUEw6ICdpbnB1dC5udW1iZXItaW5wdXQnLFxuXG4gICAgLyoqXG4gICAgICogTGlzdCBvZiBpbnB1dCBtYXNrcy5cbiAgICAgKiBAdHlwZSB7bnVsbHxBcnJheX1cbiAgICAgKi9cbiAgICAkbWFza0xpc3Q6IG51bGwsXG5cbiAgICAvLyBVUkxzIGZvciBBSkFYIHJlcXVlc3RzXG4gICAgZ2V0TmV3UmVjb3Jkc0FKQVhVcmw6IGAke2dsb2JhbFJvb3RVcmx9bW9kdWxlLXBob25lLWJvb2svZ2V0TmV3UmVjb3Jkc2AsXG5cbiAgICBkZWxldGVSZWNvcmRBSkFYVXJsOiBgJHtnbG9iYWxSb290VXJsfW1vZHVsZS1waG9uZS1ib29rL2RlbGV0ZWAsXG5cbiAgICBzYXZlUmVjb3JkQUpBWFVybDogYCR7Z2xvYmFsUm9vdFVybH1tb2R1bGUtcGhvbmUtYm9vay9zYXZlYCxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgdGhlIG1vZHVsZS5cbiAgICAgKiBUaGlzIGluY2x1ZGVzIHNldHRpbmcgdXAgZXZlbnQgbGlzdGVuZXJzIGFuZCBpbml0aWFsaXppbmcgdGhlIERhdGFUYWJsZS5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplKCkge1xuICAgICAgICB0aGlzLmluaXRpYWxpemVTZWFyY2goKTtcbiAgICAgICAgdGhpcy5pbml0aWFsaXplRGF0YVRhYmxlKCk7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUV2ZW50TGlzdGVuZXJzKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgdGhlIHNlYXJjaCBmdW5jdGlvbmFsaXR5LlxuICAgICAqIEl0IGxpc3RlbnMgZm9yIGtleSBldmVudHMgYW5kIGFwcGxpZXMgYSBmaWx0ZXIgYmFzZWQgb24gdGhlIHVzZXIncyBpbnB1dC5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplU2VhcmNoKCkge1xuICAgICAgICB0aGlzLiRnbG9iYWxTZWFyY2gub24oJ2tleXVwJywgKGUpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNlYXJjaFRleHQgPSB0aGlzLiRnbG9iYWxTZWFyY2gudmFsKCkudHJpbSgpO1xuICAgICAgICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMTMgfHwgZS5rZXlDb2RlID09PSA4IHx8IHNlYXJjaFRleHQubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hcHBseUZpbHRlcihzZWFyY2hUZXh0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgYWxsIGV2ZW50IGxpc3RlbmVycy5cbiAgICAgKiBIYW5kbGVzIGlucHV0IGZvY3VzLCBmb3JtIHN1Ym1pc3Npb24sIGFkZGluZyBuZXcgcm93cywgYW5kIGRlbGV0ZSBhY3Rpb25zLlxuICAgICAqL1xuICAgIGluaXRpYWxpemVFdmVudExpc3RlbmVycygpIHtcblxuICAgICAgICAvLyBIYW5kbGUgZm9jdXMgb24gaW5wdXQgZmllbGRzIGZvciBlZGl0aW5nXG4gICAgICAgIHRoaXMuJGJvZHkub24oJ2ZvY3VzaW4nLCAnLmNhbGxlci1pZC1pbnB1dCwgLm51bWJlci1pbnB1dCcsIChlKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm9uRmllbGRGb2N1cygkKGUudGFyZ2V0KSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEhhbmRsZSBsb3NzIG9mIGZvY3VzIG9uIGlucHV0IGZpZWxkcyBhbmQgc2F2ZSBjaGFuZ2VzXG4gICAgICAgIHRoaXMuJGJvZHkub24oJ2ZvY3Vzb3V0JywgJy5jYWxsZXItaWQtaW5wdXQsIC5udW1iZXItaW5wdXQnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNhdmVDaGFuZ2VzRm9yQWxsUm93cygpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBIYW5kbGUgZGVsZXRlIGJ1dHRvbiBjbGlja1xuICAgICAgICB0aGlzLiRib2R5Lm9uKCdjbGljaycsICdhLmRlbGV0ZScsIChlKSA9PiB7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICBjb25zdCBpZCA9ICQoZS50YXJnZXQpLmNsb3Nlc3QoJ2EnKS5kYXRhKCd2YWx1ZScpO1xuICAgICAgICAgICAgdGhpcy5kZWxldGVSb3coJChlLnRhcmdldCksIGlkKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSGFuZGxlIEVudGVyIG9yIFRhYiBrZXkgdG8gdHJpZ2dlciBmb3JtIHN1Ym1pc3Npb25cbiAgICAgICAgJChkb2N1bWVudCkub24oJ2tleWRvd24nLCAoZSkgPT4ge1xuICAgICAgICAgICAgaWYgKGUua2V5ID09PSAnRW50ZXInIHx8IChlLmtleSA9PT0gJ1RhYicgJiYgISQoJzpmb2N1cycpLmhhc0NsYXNzKCcubnVtYmVyLWlucHV0JykpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zYXZlQ2hhbmdlc0ZvckFsbFJvd3MoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSGFuZGxlIGFkZGluZyBhIG5ldyByb3dcbiAgICAgICAgdGhpcy4kYWRkTmV3QnV0dG9uLm9uKCdjbGljaycsIChlKSA9PiB7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICB0aGlzLmFkZE5ld1JvdygpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBIYW5kbGUgcGFnZSBsZW5ndGggc2VsZWN0aW9uXG4gICAgICAgIHRoaXMuJHBhZ2VMZW5ndGhTZWxlY3Rvci5kcm9wZG93bih7XG4gICAgICAgICAgICBvbkNoYW5nZShwYWdlTGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgaWYgKHBhZ2VMZW5ndGg9PT0nYXV0bycpe1xuICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gdGhpcy5jYWxjdWxhdGVQYWdlTGVuZ3RoKCk7XG4gICAgICAgICAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKCdwaG9uZWJvb2tUYWJsZVBhZ2VMZW5ndGgnKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgncGhvbmVib29rVGFibGVQYWdlTGVuZ3RoJywgcGFnZUxlbmd0aCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIE1vZHVsZVBob25lQm9va0RULmRhdGFUYWJsZS5wYWdlLmxlbihwYWdlTGVuZ3RoKS5kcmF3KCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBQcmV2ZW50IGV2ZW50IGJ1YmJsaW5nIG9uIGRyb3Bkb3duIGNsaWNrXG4gICAgICAgIHRoaXMuJHBhZ2VMZW5ndGhTZWxlY3Rvci5vbignY2xpY2snLCBmdW5jdGlvbihldmVudCkge1xuICAgICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7IC8vIFByZXZlbnQgdGhlIGV2ZW50IGZyb20gYnViYmxpbmdcbiAgICAgICAgfSk7XG4gICAgfSxcblxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIGZvY3VzIGV2ZW50IG9uIGEgZmllbGQgYnkgYWRkaW5nIGEgZ2xvd2luZyBlZmZlY3QgYW5kIGVuYWJsaW5nIGVkaXRpbmcuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge2pRdWVyeX0gJGlucHV0IC0gVGhlIGlucHV0IGZpZWxkIHRoYXQgcmVjZWl2ZWQgZm9jdXMuXG4gICAgICovXG4gICAgb25GaWVsZEZvY3VzKCRpbnB1dCkge1xuICAgICAgICAkaW5wdXQudHJhbnNpdGlvbignZ2xvdycpO1xuICAgICAgICAkaW5wdXQuY2xvc2VzdCgnZGl2JykucmVtb3ZlQ2xhc3MoJ3RyYW5zcGFyZW50JykuYWRkQ2xhc3MoJ2NoYW5nZWQtZmllbGQnKTtcbiAgICAgICAgJGlucHV0LmF0dHIoJ3JlYWRvbmx5JywgZmFsc2UpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTYXZlIGNoYW5nZXMgZm9yIGFsbCBtb2RpZmllZCByb3dzLlxuICAgICAqIEl0IHNlbmRzIHRoZSBjaGFuZ2VzIGZvciBlYWNoIG1vZGlmaWVkIHJvdyB0byB0aGUgc2VydmVyLlxuICAgICAqL1xuICAgIHNhdmVDaGFuZ2VzRm9yQWxsUm93cygpIHtcbiAgICAgICAgY29uc3QgJHJvd3MgPSAkKCcuY2hhbmdlZC1maWVsZCcpLmNsb3Nlc3QoJ3RyJyk7XG4gICAgICAgICRyb3dzLmVhY2goKF8sIHJvdykgPT4ge1xuICAgICAgICAgICAgY29uc3Qgcm93SWQgPSAkKHJvdykuYXR0cignaWQnKTtcbiAgICAgICAgICAgIGlmIChyb3dJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kQ2hhbmdlc1RvU2VydmVyKHJvd0lkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEFkZCBhIG5ldyByb3cgdG8gdGhlIHBob25lYm9vayB0YWJsZS5cbiAgICAgKiBUaGUgcm93IGlzIGVkaXRhYmxlIGFuZCBhbGxvd3MgZm9yIGlucHV0IG9mIG5ldyBjb250YWN0IGluZm9ybWF0aW9uLlxuICAgICAqL1xuICAgIGFkZE5ld1JvdygpIHtcbiAgICAgICAgY29uc3QgJGVtcHR5Um93ID0gJCgnLmRhdGFUYWJsZXNfZW1wdHknKTtcbiAgICAgICAgaWYgKCRlbXB0eVJvdy5sZW5ndGgpICRlbXB0eVJvdy5yZW1vdmUoKTtcblxuICAgICAgICB0aGlzLnNhdmVDaGFuZ2VzRm9yQWxsUm93cygpO1xuXG4gICAgICAgIGNvbnN0IG5ld0lkID0gYG5ldyR7TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogNTAwKX1gO1xuICAgICAgICBjb25zdCBuZXdSb3dUZW1wbGF0ZSA9IGBcbiAgICAgICAgICAgIDx0ciBpZD1cIiR7bmV3SWR9XCI+XG4gICAgICAgICAgICAgICAgPHRkPjxpIGNsYXNzPVwidWkgdXNlciBjaXJjbGUgaWNvblwiPjwvaT48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48ZGl2IGNsYXNzPVwidWkgZmx1aWQgaW5wdXQgaW5saW5lLWVkaXQgY2hhbmdlZC1maWVsZFwiPjxpbnB1dCBjbGFzcz1cImNhbGxlci1pZC1pbnB1dFwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJcIj48L2Rpdj48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48ZGl2IGNsYXNzPVwidWkgZmx1aWQgaW5wdXQgaW5saW5lLWVkaXQgY2hhbmdlZC1maWVsZFwiPjxpbnB1dCBjbGFzcz1cIm51bWJlci1pbnB1dFwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJcIj48L2Rpdj48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48ZGl2IGNsYXNzPVwidWkgYmFzaWMgaWNvbiBidXR0b25zIGFjdGlvbi1idXR0b25zIHRpbnlcIj5cbiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj1cIiNcIiBjbGFzcz1cInVpIGJ1dHRvbiBkZWxldGVcIiBkYXRhLXZhbHVlPVwibmV3XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8aSBjbGFzcz1cImljb24gdHJhc2ggcmVkXCI+PC9pPlxuICAgICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgPC9kaXY+PC90ZD5cbiAgICAgICAgICAgIDwvdHI+YDtcblxuICAgICAgICB0aGlzLiRyZWNvcmRzVGFibGUuZmluZCgndGJvZHknKS5wcmVwZW5kKG5ld1Jvd1RlbXBsYXRlKTtcbiAgICAgICAgY29uc3QgJG5ld1JvdyA9ICQoYCMke25ld0lkfWApO1xuICAgICAgICAkbmV3Um93LmZpbmQoJ2lucHV0JykudHJhbnNpdGlvbignZ2xvdycpO1xuICAgICAgICAkbmV3Um93LmZpbmQoJy5jYWxsZXItaWQtaW5wdXQnKS5mb2N1cygpO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVJbnB1dG1hc2soJG5ld1Jvdy5maW5kKCcubnVtYmVyLWlucHV0JykpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSBEYXRhVGFibGUgaW5zdGFuY2Ugd2l0aCB0aGUgcmVxdWlyZWQgc2V0dGluZ3MgYW5kIG9wdGlvbnMuXG4gICAgICovXG4gICAgaW5pdGlhbGl6ZURhdGFUYWJsZSgpIHtcblxuICAgICAgICAvLyBHZXQgdGhlIHVzZXIncyBzYXZlZCB2YWx1ZSBvciB1c2UgdGhlIGF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlZCB2YWx1ZSBpZiBub25lIGV4aXN0c1xuICAgICAgICBjb25zdCBzYXZlZFBhZ2VMZW5ndGggPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgncGhvbmVib29rVGFibGVQYWdlTGVuZ3RoJyk7XG4gICAgICAgIGNvbnN0IHBhZ2VMZW5ndGggPSBzYXZlZFBhZ2VMZW5ndGggPyBzYXZlZFBhZ2VMZW5ndGggOiB0aGlzLmNhbGN1bGF0ZVBhZ2VMZW5ndGgoKTtcblxuICAgICAgICB0aGlzLiRyZWNvcmRzVGFibGUuZGF0YVRhYmxlKHtcbiAgICAgICAgICAgIHNlYXJjaDogeyBzZWFyY2g6IHRoaXMuJGdsb2JhbFNlYXJjaC52YWwoKSB9LFxuICAgICAgICAgICAgc2VydmVyU2lkZTogdHJ1ZSxcbiAgICAgICAgICAgIHByb2Nlc3Npbmc6IHRydWUsXG4gICAgICAgICAgICBhamF4OiB7XG4gICAgICAgICAgICAgICAgdXJsOiB0aGlzLmdldE5ld1JlY29yZHNBSkFYVXJsLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICBkYXRhU3JjOiAnZGF0YScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29sdW1uczogW1xuICAgICAgICAgICAgICAgIHsgZGF0YTogbnVsbCB9LFxuICAgICAgICAgICAgICAgIHsgZGF0YTogJ2NhbGxfaWQnIH0sXG4gICAgICAgICAgICAgICAgeyBkYXRhOiAnbnVtYmVyJyB9LFxuICAgICAgICAgICAgICAgIHsgZGF0YTogbnVsbCB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIHBhZ2luZzogdHJ1ZSxcbiAgICAgICAgICAgIHBhZ2VMZW5ndGg6IHBhZ2VMZW5ndGgsXG4gICAgICAgICAgICBkZWZlclJlbmRlcjogdHJ1ZSxcbiAgICAgICAgICAgIHNEb206ICdydGlwJyxcbiAgICAgICAgICAgIG9yZGVyaW5nOiBmYWxzZSxcbiAgICAgICAgICAgIGNyZWF0ZWRSb3c6IChyb3csIGRhdGEpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmJ1aWxkUm93VGVtcGxhdGUocm93LCBkYXRhKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkcmF3Q2FsbGJhY2s6ICgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxpemVJbnB1dG1hc2soJCh0aGlzLmlucHV0TnVtYmVySlFUUEwpKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBsYW5ndWFnZTogU2VtYW50aWNMb2NhbGl6YXRpb24uZGF0YVRhYmxlTG9jYWxpc2F0aW9uLFxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmRhdGFUYWJsZSA9IHRoaXMuJHJlY29yZHNUYWJsZS5EYXRhVGFibGUoKTtcblxuXG4gICAgICAgIC8vIFNldCB0aGUgc2VsZWN0IGlucHV0IHZhbHVlIHRvIHRoZSBzYXZlZCB2YWx1ZSBpZiBpdCBleGlzdHNcbiAgICAgICAgaWYgKHNhdmVkUGFnZUxlbmd0aCkge1xuICAgICAgICAgICAgdGhpcy4kcGFnZUxlbmd0aFNlbGVjdG9yLmRyb3Bkb3duKCdzZXQgdmFsdWUnLCBzYXZlZFBhZ2VMZW5ndGgpO1xuICAgICAgICB9XG5cblxuICAgICAgICAvLyBJbml0aWFsaXplIGRlYm91bmNlIHRpbWVyIHZhcmlhYmxlXG4gICAgICAgIGxldCBzZWFyY2hEZWJvdW5jZVRpbWVyID0gbnVsbDtcblxuICAgICAgICB0aGlzLiRnbG9iYWxTZWFyY2gub24oJ2tleXVwJywgKGUpID0+IHtcbiAgICAgICAgICAgIC8vIENsZWFyIHByZXZpb3VzIHRpbWVyIGlmIHRoZSB1c2VyIGlzIHN0aWxsIHR5cGluZ1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHNlYXJjaERlYm91bmNlVGltZXIpO1xuXG4gICAgICAgICAgICAvLyBTZXQgYSBuZXcgdGltZXIgZm9yIGRlbGF5ZWQgZXhlY3V0aW9uXG4gICAgICAgICAgICBzZWFyY2hEZWJvdW5jZVRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGV4dCA9IHRoaXMuJGdsb2JhbFNlYXJjaC52YWwoKTtcbiAgICAgICAgICAgICAgICAvLyBUcmlnZ2VyIHRoZSBzZWFyY2ggaWYgaW5wdXQgaXMgdmFsaWQgKEVudGVyLCBCYWNrc3BhY2UsIG9yIG1vcmUgdGhhbiAyIGNoYXJhY3RlcnMpXG4gICAgICAgICAgICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMTMgfHwgZS5rZXlDb2RlID09PSA4IHx8IHRleHQubGVuZ3RoID49IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHBseUZpbHRlcih0ZXh0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCA1MDApOyAvLyA1MDBtcyBkZWxheSBiZWZvcmUgZXhlY3V0aW5nIHRoZSBzZWFyY2hcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gUmVzdG9yZSB0aGUgc2F2ZWQgc2VhcmNoIHBocmFzZSBmcm9tIERhdGFUYWJsZXMgc3RhdGVcbiAgICAgICAgY29uc3Qgc3RhdGUgPSB0aGlzLmRhdGFUYWJsZS5zdGF0ZS5sb2FkZWQoKTtcbiAgICAgICAgaWYgKHN0YXRlICYmIHN0YXRlLnNlYXJjaCkge1xuICAgICAgICAgICAgdGhpcy4kZ2xvYmFsU2VhcmNoLnZhbChzdGF0ZS5zZWFyY2guc2VhcmNoKTsgLy8gU2V0IHRoZSBzZWFyY2ggZmllbGQgd2l0aCB0aGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJldHJpZXZlcyB0aGUgdmFsdWUgb2YgJ3NlYXJjaCcgcXVlcnkgcGFyYW1ldGVyIGZyb20gdGhlIFVSTC5cbiAgICAgICAgY29uc3Qgc2VhcmNoVmFsdWUgPSB0aGlzLmdldFF1ZXJ5UGFyYW0oJ3NlYXJjaCcpO1xuXG4gICAgICAgIC8vIFNldHMgdGhlIGdsb2JhbCBzZWFyY2ggaW5wdXQgdmFsdWUgYW5kIGFwcGxpZXMgdGhlIGZpbHRlciBpZiBhIHNlYXJjaCB2YWx1ZSBpcyBwcm92aWRlZC5cbiAgICAgICAgaWYgKHNlYXJjaFZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLiRnbG9iYWxTZWFyY2gudmFsKHNlYXJjaFZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMuYXBwbHlGaWx0ZXIoc2VhcmNoVmFsdWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5kYXRhVGFibGUub24oJ2RyYXcnLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLiRnbG9iYWxTZWFyY2guY2xvc2VzdCgnZGl2JykucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcnKTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEJ1aWxkIHRoZSBIVE1MIHRlbXBsYXRlIGZvciBlYWNoIHJvdyBpbiB0aGUgRGF0YVRhYmxlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gcm93IC0gVGhlIHJvdyBlbGVtZW50LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gVGhlIGRhdGEgb2JqZWN0IGZvciB0aGUgcm93LlxuICAgICAqL1xuICAgIGJ1aWxkUm93VGVtcGxhdGUocm93LCBkYXRhKSB7XG4gICAgICAgIGNvbnN0IG5hbWVUZW1wbGF0ZSA9IGBcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ1aSB0cmFuc3BhcmVudCBmbHVpZCBpbnB1dCBpbmxpbmUtZWRpdFwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dCBjbGFzcz1cImNhbGxlci1pZC1pbnB1dFwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCIke2RhdGEuY2FsbF9pZH1cIiAvPlxuICAgICAgICAgICAgPC9kaXY+YDtcbiAgICAgICAgY29uc3QgbnVtYmVyVGVtcGxhdGUgPSBgXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwidWkgdHJhbnNwYXJlbnQgaW5wdXQgaW5saW5lLWVkaXRcIj5cbiAgICAgICAgICAgICAgICA8aW5wdXQgY2xhc3M9XCJudW1iZXItaW5wdXRcIiB0eXBlPVwidGV4dFwiIHZhbHVlPVwiJHtkYXRhLm51bWJlcn1cIiAvPlxuICAgICAgICAgICAgPC9kaXY+YDtcbiAgICAgICAgY29uc3QgZGVsZXRlQnV0dG9uVGVtcGxhdGUgPSBgXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwidWkgYmFzaWMgaWNvbiBidXR0b25zIGFjdGlvbi1idXR0b25zIHRpbnlcIj5cbiAgICAgICAgICAgICAgICA8YSBocmVmPVwiI1wiIGRhdGEtdmFsdWU9XCIke2RhdGEuRFRfUm93SWR9XCIgY2xhc3M9XCJ1aSBkZWxldGUgYnV0dG9uXCI+XG4gICAgICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwiaWNvbiB0cmFzaCByZWRcIj48L2k+XG4gICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgPC9kaXY+YDtcblxuICAgICAgICAkKCd0ZCcsIHJvdykuZXEoMCkuaHRtbCgnPGkgY2xhc3M9XCJ1aSB1c2VyIGNpcmNsZSBpY29uXCI+PC9pPicpO1xuICAgICAgICAkKCd0ZCcsIHJvdykuZXEoMSkuaHRtbChuYW1lVGVtcGxhdGUpO1xuICAgICAgICAkKCd0ZCcsIHJvdykuZXEoMikuaHRtbChudW1iZXJUZW1wbGF0ZSk7XG4gICAgICAgICQoJ3RkJywgcm93KS5lcSgzKS5odG1sKGRlbGV0ZUJ1dHRvblRlbXBsYXRlKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQXBwbHkgYSBzZWFyY2ggZmlsdGVyIHRvIHRoZSBEYXRhVGFibGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBzZWFyY2ggdGV4dCB0byBhcHBseS5cbiAgICAgKi9cbiAgICBhcHBseUZpbHRlcih0ZXh0KSB7XG4gICAgICAgIGNvbnN0ICRjaGFuZ2VkRmllbGRzID0gJCgnLmNoYW5nZWQtZmllbGQnKTtcbiAgICAgICAgJGNoYW5nZWRGaWVsZHMuZWFjaCgoXywgb2JqKSA9PiB7XG4gICAgICAgICAgICBjb25zdCAkaW5wdXQgPSAkKG9iaikuZmluZCgnaW5wdXQnKTtcbiAgICAgICAgICAgICRpbnB1dC52YWwoJGlucHV0LmRhdGEoJ3ZhbHVlJykpO1xuICAgICAgICAgICAgJGlucHV0LmF0dHIoJ3JlYWRvbmx5JywgdHJ1ZSk7XG4gICAgICAgICAgICAkKG9iaikucmVtb3ZlQ2xhc3MoJ2NoYW5nZWQtZmllbGQnKS5hZGRDbGFzcygndHJhbnNwYXJlbnQnKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZGF0YVRhYmxlLnNlYXJjaCh0ZXh0KS5kcmF3KCk7XG4gICAgICAgIHRoaXMuJGdsb2JhbFNlYXJjaC5jbG9zZXN0KCdkaXYnKS5hZGRDbGFzcygnbG9hZGluZycpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIGlucHV0IG1hc2tzIGZvciBwaG9uZSBudW1iZXIgZmllbGRzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtqUXVlcnl9ICRlbCAtIFRoZSBpbnB1dCBlbGVtZW50cyB0byBhcHBseSBtYXNrcyB0by5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplSW5wdXRtYXNrKCRlbCkge1xuICAgICAgICBpZiAodGhpcy4kZGlzYWJsZUlucHV0TWFza1RvZ2dsZS5jaGVja2JveCgnaXMgY2hlY2tlZCcpKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRoaXMuJG1hc2tMaXN0ID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLiRtYXNrTGlzdCA9ICQubWFza3NTb3J0KElucHV0TWFza1BhdHRlcm5zLCBbJyMnXSwgL1swLTldfCMvLCAnbWFzaycpO1xuICAgICAgICB9XG5cbiAgICAgICAgJGVsLmlucHV0bWFza3Moe1xuICAgICAgICAgICAgaW5wdXRtYXNrOiB7XG4gICAgICAgICAgICAgICAgZGVmaW5pdGlvbnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJyMnOiB7IHZhbGlkYXRvcjogJ1swLTldJywgY2FyZGluYWxpdHk6IDEgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHNob3dNYXNrT25Ib3ZlcjogZmFsc2UsXG4gICAgICAgICAgICAgICAgb25CZWZvcmVQYXN0ZTogdGhpcy5jYk9uTnVtYmVyQmVmb3JlUGFzdGUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbWF0Y2g6IC9bMC05XS8sXG4gICAgICAgICAgICByZXBsYWNlOiAnOScsXG4gICAgICAgICAgICBsaXN0OiB0aGlzLiRtYXNrTGlzdCxcbiAgICAgICAgICAgIGxpc3RLZXk6ICdtYXNrJyxcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNlbmQgdGhlIGNoYW5nZXMgZm9yIGEgc3BlY2lmaWMgcm93IHRvIHRoZSBzZXJ2ZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcmVjb3JkSWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZCB0byBzYXZlLlxuICAgICAqL1xuICAgIHNlbmRDaGFuZ2VzVG9TZXJ2ZXIocmVjb3JkSWQpIHtcbiAgICAgICAgY29uc3QgY2FsbGVySWQgPSAkKGB0ciMke3JlY29yZElkfSAuY2FsbGVyLWlkLWlucHV0YCkudmFsKCk7XG4gICAgICAgIGNvbnN0IG51bWJlcklucHV0VmFsID0gJChgdHIjJHtyZWNvcmRJZH0gLm51bWJlci1pbnB1dGApLnZhbCgpO1xuXG4gICAgICAgIGlmICghY2FsbGVySWQgfHwgIW51bWJlcklucHV0VmFsKSByZXR1cm47XG5cbiAgICAgICAgbGV0IG51bWJlciA9IG51bWJlcklucHV0VmFsLnJlcGxhY2UoL1xcRCsvZywgJycpO1xuICAgICAgICBudW1iZXIgPSBgMSR7bnVtYmVyLnN1YnN0cihudW1iZXIubGVuZ3RoIC0gOSl9YDtcblxuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgICAgY2FsbF9pZDogY2FsbGVySWQsXG4gICAgICAgICAgICBudW1iZXJfcmVwOiBudW1iZXJJbnB1dFZhbCxcbiAgICAgICAgICAgIG51bWJlcixcbiAgICAgICAgICAgIGlkOiByZWNvcmRJZCxcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmRpc3BsYXlTYXZpbmdJY29uKHJlY29yZElkKTtcblxuICAgICAgICAkLmFwaSh7XG4gICAgICAgICAgICB1cmw6IHRoaXMuc2F2ZVJlY29yZEFKQVhVcmwsXG4gICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIG9uOiAnbm93JyxcbiAgICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgICBzdWNjZXNzVGVzdDogKHJlc3BvbnNlKSA9PiByZXNwb25zZSAmJiByZXNwb25zZS5zdWNjZXNzID09PSB0cnVlLFxuICAgICAgICAgICAgb25TdWNjZXNzOiAocmVzcG9uc2UpID0+IHRoaXMub25TYXZlU3VjY2VzcyhyZXNwb25zZSwgcmVjb3JkSWQpLFxuICAgICAgICAgICAgb25GYWlsdXJlOiAocmVzcG9uc2UpID0+IFVzZXJNZXNzYWdlLnNob3dNdWx0aVN0cmluZyhyZXNwb25zZS5tZXNzYWdlKSxcbiAgICAgICAgICAgIG9uRXJyb3I6IChlcnJvck1lc3NhZ2UsIGVsZW1lbnQsIHhocikgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh4aHIuc3RhdHVzID09PSA0MDMpIHdpbmRvdy5sb2NhdGlvbiA9IGAke2dsb2JhbFJvb3RVcmx9c2Vzc2lvbi9pbmRleGA7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogRGlzcGxheSBhIHNhdmluZyBpY29uIGZvciB0aGUgZ2l2ZW4gcmVjb3JkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJlY29yZElkIC0gVGhlIElEIG9mIHRoZSByZWNvcmQgYmVpbmcgc2F2ZWQuXG4gICAgICovXG4gICAgZGlzcGxheVNhdmluZ0ljb24ocmVjb3JkSWQpIHtcbiAgICAgICAgJChgdHIjJHtyZWNvcmRJZH0gLnVzZXIuY2lyY2xlYClcbiAgICAgICAgICAgIC5yZW1vdmVDbGFzcygndXNlciBjaXJjbGUnKVxuICAgICAgICAgICAgLmFkZENsYXNzKCdzcGlubmVyIGxvYWRpbmcnKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIHN1Y2Nlc3NmdWwgc2F2aW5nIG9mIGEgcmVjb3JkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHJlc3BvbnNlIC0gVGhlIHNlcnZlciByZXNwb25zZS5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcmVjb3JkSWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZCB0aGF0IHdhcyBzYXZlZC5cbiAgICAgKi9cbiAgICBvblNhdmVTdWNjZXNzKHJlc3BvbnNlLCByZWNvcmRJZCkge1xuICAgICAgICBpZiAocmVzcG9uc2UuZGF0YSkge1xuICAgICAgICAgICAgbGV0IG9sZElkID0gcmVzcG9uc2UuZGF0YS5vbGRJZCB8fCByZWNvcmRJZDtcbiAgICAgICAgICAgICQoYHRyIyR7b2xkSWR9IGlucHV0YCkuYXR0cigncmVhZG9ubHknLCB0cnVlKTtcbiAgICAgICAgICAgICQoYHRyIyR7b2xkSWR9IGRpdmApLnJlbW92ZUNsYXNzKCdjaGFuZ2VkLWZpZWxkIGxvYWRpbmcnKS5hZGRDbGFzcygndHJhbnNwYXJlbnQnKTtcbiAgICAgICAgICAgICQoYHRyIyR7b2xkSWR9IC5zcGlubmVyLmxvYWRpbmdgKS5hZGRDbGFzcygndXNlciBjaXJjbGUnKS5yZW1vdmVDbGFzcygnc3Bpbm5lciBsb2FkaW5nJyk7XG4gICAgICAgICAgICBpZiAob2xkSWQgIT09IHJlc3BvbnNlLmRhdGEubmV3SWQpIHtcbiAgICAgICAgICAgICAgICAkKGB0ciMke29sZElkfWApLmF0dHIoJ2lkJywgcmVzcG9uc2UuZGF0YS5uZXdJZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogRGVsZXRlIGEgcm93IGZyb20gdGhlIHBob25lYm9vayB0YWJsZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7alF1ZXJ5fSAkdGFyZ2V0IC0gVGhlIGRlbGV0ZSBidXR0b24gZWxlbWVudC5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZCB0byBkZWxldGUuXG4gICAgICovXG4gICAgZGVsZXRlUm93KCR0YXJnZXQsIGlkKSB7XG4gICAgICAgIGlmIChpZCA9PT0gJ25ldycpIHtcbiAgICAgICAgICAgICR0YXJnZXQuY2xvc2VzdCgndHInKS5yZW1vdmUoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgICQuYXBpKHtcbiAgICAgICAgICAgIHVybDogYCR7dGhpcy5kZWxldGVSZWNvcmRBSkFYVXJsfS8ke2lkfWAsXG4gICAgICAgICAgICBvbjogJ25vdycsXG4gICAgICAgICAgICBvblN1Y2Nlc3M6IChyZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgICR0YXJnZXQuY2xvc2VzdCgndHInKS5yZW1vdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuJHJlY29yZHNUYWJsZS5maW5kKCd0Ym9keSA+IHRyJykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLiRyZWNvcmRzVGFibGUuZmluZCgndGJvZHknKS5hcHBlbmQoJzx0ciBjbGFzcz1cIm9kZFwiPjwvdHI+Jyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2xlYW4gbnVtYmVyIGJlZm9yZSBwYXN0aW5nLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHBhc3RlZFZhbHVlIC0gVGhlIHBhc3RlZCBwaG9uZSBudW1iZXIuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFuZWQgbnVtYmVyLlxuICAgICAqL1xuICAgIGNiT25OdW1iZXJCZWZvcmVQYXN0ZShwYXN0ZWRWYWx1ZSkge1xuICAgICAgICByZXR1cm4gcGFzdGVkVmFsdWUucmVwbGFjZSgvXFxEKy9nLCAnJyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHJvd3MgdGhhdCBjYW4gZml0IG9uIGEgcGFnZSBiYXNlZCBvbiB3aW5kb3cgaGVpZ2h0LlxuICAgICAqXG4gICAgICogQHJldHVybnMge251bWJlcn0gVGhlIGNhbGN1bGF0ZWQgbnVtYmVyIG9mIHJvd3MuXG4gICAgICovXG4gICAgY2FsY3VsYXRlUGFnZUxlbmd0aCgpIHtcbiAgICAgICAgLy8gQ2FsY3VsYXRlIHJvdyBoZWlnaHRcbiAgICAgICAgbGV0IHJvd0hlaWdodCA9IHRoaXMuJHJlY29yZHNUYWJsZS5maW5kKCd0cicpLmZpcnN0KCkub3V0ZXJIZWlnaHQoKTtcblxuICAgICAgICAvLyBDYWxjdWxhdGUgd2luZG93IGhlaWdodCBhbmQgYXZhaWxhYmxlIHNwYWNlIGZvciB0YWJsZVxuICAgICAgICBjb25zdCB3aW5kb3dIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIGNvbnN0IGhlYWRlckZvb3RlckhlaWdodCA9IDU1MDsgLy8gRXN0aW1hdGUgaGVpZ2h0IGZvciBoZWFkZXIsIGZvb3RlciwgYW5kIG90aGVyIGVsZW1lbnRzXG5cbiAgICAgICAgLy8gQ2FsY3VsYXRlIG5ldyBwYWdlIGxlbmd0aFxuICAgICAgICByZXR1cm4gTWF0aC5tYXgoTWF0aC5mbG9vcigod2luZG93SGVpZ2h0IC0gaGVhZGVyRm9vdGVySGVpZ2h0KSAvIHJvd0hlaWdodCksIDUpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIHZhbHVlIG9mIGEgcXVlcnkgcGFyYW1ldGVyIGZyb20gdGhlIFVSTC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbSAtIFRoZSBuYW1lIG9mIHRoZSBxdWVyeSBwYXJhbWV0ZXIgdG8gcmV0cmlldmUuXG4gICAgICogQHJldHVybnMge3N0cmluZ3xudWxsfSBUaGUgdmFsdWUgb2YgdGhlIHF1ZXJ5IHBhcmFtZXRlciwgb3IgbnVsbCBpZiBub3QgZm91bmQuXG4gICAgICovXG4gICAgZ2V0UXVlcnlQYXJhbShwYXJhbSkge1xuICAgICAgICBjb25zdCB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgICAgICByZXR1cm4gdXJsUGFyYW1zLmdldChwYXJhbSk7XG4gICAgfSxcbn07XG5cbiQoZG9jdW1lbnQpLnJlYWR5KCgpID0+IHtcbiAgICBNb2R1bGVQaG9uZUJvb2tEVC5pbml0aWFsaXplKCk7XG59KTsiXX0= \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtcGhvbmVib29rLWRhdGF0YWJsZS5qcyJdLCJuYW1lcyI6WyJNb2R1bGVQaG9uZUJvb2tEVCIsIiRnbG9iYWxTZWFyY2giLCIkIiwiJHBhZ2VMZW5ndGhTZWxlY3RvciIsIiRzZWFyY2hFeHRlbnNpb25zSW5wdXQiLCJkYXRhVGFibGUiLCIkYm9keSIsIiRkaXNhYmxlSW5wdXRNYXNrVG9nZ2xlIiwiJHJlY29yZHNUYWJsZSIsIiRhZGROZXdCdXR0b24iLCJpbnB1dE51bWJlckpRVFBMIiwiJG1hc2tMaXN0IiwiZ2V0TmV3UmVjb3Jkc0FKQVhVcmwiLCJnbG9iYWxSb290VXJsIiwiZGVsZXRlUmVjb3JkQUpBWFVybCIsInNhdmVSZWNvcmRBSkFYVXJsIiwiaW5pdGlhbGl6ZSIsImluaXRpYWxpemVTZWFyY2giLCJpbml0aWFsaXplRGF0YVRhYmxlIiwiaW5pdGlhbGl6ZUV2ZW50TGlzdGVuZXJzIiwib24iLCJlIiwib25GaWVsZEZvY3VzIiwidGFyZ2V0Iiwic2F2ZUNoYW5nZXNGb3JBbGxSb3dzIiwicHJldmVudERlZmF1bHQiLCJpZCIsImNsb3Nlc3QiLCJkYXRhIiwiZGVsZXRlUm93IiwiZG9jdW1lbnQiLCJrZXkiLCJoYXNDbGFzcyIsImFkZE5ld1JvdyIsImRyb3Bkb3duIiwib25DaGFuZ2UiLCJwYWdlTGVuZ3RoIiwiY2FsY3VsYXRlUGFnZUxlbmd0aCIsImxvY2FsU3RvcmFnZSIsInJlbW92ZUl0ZW0iLCJzZXRJdGVtIiwicGFnZSIsImxlbiIsImRyYXciLCJldmVudCIsInN0b3BQcm9wYWdhdGlvbiIsIiRpbnB1dCIsInRyYW5zaXRpb24iLCJyZW1vdmVDbGFzcyIsImFkZENsYXNzIiwiYXR0ciIsIiRyb3dzIiwiZWFjaCIsIl8iLCJyb3ciLCJyb3dJZCIsInVuZGVmaW5lZCIsInNlbmRDaGFuZ2VzVG9TZXJ2ZXIiLCIkZW1wdHlSb3ciLCJsZW5ndGgiLCJyZW1vdmUiLCJuZXdJZCIsIk1hdGgiLCJmbG9vciIsInJhbmRvbSIsIm5ld1Jvd1RlbXBsYXRlIiwiZmluZCIsInByZXBlbmQiLCIkbmV3Um93IiwiZm9jdXMiLCJpbml0aWFsaXplSW5wdXRtYXNrIiwic2F2ZWRQYWdlTGVuZ3RoIiwiZ2V0SXRlbSIsInNlYXJjaCIsInZhbCIsInNlcnZlclNpZGUiLCJwcm9jZXNzaW5nIiwiYWpheCIsInVybCIsInR5cGUiLCJkYXRhU3JjIiwiY29sdW1ucyIsInBhZ2luZyIsImRlZmVyUmVuZGVyIiwic0RvbSIsIm9yZGVyaW5nIiwiY3JlYXRlZFJvdyIsImJ1aWxkUm93VGVtcGxhdGUiLCJkcmF3Q2FsbGJhY2siLCJsYW5ndWFnZSIsIlNlbWFudGljTG9jYWxpemF0aW9uIiwiZGF0YVRhYmxlTG9jYWxpc2F0aW9uIiwiRGF0YVRhYmxlIiwic2VhcmNoRGVib3VuY2VUaW1lciIsImNsZWFyVGltZW91dCIsInNldFRpbWVvdXQiLCJ0ZXh0Iiwia2V5Q29kZSIsImFwcGx5RmlsdGVyIiwic3RhdGUiLCJsb2FkZWQiLCJzZWFyY2hWYWx1ZSIsImdldFF1ZXJ5UGFyYW0iLCJuYW1lVGVtcGxhdGUiLCJjYWxsX2lkIiwibnVtYmVyVGVtcGxhdGUiLCJudW1iZXIiLCJkZWxldGVCdXR0b25UZW1wbGF0ZSIsIkRUX1Jvd0lkIiwiY3JlYXRlZCIsImVxIiwiaHRtbCIsIiRjaGFuZ2VkRmllbGRzIiwib2JqIiwiJGVsIiwiY2hlY2tib3giLCJtYXNrc1NvcnQiLCJJbnB1dE1hc2tQYXR0ZXJucyIsImlucHV0bWFza3MiLCJpbnB1dG1hc2siLCJkZWZpbml0aW9ucyIsInZhbGlkYXRvciIsImNhcmRpbmFsaXR5Iiwic2hvd01hc2tPbkhvdmVyIiwib25CZWZvcmVQYXN0ZSIsImNiT25OdW1iZXJCZWZvcmVQYXN0ZSIsIm1hdGNoIiwicmVwbGFjZSIsImxpc3QiLCJsaXN0S2V5IiwicmVjb3JkSWQiLCJjYWxsZXJJZCIsIm51bWJlcklucHV0VmFsIiwibnVtYmVyX3JlcCIsImRpc3BsYXlTYXZpbmdJY29uIiwiYXBpIiwibWV0aG9kIiwic3VjY2Vzc1Rlc3QiLCJyZXNwb25zZSIsInN1Y2Nlc3MiLCJvblN1Y2Nlc3MiLCJvblNhdmVTdWNjZXNzIiwib25GYWlsdXJlIiwiVXNlck1lc3NhZ2UiLCJzaG93TXVsdGlTdHJpbmciLCJtZXNzYWdlIiwib25FcnJvciIsImVycm9yTWVzc2FnZSIsImVsZW1lbnQiLCJ4aHIiLCJzdGF0dXMiLCJ3aW5kb3ciLCJsb2NhdGlvbiIsIm9sZElkIiwiJHRhcmdldCIsImFwcGVuZCIsInBhc3RlZFZhbHVlIiwicm93SGVpZ2h0IiwiZmlyc3QiLCJvdXRlckhlaWdodCIsIndpbmRvd0hlaWdodCIsImlubmVySGVpZ2h0IiwiaGVhZGVyRm9vdGVySGVpZ2h0IiwibWF4IiwicGFyYW0iLCJ1cmxQYXJhbXMiLCJVUkxTZWFyY2hQYXJhbXMiLCJnZXQiLCJyZWFkeSJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBRUEsSUFBTUEsaUJBQWlCLEdBQUc7QUFFdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsYUFBYSxFQUFFQyxDQUFDLENBQUMsZ0JBQUQsQ0FOTTs7QUFRdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsbUJBQW1CLEVBQUVELENBQUMsQ0FBQyxxQkFBRCxDQVpBOztBQWN0QjtBQUNKO0FBQ0E7QUFDQTtBQUNJRSxFQUFBQSxzQkFBc0IsRUFBRUYsQ0FBQyxDQUFDLDBCQUFELENBbEJIOztBQXFCdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUcsRUFBQUEsU0FBUyxFQUFFLEVBekJXOztBQTJCdEI7QUFDSjtBQUNBO0FBQ0E7QUFDSUMsRUFBQUEsS0FBSyxFQUFFSixDQUFDLENBQUMsTUFBRCxDQS9CYztBQWlDdEI7QUFDQUssRUFBQUEsdUJBQXVCLEVBQUVMLENBQUMsQ0FBQyxxQkFBRCxDQWxDSjs7QUFvQ3RCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lNLEVBQUFB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Q0EsV0FBTzRGLFNBQVMsQ0FBQ0UsR0FBVixDQUFjSCxLQUFkLENBQVA7QUFDSDtBQTFkcUIsQ0FBMUI7QUE2ZEFsSyxDQUFDLENBQUM0QixRQUFELENBQUQsQ0FBWTBJLEtBQVosQ0FBa0IsWUFBTTtBQUNwQnhLLEVBQUFBLGlCQUFpQixDQUFDZ0IsVUFBbEI7QUFDSCxDQUZEIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pa29QQlggLSBmcmVlIHBob25lIHN5c3RlbSBmb3Igc21hbGwgYnVzaW5lc3NcbiAqIENvcHlyaWdodCDCqSAyMDE3LTIwMjQgQWxleGV5IFBvcnRub3YgYW5kIE5pa29sYXkgQmVrZXRvdlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAqIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbiAqXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS5cbiAqIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gKi9cblxuLyogZ2xvYmFsIGdsb2JhbFJvb3RVcmwsIGdsb2JhbFRyYW5zbGF0ZSwgU2VtYW50aWNMb2NhbGl6YXRpb24sIFVzZXJNZXNzYWdlLCBJbnB1dE1hc2tQYXR0ZXJucyAqL1xuXG5jb25zdCBNb2R1bGVQaG9uZUJvb2tEVCA9IHtcblxuICAgIC8qKlxuICAgICAqIFRoZSBnbG9iYWwgc2VhcmNoIGlucHV0IGVsZW1lbnQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkZ2xvYmFsU2VhcmNoOiAkKCcjZ2xvYmFsLXNlYXJjaCcpLFxuXG4gICAgLyoqXG4gICAgICogVGhlIHBhZ2UgbGVuZ3RoIHNlbGVjdG9yLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJHBhZ2VMZW5ndGhTZWxlY3RvcjogJCgnI3BhZ2UtbGVuZ3RoLXNlbGVjdCcpLFxuXG4gICAgLyoqXG4gICAgICogVGhlIHBhZ2UgbGVuZ3RoIHNlbGVjdG9yLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJHNlYXJjaEV4dGVuc2lvbnNJbnB1dDogJCgnI3NlYXJjaC1leHRlbnNpb25zLWlucHV0JyksXG5cblxuICAgIC8qKlxuICAgICAqIFRoZSBkYXRhIHRhYmxlIG9iamVjdC5cbiAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAqL1xuICAgIGRhdGFUYWJsZToge30sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgZG9jdW1lbnQgYm9keS5cbiAgICAgKiBAdHlwZSB7alF1ZXJ5fVxuICAgICAqL1xuICAgICRib2R5OiAkKCdib2R5JyksXG5cbiAgICAvLyBDYWNoZWQgRE9NIGVsZW1lbnRzXG4gICAgJGRpc2FibGVJbnB1dE1hc2tUb2dnbGU6ICQoJyNkaXNhYmxlLWlucHV0LW1hc2snKSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBleHRlbnNpb25zIHRhYmxlIGVsZW1lbnQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkcmVjb3Jkc1RhYmxlOiAkKCcjcGhvbmVib29rLXRhYmxlJyksXG5cbiAgICAvKipcbiAgICAgKiBUaGUgYWRkIG5ldyBidXR0b24gZWxlbWVudC5cbiAgICAgKiBAdHlwZSB7alF1ZXJ5fVxuICAgICAqL1xuICAgICRhZGROZXdCdXR0b246ICQoJyNhZGQtbmV3LWJ1dHRvbicpLFxuXG4gICAgLyoqXG4gICAgICogU2VsZWN0b3IgZm9yIG51bWJlciBpbnB1dCBmaWVsZHMuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBpbnB1dE51bWJlckpRVFBMOiAnaW5wdXQubnVtYmVyLWlucHV0JyxcblxuICAgIC8qKlxuICAgICAqIExpc3Qgb2YgaW5wdXQgbWFza3MuXG4gICAgICogQHR5cGUge251bGx8QXJyYXl9XG4gICAgICovXG4gICAgJG1hc2tMaXN0OiBudWxsLFxuXG4gICAgLy8gVVJMcyBmb3IgQUpBWCByZXF1ZXN0c1xuICAgIGdldE5ld1JlY29yZHNBSkFYVXJsOiBgJHtnbG9iYWxSb290VXJsfW1vZHVsZS1waG9uZS1ib29rL2dldE5ld1JlY29yZHNgLFxuXG4gICAgZGVsZXRlUmVjb3JkQUpBWFVybDogYCR7Z2xvYmFsUm9vdFVybH1tb2R1bGUtcGhvbmUtYm9vay9kZWxldGVgLFxuXG4gICAgc2F2ZVJlY29yZEFKQVhVcmw6IGAke2dsb2JhbFJvb3RVcmx9bW9kdWxlLXBob25lLWJvb2svc2F2ZWAsXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSBtb2R1bGUuXG4gICAgICogVGhpcyBpbmNsdWRlcyBzZXR0aW5nIHVwIGV2ZW50IGxpc3RlbmVycyBhbmQgaW5pdGlhbGl6aW5nIHRoZSBEYXRhVGFibGUuXG4gICAgICovXG4gICAgaW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgdGhpcy5pbml0aWFsaXplU2VhcmNoKCk7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZURhdGFUYWJsZSgpO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVFdmVudExpc3RlbmVycygpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSBzZWFyY2ggZnVuY3Rpb25hbGl0eS5cbiAgICAgKiBTZXRzIHVwIHRoZSBzZWFyY2ggaW5wdXQgZmllbGQgcmVhZHkgZm9yIHVzZS5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplU2VhcmNoKCkge1xuICAgICAgICAvLyBTZWFyY2ggaGFuZGxlciBpcyBpbml0aWFsaXplZCBpbiBpbml0aWFsaXplRGF0YVRhYmxlKCkgd2l0aCBkZWJvdW5jZVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIGFsbCBldmVudCBsaXN0ZW5lcnMuXG4gICAgICogSGFuZGxlcyBpbnB1dCBmb2N1cywgZm9ybSBzdWJtaXNzaW9uLCBhZGRpbmcgbmV3IHJvd3MsIGFuZCBkZWxldGUgYWN0aW9ucy5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplRXZlbnRMaXN0ZW5lcnMoKSB7XG5cbiAgICAgICAgLy8gSGFuZGxlIGZvY3VzIG9uIGlucHV0IGZpZWxkcyBmb3IgZWRpdGluZ1xuICAgICAgICB0aGlzLiRib2R5Lm9uKCdmb2N1c2luJywgJy5jYWxsZXItaWQtaW5wdXQsIC5udW1iZXItaW5wdXQnLCAoZSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vbkZpZWxkRm9jdXMoJChlLnRhcmdldCkpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBIYW5kbGUgbG9zcyBvZiBmb2N1cyBvbiBpbnB1dCBmaWVsZHMgYW5kIHNhdmUgY2hhbmdlc1xuICAgICAgICB0aGlzLiRib2R5Lm9uKCdmb2N1c291dCcsICcuY2FsbGVyLWlkLWlucHV0LCAubnVtYmVyLWlucHV0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zYXZlQ2hhbmdlc0ZvckFsbFJvd3MoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSGFuZGxlIGRlbGV0ZSBidXR0b24gY2xpY2tcbiAgICAgICAgdGhpcy4kYm9keS5vbignY2xpY2snLCAnYS5kZWxldGUnLCAoZSkgPT4ge1xuICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgY29uc3QgaWQgPSAkKGUudGFyZ2V0KS5jbG9zZXN0KCdhJykuZGF0YSgndmFsdWUnKTtcbiAgICAgICAgICAgIHRoaXMuZGVsZXRlUm93KCQoZS50YXJnZXQpLCBpZCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEhhbmRsZSBFbnRlciBvciBUYWIga2V5IHRvIHRyaWdnZXIgZm9ybSBzdWJtaXNzaW9uXG4gICAgICAgICQoZG9jdW1lbnQpLm9uKCdrZXlkb3duJywgKGUpID0+IHtcbiAgICAgICAgICAgIGlmIChlLmtleSA9PT0gJ0VudGVyJyB8fCAoZS5rZXkgPT09ICdUYWInICYmICEkKCc6Zm9jdXMnKS5oYXNDbGFzcygnLm51bWJlci1pbnB1dCcpKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2F2ZUNoYW5nZXNGb3JBbGxSb3dzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEhhbmRsZSBhZGRpbmcgYSBuZXcgcm93XG4gICAgICAgIHRoaXMuJGFkZE5ld0J1dHRvbi5vbignY2xpY2snLCAoZSkgPT4ge1xuICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgdGhpcy5hZGROZXdSb3coKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSGFuZGxlIHBhZ2UgbGVuZ3RoIHNlbGVjdGlvblxuICAgICAgICB0aGlzLiRwYWdlTGVuZ3RoU2VsZWN0b3IuZHJvcGRvd24oe1xuICAgICAgICAgICAgb25DaGFuZ2UocGFnZUxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGlmIChwYWdlTGVuZ3RoID09PSAnYXV0bycpIHtcbiAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IHRoaXMuY2FsY3VsYXRlUGFnZUxlbmd0aCgpO1xuICAgICAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSgncGhvbmVib29rVGFibGVQYWdlTGVuZ3RoJyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3Bob25lYm9va1RhYmxlUGFnZUxlbmd0aCcsIHBhZ2VMZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tEVC5kYXRhVGFibGUucGFnZS5sZW4ocGFnZUxlbmd0aCkuZHJhdygpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gUHJldmVudCBldmVudCBidWJibGluZyBvbiBkcm9wZG93biBjbGlja1xuICAgICAgICB0aGlzLiRwYWdlTGVuZ3RoU2VsZWN0b3Iub24oJ2NsaWNrJywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTsgLy8gUHJldmVudCB0aGUgZXZlbnQgZnJvbSBidWJibGluZ1xuICAgICAgICB9KTtcbiAgICB9LFxuXG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgZm9jdXMgZXZlbnQgb24gYSBmaWVsZCBieSBhZGRpbmcgYSBnbG93aW5nIGVmZmVjdCBhbmQgZW5hYmxpbmcgZWRpdGluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7alF1ZXJ5fSAkaW5wdXQgLSBUaGUgaW5wdXQgZmllbGQgdGhhdCByZWNlaXZlZCBmb2N1cy5cbiAgICAgKi9cbiAgICBvbkZpZWxkRm9jdXMoJGlucHV0KSB7XG4gICAgICAgICRpbnB1dC50cmFuc2l0aW9uKCdnbG93Jyk7XG4gICAgICAgICRpbnB1dC5jbG9zZXN0KCdkaXYnKS5yZW1vdmVDbGFzcygndHJhbnNwYXJlbnQnKS5hZGRDbGFzcygnY2hhbmdlZC1maWVsZCcpO1xuICAgICAgICAkaW5wdXQuYXR0cigncmVhZG9ubHknLCBmYWxzZSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNhdmUgY2hhbmdlcyBmb3IgYWxsIG1vZGlmaWVkIHJvd3MuXG4gICAgICogSXQgc2VuZHMgdGhlIGNoYW5nZXMgZm9yIGVhY2ggbW9kaWZpZWQgcm93IHRvIHRoZSBzZXJ2ZXIuXG4gICAgICovXG4gICAgc2F2ZUNoYW5nZXNGb3JBbGxSb3dzKCkge1xuICAgICAgICBjb25zdCAkcm93cyA9ICQoJy5jaGFuZ2VkLWZpZWxkJykuY2xvc2VzdCgndHInKTtcbiAgICAgICAgJHJvd3MuZWFjaCgoXywgcm93KSA9PiB7XG4gICAgICAgICAgICBjb25zdCByb3dJZCA9ICQocm93KS5hdHRyKCdpZCcpO1xuICAgICAgICAgICAgaWYgKHJvd0lkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRDaGFuZ2VzVG9TZXJ2ZXIocm93SWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQWRkIGEgbmV3IHJvdyB0byB0aGUgcGhvbmVib29rIHRhYmxlLlxuICAgICAqIFRoZSByb3cgaXMgZWRpdGFibGUgYW5kIGFsbG93cyBmb3IgaW5wdXQgb2YgbmV3IGNvbnRhY3QgaW5mb3JtYXRpb24uXG4gICAgICovXG4gICAgYWRkTmV3Um93KCkge1xuICAgICAgICBjb25zdCAkZW1wdHlSb3cgPSAkKCcuZGF0YVRhYmxlc19lbXB0eScpO1xuICAgICAgICBpZiAoJGVtcHR5Um93Lmxlbmd0aCkgJGVtcHR5Um93LnJlbW92ZSgpO1xuXG4gICAgICAgIHRoaXMuc2F2ZUNoYW5nZXNGb3JBbGxSb3dzKCk7XG5cbiAgICAgICAgY29uc3QgbmV3SWQgPSBgbmV3JHtNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiA1MDApfWA7XG4gICAgICAgIGNvbnN0IG5ld1Jvd1RlbXBsYXRlID0gYFxuICAgICAgICAgICAgPHRyIGlkPVwiJHtuZXdJZH1cIj5cbiAgICAgICAgICAgICAgICA8dGQ+PGkgY2xhc3M9XCJ1aSB1c2VyIGNpcmNsZSBpY29uXCI+PC9pPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjxkaXYgY2xhc3M9XCJ1aSBmbHVpZCBpbnB1dCBpbmxpbmUtZWRpdCBjaGFuZ2VkLWZpZWxkXCI+PGlucHV0IGNsYXNzPVwiY2FsbGVyLWlkLWlucHV0XCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIlwiPjwvZGl2PjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjxkaXYgY2xhc3M9XCJ1aSBmbHVpZCBpbnB1dCBpbmxpbmUtZWRpdCBjaGFuZ2VkLWZpZWxkXCI+PGlucHV0IGNsYXNzPVwibnVtYmVyLWlucHV0XCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIlwiPjwvZGl2PjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjxkaXYgY2xhc3M9XCJ1aSBiYXNpYyBpY29uIGJ1dHRvbnMgYWN0aW9uLWJ1dHRvbnMgdGlueVwiPlxuICAgICAgICAgICAgICAgICAgICA8YSBocmVmPVwiI1wiIGNsYXNzPVwidWkgYnV0dG9uIGRlbGV0ZVwiIGRhdGEtdmFsdWU9XCJuZXdcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwiaWNvbiB0cmFzaCByZWRcIj48L2k+XG4gICAgICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgICA8L2Rpdj48L3RkPlxuICAgICAgICAgICAgPC90cj5gO1xuXG4gICAgICAgIHRoaXMuJHJlY29yZHNUYWJsZS5maW5kKCd0Ym9keScpLnByZXBlbmQobmV3Um93VGVtcGxhdGUpO1xuICAgICAgICBjb25zdCAkbmV3Um93ID0gJChgIyR7bmV3SWR9YCk7XG4gICAgICAgICRuZXdSb3cuZmluZCgnaW5wdXQnKS50cmFuc2l0aW9uKCdnbG93Jyk7XG4gICAgICAgICRuZXdSb3cuZmluZCgnLmNhbGxlci1pZC1pbnB1dCcpLmZvY3VzKCk7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUlucHV0bWFzaygkbmV3Um93LmZpbmQoJy5udW1iZXItaW5wdXQnKSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgdGhlIERhdGFUYWJsZSBpbnN0YW5jZSB3aXRoIHRoZSByZXF1aXJlZCBzZXR0aW5ncyBhbmQgb3B0aW9ucy5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplRGF0YVRhYmxlKCkge1xuXG4gICAgICAgIC8vIEdldCB0aGUgdXNlcidzIHNhdmVkIHZhbHVlIG9yIHVzZSB0aGUgYXV0b21hdGljYWxseSBjYWxjdWxhdGVkIHZhbHVlIGlmIG5vbmUgZXhpc3RzXG4gICAgICAgIGNvbnN0IHNhdmVkUGFnZUxlbmd0aCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdwaG9uZWJvb2tUYWJsZVBhZ2VMZW5ndGgnKTtcbiAgICAgICAgY29uc3QgcGFnZUxlbmd0aCA9IHNhdmVkUGFnZUxlbmd0aCA/IHNhdmVkUGFnZUxlbmd0aCA6IHRoaXMuY2FsY3VsYXRlUGFnZUxlbmd0aCgpO1xuXG4gICAgICAgIHRoaXMuJHJlY29yZHNUYWJsZS5kYXRhVGFibGUoe1xuICAgICAgICAgICAgc2VhcmNoOiB7c2VhcmNoOiB0aGlzLiRnbG9iYWxTZWFyY2gudmFsKCl9LFxuICAgICAgICAgICAgc2VydmVyU2lkZTogdHJ1ZSxcbiAgICAgICAgICAgIHByb2Nlc3Npbmc6IHRydWUsXG4gICAgICAgICAgICBhamF4OiB7XG4gICAgICAgICAgICAgICAgdXJsOiB0aGlzLmdldE5ld1JlY29yZHNBSkFYVXJsLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICBkYXRhU3JjOiAnZGF0YScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29sdW1uczogW1xuICAgICAgICAgICAgICAgIHtkYXRhOiBudWxsfSxcbiAgICAgICAgICAgICAgICB7ZGF0YTogJ2NhbGxfaWQnfSxcbiAgICAgICAgICAgICAgICB7ZGF0YTogJ251bWJlcid9LFxuICAgICAgICAgICAgICAgIHtkYXRhOiBudWxsfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBwYWdpbmc6IHRydWUsXG4gICAgICAgICAgICBwYWdlTGVuZ3RoOiBwYWdlTGVuZ3RoLFxuICAgICAgICAgICAgZGVmZXJSZW5kZXI6IHRydWUsXG4gICAgICAgICAgICBzRG9tOiAncnRpcCcsXG4gICAgICAgICAgICBvcmRlcmluZzogZmFsc2UsXG4gICAgICAgICAgICBjcmVhdGVkUm93OiAocm93LCBkYXRhKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5idWlsZFJvd1RlbXBsYXRlKHJvdywgZGF0YSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZHJhd0NhbGxiYWNrOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0aWFsaXplSW5wdXRtYXNrKCQodGhpcy5pbnB1dE51bWJlckpRVFBMKSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbGFuZ3VhZ2U6IFNlbWFudGljTG9jYWxpemF0aW9uLmRhdGFUYWJsZUxvY2FsaXNhdGlvbixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5kYXRhVGFibGUgPSB0aGlzLiRyZWNvcmRzVGFibGUuRGF0YVRhYmxlKCk7XG5cblxuICAgICAgICAvLyBTZXQgdGhlIHNlbGVjdCBpbnB1dCB2YWx1ZSB0byB0aGUgc2F2ZWQgdmFsdWUgaWYgaXQgZXhpc3RzXG4gICAgICAgIGlmIChzYXZlZFBhZ2VMZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMuJHBhZ2VMZW5ndGhTZWxlY3Rvci5kcm9wZG93bignc2V0IHZhbHVlJywgc2F2ZWRQYWdlTGVuZ3RoKTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBkZWJvdW5jZSB0aW1lciB2YXJpYWJsZVxuICAgICAgICBsZXQgc2VhcmNoRGVib3VuY2VUaW1lciA9IG51bGw7XG5cbiAgICAgICAgdGhpcy4kZ2xvYmFsU2VhcmNoLm9uKCdrZXl1cCcsIChlKSA9PiB7XG4gICAgICAgICAgICAvLyBDbGVhciBwcmV2aW91cyB0aW1lciBpZiB0aGUgdXNlciBpcyBzdGlsbCB0eXBpbmdcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChzZWFyY2hEZWJvdW5jZVRpbWVyKTtcblxuICAgICAgICAgICAgLy8gU2V0IGEgbmV3IHRpbWVyIGZvciBkZWxheWVkIGV4ZWN1dGlvblxuICAgICAgICAgICAgc2VhcmNoRGVib3VuY2VUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRleHQgPSB0aGlzLiRnbG9iYWxTZWFyY2gudmFsKCk7XG4gICAgICAgICAgICAgICAgLy8gVHJpZ2dlciB0aGUgc2VhcmNoIGlmIGlucHV0IGlzIHZhbGlkIChFbnRlciwgQmFja3NwYWNlLCBvciBtb3JlIHRoYW4gMiBjaGFyYWN0ZXJzKVxuICAgICAgICAgICAgICAgIGlmIChlLmtleUNvZGUgPT09IDEzIHx8IGUua2V5Q29kZSA9PT0gOCB8fCB0ZXh0Lmxlbmd0aCA+PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlGaWx0ZXIodGV4dCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgNTAwKTsgLy8gNTAwbXMgZGVsYXkgYmVmb3JlIGV4ZWN1dGluZyB0aGUgc2VhcmNoXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFJlc3RvcmUgdGhlIHNhdmVkIHNlYXJjaCBwaHJhc2UgZnJvbSBEYXRhVGFibGVzIHN0YXRlXG4gICAgICAgIGNvbnN0IHN0YXRlID0gdGhpcy5kYXRhVGFibGUuc3RhdGUubG9hZGVkKCk7XG4gICAgICAgIGlmIChzdGF0ZSAmJiBzdGF0ZS5zZWFyY2gpIHtcbiAgICAgICAgICAgIHRoaXMuJGdsb2JhbFNlYXJjaC52YWwoc3RhdGUuc2VhcmNoLnNlYXJjaCk7IC8vIFNldCB0aGUgc2VhcmNoIGZpZWxkIHdpdGggdGhlIHNhdmVkIHZhbHVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZXRyaWV2ZXMgdGhlIHZhbHVlIG9mICdzZWFyY2gnIHF1ZXJ5IHBhcmFtZXRlciBmcm9tIHRoZSBVUkwuXG4gICAgICAgIGNvbnN0IHNlYXJjaFZhbHVlID0gdGhpcy5nZXRRdWVyeVBhcmFtKCdzZWFyY2gnKTtcblxuICAgICAgICAvLyBTZXRzIHRoZSBnbG9iYWwgc2VhcmNoIGlucHV0IHZhbHVlIGFuZCBhcHBsaWVzIHRoZSBmaWx0ZXIgaWYgYSBzZWFyY2ggdmFsdWUgaXMgcHJvdmlkZWQuXG4gICAgICAgIGlmIChzZWFyY2hWYWx1ZSkge1xuICAgICAgICAgICAgdGhpcy4kZ2xvYmFsU2VhcmNoLnZhbChzZWFyY2hWYWx1ZSk7XG4gICAgICAgICAgICB0aGlzLmFwcGx5RmlsdGVyKHNlYXJjaFZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZGF0YVRhYmxlLm9uKCdkcmF3JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy4kZ2xvYmFsU2VhcmNoLmNsb3Nlc3QoJ2RpdicpLnJlbW92ZUNsYXNzKCdsb2FkaW5nJyk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBCdWlsZCB0aGUgSFRNTCB0ZW1wbGF0ZSBmb3IgZWFjaCByb3cgaW4gdGhlIERhdGFUYWJsZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHJvdyAtIFRoZSByb3cgZWxlbWVudC5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIFRoZSBkYXRhIG9iamVjdCBmb3IgdGhlIHJvdy5cbiAgICAgKi9cbiAgICBidWlsZFJvd1RlbXBsYXRlKHJvdywgZGF0YSkge1xuICAgICAgICBjb25zdCBuYW1lVGVtcGxhdGUgPSBgPGRpdiBjbGFzcz1cInVpIHRyYW5zcGFyZW50IGZsdWlkIGlucHV0IGlubGluZS1lZGl0XCI+XG4gICAgICAgICAgICAgICAgPGlucHV0IGNsYXNzPVwiY2FsbGVyLWlkLWlucHV0XCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIiR7ZGF0YS5jYWxsX2lkfVwiIC8+XG4gICAgICAgICAgICA8L2Rpdj5gO1xuICAgICAgICBjb25zdCBudW1iZXJUZW1wbGF0ZSA9IGA8ZGl2IGNsYXNzPVwidWkgdHJhbnNwYXJlbnQgaW5wdXQgaW5saW5lLWVkaXRcIj5cbiAgICAgICAgICAgICAgICA8aW5wdXQgY2xhc3M9XCJudW1iZXItaW5wdXRcIiB0eXBlPVwidGV4dFwiIHZhbHVlPVwiJHtkYXRhLm51bWJlcn1cIiAvPlxuICAgICAgICAgICAgPC9kaXY+YDtcbiAgICAgICAgY29uc3QgZGVsZXRlQnV0dG9uVGVtcGxhdGUgPSBgPGRpdiBjbGFzcz1cInVpIGJhc2ljIGljb24gYnV0dG9ucyBhY3Rpb24tYnV0dG9ucyB0aW55XCI+XG4gICAgICAgICAgICAgICAgPGEgaHJlZj1cIiNcIiBkYXRhLXZhbHVlPVwiJHtkYXRhLkRUX1Jvd0lkfVwiIGNsYXNzPVwidWkgZGVsZXRlIGJ1dHRvblwiPlxuICAgICAgICAgICAgICAgICAgICA8aSBjbGFzcz1cImljb24gdHJhc2ggJHtkYXRhPy5jcmVhdGVkID4gMCA/ICdibHVlJyA6ICdyZWQnfVwiIC8+XG4gICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgPC9kaXY+YDtcblxuICAgICAgICAkKCd0ZCcsIHJvdykuZXEoMCkuaHRtbCgnPGkgY2xhc3M9XCJ1aSB1c2VyIGNpcmNsZSBpY29uXCI+PC9pPicpO1xuICAgICAgICAkKCd0ZCcsIHJvdykuZXEoMSkuaHRtbChuYW1lVGVtcGxhdGUpO1xuICAgICAgICAkKCd0ZCcsIHJvdykuZXEoMikuaHRtbChudW1iZXJUZW1wbGF0ZSk7XG4gICAgICAgICQoJ3RkJywgcm93KS5lcSgzKS5odG1sKGRlbGV0ZUJ1dHRvblRlbXBsYXRlKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQXBwbHkgYSBzZWFyY2ggZmlsdGVyIHRvIHRoZSBEYXRhVGFibGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBzZWFyY2ggdGV4dCB0byBhcHBseS5cbiAgICAgKi9cbiAgICBhcHBseUZpbHRlcih0ZXh0KSB7XG4gICAgICAgIGNvbnN0ICRjaGFuZ2VkRmllbGRzID0gJCgnLmNoYW5nZWQtZmllbGQnKTtcbiAgICAgICAgJGNoYW5nZWRGaWVsZHMuZWFjaCgoXywgb2JqKSA9PiB7XG4gICAgICAgICAgICBjb25zdCAkaW5wdXQgPSAkKG9iaikuZmluZCgnaW5wdXQnKTtcbiAgICAgICAgICAgICRpbnB1dC52YWwoJGlucHV0LmRhdGEoJ3ZhbHVlJykpO1xuICAgICAgICAgICAgJGlucHV0LmF0dHIoJ3JlYWRvbmx5JywgdHJ1ZSk7XG4gICAgICAgICAgICAkKG9iaikucmVtb3ZlQ2xhc3MoJ2NoYW5nZWQtZmllbGQnKS5hZGRDbGFzcygndHJhbnNwYXJlbnQnKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZGF0YVRhYmxlLnNlYXJjaCh0ZXh0KS5kcmF3KCk7XG4gICAgICAgIHRoaXMuJGdsb2JhbFNlYXJjaC5jbG9zZXN0KCdkaXYnKS5hZGRDbGFzcygnbG9hZGluZycpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIGlucHV0IG1hc2tzIGZvciBwaG9uZSBudW1iZXIgZmllbGRzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtqUXVlcnl9ICRlbCAtIFRoZSBpbnB1dCBlbGVtZW50cyB0byBhcHBseSBtYXNrcyB0by5cbiAgICAgKi9cbiAgICBpbml0aWFsaXplSW5wdXRtYXNrKCRlbCkge1xuICAgICAgICBpZiAodGhpcy4kZGlzYWJsZUlucHV0TWFza1RvZ2dsZS5jaGVja2JveCgnaXMgY2hlY2tlZCcpKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRoaXMuJG1hc2tMaXN0ID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLiRtYXNrTGlzdCA9ICQubWFza3NTb3J0KElucHV0TWFza1BhdHRlcm5zLCBbJyMnXSwgL1swLTldfCMvLCAnbWFzaycpO1xuICAgICAgICB9XG5cbiAgICAgICAgJGVsLmlucHV0bWFza3Moe1xuICAgICAgICAgICAgaW5wdXRtYXNrOiB7XG4gICAgICAgICAgICAgICAgZGVmaW5pdGlvbnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJyMnOiB7dmFsaWRhdG9yOiAnWzAtOV0nLCBjYXJkaW5hbGl0eTogMX0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBzaG93TWFza09uSG92ZXI6IGZhbHNlLFxuICAgICAgICAgICAgICAgIG9uQmVmb3JlUGFzdGU6IHRoaXMuY2JPbk51bWJlckJlZm9yZVBhc3RlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG1hdGNoOiAvWzAtOV0vLFxuICAgICAgICAgICAgcmVwbGFjZTogJzknLFxuICAgICAgICAgICAgbGlzdDogdGhpcy4kbWFza0xpc3QsXG4gICAgICAgICAgICBsaXN0S2V5OiAnbWFzaycsXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSBjaGFuZ2VzIGZvciBhIHNwZWNpZmljIHJvdyB0byB0aGUgc2VydmVyLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJlY29yZElkIC0gVGhlIElEIG9mIHRoZSByZWNvcmQgdG8gc2F2ZS5cbiAgICAgKi9cbiAgICBzZW5kQ2hhbmdlc1RvU2VydmVyKHJlY29yZElkKSB7XG4gICAgICAgIGNvbnN0IGNhbGxlcklkID0gJChgdHIjJHtyZWNvcmRJZH0gLmNhbGxlci1pZC1pbnB1dGApLnZhbCgpO1xuICAgICAgICBjb25zdCBudW1iZXJJbnB1dFZhbCA9ICQoYHRyIyR7cmVjb3JkSWR9IC5udW1iZXItaW5wdXRgKS52YWwoKTtcblxuICAgICAgICBpZiAoIWNhbGxlcklkIHx8ICFudW1iZXJJbnB1dFZhbCkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICAgICAgICBjYWxsX2lkOiBjYWxsZXJJZCxcbiAgICAgICAgICAgIG51bWJlcl9yZXA6IG51bWJlcklucHV0VmFsLFxuICAgICAgICAgICAgaWQ6IHJlY29yZElkXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5kaXNwbGF5U2F2aW5nSWNvbihyZWNvcmRJZCk7XG5cbiAgICAgICAgJC5hcGkoe1xuICAgICAgICAgICAgdXJsOiB0aGlzLnNhdmVSZWNvcmRBSkFYVXJsLFxuICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICBvbjogJ25vdycsXG4gICAgICAgICAgICBkYXRhLFxuICAgICAgICAgICAgc3VjY2Vzc1Rlc3Q6IChyZXNwb25zZSkgPT4gcmVzcG9uc2UgJiYgcmVzcG9uc2Uuc3VjY2VzcyA9PT0gdHJ1ZSxcbiAgICAgICAgICAgIG9uU3VjY2VzczogKHJlc3BvbnNlKSA9PiB0aGlzLm9uU2F2ZVN1Y2Nlc3MocmVzcG9uc2UsIHJlY29yZElkKSxcbiAgICAgICAgICAgIG9uRmFpbHVyZTogKHJlc3BvbnNlKSA9PiBVc2VyTWVzc2FnZS5zaG93TXVsdGlTdHJpbmcocmVzcG9uc2UubWVzc2FnZSksXG4gICAgICAgICAgICBvbkVycm9yOiAoZXJyb3JNZXNzYWdlLCBlbGVtZW50LCB4aHIpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoeGhyLnN0YXR1cyA9PT0gNDAzKSB3aW5kb3cubG9jYXRpb24gPSBgJHtnbG9iYWxSb290VXJsfXNlc3Npb24vaW5kZXhgO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIERpc3BsYXkgYSBzYXZpbmcgaWNvbiBmb3IgdGhlIGdpdmVuIHJlY29yZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSByZWNvcmRJZCAtIFRoZSBJRCBvZiB0aGUgcmVjb3JkIGJlaW5nIHNhdmVkLlxuICAgICAqL1xuICAgIGRpc3BsYXlTYXZpbmdJY29uKHJlY29yZElkKSB7XG4gICAgICAgICQoYHRyIyR7cmVjb3JkSWR9IC51c2VyLmNpcmNsZWApXG4gICAgICAgICAgICAucmVtb3ZlQ2xhc3MoJ3VzZXIgY2lyY2xlJylcbiAgICAgICAgICAgIC5hZGRDbGFzcygnc3Bpbm5lciBsb2FkaW5nJyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSBzdWNjZXNzZnVsIHNhdmluZyBvZiBhIHJlY29yZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSByZXNwb25zZSAtIFRoZSBzZXJ2ZXIgcmVzcG9uc2UuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJlY29yZElkIC0gVGhlIElEIG9mIHRoZSByZWNvcmQgdGhhdCB3YXMgc2F2ZWQuXG4gICAgICovXG4gICAgb25TYXZlU3VjY2VzcyhyZXNwb25zZSwgcmVjb3JkSWQpIHtcbiAgICAgICAgaWYgKHJlc3BvbnNlLmRhdGEpIHtcbiAgICAgICAgICAgIGxldCBvbGRJZCA9IHJlc3BvbnNlLmRhdGEub2xkSWQgfHwgcmVjb3JkSWQ7XG4gICAgICAgICAgICAkKGB0ciMke29sZElkfSBpbnB1dGApLmF0dHIoJ3JlYWRvbmx5JywgdHJ1ZSk7XG4gICAgICAgICAgICAkKGB0ciMke29sZElkfSBhLmRlbGV0ZS5idXR0b25gKS5hdHRyKCdkYXRhLXZhbHVlJywgcmVzcG9uc2UuZGF0YS5uZXdJZCk7XG4gICAgICAgICAgICAkKGB0ciMke29sZElkfSBkaXZgKS5yZW1vdmVDbGFzcygnY2hhbmdlZC1maWVsZCBsb2FkaW5nJykuYWRkQ2xhc3MoJ3RyYW5zcGFyZW50Jyk7XG4gICAgICAgICAgICAkKGB0ciMke29sZElkfSAuc3Bpbm5lci5sb2FkaW5nYCkuYWRkQ2xhc3MoJ3VzZXIgY2lyY2xlJykucmVtb3ZlQ2xhc3MoJ3NwaW5uZXIgbG9hZGluZycpO1xuICAgICAgICAgICAgaWYgKG9sZElkICE9PSByZXNwb25zZS5kYXRhLm5ld0lkKSB7XG4gICAgICAgICAgICAgICAgJChgdHIjJHtvbGRJZH1gKS5hdHRyKCdpZCcsIHJlc3BvbnNlLmRhdGEubmV3SWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIERlbGV0ZSBhIHJvdyBmcm9tIHRoZSBwaG9uZWJvb2sgdGFibGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge2pRdWVyeX0gJHRhcmdldCAtIFRoZSBkZWxldGUgYnV0dG9uIGVsZW1lbnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGlkIC0gVGhlIElEIG9mIHRoZSByZWNvcmQgdG8gZGVsZXRlLlxuICAgICAqL1xuICAgIGRlbGV0ZVJvdygkdGFyZ2V0LCBpZCkge1xuICAgICAgICBpZiAoaWQgPT09ICduZXcnKSB7XG4gICAgICAgICAgICAkdGFyZ2V0LmNsb3Nlc3QoJ3RyJykucmVtb3ZlKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAkLmFwaSh7XG4gICAgICAgICAgICB1cmw6IGAke3RoaXMuZGVsZXRlUmVjb3JkQUpBWFVybH0vJHtpZH1gLFxuICAgICAgICAgICAgb246ICdub3cnLFxuICAgICAgICAgICAgb25TdWNjZXNzOiAocmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgICAgICAkdGFyZ2V0LmNsb3Nlc3QoJ3RyJykucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLiRyZWNvcmRzVGFibGUuZmluZCgndGJvZHkgPiB0cicpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy4kcmVjb3Jkc1RhYmxlLmZpbmQoJ3Rib2R5JykuYXBwZW5kKCc8dHIgY2xhc3M9XCJvZGRcIj48L3RyPicpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENsZWFuIG51bWJlciBiZWZvcmUgcGFzdGluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXN0ZWRWYWx1ZSAtIFRoZSBwYXN0ZWQgcGhvbmUgbnVtYmVyLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhbmVkIG51bWJlci5cbiAgICAgKi9cbiAgICBjYk9uTnVtYmVyQmVmb3JlUGFzdGUocGFzdGVkVmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHBhc3RlZFZhbHVlLnJlcGxhY2UoL1xcRCsvZywgJycpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiByb3dzIHRoYXQgY2FuIGZpdCBvbiBhIHBhZ2UgYmFzZWQgb24gd2luZG93IGhlaWdodC5cbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBjYWxjdWxhdGVkIG51bWJlciBvZiByb3dzLlxuICAgICAqL1xuICAgIGNhbGN1bGF0ZVBhZ2VMZW5ndGgoKSB7XG4gICAgICAgIC8vIENhbGN1bGF0ZSByb3cgaGVpZ2h0XG4gICAgICAgIGxldCByb3dIZWlnaHQgPSB0aGlzLiRyZWNvcmRzVGFibGUuZmluZCgndHInKS5maXJzdCgpLm91dGVySGVpZ2h0KCk7XG5cbiAgICAgICAgLy8gQ2FsY3VsYXRlIHdpbmRvdyBoZWlnaHQgYW5kIGF2YWlsYWJsZSBzcGFjZSBmb3IgdGFibGVcbiAgICAgICAgY29uc3Qgd2luZG93SGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0O1xuICAgICAgICBjb25zdCBoZWFkZXJGb290ZXJIZWlnaHQgPSA1NTA7IC8vIEVzdGltYXRlIGhlaWdodCBmb3IgaGVhZGVyLCBmb290ZXIsIGFuZCBvdGhlciBlbGVtZW50c1xuXG4gICAgICAgIC8vIENhbGN1bGF0ZSBuZXcgcGFnZSBsZW5ndGhcbiAgICAgICAgcmV0dXJuIE1hdGgubWF4KE1hdGguZmxvb3IoKHdpbmRvd0hlaWdodCAtIGhlYWRlckZvb3RlckhlaWdodCkgLyByb3dIZWlnaHQpLCA1KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSB2YWx1ZSBvZiBhIHF1ZXJ5IHBhcmFtZXRlciBmcm9tIHRoZSBVUkwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW0gLSBUaGUgbmFtZSBvZiB0aGUgcXVlcnkgcGFyYW1ldGVyIHRvIHJldHJpZXZlLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH0gVGhlIHZhbHVlIG9mIHRoZSBxdWVyeSBwYXJhbWV0ZXIsIG9yIG51bGwgaWYgbm90IGZvdW5kLlxuICAgICAqL1xuICAgIGdldFF1ZXJ5UGFyYW0ocGFyYW0pIHtcbiAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgcmV0dXJuIHVybFBhcmFtcy5nZXQocGFyYW0pO1xuICAgIH0sXG59O1xuXG4kKGRvY3VtZW50KS5yZWFkeSgoKSA9PiB7XG4gICAgTW9kdWxlUGhvbmVCb29rRFQuaW5pdGlhbGl6ZSgpO1xufSk7XG4iXX0= \ No newline at end of file diff --git a/public/assets/js/module-phonebook-settings.js b/public/assets/js/module-phonebook-settings.js index c10a6c8..fe54b22 100644 --- a/public/assets/js/module-phonebook-settings.js +++ b/public/assets/js/module-phonebook-settings.js @@ -20,30 +20,39 @@ /* global globalRootUrl, globalTranslate, SemanticLocalization, UserMessage, InputMaskPatterns */ + var ModulePhoneBookSettings = { $disableInputMaskToggle: $('#disable-input-mask'), $deleteAllRecordsButton: $('#delete-all-records'), $deleteAllModal: $('#delete-all-modal-form'), + $saveSettingsApiButton: $('#btn-save-settings-api'), + $inputPhoneBookApiUrl: $('#phoneBookApiUrl'), + $phoneBookLifeTime: $('#phoneBookLifeTime'), deleteAllRecordsAJAXUrl: "".concat(globalRootUrl, "module-phone-book/module-phone-book/deleteAllRecords"), - disableInputMaskAJAXUrl: "".concat(globalRootUrl, "module-phone-book/module-phone-book/toggleDisableInputMask"), - + saveSettingsAJAXUrl: "".concat(globalRootUrl, "module-phone-book/module-phone-book/saveSettings"), /** * Initialize the settings module for the phonebook. * It sets up the event listeners for toggling input masks and deleting all records. */ initialize: function initialize() { // Hide the delete confirmation modal initially - ModulePhoneBookSettings.$deleteAllModal.modal('hide'); // Set up the checkbox for disabling/enabling the input mask + ModulePhoneBookSettings.$deleteAllModal.modal('hide'); + // Set up the checkbox for disabling/enabling the input mask ModulePhoneBookSettings.$disableInputMaskToggle.checkbox({ - onChange: ModulePhoneBookSettings.onChangeInputMaskToggle - }); // Attach event listener for the "Delete All Records" button + onChange: ModulePhoneBookSettings.onSaveSettingsApi + }); + // Attach event listener for the "Delete All Records" button ModulePhoneBookSettings.$deleteAllRecordsButton.on('click', function () { ModulePhoneBookSettings.deleteAllRecords(); }); - }, + // Save settings + ModulePhoneBookSettings.$saveSettingsApiButton.on('click', function () { + ModulePhoneBookSettings.onSaveSettingsApi(false); + }); + }, /** * Handle the deletion of all records. * Displays a confirmation modal, and if approved, sends a request to delete all phonebook records. @@ -56,8 +65,8 @@ var ModulePhoneBookSettings = { return true; // Allows modal to close on "Cancel" }, onApprove: function onApprove() { - ModulePhoneBookSettings.$deleteAllRecordsButton.addClass('loading'); // On approval, send a request to delete all records - + ModulePhoneBookSettings.$deleteAllRecordsButton.addClass('loading'); + // On approval, send a request to delete all records $.api({ url: ModulePhoneBookSettings.deleteAllRecordsAJAXUrl, on: 'now', @@ -65,13 +74,13 @@ var ModulePhoneBookSettings = { successTest: PbxApi.successTest, onSuccess: function onSuccess(response) { ModulePhoneBookSettings.$deleteAllRecordsButton.removeClass('loading'); - UserMessage.showInformation(globalTranslate.module_phnbk_AllRecordsDeleted); // Reload the page after successful update - + UserMessage.showInformation(globalTranslate.module_phnbk_AllRecordsDeleted); + // Reload the page after successful update ModulePhoneBookDT.dataTable.ajax.reload(); }, onFailure: function onFailure(response) { - ModulePhoneBookSettings.$deleteAllRecordsButton.removeClass('loading'); // Show error message if deletion fails - + ModulePhoneBookSettings.$deleteAllRecordsButton.removeClass('loading'); + // Show error message if deletion fails UserMessage.showMultiString(response.messages); } }); @@ -79,35 +88,45 @@ var ModulePhoneBookSettings = { } }).modal('show'); // Display the confirmation modal }, - /** * Handle the toggle of the input mask. * Sends a request to update the setting for enabling or disabling input masks. + * + * @param {boolean} isOnlyInputMask + * @returns {boolean} */ - onChangeInputMaskToggle: function onChangeInputMaskToggle() { - var currentState = ModulePhoneBookSettings.$disableInputMaskToggle.checkbox('is checked'); // Send request to toggle the input mask setting + onSaveSettingsApi: function onSaveSettingsApi() { + var isOnlyInputMask = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + var data = {}; + if (isOnlyInputMask) { + data.disableInputMask = ModulePhoneBookSettings.$disableInputMaskToggle.checkbox('is checked'); + } else { + data.phoneBookApiUrl = ModulePhoneBookSettings.$inputPhoneBookApiUrl.val(); + data.phoneBookLifeTime = ModulePhoneBookSettings.$phoneBookLifeTime.val(); + } + // Send request to toggle the input mask setting $.api({ - url: ModulePhoneBookSettings.disableInputMaskAJAXUrl, + url: ModulePhoneBookSettings.saveSettingsAJAXUrl, on: 'now', method: 'POST', - data: { - disableInputMask: currentState - }, + data: data, successTest: PbxApi.successTest, onSuccess: function onSuccess(response) { window.location.reload(); }, onFailure: function onFailure(response) { + var _response$message; // Show error message if the update fails - UserMessage.showMultiString(response.messages); + UserMessage.showMultiString((_response$message = response === null || response === void 0 ? void 0 : response.message) !== null && _response$message !== void 0 ? _response$message : response.messages); } }); return true; } -}; // Initialize the settings module when the document is ready +}; +// Initialize the settings module when the document is ready $(document).ready(function () { ModulePhoneBookSettings.initialize(); }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9tb2R1bGUtcGhvbmVib29rLXNldHRpbmdzLmpzIl0sIm5hbWVzIjpbIk1vZHVsZVBob25lQm9va1NldHRpbmdzIiwiJGRpc2FibGVJbnB1dE1hc2tUb2dnbGUiLCIkIiwiJGRlbGV0ZUFsbFJlY29yZHNCdXR0b24iLCIkZGVsZXRlQWxsTW9kYWwiLCJkZWxldGVBbGxSZWNvcmRzQUpBWFVybCIsImdsb2JhbFJvb3RVcmwiLCJkaXNhYmxlSW5wdXRNYXNrQUpBWFVybCIsImluaXRpYWxpemUiLCJtb2RhbCIsImNoZWNrYm94Iiwib25DaGFuZ2UiLCJvbkNoYW5nZUlucHV0TWFza1RvZ2dsZSIsIm9uIiwiZGVsZXRlQWxsUmVjb3JkcyIsImNsb3NhYmxlIiwib25EZW55Iiwib25BcHByb3ZlIiwiYWRkQ2xhc3MiLCJhcGkiLCJ1cmwiLCJtZXRob2QiLCJzdWNjZXNzVGVzdCIsIlBieEFwaSIsIm9uU3VjY2VzcyIsInJlc3BvbnNlIiwicmVtb3ZlQ2xhc3MiLCJVc2VyTWVzc2FnZSIsInNob3dJbmZvcm1hdGlvbiIsImdsb2JhbFRyYW5zbGF0ZSIsIm1vZHVsZV9waG5ia19BbGxSZWNvcmRzRGVsZXRlZCIsIk1vZHVsZVBob25lQm9va0RUIiwiZGF0YVRhYmxlIiwiYWpheCIsInJlbG9hZCIsIm9uRmFpbHVyZSIsInNob3dNdWx0aVN0cmluZyIsIm1lc3NhZ2VzIiwiY3VycmVudFN0YXRlIiwiZGF0YSIsImRpc2FibGVJbnB1dE1hc2siLCJ3aW5kb3ciLCJsb2NhdGlvbiIsImRvY3VtZW50IiwicmVhZHkiXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBRUEsSUFBTUEsdUJBQXVCLEdBQUc7QUFDNUJDLEVBQUFBLHVCQUF1QixFQUFFQyxDQUFDLENBQUMscUJBQUQsQ0FERTtBQUU1QkMsRUFBQUEs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VyxFQUFFQyxNQUFNLENBQUNELFdBTGxCO0FBTUZFLE1BQUFBLFNBTkUscUJBTVFDLFFBTlIsRUFNa0I7QUFDaEJnQixRQUFBQSxNQUFNLENBQUNDLFFBQVAsQ0FBZ0JSLE1BQWhCO0FBQ0gsT0FSQztBQVNGQyxNQUFBQSxTQVRFLHFCQVNRVixRQVRSLEVBU2tCO0FBQ2hCO0FBQ0FFLFFBQUFBLFdBQVcsQ0FBQ1MsZUFBWixDQUE0QlgsUUFBUSxDQUFDWSxRQUFyQztBQUNIO0FBWkMsS0FBTjtBQWNBLFdBQU8sSUFBUDtBQUNIO0FBdEYyQixDQUFoQyxDLENBeUZBOztBQUNBbkMsQ0FBQyxDQUFDeUMsUUFBRCxDQUFELENBQVlDLEtBQVosQ0FBa0IsWUFBTTtBQUNwQjVDLEVBQUFBLHVCQUF1QixDQUFDUSxVQUF4QjtBQUNILENBRkQiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogTWlrb1BCWCAtIGZyZWUgcGhvbmUgc3lzdGVtIGZvciBzbWFsbCBidXNpbmVzc1xuICogQ29weXJpZ2h0IMKpIDIwMTctMjAyNCBBbGV4ZXkgUG9ydG5vdiBhbmQgTmlrb2xheSBCZWtldG92XG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICogKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLlxuICogSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiAqL1xuXG4vKiBnbG9iYWwgZ2xvYmFsUm9vdFVybCwgZ2xvYmFsVHJhbnNsYXRlLFxuU2VtYW50aWNMb2NhbGl6YXRpb24sIFVzZXJNZXNzYWdlLCBJbnB1dE1hc2tQYXR0ZXJucyAqL1xuXG5jb25zdCBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncyA9IHtcbiAgICAkZGlzYWJsZUlucHV0TWFza1RvZ2dsZTogJCgnI2Rpc2FibGUtaW5wdXQtbWFzaycpLFxuICAgICRkZWxldGVBbGxSZWNvcmRzQnV0dG9uOiAkKCcjZGVsZXRlLWFsbC1yZWNvcmRzJyksXG4gICAgJGRlbGV0ZUFsbE1vZGFsOiAkKCcjZGVsZXRlLWFsbC1tb2RhbC1mb3JtJyksXG4gICAgZGVsZXRlQWxsUmVjb3Jkc0FKQVhVcmw6IGAke2dsb2JhbFJvb3RVcmx9bW9kdWxlLXBob25lLWJvb2svbW9kdWxlLXBob25lLWJvb2svZGVsZXRlQWxsUmVjb3Jkc2AsXG4gICAgZGlzYWJsZUlucHV0TWFza0FKQVhVcmw6IGAke2dsb2JhbFJvb3RVcmx9bW9kdWxlLXBob25lLWJvb2svbW9kdWxlLXBob25lLWJvb2svdG9nZ2xlRGlzYWJsZUlucHV0TWFza2AsXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSBzZXR0aW5ncyBtb2R1bGUgZm9yIHRoZSBwaG9uZWJvb2suXG4gICAgICogSXQgc2V0cyB1cCB0aGUgZXZlbnQgbGlzdGVuZXJzIGZvciB0b2dnbGluZyBpbnB1dCBtYXNrcyBhbmQgZGVsZXRpbmcgYWxsIHJlY29yZHMuXG4gICAgICovXG4gICAgaW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgLy8gSGlkZSB0aGUgZGVsZXRlIGNvbmZpcm1hdGlvbiBtb2RhbCBpbml0aWFsbHlcbiAgICAgICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuJGRlbGV0ZUFsbE1vZGFsLm1vZGFsKCdoaWRlJyk7XG5cbiAgICAgICAgLy8gU2V0IHVwIHRoZSBjaGVja2JveCBmb3IgZGlzYWJsaW5nL2VuYWJsaW5nIHRoZSBpbnB1dCBtYXNrXG4gICAgICAgIE1vZHVsZVBob25lQm9va1NldHRpbmdzLiRkaXNhYmxlSW5wdXRNYXNrVG9nZ2xlLmNoZWNrYm94KHtcbiAgICAgICAgICAgIG9uQ2hhbmdlOiBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy5vbkNoYW5nZUlucHV0TWFza1RvZ2dsZVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBBdHRhY2ggZXZlbnQgbGlzdGVuZXIgZm9yIHRoZSBcIkRlbGV0ZSBBbGwgUmVjb3Jkc1wiIGJ1dHRvblxuICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGVsZXRlQWxsUmVjb3Jkc0J1dHRvbi5vbignY2xpY2snLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy5kZWxldGVBbGxSZWNvcmRzKCk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIGRlbGV0aW9uIG9mIGFsbCByZWNvcmRzLlxuICAgICAqIERpc3BsYXlzIGEgY29uZmlybWF0aW9uIG1vZGFsLCBhbmQgaWYgYXBwcm92ZWQsIHNlbmRzIGEgcmVxdWVzdCB0byBkZWxldGUgYWxsIHBob25lYm9vayByZWNvcmRzLlxuICAgICAqL1xuICAgIGRlbGV0ZUFsbFJlY29yZHMoKSB7XG4gICAgICAgIE1vZHVsZVBob25lQm9va1NldHRpbmdzLiRkZWxldGVBbGxNb2RhbFxuICAgICAgICAgICAgLm1vZGFsKHtcbiAgICAgICAgICAgICAgICBjbG9zYWJsZTogZmFsc2UsIC8vIFByZXZlbnQgY2xvc2luZyB0aGUgbW9kYWwgd2l0aG91dCB1c2VyIGFjdGlvblxuICAgICAgICAgICAgICAgIG9uRGVueTogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gQWxsb3dzIG1vZGFsIHRvIGNsb3NlIG9uIFwiQ2FuY2VsXCJcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG9uQXBwcm92ZTogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGVsZXRlQWxsUmVjb3Jkc0J1dHRvbi5hZGRDbGFzcygnbG9hZGluZycpO1xuICAgICAgICAgICAgICAgICAgICAvLyBPbiBhcHByb3ZhbCwgc2VuZCBhIHJlcXVlc3QgdG8gZGVsZXRlIGFsbCByZWNvcmRzXG4gICAgICAgICAgICAgICAgICAgICQuYXBpKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybDogTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuZGVsZXRlQWxsUmVjb3Jkc0FKQVhVcmwsXG4gICAgICAgICAgICAgICAgICAgICAgICBvbjogJ25vdycsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3NUZXN0OiBQYnhBcGkuc3VjY2Vzc1Rlc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICBvblN1Y2Nlc3MocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGVsZXRlQWxsUmVjb3Jkc0J1dHRvbi5yZW1vdmVDbGFzcygnbG9hZGluZycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVzZXJNZXNzYWdlLnNob3dJbmZvcm1hdGlvbihnbG9iYWxUcmFuc2xhdGUubW9kdWxlX3BobmJrX0FsbFJlY29yZHNEZWxldGVkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZWxvYWQgdGhlIHBhZ2UgYWZ0ZXIgc3VjY2Vzc2Z1bCB1cGRhdGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tEVC5kYXRhVGFibGUuYWpheC5yZWxvYWQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkZhaWx1cmUocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGVsZXRlQWxsUmVjb3Jkc0J1dHRvbi5yZW1vdmVDbGFzcygnbG9hZGluZycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3cgZXJyb3IgbWVzc2FnZSBpZiBkZWxldGlvbiBmYWlsc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVzZXJNZXNzYWdlLnNob3dNdWx0aVN0cmluZyhyZXNwb25zZS5tZXNzYWdlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAubW9kYWwoJ3Nob3cnKTsgLy8gRGlzcGxheSB0aGUgY29uZmlybWF0aW9uIG1vZGFsXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB0aGUgdG9nZ2xlIG9mIHRoZSBpbnB1dCBtYXNrLlxuICAgICAqIFNlbmRzIGEgcmVxdWVzdCB0byB1cGRhdGUgdGhlIHNldHRpbmcgZm9yIGVuYWJsaW5nIG9yIGRpc2FibGluZyBpbnB1dCBtYXNrcy5cbiAgICAgKi9cbiAgICBvbkNoYW5nZUlucHV0TWFza1RvZ2dsZSgpIHtcbiAgICAgICAgY29uc3QgY3VycmVudFN0YXRlID0gTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuJGRpc2FibGVJbnB1dE1hc2tUb2dnbGUuY2hlY2tib3goJ2lzIGNoZWNrZWQnKTtcblxuICAgICAgICAvLyBTZW5kIHJlcXVlc3QgdG8gdG9nZ2xlIHRoZSBpbnB1dCBtYXNrIHNldHRpbmdcbiAgICAgICAgJC5hcGkoe1xuICAgICAgICAgICAgdXJsOiBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy5kaXNhYmxlSW5wdXRNYXNrQUpBWFVybCxcbiAgICAgICAgICAgIG9uOiAnbm93JyxcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgZGF0YTogeyBkaXNhYmxlSW5wdXRNYXNrOiBjdXJyZW50U3RhdGUgfSxcbiAgICAgICAgICAgIHN1Y2Nlc3NUZXN0OiBQYnhBcGkuc3VjY2Vzc1Rlc3QsXG4gICAgICAgICAgICBvblN1Y2Nlc3MocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25GYWlsdXJlKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgLy8gU2hvdyBlcnJvciBtZXNzYWdlIGlmIHRoZSB1cGRhdGUgZmFpbHNcbiAgICAgICAgICAgICAgICBVc2VyTWVzc2FnZS5zaG93TXVsdGlTdHJpbmcocmVzcG9uc2UubWVzc2FnZXMpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG59O1xuXG4vLyBJbml0aWFsaXplIHRoZSBzZXR0aW5ncyBtb2R1bGUgd2hlbiB0aGUgZG9jdW1lbnQgaXMgcmVhZHlcbiQoZG9jdW1lbnQpLnJlYWR5KCgpID0+IHtcbiAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy5pbml0aWFsaXplKCk7XG59KTsiXX0= \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncyIsIiRkaXNhYmxlSW5wdXRNYXNrVG9nZ2xlIiwiJCIsIiRkZWxldGVBbGxSZWNvcmRzQnV0dG9uIiwiJGRlbGV0ZUFsbE1vZGFsIiwiJHNhdmVTZXR0aW5nc0FwaUJ1dHRvbiIsIiRpbnB1dFBob25lQm9va0FwaVVybCIsIiRwaG9uZUJvb2tMaWZlVGltZSIsImRlbGV0ZUFsbFJlY29yZHNBSkFYVXJsIiwiY29uY2F0IiwiZ2xvYmFsUm9vdFVybCIsInNhdmVTZXR0aW5nc0FKQVhVcmwiLCJpbml0aWFsaXplIiwibW9kYWwiLCJjaGVja2JveCIsIm9uQ2hhbmdlIiwib25TYXZlU2V0dGluZ3NBcGkiLCJvbiIsImRlbGV0ZUFsbFJlY29yZHMiLCJjbG9zYWJsZSIsIm9uRGVueSIsIm9uQXBwcm92ZSIsImFkZENsYXNzIiwiYXBpIiwidXJsIiwibWV0aG9kIiwic3VjY2Vzc1Rlc3QiLCJQYnhBcGkiLCJvblN1Y2Nlc3MiLCJyZXNwb25zZSIsInJlbW92ZUNsYXNzIiwiVXNlck1lc3NhZ2UiLCJzaG93SW5mb3JtYXRpb24iLCJnbG9iYWxUcmFuc2xhdGUiLCJtb2R1bGVfcGhuYmtfQWxsUmVjb3Jkc0RlbGV0ZWQiLCJNb2R1bGVQaG9uZUJvb2tEVCIsImRhdGFUYWJsZSIsImFqYXgiLCJyZWxvYWQiLCJvbkZhaWx1cmUiLCJzaG93TXVsdGlTdHJpbmciLCJtZXNzYWdlcyIsImlzT25seUlucHV0TWFzayIsImFyZ3VtZW50cyIsImxlbmd0aCIsInVuZGVmaW5lZCIsImRhdGEiLCJkaXNhYmxlSW5wdXRNYXNrIiwicGhvbmVCb29rQXBpVXJsIiwidmFsIiwicGhvbmVCb29rTGlmZVRpbWUiLCJ3aW5kb3ciLCJsb2NhdGlvbiIsIl9yZXNwb25zZSRtZXNzYWdlIiwibWVzc2FnZSIsImRvY3VtZW50IiwicmVhZHkiXSwic291cmNlcyI6WyJzcmMvbW9kdWxlLXBob25lYm9vay1zZXR0aW5ncy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxyXG4gKiBNaWtvUEJYIC0gZnJlZSBwaG9uZSBzeXN0ZW0gZm9yIHNtYWxsIGJ1c2luZXNzXHJcbiAqIENvcHlyaWdodCDCqSAyMDE3LTIwMjQgQWxleGV5IFBvcnRub3YgYW5kIE5pa29sYXkgQmVrZXRvdlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxyXG4gKiAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS5cclxuICogSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICovXHJcblxyXG4vKiBnbG9iYWwgZ2xvYmFsUm9vdFVybCwgZ2xvYmFsVHJhbnNsYXRlLFxyXG5TZW1hbnRpY0xvY2FsaXphdGlvbiwgVXNlck1lc3NhZ2UsIElucHV0TWFza1BhdHRlcm5zICovXHJcblxyXG5jb25zdCBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncyA9IHtcclxuICAgICRkaXNhYmxlSW5wdXRNYXNrVG9nZ2xlOiAkKCcjZGlzYWJsZS1pbnB1dC1tYXNrJyksXHJcbiAgICAkZGVsZXRlQWxsUmVjb3Jkc0J1dHRvbjogJCgnI2RlbGV0ZS1hbGwtcmVjb3JkcycpLFxyXG4gICAgJGRlbGV0ZUFsbE1vZGFsOiAkKCcjZGVsZXRlLWFsbC1tb2RhbC1mb3JtJyksXHJcbiAgICAkc2F2ZVNldHRpbmdzQXBpQnV0dG9uOiAkKCcjYnRuLXNhdmUtc2V0dGluZ3MtYXBpJyksXHJcbiAgICAkaW5wdXRQaG9uZUJvb2tBcGlVcmw6ICQoJyNwaG9uZUJvb2tBcGlVcmwnKSxcclxuICAgICRwaG9uZUJvb2tMaWZlVGltZTogJCgnI3Bob25lQm9va0xpZmVUaW1lJyksXHJcbiAgICBkZWxldGVBbGxSZWNvcmRzQUpBWFVybDogYCR7Z2xvYmFsUm9vdFVybH1tb2R1bGUtcGhvbmUtYm9vay9tb2R1bGUtcGhvbmUtYm9vay9kZWxldGVBbGxSZWNvcmRzYCxcclxuICAgIHNhdmVTZXR0aW5nc0FKQVhVcmw6IGAke2dsb2JhbFJvb3RVcmx9bW9kdWxlLXBob25lLWJvb2svbW9kdWxlLXBob25lLWJvb2svc2F2ZVNldHRpbmdzYCxcclxuXHJcbiAgICAvKipcclxuICAgICAqIEluaXRpYWxpemUgdGhlIHNldHRpbmdzIG1vZHVsZSBmb3IgdGhlIHBob25lYm9vay5cclxuICAgICAqIEl0IHNldHMgdXAgdGhlIGV2ZW50IGxpc3RlbmVycyBmb3IgdG9nZ2xpbmcgaW5wdXQgbWFza3MgYW5kIGRlbGV0aW5nIGFsbCByZWNvcmRzLlxyXG4gICAgICovXHJcbiAgICBpbml0aWFsaXplKCkge1xyXG4gICAgICAgIC8vIEhpZGUgdGhlIGRlbGV0ZSBjb25maXJtYXRpb24gbW9kYWwgaW5pdGlhbGx5XHJcbiAgICAgICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuJGRlbGV0ZUFsbE1vZGFsLm1vZGFsKCdoaWRlJyk7XHJcblxyXG4gICAgICAgIC8vIFNldCB1cCB0aGUgY2hlY2tib3ggZm9yIGRpc2FibGluZy9lbmFibGluZyB0aGUgaW5wdXQgbWFza1xyXG4gICAgICAgIE1vZHVsZVBob25lQm9va1NldHRpbmdzLiRkaXNhYmxlSW5wdXRNYXNrVG9nZ2xlLmNoZWNrYm94KHtcclxuICAgICAgICAgICAgb25DaGFuZ2U6IE1vZHVsZVBob25lQm9va1NldHRpbmdzLm9uU2F2ZVNldHRpbmdzQXBpXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBldmVudCBsaXN0ZW5lciBmb3IgdGhlIFwiRGVsZXRlIEFsbCBSZWNvcmRzXCIgYnV0dG9uXHJcbiAgICAgICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuJGRlbGV0ZUFsbFJlY29yZHNCdXR0b24ub24oJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy5kZWxldGVBbGxSZWNvcmRzKCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFNhdmUgc2V0dGluZ3NcclxuICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kc2F2ZVNldHRpbmdzQXBpQnV0dG9uLm9uKCdjbGljaycsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3Mub25TYXZlU2V0dGluZ3NBcGkoZmFsc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIEhhbmRsZSB0aGUgZGVsZXRpb24gb2YgYWxsIHJlY29yZHMuXHJcbiAgICAgKiBEaXNwbGF5cyBhIGNvbmZpcm1hdGlvbiBtb2RhbCwgYW5kIGlmIGFwcHJvdmVkLCBzZW5kcyBhIHJlcXVlc3QgdG8gZGVsZXRlIGFsbCBwaG9uZWJvb2sgcmVjb3Jkcy5cclxuICAgICAqL1xyXG4gICAgZGVsZXRlQWxsUmVjb3JkcygpIHtcclxuICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGVsZXRlQWxsTW9kYWxcclxuICAgICAgICAgICAgLm1vZGFsKHtcclxuICAgICAgICAgICAgICAgIGNsb3NhYmxlOiBmYWxzZSwgLy8gUHJldmVudCBjbG9zaW5nIHRoZSBtb2RhbCB3aXRob3V0IHVzZXIgYWN0aW9uXHJcbiAgICAgICAgICAgICAgICBvbkRlbnk6ICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gQWxsb3dzIG1vZGFsIHRvIGNsb3NlIG9uIFwiQ2FuY2VsXCJcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICBvbkFwcHJvdmU6ICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGVsZXRlQWxsUmVjb3Jkc0J1dHRvbi5hZGRDbGFzcygnbG9hZGluZycpO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIE9uIGFwcHJvdmFsLCBzZW5kIGEgcmVxdWVzdCB0byBkZWxldGUgYWxsIHJlY29yZHNcclxuICAgICAgICAgICAgICAgICAgICAkLmFwaSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybDogTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuZGVsZXRlQWxsUmVjb3Jkc0FKQVhVcmwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uOiAnbm93JyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3NUZXN0OiBQYnhBcGkuc3VjY2Vzc1Rlc3QsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uU3VjY2VzcyhyZXNwb25zZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuJGRlbGV0ZUFsbFJlY29yZHNCdXR0b24ucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcnKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVzZXJNZXNzYWdlLnNob3dJbmZvcm1hdGlvbihnbG9iYWxUcmFuc2xhdGUubW9kdWxlX3BobmJrX0FsbFJlY29yZHNEZWxldGVkKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlbG9hZCB0aGUgcGFnZSBhZnRlciBzdWNjZXNzZnVsIHVwZGF0ZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kdWxlUGhvbmVCb29rRFQuZGF0YVRhYmxlLmFqYXgucmVsb2FkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uRmFpbHVyZShyZXNwb25zZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuJGRlbGV0ZUFsbFJlY29yZHNCdXR0b24ucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcnKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3cgZXJyb3IgbWVzc2FnZSBpZiBkZWxldGlvbiBmYWlsc1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd011bHRpU3RyaW5nKHJlc3BvbnNlLm1lc3NhZ2VzKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIC5tb2RhbCgnc2hvdycpOyAvLyBEaXNwbGF5IHRoZSBjb25maXJtYXRpb24gbW9kYWxcclxuICAgIH0sXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBIYW5kbGUgdGhlIHRvZ2dsZSBvZiB0aGUgaW5wdXQgbWFzay5cclxuICAgICAqIFNlbmRzIGEgcmVxdWVzdCB0byB1cGRhdGUgdGhlIHNldHRpbmcgZm9yIGVuYWJsaW5nIG9yIGRpc2FibGluZyBpbnB1dCBtYXNrcy5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzT25seUlucHV0TWFza1xyXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAgICAgKi9cclxuICAgIG9uU2F2ZVNldHRpbmdzQXBpKGlzT25seUlucHV0TWFzayA9IHRydWUpIHtcclxuICAgICAgICBjb25zdCBkYXRhID0ge31cclxuICAgICAgICBpZihpc09ubHlJbnB1dE1hc2spe1xyXG4gICAgICAgICAgICBkYXRhLmRpc2FibGVJbnB1dE1hc2sgPSBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy4kZGlzYWJsZUlucHV0TWFza1RvZ2dsZS5jaGVja2JveCgnaXMgY2hlY2tlZCcpO1xyXG4gICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICBkYXRhLnBob25lQm9va0FwaVVybCA9IE1vZHVsZVBob25lQm9va1NldHRpbmdzLiRpbnB1dFBob25lQm9va0FwaVVybC52YWwoKTtcclxuICAgICAgICAgICAgZGF0YS5waG9uZUJvb2tMaWZlVGltZSA9IE1vZHVsZVBob25lQm9va1NldHRpbmdzLiRwaG9uZUJvb2tMaWZlVGltZS52YWwoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNlbmQgcmVxdWVzdCB0byB0b2dnbGUgdGhlIGlucHV0IG1hc2sgc2V0dGluZ1xyXG4gICAgICAgICQuYXBpKHtcclxuICAgICAgICAgICAgdXJsOiBNb2R1bGVQaG9uZUJvb2tTZXR0aW5ncy5zYXZlU2V0dGluZ3NBSkFYVXJsLFxyXG4gICAgICAgICAgICBvbjogJ25vdycsXHJcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgICAgICBkYXRhOiBkYXRhLFxyXG4gICAgICAgICAgICBzdWNjZXNzVGVzdDogUGJ4QXBpLnN1Y2Nlc3NUZXN0LFxyXG4gICAgICAgICAgICBvblN1Y2Nlc3MocmVzcG9uc2UpIHtcclxuICAgICAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgb25GYWlsdXJlKHJlc3BvbnNlKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBTaG93IGVycm9yIG1lc3NhZ2UgaWYgdGhlIHVwZGF0ZSBmYWlsc1xyXG4gICAgICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd011bHRpU3RyaW5nKHJlc3BvbnNlPy5tZXNzYWdlID8/IHJlc3BvbnNlLm1lc3NhZ2VzKTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICB9KTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0sXHJcbn07XHJcblxyXG4vLyBJbml0aWFsaXplIHRoZSBzZXR0aW5ncyBtb2R1bGUgd2hlbiB0aGUgZG9jdW1lbnQgaXMgcmVhZHlcclxuJChkb2N1bWVudCkucmVhZHkoKCkgPT4ge1xyXG4gICAgTW9kdWxlUGhvbmVCb29rU2V0dGluZ3MuaW5pdGlhbGl6ZSgpO1xyXG59KTtcclxuIl0sIm1hcHBpbmdzIjoiOztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxJQUFNQSx1QkFBdUIsR0FBRztFQUM1QkMsdUJBQXVCLEVBQUVDLENBQUMsQ0FBQyxxQkFBcUIsQ0FBQztFQUNqREMsdUJBQXVCLEVBQUVELENBQUMsQ0FBQyxxQkFBcUIsQ0FBQztFQUNqREUsZUFBZSxFQUFFRixDQUFDLENBQUMsd0JBQXdCLENBQUM7RUFDNUNHLHNCQUFzQixFQUFFSCxDQUFDLENBQUMsd0JBQXdCLENBQUM7RUFDbkRJLHFCQUFxQixFQUFFSixDQUFDLENBQUMsa0JBQWtCLENBQUM7RUFDNUNLLGtCQUFrQixFQUFFTCxDQUFDLENBQUMsb0JBQW9CLENBQUM7RUFDM0NNLHVCQUF1QixLQUFBQyxNQUFBLENBQUtDLGFBQWEseURBQXNE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 \ No newline at end of file diff --git a/public/assets/js/src/module-phonebook-datatable.js b/public/assets/js/src/module-phonebook-datatable.js index 1ac2c7a..073fde5 100644 --- a/public/assets/js/src/module-phonebook-datatable.js +++ b/public/assets/js/src/module-phonebook-datatable.js @@ -30,7 +30,7 @@ const ModulePhoneBookDT = { * The page length selector. * @type {jQuery} */ - $pageLengthSelector:$('#page-length-select'), + $pageLengthSelector: $('#page-length-select'), /** * The page length selector. @@ -97,15 +97,10 @@ const ModulePhoneBookDT = { /** * Initialize the search functionality. - * It listens for key events and applies a filter based on the user's input. + * Sets up the search input field ready for use. */ initializeSearch() { - this.$globalSearch.on('keyup', (e) => { - const searchText = this.$globalSearch.val().trim(); - if (e.keyCode === 13 || e.keyCode === 8 || searchText.length === 0) { - this.applyFilter(searchText); - } - }); + // Search handler is initialized in initializeDataTable() with debounce }, /** @@ -147,7 +142,7 @@ const ModulePhoneBookDT = { // Handle page length selection this.$pageLengthSelector.dropdown({ onChange(pageLength) { - if (pageLength==='auto'){ + if (pageLength === 'auto') { pageLength = this.calculatePageLength(); localStorage.removeItem('phonebookTablePageLength'); } else { @@ -158,7 +153,7 @@ const ModulePhoneBookDT = { }); // Prevent event bubbling on dropdown click - this.$pageLengthSelector.on('click', function(event) { + this.$pageLengthSelector.on('click', function (event) { event.stopPropagation(); // Prevent the event from bubbling }); }, @@ -229,7 +224,7 @@ const ModulePhoneBookDT = { const pageLength = savedPageLength ? savedPageLength : this.calculatePageLength(); this.$recordsTable.dataTable({ - search: { search: this.$globalSearch.val() }, + search: {search: this.$globalSearch.val()}, serverSide: true, processing: true, ajax: { @@ -238,10 +233,10 @@ const ModulePhoneBookDT = { dataSrc: 'data', }, columns: [ - { data: null }, - { data: 'call_id' }, - { data: 'number' }, - { data: null }, + {data: null}, + {data: 'call_id'}, + {data: 'number'}, + {data: null}, ], paging: true, pageLength: pageLength, @@ -310,18 +305,15 @@ const ModulePhoneBookDT = { * @param {Object} data - The data object for the row. */ buildRowTemplate(row, data) { - const nameTemplate = ` -
+ const nameTemplate = `
`; - const numberTemplate = ` -
+ const numberTemplate = `
`; - const deleteButtonTemplate = ` -
+ const deleteButtonTemplate = ``; @@ -363,7 +355,7 @@ const ModulePhoneBookDT = { $el.inputmasks({ inputmask: { definitions: { - '#': { validator: '[0-9]', cardinality: 1 }, + '#': {validator: '[0-9]', cardinality: 1}, }, showMaskOnHover: false, onBeforePaste: this.cbOnNumberBeforePaste, @@ -386,14 +378,10 @@ const ModulePhoneBookDT = { if (!callerId || !numberInputVal) return; - let number = numberInputVal.replace(/\D+/g, ''); - number = `1${number.substr(number.length - 9)}`; - const data = { call_id: callerId, number_rep: numberInputVal, - number, - id: recordId, + id: recordId }; this.displaySavingIcon(recordId); @@ -433,6 +421,7 @@ const ModulePhoneBookDT = { if (response.data) { let oldId = response.data.oldId || recordId; $(`tr#${oldId} input`).attr('readonly', true); + $(`tr#${oldId} a.delete.button`).attr('data-value', response.data.newId); $(`tr#${oldId} div`).removeClass('changed-field loading').addClass('transparent'); $(`tr#${oldId} .spinner.loading`).addClass('user circle').removeClass('spinner loading'); if (oldId !== response.data.newId) { @@ -508,4 +497,4 @@ const ModulePhoneBookDT = { $(document).ready(() => { ModulePhoneBookDT.initialize(); -}); \ No newline at end of file +}); diff --git a/public/assets/js/src/module-phonebook-settings.js b/public/assets/js/src/module-phonebook-settings.js index 3d9109d..de74db8 100644 --- a/public/assets/js/src/module-phonebook-settings.js +++ b/public/assets/js/src/module-phonebook-settings.js @@ -23,8 +23,11 @@ const ModulePhoneBookSettings = { $disableInputMaskToggle: $('#disable-input-mask'), $deleteAllRecordsButton: $('#delete-all-records'), $deleteAllModal: $('#delete-all-modal-form'), + $saveSettingsApiButton: $('#btn-save-settings-api'), + $inputPhoneBookApiUrl: $('#phoneBookApiUrl'), + $phoneBookLifeTime: $('#phoneBookLifeTime'), deleteAllRecordsAJAXUrl: `${globalRootUrl}module-phone-book/module-phone-book/deleteAllRecords`, - disableInputMaskAJAXUrl: `${globalRootUrl}module-phone-book/module-phone-book/toggleDisableInputMask`, + saveSettingsAJAXUrl: `${globalRootUrl}module-phone-book/module-phone-book/saveSettings`, /** * Initialize the settings module for the phonebook. @@ -36,13 +39,18 @@ const ModulePhoneBookSettings = { // Set up the checkbox for disabling/enabling the input mask ModulePhoneBookSettings.$disableInputMaskToggle.checkbox({ - onChange: ModulePhoneBookSettings.onChangeInputMaskToggle + onChange: ModulePhoneBookSettings.onSaveSettingsApi }); // Attach event listener for the "Delete All Records" button ModulePhoneBookSettings.$deleteAllRecordsButton.on('click', function () { ModulePhoneBookSettings.deleteAllRecords(); }); + + // Save settings + ModulePhoneBookSettings.$saveSettingsApiButton.on('click', function () { + ModulePhoneBookSettings.onSaveSettingsApi(false); + }); }, /** @@ -85,23 +93,32 @@ const ModulePhoneBookSettings = { /** * Handle the toggle of the input mask. * Sends a request to update the setting for enabling or disabling input masks. + * + * @param {boolean} isOnlyInputMask + * @returns {boolean} */ - onChangeInputMaskToggle() { - const currentState = ModulePhoneBookSettings.$disableInputMaskToggle.checkbox('is checked'); + onSaveSettingsApi(isOnlyInputMask = true) { + const data = {} + if(isOnlyInputMask){ + data.disableInputMask = ModulePhoneBookSettings.$disableInputMaskToggle.checkbox('is checked'); + }else{ + data.phoneBookApiUrl = ModulePhoneBookSettings.$inputPhoneBookApiUrl.val(); + data.phoneBookLifeTime = ModulePhoneBookSettings.$phoneBookLifeTime.val(); + } // Send request to toggle the input mask setting $.api({ - url: ModulePhoneBookSettings.disableInputMaskAJAXUrl, + url: ModulePhoneBookSettings.saveSettingsAJAXUrl, on: 'now', method: 'POST', - data: { disableInputMask: currentState }, + data: data, successTest: PbxApi.successTest, onSuccess(response) { window.location.reload(); }, onFailure(response) { // Show error message if the update fails - UserMessage.showMultiString(response.messages); + UserMessage.showMultiString(response?.message ?? response.messages); }, }); return true; @@ -111,4 +128,4 @@ const ModulePhoneBookSettings = { // Initialize the settings module when the document is ready $(document).ready(() => { ModulePhoneBookSettings.initialize(); -}); \ No newline at end of file +});