diff --git a/README.md b/README.md
index 688d983a0..ff0a47663 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ The system has an easy and convenient web interface, call recording, conference
## Getting Started
1. Download [latest released](https://github.com/mikopbx/Core/releases/latest) ISO file in assets section
2. Create a new virtual machine (e.g. VMware Player)
-3. Select **Other Linux 4.x kernel 64-bit** on the virtual machine settings
+3. Select **Other Linux 6.6.1 kernel 64-bit** on the virtual machine settings
4. Boot from ISO firmware and install MikoPBX on storage according to internal instructions.
5. Continue set up your PBX system over a web interface with default credentials. Username: *admin* password: *admin*
@@ -52,7 +52,7 @@ Or follow our wiki for [additional instructions](https://wiki.mikopbx.com/en:set
* Easy to install and easy to setup.
* Multilingual interface with community-supported translation service.
* Wiki documentation with context helpers on the web interface.
-* Latest PJSIP stack and Asterisk LTS 16 release installed.
+* Latest PJSIP stack and Asterisk LTS 20 release installed.
* Fail2Ban and iptables already included.
* Modular architecture.
* Plugins marketplace.
@@ -107,7 +107,7 @@ Become a sponsor and get your logo on our README on Github with a link to your s
## License
MikoPBX© - free phone system for small business
-Copyright © 2017-2021 Alexey Portnov and Nikolay Beketov
+Copyright © 2017-2024 Alexey Portnov and Nikolay Beketov
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sites/admin-cabinet/assets/js/pbx/GeneralSettings/general-settings-modify.js b/sites/admin-cabinet/assets/js/pbx/GeneralSettings/general-settings-modify.js
index ee35cce5d..89800a675 100644
--- a/sites/admin-cabinet/assets/js/pbx/GeneralSettings/general-settings-modify.js
+++ b/sites/admin-cabinet/assets/js/pbx/GeneralSettings/general-settings-modify.js
@@ -356,8 +356,11 @@ var generalSettingsModify = {
* @param {Object} response - The response from the server after the form is sent
*/
cbAfterSendForm: function cbAfterSendForm(response) {
+ $("#error-messages").remove();
+
if (!response.success) {
Form.$submitButton.removeClass('disabled');
+ generalSettingsModify.generateErrorMessageHtml(response);
} else {
$('.password-validate').remove();
}
@@ -365,6 +368,47 @@ var generalSettingsModify = {
generalSettingsModify.checkDeleteAllConditions();
},
+ /**
+ * The function collects an information message about a data saving error
+ * @param response
+ */
+ generateErrorMessageHtml: function generateErrorMessageHtml(response) {
+ if (response.messages && response.messages.error) {
+ var $div = $('
', {
+ "class": 'ui negative message',
+ id: 'error-messages'
+ });
+ var $header = $('
', {
+ "class": 'header'
+ }).text(globalTranslate.gs_ErrorSaveSettings);
+ $div.append($header);
+ var $ul = $('
', {
+ "class": 'list'
+ });
+ var messagesSet = new Set();
+ response.messages.error.forEach(function (errorArray) {
+ errorArray.forEach(function (error) {
+ var textContent = '';
+
+ if (globalTranslate[error.message] === undefined) {
+ textContent = error.message;
+ } else {
+ textContent = globalTranslate[error.message];
+ }
+
+ if (messagesSet.has(textContent)) {
+ return;
+ }
+
+ messagesSet.add(error.message);
+ $ul.append($('- ').text(textContent));
+ });
+ });
+ $div.append($ul);
+ $('#submitbutton').before($div);
+ }
+ },
+
/**
* Initialize the validation rules of the form
*/
@@ -406,4 +450,4 @@ var generalSettingsModify = {
$(document).ready(function () {
generalSettingsModify.initialize();
});
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9HZW5lcmFsU2V0dGluZ3MvZ2VuZXJhbC1zZXR0aW5ncy1tb2RpZnkuanMiXSwibmFtZXMiOlsiZ2VuZXJhbFNldHRpbmdzTW9kaWZ5IiwiJGZvcm1PYmoiLCIkIiwiJHdlYkFkbWluUGFzc3dvcmQiLCIkc3NoUGFzc3dvcmQiLCIkZGlzYWJsZVNTSFBhc3N3b3JkIiwicGFyZW50IiwiJHNzaFBhc3N3b3JkU2VnbWVudCIsImhpZGRlblBhc3N3b3JkIiwiJHJlY29yZHNTYXZlUGVyaW9kU2xpZGVyIiwic2F2ZVJlY29yZHNQZXJpb2QiLCJ2YWxpZGF0ZVJ1bGVzIiwicGJ4bmFtZSIsImlkZW50aWZpZXIiLCJydWxlcyIsInR5cGUiLCJwcm9tcHQiLCJnbG9iYWxUcmFuc2xhdGUiLCJnc19WYWxpZGF0ZUVtcHR5UEJYTmFtZSIsIldlYkFkbWluUGFzc3dvcmQiLCJXZWJBZG1pblBhc3N3b3JkUmVwZWF0IiwiZ3NfVmFsaWRhdGVXZWJQYXNzd29yZHNGaWVsZERpZmZlcmVudCIsIlNTSFBhc3N3b3JkIiwiU1NIUGFzc3dvcmRSZXBlYXQiLCJnc19WYWxpZGF0ZVNTSFBhc3N3b3Jkc0ZpZWxkRGlmZmVyZW50IiwiV0VCUG9ydCIsImdzX1ZhbGlkYXRlV0VCUG9ydE91dE9mUmFuZ2UiLCJnc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE5vdEVxdWFsVG9XRUJQb3J0IiwiZ3NfVmFsaWRhdGVXRUJQb3J0Tm90RXF1YWxUb0FqYW1Qb3J0IiwiZ3NfVmFsaWRhdGVXRUJQb3J0Tm90RXF1YWxUb0FqYW1UTFNQb3J0IiwiV0VCSFRUUFNQb3J0IiwiZ3NfVmFsaWRhdGVXRUJIVFRQU1BvcnRPdXRPZlJhbmdlIiwiZ3NfVmFsaWRhdGVXRUJIVFRQU1BvcnROb3RFcXVhbFRvQWphbVBvcnQiLCJnc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE5vdEVxdWFsVG9BamFtVExTUG9ydCIsIkFKQU1Qb3J0IiwiZ3NfVmFsaWRhdGVBSkFNUG9ydE91dE9mUmFuZ2UiLCJ3ZWJBZG1pblBhc3N3b3JkUnVsZXMiLCJnc19WYWxpZGF0ZUVtcHR5V2ViUGFzc3dvcmQiLCJnc19WYWxpZGF0ZVdlYWtXZWJQYXNzd29yZCIsInZhbHVlIiwiZ3NfUGFzc3dvcmRzIiwiZ3NfUGFzc3dvcmROb0xvd1NpbXZvbCIsImdzX1Bhc3N3b3JkTm9OdW1iZXJzIiwiZ3NfUGFzc3dvcmROb1VwcGVyU2ltdm9sIiwiYWRkaXRpb25hbFNzaFZhbGlkUnVsZXNQYXNzIiwiZ3NfVmFsaWRhdGVFbXB0eVNTSFBhc3N3b3JkIiwiZ3NfVmFsaWRhdGVXZWFrU1NIUGFzc3dvcmQiLCJnc19TU0hQYXNzd29yZCIsImFkZGl0aW9uYWxTc2hWYWxpZFJ1bGVzTm9QYXNzIiwiaW5pdGlhbGl6ZSIsIm9uIiwidmFsIiwiaW5pdFJ1bGVzIiwiUGFzc3dvcmRTY29yZSIsImNoZWNrUGFzc1N0cmVuZ3RoIiwicGFzcyIsImJhciIsInNlY3Rpb24iLCJmaW5kIiwidGFiIiwiaGlzdG9yeSIsImhpc3RvcnlUeXBlIiwiZHJvcGRvd24iLCJjaGVja2JveCIsInRhYmxlRG5EIiwib25Ecm9wIiwiRm9ybSIsImRhdGFDaGFuZ2VkIiwib25EcmFnQ2xhc3MiLCJkcmFnSGFuZGxlIiwiU291bmRGaWxlc1NlbGVjdG9yIiwiZ2V0RHJvcGRvd25TZXR0aW5nc1dpdGhFbXB0eSIsInNsaWRlciIsIm1pbiIsIm1heCIsInN0ZXAiLCJzbW9vdGgiLCJpbnRlcnByZXRMYWJlbCIsImxhYmVscyIsImdzX1N0b3JlMU1vbnRoT2ZSZWNvcmRzIiwiZ3NfU3RvcmUzTW9udGhzT2ZSZWNvcmRzIiwiZ3NfU3RvcmU2TW9udGhzT2ZSZWNvcmRzIiwiZ3NfU3RvcmUxWWVhck9mUmVjb3JkcyIsImdzX1N0b3JlM1llYXJzT2ZSZWNvcmRzIiwiZ3NfU3RvcmVBbGxQb3NzaWJsZVJlY29yZHMiLCJvbkNoYW5nZSIsImNiQWZ0ZXJTZWxlY3RTYXZlUGVyaW9kU2xpZGVyIiwiaW5pdGlhbGl6ZUZvcm0iLCJzaG93SGlkZVNTSFBhc3N3b3JkIiwicmVjb3JkU2F2ZVBlcmlvZCIsImZvcm0iLCJpbmRleE9mIiwid2luZG93IiwiZXZlbnQiLCJuYW1lVGFiIiwiaGlkZSIsInNob3ciLCJjaGVja0RlbGV0ZUFsbENvbmRpdGlvbnMiLCJkZWxldGVBbGxJbnB1dCIsImdzX0VudGVyRGVsZXRlQWxsUGhyYXNlIiwiUGJ4QXBpIiwiU3lzdGVtUmVzdG9yZURlZmF1bHRTZXR0aW5ncyIsImNiQWZ0ZXJSZXN0b3JlRGVmYXVsdFNldHRpbmdzIiwicmVzcG9uc2UiLCJVc2VyTWVzc2FnZSIsInNob3dJbmZvcm1hdGlvbiIsImdzX0FsbFNldHRpbmdzRGVsZXRlZCIsInNob3dNdWx0aVN0cmluZyIsInNhdmVQZXJpb2QiLCJjYkJlZm9yZVNlbmRGb3JtIiwic2V0dGluZ3MiLCJyZXN1bHQiLCJkYXRhIiwiYXJyQ29kZWNzIiwiZWFjaCIsImluZGV4Iiwib2JqIiwiYXR0ciIsInB1c2giLCJjb2RlY0lkIiwiZGlzYWJsZWQiLCJwcmlvcml0eSIsImNvZGVjcyIsIkpTT04iLCJzdHJpbmdpZnkiLCJjYkFmdGVyU2VuZEZvcm0iLCJzdWNjZXNzIiwiJHN1Ym1pdEJ1dHRvbiIsInJlbW92ZUNsYXNzIiwicmVtb3ZlIiwidXJsIiwiZ2xvYmFsUm9vdFVybCIsImRvY3VtZW50IiwicmVhZHkiXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFNQSxxQkFBcUIsR0FBRztBQUMxQjtBQUNKO0FBQ0E7QUFDQTtBQUNJQyxFQUFBQSxRQUFRLEVBQUVDLENBQUMsQ0FBQyx3QkFBRCxDQUxlOztBQU8xQjtBQUNKO0FBQ0E7QUFDQTtBQUNJQyxFQUFBQSxpQkFBaUIsRUFBRUQsQ0FBQyxDQUFDLG1CQUFELENBWE07O0FBYTFCO0FBQ0o7QUFDQTtBQUNBO0FBQ0lFLEVBQUFBLFlBQVksRUFBRUYsQ0FBQyxD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RkQsTUFFTztBQUNIb0QsTUFBQUEsSUFBSSxDQUFDdkQsYUFBTCxDQUFtQlEsZ0JBQW5CLENBQW9DTCxLQUFwQyxHQUE0Q2QscUJBQXFCLENBQUNvQyxxQkFBbEU7QUFDSDtBQUNKLEdBdmF5Qjs7QUF5YTFCO0FBQ0o7QUFDQTtBQUNJbUQsRUFBQUEsY0E1YTBCLDRCQTRhVDtBQUNickIsSUFBQUEsSUFBSSxDQUFDakUsUUFBTCxHQUFnQkQscUJBQXFCLENBQUNDLFFBQXRDO0FBQ0FpRSxJQUFBQSxJQUFJLENBQUNnRSxHQUFMLGFBQWNDLGFBQWQsMkJBRmEsQ0FFdUM7O0FBQ3BEakUsSUFBQUEsSUFBSSxDQUFDdkQsYUFBTCxHQUFxQlgscUJBQXFCLENBQUNXLGFBQTNDLENBSGEsQ0FHNkM7O0FBQzFEdUQsSUFBQUEsSUFBSSxDQUFDMkMsZ0JBQUwsR0FBd0I3RyxxQkFBcUIsQ0FBQzZHLGdCQUE5QyxDQUphLENBSW1EOztBQUNoRTNDLElBQUFBLElBQUksQ0FBQzJELGVBQUwsR0FBdUI3SCxxQkFBcUIsQ0FBQzZILGVBQTdDLENBTGEsQ0FLaUQ7O0FBQzlEM0QsSUFBQUEsSUFBSSxDQUFDakIsVUFBTDtBQUNIO0FBbmJ5QixDQUE5QixDLENBc2JBOztBQUNBL0MsQ0FBQyxDQUFDa0ksUUFBRCxDQUFELENBQVlDLEtBQVosQ0FBa0IsWUFBTTtBQUNwQnJJLEVBQUFBLHFCQUFxQixDQUFDaUQsVUFBdEI7QUFDSCxDQUZEIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pa29QQlggLSBmcmVlIHBob25lIHN5c3RlbSBmb3Igc21hbGwgYnVzaW5lc3NcbiAqIENvcHlyaWdodCDCqSAyMDE3LTIwMjMgQWxleGV5IFBvcnRub3YgYW5kIE5pa29sYXkgQmVrZXRvdlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAqIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbiAqXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS5cbiAqIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gKi9cblxuXG4vKiBnbG9iYWwgZ2xvYmFsUm9vdFVybCxnbG9iYWxUcmFuc2xhdGUsIEZvcm0sIFBhc3N3b3JkU2NvcmUsIFBieEFwaSwgVXNlck1lc3NhZ2UsIFNvdW5kRmlsZXNTZWxlY3RvciwgJCAqL1xuXG4vKipcbiAqIEEgbW9kdWxlIHRvIGhhbmRsZSBtb2RpZmljYXRpb24gb2YgZ2VuZXJhbCBzZXR0aW5ncy5cbiAqL1xuY29uc3QgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5ID0ge1xuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSBmb3JtLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJGZvcm1PYmo6ICQoJyNnZW5lcmFsLXNldHRpbmdzLWZvcm0nKSxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSB3ZWIgYWRtaW4gcGFzc3dvcmQgaW5wdXQgZmllbGQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkd2ViQWRtaW5QYXNzd29yZDogJCgnI1dlYkFkbWluUGFzc3dvcmQnKSxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSBzc2ggcGFzc3dvcmQgaW5wdXQgZmllbGQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkc3NoUGFzc3dvcmQ6ICQoJyNTU0hQYXNzd29yZCcpLFxuXG4gICAgLyoqXG4gICAgICogalF1ZXJ5IG9iamVjdCBmb3IgdGhlIHdlYiBzc2ggcGFzc3dvcmQgaW5wdXQgZmllbGQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkZGlzYWJsZVNTSFBhc3N3b3JkOiAkKCcjU1NIRGlzYWJsZVBhc3N3b3JkTG9naW5zJykucGFyZW50KCcuY2hlY2tib3gnKSxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSBTU0ggcGFzc3dvcmQgZmllbGRzXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkc3NoUGFzc3dvcmRTZWdtZW50OiAkKCcjb25seS1pZi1wYXNzd29yZC1lbmFibGVkJyksXG5cbiAgICAvKipcbiAgICAgKiBJZiBwYXNzd29yZCBzZXQsIGl0IHdpbGwgYmUgaGlkZWQgZnJvbSB3ZWIgdWkuXG4gICAgICovXG4gICAgaGlkZGVuUGFzc3dvcmQ6ICd4eHh4eHh4JyxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSByZWNvcmRzIHJldGVudGlvbiBwZXJpb2Qgc2xpZGVyLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJHJlY29yZHNTYXZlUGVyaW9kU2xpZGVyOiAkKCcjUEJYUmVjb3JkU2F2ZVBlcmlvZFNsaWRlcicpLFxuXG4gICAgLyoqXG4gICAgICogUG9zc2libGUgcGVyaW9kIHZhbHVlcyBmb3IgdGhlIHJlY29yZHMgcmV0ZW50aW9uLlxuICAgICAqL1xuICAgIHNhdmVSZWNvcmRzUGVyaW9kOiBbJzMwJywgJzkwJywgJzE4MCcsICczNjAnLCAnMTA4MCcsICcnXSxcblxuICAgIC8qKlxuICAgICAqIFZhbGlkYXRpb24gcnVsZXMgZm9yIHRoZSBmb3JtIGZpZWxkcyBiZWZvcmUgc3VibWlzc2lvbi5cbiAgICAgKlxuICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICovXG4gICAgdmFsaWRhdGVSdWxlczogeyAvLyBnZW5lcmFsU2V0dGluZ3NNb2RpZnkudmFsaWRhdGVSdWxlcy5TU0hQYXNzd29yZC5ydWxlc1xuICAgICAgICBwYnhuYW1lOiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnUEJYTmFtZScsXG4gICAgICAgICAgICBydWxlczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2VtcHR5JyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVFbXB0eVBCWE5hbWUsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIFdlYkFkbWluUGFzc3dvcmQ6IHtcbiAgICAgICAgICAgIGlkZW50aWZpZXI6ICdXZWJBZG1pblBhc3N3b3JkJyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXSxcbiAgICAgICAgfSxcbiAgICAgICAgV2ViQWRtaW5QYXNzd29yZFJlcGVhdDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ1dlYkFkbWluUGFzc3dvcmRSZXBlYXQnLFxuICAgICAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdtYXRjaFtXZWJBZG1pblBhc3N3b3JkXScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV2ViUGFzc3dvcmRzRmllbGREaWZmZXJlbnQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIFNTSFBhc3N3b3JkOiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnU1NIUGFzc3dvcmQnLFxuICAgICAgICAgICAgcnVsZXM6IFtdLFxuICAgICAgICB9LFxuICAgICAgICBTU0hQYXNzd29yZFJlcGVhdDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ1NTSFBhc3N3b3JkUmVwZWF0JyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnbWF0Y2hbU1NIUGFzc3dvcmRdJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVTU0hQYXNzd29yZHNGaWVsZERpZmZlcmVudCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgV0VCUG9ydDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ1dFQlBvcnQnLFxuICAgICAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdpbnRlZ2VyWzEuLjY1NTM1XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCUG9ydE91dE9mUmFuZ2UsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdkaWZmZXJlbnRbV0VCSFRUUFNQb3J0XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCSFRUUFNQb3J0Tm90RXF1YWxUb1dFQlBvcnQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdkaWZmZXJlbnRbQUpBTVBvcnRUTFNdJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVXRUJQb3J0Tm90RXF1YWxUb0FqYW1Qb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGlmZmVyZW50W0FKQU1Qb3J0XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCUG9ydE5vdEVxdWFsVG9BamFtVExTUG9ydCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgV0VCSFRUUFNQb3J0OiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnV0VCSFRUUFNQb3J0JyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnaW50ZWdlclsxLi42NTUzNV0nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE91dE9mUmFuZ2UsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdkaWZmZXJlbnRbV0VCUG9ydF0nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE5vdEVxdWFsVG9XRUJQb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGlmZmVyZW50W0FKQU1Qb3J0VExTXScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCSFRUUFNQb3J0Tm90RXF1YWxUb0FqYW1Qb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGlmZmVyZW50W0FKQU1Qb3J0XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCSFRUUFNQb3J0Tm90RXF1YWxUb0FqYW1UTFNQb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgICBBSkFNUG9ydDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ0FKQU1Qb3J0JyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnaW50ZWdlclsxLi42NTUzNV0nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZUFKQU1Qb3J0T3V0T2ZSYW5nZSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2RpZmZlcmVudFtBSkFNUG9ydFRMU10nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZUFKQU1Qb3J0T3V0T2ZSYW5nZSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICB9LFxuXG4gICAgLy8gUnVsZXMgZm9yIHRoZSB3ZWIgYWRtaW4gcGFzc3dvcmQgZmllbGQgd2hlbiBpdCBub3QgZXF1YWwgdG8gaGlkZGVuUGFzc3dvcmRcbiAgICB3ZWJBZG1pblBhc3N3b3JkUnVsZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ2VtcHR5JyxcbiAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlRW1wdHlXZWJQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ21pbkxlbmd0aFs1XScsXG4gICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdlYWtXZWJQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ25vdFJlZ0V4cCcsXG4gICAgICAgICAgICB2YWx1ZTogL1thLXpdLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmRzICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb0xvd1NpbXZvbFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAnbm90UmVnRXhwJyxcbiAgICAgICAgICAgIHZhbHVlOiAvXFxkLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmRzICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb051bWJlcnNcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ25vdFJlZ0V4cCcsXG4gICAgICAgICAgICB2YWx1ZTogL1tBLVpdLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmRzICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb1VwcGVyU2ltdm9sXG4gICAgICAgIH1cbiAgICBdLFxuICAgIC8vIFJ1bGVzIGZvciB0aGUgU1NIIHBhc3N3b3JkIGZpZWxkIHdoZW4gU1NIIGxvZ2luIHRocm91Z2ggdGhlIHBhc3N3b3JkIGVuYWJsZWQsIGFuZCBpdCBub3QgZXF1YWwgdG8gaGlkZGVuUGFzc3dvcmRcbiAgICBhZGRpdGlvbmFsU3NoVmFsaWRSdWxlc1Bhc3M6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ2VtcHR5JyxcbiAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlRW1wdHlTU0hQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ21pbkxlbmd0aFs1XScsXG4gICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdlYWtTU0hQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ25vdFJlZ0V4cCcsXG4gICAgICAgICAgICB2YWx1ZTogL1thLXpdLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfU1NIUGFzc3dvcmQgKyAnPC9iPjogJyArIGdsb2JhbFRyYW5zbGF0ZS5nc19QYXNzd29yZE5vTG93U2ltdm9sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHR5cGU6ICdub3RSZWdFeHAnLFxuICAgICAgICAgICAgdmFsdWU6IC9cXGQvLFxuICAgICAgICAgICAgcHJvbXB0OiAnPGI+JyArIGdsb2JhbFRyYW5zbGF0ZS5nc19TU0hQYXNzd29yZCArICc8L2I+OiAnICsgZ2xvYmFsVHJhbnNsYXRlLmdzX1Bhc3N3b3JkTm9OdW1iZXJzXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHR5cGU6ICdub3RSZWdFeHAnLFxuICAgICAgICAgICAgdmFsdWU6IC9bQS1aXS8sXG4gICAgICAgICAgICBwcm9tcHQ6ICc8Yj4nICsgZ2xvYmFsVHJhbnNsYXRlLmdzX1NTSFBhc3N3b3JkICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb1VwcGVyU2ltdm9sXG4gICAgICAgIH1cbiAgICBdLFxuXG4gICAgLy8gUnVsZXMgZm9yIHRoZSBTU0ggcGFzc3dvcmQgZmllbGQgd2hlbiBTU0ggbG9naW4gdGhyb3VnaCB0aGUgcGFzc3dvcmQgZGlzYWJsZWRcbiAgICBhZGRpdGlvbmFsU3NoVmFsaWRSdWxlc05vUGFzczogW1xuICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAnZW1wdHknLFxuICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVFbXB0eVNTSFBhc3N3b3JkLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAnbWluTGVuZ3RoWzVdJyxcbiAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV2Vha1NTSFBhc3N3b3JkLFxuICAgICAgICB9XG4gICAgXSxcblxuICAgIC8qKlxuICAgICAqICBJbml0aWFsaXplIG1vZHVsZSB3aXRoIGV2ZW50IGJpbmRpbmdzIGFuZCBjb21wb25lbnQgaW5pdGlhbGl6YXRpb25zLlxuICAgICAqL1xuICAgIGluaXRpYWxpemUoKSB7XG5cbiAgICAgICAgLy8gV2hlbiBXZWJBZG1pblBhc3N3b3JkIGlucHV0IGlzIGNoYW5nZWQsIHJlY2FsY3VsYXRlIHRoZSBwYXNzd29yZCBzdHJlbmd0aFxuICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHdlYkFkbWluUGFzc3dvcmQub24oJ2tleXVwJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kd2ViQWRtaW5QYXNzd29yZC52YWwoKSAhPT0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmhpZGRlblBhc3N3b3JkKSB7XG4gICAgICAgICAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRSdWxlcygpO1xuICAgICAgICAgICAgICAgIFBhc3N3b3JkU2NvcmUuY2hlY2tQYXNzU3RyZW5ndGgoe1xuICAgICAgICAgICAgICAgICAgICBwYXNzOiBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHdlYkFkbWluUGFzc3dvcmQudmFsKCksXG4gICAgICAgICAgICAgICAgICAgIGJhcjogJCgnLnBhc3N3b3JkLXNjb3JlJyksXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246ICQoJy5wYXNzd29yZC1zY29yZS1zZWN0aW9uJyksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFdoZW4gU1NIUGFzc3dvcmQgaW5wdXQgaXMgY2hhbmdlZCwgcmVjYWxjdWxhdGUgdGhlIHBhc3N3b3JkIHN0cmVuZ3RoXG4gICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kc3NoUGFzc3dvcmQub24oJ2tleXVwJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kc3NoUGFzc3dvcmQudmFsKCkgIT09IGdlbmVyYWxTZXR0aW5nc01vZGlmeS5oaWRkZW5QYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS5pbml0UnVsZXMoKTtcbiAgICAgICAgICAgICAgICBQYXNzd29yZFNjb3JlLmNoZWNrUGFzc1N0cmVuZ3RoKHtcbiAgICAgICAgICAgICAgICAgICAgcGFzczogZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRzc2hQYXNzd29yZC52YWwoKSxcbiAgICAgICAgICAgICAgICAgICAgYmFyOiAkKCcuc3NoLXBhc3N3b3JkLXNjb3JlJyksXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246ICQoJy5zc2gtcGFzc3dvcmQtc2NvcmUtc2VjdGlvbicpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBFbmFibGUgdGFiIG5hdmlnYXRpb24gd2l0aCBoaXN0b3J5IHN1cHBvcnRcbiAgICAgICAgJCgnI2dlbmVyYWwtc2V0dGluZ3MtbWVudScpLmZpbmQoJy5pdGVtJykudGFiKHtcbiAgICAgICAgICAgIGhpc3Rvcnk6IHRydWUsXG4gICAgICAgICAgICBoaXN0b3J5VHlwZTogJ2hhc2gnLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBFbmFibGUgZHJvcGRvd25zIG9uIHRoZSBmb3JtXG4gICAgICAgICQoJyNnZW5lcmFsLXNldHRpbmdzLWZvcm0gLmRyb3Bkb3duJykuZHJvcGRvd24oKTtcblxuICAgICAgICAvLyBFbmFibGUgY2hlY2tib3hlcyBvbiB0aGUgZm9ybVxuICAgICAgICAkKCcjZ2VuZXJhbC1zZXR0aW5ncy1mb3JtIC5jaGVja2JveCcpLmNoZWNrYm94KCk7XG5cbiAgICAgICAgLy8gRW5hYmxlIHRhYmxlIGRyYWctbi1kcm9wIGZ1bmN0aW9uYWxpdHlcbiAgICAgICAgJCgnI2F1ZGlvLWNvZGVjcy10YWJsZSwgI3ZpZGVvLWNvZGVjcy10YWJsZScpLnRhYmxlRG5EKHtcbiAgICAgICAgICAgIG9uRHJvcCgpIHtcbiAgICAgICAgICAgICAgICAvLyBUcmlnZ2VyIGNoYW5nZSBldmVudCB0byBhY2tub3dsZWRnZSB0aGUgbW9kaWZpY2F0aW9uXG4gICAgICAgICAgICAgICAgRm9ybS5kYXRhQ2hhbmdlZCgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uRHJhZ0NsYXNzOiAnaG92ZXJpbmdSb3cnLFxuICAgICAgICAgICAgZHJhZ0hhbmRsZTogJy5kcmFnSGFuZGxlJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gRW5hYmxlIGRyb3Bkb3duIHdpdGggc291bmQgZmlsZSBzZWxlY3Rpb25cbiAgICAgICAgJCgnI2dlbmVyYWwtc2V0dGluZ3MtZm9ybSAuYXVkaW8tbWVzc2FnZS1zZWxlY3QnKS5kcm9wZG93bihTb3VuZEZpbGVzU2VsZWN0b3IuZ2V0RHJvcGRvd25TZXR0aW5nc1dpdGhFbXB0eSgpKTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHJlY29yZHMgc2F2ZSBwZXJpb2Qgc2xpZGVyXG4gICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kcmVjb3Jkc1NhdmVQZXJpb2RTbGlkZXJcbiAgICAgICAgICAgIC5zbGlkZXIoe1xuICAgICAgICAgICAgICAgIG1pbjogMCxcbiAgICAgICAgICAgICAgICBtYXg6IDUsXG4gICAgICAgICAgICAgICAgc3RlcDogMSxcbiAgICAgICAgICAgICAgICBzbW9vdGg6IHRydWUsXG4gICAgICAgICAgICAgICAgaW50ZXJwcmV0TGFiZWw6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgbGFiZWxzID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsVHJhbnNsYXRlLmdzX1N0b3JlMU1vbnRoT2ZSZWNvcmRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsVHJhbnNsYXRlLmdzX1N0b3JlM01vbnRoc09mUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbFRyYW5zbGF0ZS5nc19TdG9yZTZNb250aHNPZlJlY29yZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWxUcmFuc2xhdGUuZ3NfU3RvcmUxWWVhck9mUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbFRyYW5zbGF0ZS5nc19TdG9yZTNZZWFyc09mUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbFRyYW5zbGF0ZS5nc19TdG9yZUFsbFBvc3NpYmxlUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxhYmVsc1t2YWx1ZV07XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBvbkNoYW5nZTogZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNiQWZ0ZXJTZWxlY3RTYXZlUGVyaW9kU2xpZGVyLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGZvcm1cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRpYWxpemVGb3JtKCk7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBhZGRpdGlvbmFsIHZhbGlkYXRpb24gcnVsZXNcbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRSdWxlcygpO1xuXG4gICAgICAgIC8vIFNob3csIGhpZGUgc3NoIHBhc3N3b3JkIHNlZ21lbnRcbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRkaXNhYmxlU1NIUGFzc3dvcmQuY2hlY2tib3goe1xuICAgICAgICAgICAgJ29uQ2hhbmdlJzogZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LnNob3dIaWRlU1NIUGFzc3dvcmRcbiAgICAgICAgfSk7XG4gICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS5zaG93SGlkZVNTSFBhc3N3b3JkKCk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBpbml0aWFsIHZhbHVlIGZvciB0aGUgcmVjb3JkcyBzYXZlIHBlcmlvZCBzbGlkZXJcbiAgICAgICAgY29uc3QgcmVjb3JkU2F2ZVBlcmlvZCA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnUEJYUmVjb3JkU2F2ZVBlcmlvZCcpO1xuICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHJlY29yZHNTYXZlUGVyaW9kU2xpZGVyXG4gICAgICAgICAgICAuc2xpZGVyKCdzZXQgdmFsdWUnLCBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuc2F2ZVJlY29yZHNQZXJpb2QuaW5kZXhPZihyZWNvcmRTYXZlUGVyaW9kKSwgZmFsc2UpO1xuXG4gICAgICAgIC8vIEFkZCBldmVudCBsaXN0ZW5lciB0byBoYW5kbGUgdGFiIGFjdGl2YXRpb25cbiAgICAgICAgJCh3aW5kb3cpLm9uKCdHUy1BY3RpdmF0ZVRhYicsIChldmVudCwgbmFtZVRhYikgPT4ge1xuICAgICAgICAgICAgJCgnI2dlbmVyYWwtc2V0dGluZ3MtbWVudScpLmZpbmQoJy5pdGVtJykudGFiKCdjaGFuZ2UgdGFiJywgbmFtZVRhYik7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTaG93LCBoaWRlIHNzaCBwYXNzd29yZCBzZWdtZW50IGFjY29yZGluZyB0byB0aGUgdmFsdWUgb2YgdXNlIFNTSCBwYXNzd29yZCBjaGVja2JveC5cbiAgICAgKi9cbiAgICBzaG93SGlkZVNTSFBhc3N3b3JkKCl7XG4gICAgICAgIGlmIChnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJGRpc2FibGVTU0hQYXNzd29yZC5jaGVja2JveCgnaXMgY2hlY2tlZCcpKSB7XG4gICAgICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHNzaFBhc3N3b3JkU2VnbWVudC5oaWRlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHNzaFBhc3N3b3JkU2VnbWVudC5zaG93KCk7XG4gICAgICAgIH1cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRSdWxlcygpO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGNvbmRpdGlvbnMgZm9yIGRlbGV0aW5nIGFsbCByZWNvcmRzLlxuICAgICAqIENvbXBhcmVzIHRoZSB2YWx1ZSBvZiB0aGUgJ2RlbGV0ZUFsbElucHV0JyBmaWVsZCB3aXRoIGEgcGhyYXNlLlxuICAgICAqIElmIHRoZXkgbWF0Y2gsIGl0IHRyaWdnZXJzIGEgc3lzdGVtIHJlc3RvcmUgdG8gZGVmYXVsdCBzZXR0aW5ncy5cbiAgICAgKi9cbiAgICBjaGVja0RlbGV0ZUFsbENvbmRpdGlvbnMoKSB7XG5cbiAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZSBvZiAnZGVsZXRlQWxsSW5wdXQnIGZpZWxkLlxuICAgICAgICBjb25zdCBkZWxldGVBbGxJbnB1dCA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnZGVsZXRlQWxsSW5wdXQnKTtcblxuICAgICAgICAvLyBJZiB0aGUgZW50ZXJlZCBwaHJhc2UgbWF0Y2hlcyB0aGUgcGhyYXNlIGluICdnbG9iYWxUcmFuc2xhdGUuZ3NfRW50ZXJEZWxldGVBbGxQaHJhc2UnLFxuICAgICAgICAvLyBjYWxsICdQYnhBcGkuU3lzdGVtUmVzdG9yZURlZmF1bHRTZXR0aW5ncycgdG8gcmVzdG9yZSBkZWZhdWx0IHNldHRpbmdzLlxuICAgICAgICBpZiAoZGVsZXRlQWxsSW5wdXQgPT09IGdsb2JhbFRyYW5zbGF0ZS5nc19FbnRlckRlbGV0ZUFsbFBocmFzZSkge1xuICAgICAgICAgICAgUGJ4QXBpLlN5c3RlbVJlc3RvcmVEZWZhdWx0U2V0dGluZ3MoZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNiQWZ0ZXJSZXN0b3JlRGVmYXVsdFNldHRpbmdzKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgcmVzcG9uc2UgYWZ0ZXIgcmVzdG9yaW5nIGRlZmF1bHQgc2V0dGluZ3MuXG4gICAgICogQHBhcmFtIHtib29sZWFufHN0cmluZ30gcmVzcG9uc2UgLSBSZXNwb25zZSBmcm9tIHRoZSBzZXJ2ZXIgYWZ0ZXIgcmVzdG9yaW5nIGRlZmF1bHQgc2V0dGluZ3MuXG4gICAgICovXG4gICAgY2JBZnRlclJlc3RvcmVEZWZhdWx0U2V0dGluZ3MocmVzcG9uc2UpIHtcblxuICAgICAgICAvLyBDaGVjayBpZiB0aGUgcmVzcG9uc2UgaXMgdHJ1ZSwgZGlzcGxheSBhIHN1Y2Nlc3MgbWVzc2FnZVxuICAgICAgICAvLyBvdGhlcndpc2UsIGRpc3BsYXkgdGhlIHJlc3BvbnNlIG1lc3NhZ2UuXG4gICAgICAgIGlmIChyZXNwb25zZSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd0luZm9ybWF0aW9uKGdsb2JhbFRyYW5zbGF0ZS5nc19BbGxTZXR0aW5nc0RlbGV0ZWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd011bHRpU3RyaW5nKHJlc3BvbnNlKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgZXZlbnQgYWZ0ZXIgdGhlIHNlbGVjdCBzYXZlIHBlcmlvZCBzbGlkZXIgaXMgY2hhbmdlZC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgc2VsZWN0ZWQgdmFsdWUgZnJvbSB0aGUgc2xpZGVyLlxuICAgICAqL1xuICAgIGNiQWZ0ZXJTZWxlY3RTYXZlUGVyaW9kU2xpZGVyKHZhbHVlKSB7XG5cbiAgICAgICAgLy8gR2V0IHRoZSBzYXZlIHBlcmlvZCBjb3JyZXNwb25kaW5nIHRvIHRoZSBzbGlkZXIgdmFsdWUuXG4gICAgICAgIGNvbnN0IHNhdmVQZXJpb2QgPSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuc2F2ZVJlY29yZHNQZXJpb2RbdmFsdWVdO1xuXG4gICAgICAgIC8vIFNldCB0aGUgZm9ybSB2YWx1ZSBmb3IgJ1BCWFJlY29yZFNhdmVQZXJpb2QnIHRvIHRoZSBzZWxlY3RlZCBzYXZlIHBlcmlvZC5cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRmb3JtT2JqLmZvcm0oJ3NldCB2YWx1ZScsICdQQlhSZWNvcmRTYXZlUGVyaW9kJywgc2F2ZVBlcmlvZCk7XG5cbiAgICAgICAgLy8gVHJpZ2dlciBjaGFuZ2UgZXZlbnQgdG8gYWNrbm93bGVkZ2UgdGhlIG1vZGlmaWNhdGlvblxuICAgICAgICBGb3JtLmRhdGFDaGFuZ2VkKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBiZWZvcmUgdGhlIGZvcm0gaXMgc2VudFxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBjdXJyZW50IHNldHRpbmdzIG9mIHRoZSBmb3JtXG4gICAgICogQHJldHVybnMge09iamVjdH0gLSBUaGUgdXBkYXRlZCBzZXR0aW5ncyBvZiB0aGUgZm9ybVxuICAgICAqL1xuICAgIGNiQmVmb3JlU2VuZEZvcm0oc2V0dGluZ3MpIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gc2V0dGluZ3M7XG4gICAgICAgIHJlc3VsdC5kYXRhID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZXMnKTtcbiAgICAgICAgY29uc3QgYXJyQ29kZWNzID0gW107XG4gICAgICAgICQoJyNhdWRpby1jb2RlY3MtdGFibGUgLmNvZGVjLXJvdywgI3ZpZGVvLWNvZGVjcy10YWJsZSAuY29kZWMtcm93JykuZWFjaCgoaW5kZXgsIG9iaikgPT4ge1xuICAgICAgICAgICAgaWYgKCQob2JqKS5hdHRyKCdpZCcpKSB7XG4gICAgICAgICAgICAgICAgYXJyQ29kZWNzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBjb2RlY0lkOiAkKG9iaikuYXR0cignaWQnKSxcbiAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQ6ICQob2JqKS5maW5kKCcuY2hlY2tib3gnKS5jaGVja2JveCgnaXMgdW5jaGVja2VkJyksXG4gICAgICAgICAgICAgICAgICAgIHByaW9yaXR5OiBpbmRleCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3VsdC5kYXRhLmNvZGVjcyA9IEpTT04uc3RyaW5naWZ5KGFyckNvZGVjcyk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGFmdGVyIHRoZSBmb3JtIGhhcyBiZWVuIHNlbnQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZlciBhZnRlciB0aGUgZm9ybSBpcyBzZW50XG4gICAgICovXG4gICAgY2JBZnRlclNlbmRGb3JtKHJlc3BvbnNlKSB7XG4gICAgICAgIGlmICghcmVzcG9uc2Uuc3VjY2Vzcykge1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnJlbW92ZUNsYXNzKCdkaXNhYmxlZCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJCgnLnBhc3N3b3JkLXZhbGlkYXRlJykucmVtb3ZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNoZWNrRGVsZXRlQWxsQ29uZGl0aW9ucygpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSB2YWxpZGF0aW9uIHJ1bGVzIG9mIHRoZSBmb3JtXG4gICAgICovXG4gICAgaW5pdFJ1bGVzKCkge1xuICAgICAgICAvLyBTU0hQYXNzd29yZFxuICAgICAgICBpZiAoZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRkaXNhYmxlU1NIUGFzc3dvcmQuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLlNTSFBhc3N3b3JkLnJ1bGVzID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmFkZGl0aW9uYWxTc2hWYWxpZFJ1bGVzTm9QYXNzO1xuICAgICAgICB9IGVsc2UgaWYgKGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kc3NoUGFzc3dvcmQudmFsKCkgPT09IGdlbmVyYWxTZXR0aW5nc01vZGlmeS5oaWRkZW5QYXNzd29yZCkge1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLlNTSFBhc3N3b3JkLnJ1bGVzID0gW107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMuU1NIUGFzc3dvcmQucnVsZXMgPSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuYWRkaXRpb25hbFNzaFZhbGlkUnVsZXNQYXNzO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV2ViQWRtaW5QYXNzd29yZFxuICAgICAgICBpZiAoZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiR3ZWJBZG1pblBhc3N3b3JkLnZhbCgpID09PSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuaGlkZGVuUGFzc3dvcmQpIHtcbiAgICAgICAgICAgIEZvcm0udmFsaWRhdGVSdWxlcy5XZWJBZG1pblBhc3N3b3JkLnJ1bGVzID0gW107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMuV2ViQWRtaW5QYXNzd29yZC5ydWxlcyA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS53ZWJBZG1pblBhc3N3b3JkUnVsZXM7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZSB0aGUgZm9ybSB3aXRoIGN1c3RvbSBzZXR0aW5nc1xuICAgICAqL1xuICAgIGluaXRpYWxpemVGb3JtKCkge1xuICAgICAgICBGb3JtLiRmb3JtT2JqID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRmb3JtT2JqO1xuICAgICAgICBGb3JtLnVybCA9IGAke2dsb2JhbFJvb3RVcmx9Z2VuZXJhbC1zZXR0aW5ncy9zYXZlYDsgLy8gRm9ybSBzdWJtaXNzaW9uIFVSTFxuICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMgPSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkudmFsaWRhdGVSdWxlczsgLy8gRm9ybSB2YWxpZGF0aW9uIHJ1bGVzXG4gICAgICAgIEZvcm0uY2JCZWZvcmVTZW5kRm9ybSA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS5jYkJlZm9yZVNlbmRGb3JtOyAvLyBDYWxsYmFjayBiZWZvcmUgZm9ybSBpcyBzZW50XG4gICAgICAgIEZvcm0uY2JBZnRlclNlbmRGb3JtID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNiQWZ0ZXJTZW5kRm9ybTsgLy8gQ2FsbGJhY2sgYWZ0ZXIgZm9ybSBpcyBzZW50XG4gICAgICAgIEZvcm0uaW5pdGlhbGl6ZSgpO1xuICAgIH1cbn07XG5cbi8vIFdoZW4gdGhlIGRvY3VtZW50IGlzIHJlYWR5LCBpbml0aWFsaXplIHRoZSBnZW5lcmFsU2V0dGluZ3MgbWFuYWdlbWVudCBpbnRlcmZhY2UuXG4kKGRvY3VtZW50KS5yZWFkeSgoKSA9PiB7XG4gICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRpYWxpemUoKTtcbn0pOyJdfQ==
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9HZW5lcmFsU2V0dGluZ3MvZ2VuZXJhbC1zZXR0aW5ncy1tb2RpZnkuanMiXSwibmFtZXMiOlsiZ2VuZXJhbFNldHRpbmdzTW9kaWZ5IiwiJGZvcm1PYmoiLCIkIiwiJHdlYkFkbWluUGFzc3dvcmQiLCIkc3NoUGFzc3dvcmQiLCIkZGlzYWJsZVNTSFBhc3N3b3JkIiwicGFyZW50IiwiJHNzaFBhc3N3b3JkU2VnbWVudCIsImhpZGRlblBhc3N3b3JkIiwiJHJlY29yZHNTYXZlUGVyaW9kU2xpZGVyIiwic2F2ZVJlY29yZHNQZXJpb2QiLCJ2YWxpZGF0ZVJ1bGVzIiwicGJ4bmFtZSIsImlkZW50aWZpZXIiLCJydWxlcyIsInR5cGUiLCJwcm9tcHQiLCJnbG9iYWxUcmFuc2xhdGUiLCJnc19WYWxpZGF0ZUVtcHR5UEJYTmFtZSIsIldlYkFkbWluUGFzc3dvcmQiLCJXZWJBZG1pblBhc3N3b3JkUmVwZWF0IiwiZ3NfVmFsaWRhdGVXZWJQYXNzd29yZHNGaWVsZERpZmZlcmVudCIsIlNTSFBhc3N3b3JkIiwiU1NIUGFzc3dvcmRSZXBlYXQiLCJnc19WYWxpZGF0ZVNTSFBhc3N3b3Jkc0ZpZWxkRGlmZmVyZW50IiwiV0VCUG9ydCIsImdzX1ZhbGlkYXRlV0VCUG9ydE91dE9mUmFuZ2UiLCJnc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE5vdEVxdWFsVG9XRUJQb3J0IiwiZ3NfVmFsaWRhdGVXRUJQb3J0Tm90RXF1YWxUb0FqYW1Qb3J0IiwiZ3NfVmFsaWRhdGVXRUJQb3J0Tm90RXF1YWxUb0FqYW1UTFNQb3J0IiwiV0VCSFRUUFNQb3J0IiwiZ3NfVmFsaWRhdGVXRUJIVFRQU1BvcnRPdXRPZlJhbmdlIiwiZ3NfVmFsaWRhdGVXRUJIVFRQU1BvcnROb3RFcXVhbFRvQWphbVBvcnQiLCJnc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE5vdEVxdWFsVG9BamFtVExTUG9ydCIsIkFKQU1Qb3J0IiwiZ3NfVmFsaWRhdGVBSkFNUG9ydE91dE9mUmFuZ2UiLCJ3ZWJBZG1pblBhc3N3b3JkUnVsZXMiLCJnc19WYWxpZGF0ZUVtcHR5V2ViUGFzc3dvcmQiLCJnc19WYWxpZGF0ZVdlYWtXZWJQYXNzd29yZCIsInZhbHVlIiwiZ3NfUGFzc3dvcmRzIiwiZ3NfUGFzc3dvcmROb0xvd1NpbXZvbCIsImdzX1Bhc3N3b3JkTm9OdW1iZXJzIiwiZ3NfUGFzc3dvcmROb1VwcGVyU2ltdm9sIiwiYWRkaXRpb25hbFNzaFZhbGlkUnVsZXNQYXNzIiwiZ3NfVmFsaWRhdGVFbXB0eVNTSFBhc3N3b3JkIiwiZ3NfVmFsaWRhdGVXZWFrU1NIUGFzc3dvcmQiLCJnc19TU0hQYXNzd29yZCIsImFkZGl0aW9uYWxTc2hWYWxpZFJ1bGVzTm9QYXNzIiwiaW5pdGlhbGl6ZSIsIm9uIiwidmFsIiwiaW5pdFJ1bGVzIiwiUGFzc3dvcmRTY29yZSIsImNoZWNrUGFzc1N0cmVuZ3RoIiwicGFzcyIsImJhciIsInNlY3Rpb24iLCJmaW5kIiwidGFiIiwiaGlzdG9yeSIsImhpc3RvcnlUeXBlIiwiZHJvcGRvd24iLCJjaGVja2JveCIsInRhYmxlRG5EIiwib25Ecm9wIiwiRm9ybSIsImRhdGFDaGFuZ2VkIiwib25EcmFnQ2xhc3MiLCJkcmFnSGFuZGxlIiwiU291bmRGaWxlc1NlbGVjdG9yIiwiZ2V0RHJvcGRvd25TZXR0aW5nc1dpdGhFbXB0eSIsInNsaWRlciIsIm1pbiIsIm1heCIsInN0ZXAiLCJzbW9vdGgiLCJpbnRlcnByZXRMYWJlbCIsImxhYmVscyIsImdzX1N0b3JlMU1vbnRoT2ZSZWNvcmRzIiwiZ3NfU3RvcmUzTW9udGhzT2ZSZWNvcmRzIiwiZ3NfU3RvcmU2TW9udGhzT2ZSZWNvcmRzIiwiZ3NfU3RvcmUxWWVhck9mUmVjb3JkcyIsImdzX1N0b3JlM1llYXJzT2ZSZWNvcmRzIiwiZ3NfU3RvcmVBbGxQb3NzaWJsZVJlY29yZHMiLCJvbkNoYW5nZSIsImNiQWZ0ZXJTZWxlY3RTYXZlUGVyaW9kU2xpZGVyIiwiaW5pdGlhbGl6ZUZvcm0iLCJzaG93SGlkZVNTSFBhc3N3b3JkIiwicmVjb3JkU2F2ZVBlcmlvZCIsImZvcm0iLCJpbmRleE9mIiwid2luZG93IiwiZXZlbnQiLCJuYW1lVGFiIiwiaGlkZSIsInNob3ciLCJjaGVja0RlbGV0ZUFsbENvbmRpdGlvbnMiLCJkZWxldGVBbGxJbnB1dCIsImdzX0VudGVyRGVsZXRlQWxsUGhyYXNlIiwiUGJ4QXBpIiwiU3lzdGVtUmVzdG9yZURlZmF1bHRTZXR0aW5ncyIsImNiQWZ0ZXJSZXN0b3JlRGVmYXVsdFNldHRpbmdzIiwicmVzcG9uc2UiLCJVc2VyTWVzc2FnZSIsInNob3dJbmZvcm1hdGlvbiIsImdzX0FsbFNldHRpbmdzRGVsZXRlZCIsInNob3dNdWx0aVN0cmluZyIsInNhdmVQZXJpb2QiLCJjYkJlZm9yZVNlbmRGb3JtIiwic2V0dGluZ3MiLCJyZXN1bHQiLCJkYXRhIiwiYXJyQ29kZWNzIiwiZWFjaCIsImluZGV4Iiwib2JqIiwiYXR0ciIsInB1c2giLCJjb2RlY0lkIiwiZGlzYWJsZWQiLCJwcmlvcml0eSIsImNvZGVjcyIsIkpTT04iLCJzdHJpbmdpZnkiLCJjYkFmdGVyU2VuZEZvcm0iLCJyZW1vdmUiLCJzdWNjZXNzIiwiJHN1Ym1pdEJ1dHRvbiIsInJlbW92ZUNsYXNzIiwiZ2VuZXJhdGVFcnJvck1lc3NhZ2VIdG1sIiwibWVzc2FnZXMiLCJlcnJvciIsIiRkaXYiLCJpZCIsIiRoZWFkZXIiLCJ0ZXh0IiwiZ3NfRXJyb3JTYXZlU2V0dGluZ3MiLCJhcHBlbmQiLCIkdWwiLCJtZXNzYWdlc1NldCIsIlNldCIsImZvckVhY2giLCJlcnJvckFycmF5IiwidGV4dENvbnRlbnQiLCJtZXNzYWdlIiwidW5kZWZpbmVkIiwiaGFzIiwiYWRkIiwiYmVmb3JlIiwidXJsIiwiZ2xvYmFsUm9vdFVybCIsImRvY3VtZW50IiwicmVhZHkiXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFHQTs7QUFFQTtBQUNB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LENBQUNXLGFBQTNDLENBSGEsQ0FHNkM7O0FBQzFEdUQsSUFBQUEsSUFBSSxDQUFDMkMsZ0JBQUwsR0FBd0I3RyxxQkFBcUIsQ0FBQzZHLGdCQUE5QyxDQUphLENBSW1EOztBQUNoRTNDLElBQUFBLElBQUksQ0FBQzJELGVBQUwsR0FBdUI3SCxxQkFBcUIsQ0FBQzZILGVBQTdDLENBTGEsQ0FLaUQ7O0FBQzlEM0QsSUFBQUEsSUFBSSxDQUFDakIsVUFBTDtBQUNIO0FBcGR5QixDQUE5QixDLENBdWRBOztBQUNBL0MsQ0FBQyxDQUFDc0osUUFBRCxDQUFELENBQVlDLEtBQVosQ0FBa0IsWUFBTTtBQUNwQnpKLEVBQUFBLHFCQUFxQixDQUFDaUQsVUFBdEI7QUFDSCxDQUZEIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pa29QQlggLSBmcmVlIHBob25lIHN5c3RlbSBmb3Igc21hbGwgYnVzaW5lc3NcbiAqIENvcHlyaWdodCDCqSAyMDE3LTIwMjMgQWxleGV5IFBvcnRub3YgYW5kIE5pa29sYXkgQmVrZXRvdlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAqIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbiAqXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS5cbiAqIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gKi9cblxuXG4vKiBnbG9iYWwgZ2xvYmFsUm9vdFVybCxnbG9iYWxUcmFuc2xhdGUsIEZvcm0sIFBhc3N3b3JkU2NvcmUsIFBieEFwaSwgVXNlck1lc3NhZ2UsIFNvdW5kRmlsZXNTZWxlY3RvciwgJCAqL1xuXG4vKipcbiAqIEEgbW9kdWxlIHRvIGhhbmRsZSBtb2RpZmljYXRpb24gb2YgZ2VuZXJhbCBzZXR0aW5ncy5cbiAqL1xuY29uc3QgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5ID0ge1xuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSBmb3JtLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJGZvcm1PYmo6ICQoJyNnZW5lcmFsLXNldHRpbmdzLWZvcm0nKSxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSB3ZWIgYWRtaW4gcGFzc3dvcmQgaW5wdXQgZmllbGQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkd2ViQWRtaW5QYXNzd29yZDogJCgnI1dlYkFkbWluUGFzc3dvcmQnKSxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSBzc2ggcGFzc3dvcmQgaW5wdXQgZmllbGQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkc3NoUGFzc3dvcmQ6ICQoJyNTU0hQYXNzd29yZCcpLFxuXG4gICAgLyoqXG4gICAgICogalF1ZXJ5IG9iamVjdCBmb3IgdGhlIHdlYiBzc2ggcGFzc3dvcmQgaW5wdXQgZmllbGQuXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkZGlzYWJsZVNTSFBhc3N3b3JkOiAkKCcjU1NIRGlzYWJsZVBhc3N3b3JkTG9naW5zJykucGFyZW50KCcuY2hlY2tib3gnKSxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSBTU0ggcGFzc3dvcmQgZmllbGRzXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkc3NoUGFzc3dvcmRTZWdtZW50OiAkKCcjb25seS1pZi1wYXNzd29yZC1lbmFibGVkJyksXG5cbiAgICAvKipcbiAgICAgKiBJZiBwYXNzd29yZCBzZXQsIGl0IHdpbGwgYmUgaGlkZWQgZnJvbSB3ZWIgdWkuXG4gICAgICovXG4gICAgaGlkZGVuUGFzc3dvcmQ6ICd4eHh4eHh4JyxcblxuICAgIC8qKlxuICAgICAqIGpRdWVyeSBvYmplY3QgZm9yIHRoZSByZWNvcmRzIHJldGVudGlvbiBwZXJpb2Qgc2xpZGVyLlxuICAgICAqIEB0eXBlIHtqUXVlcnl9XG4gICAgICovXG4gICAgJHJlY29yZHNTYXZlUGVyaW9kU2xpZGVyOiAkKCcjUEJYUmVjb3JkU2F2ZVBlcmlvZFNsaWRlcicpLFxuXG4gICAgLyoqXG4gICAgICogUG9zc2libGUgcGVyaW9kIHZhbHVlcyBmb3IgdGhlIHJlY29yZHMgcmV0ZW50aW9uLlxuICAgICAqL1xuICAgIHNhdmVSZWNvcmRzUGVyaW9kOiBbJzMwJywgJzkwJywgJzE4MCcsICczNjAnLCAnMTA4MCcsICcnXSxcblxuICAgIC8qKlxuICAgICAqIFZhbGlkYXRpb24gcnVsZXMgZm9yIHRoZSBmb3JtIGZpZWxkcyBiZWZvcmUgc3VibWlzc2lvbi5cbiAgICAgKlxuICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICovXG4gICAgdmFsaWRhdGVSdWxlczogeyAvLyBnZW5lcmFsU2V0dGluZ3NNb2RpZnkudmFsaWRhdGVSdWxlcy5TU0hQYXNzd29yZC5ydWxlc1xuICAgICAgICBwYnhuYW1lOiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnUEJYTmFtZScsXG4gICAgICAgICAgICBydWxlczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2VtcHR5JyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVFbXB0eVBCWE5hbWUsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIFdlYkFkbWluUGFzc3dvcmQ6IHtcbiAgICAgICAgICAgIGlkZW50aWZpZXI6ICdXZWJBZG1pblBhc3N3b3JkJyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXSxcbiAgICAgICAgfSxcbiAgICAgICAgV2ViQWRtaW5QYXNzd29yZFJlcGVhdDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ1dlYkFkbWluUGFzc3dvcmRSZXBlYXQnLFxuICAgICAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdtYXRjaFtXZWJBZG1pblBhc3N3b3JkXScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV2ViUGFzc3dvcmRzRmllbGREaWZmZXJlbnQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIFNTSFBhc3N3b3JkOiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnU1NIUGFzc3dvcmQnLFxuICAgICAgICAgICAgcnVsZXM6IFtdLFxuICAgICAgICB9LFxuICAgICAgICBTU0hQYXNzd29yZFJlcGVhdDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ1NTSFBhc3N3b3JkUmVwZWF0JyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnbWF0Y2hbU1NIUGFzc3dvcmRdJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVTU0hQYXNzd29yZHNGaWVsZERpZmZlcmVudCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgV0VCUG9ydDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ1dFQlBvcnQnLFxuICAgICAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdpbnRlZ2VyWzEuLjY1NTM1XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCUG9ydE91dE9mUmFuZ2UsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdkaWZmZXJlbnRbV0VCSFRUUFNQb3J0XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCSFRUUFNQb3J0Tm90RXF1YWxUb1dFQlBvcnQsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdkaWZmZXJlbnRbQUpBTVBvcnRUTFNdJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVXRUJQb3J0Tm90RXF1YWxUb0FqYW1Qb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGlmZmVyZW50W0FKQU1Qb3J0XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCUG9ydE5vdEVxdWFsVG9BamFtVExTUG9ydCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgV0VCSFRUUFNQb3J0OiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnV0VCSFRUUFNQb3J0JyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnaW50ZWdlclsxLi42NTUzNV0nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE91dE9mUmFuZ2UsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdkaWZmZXJlbnRbV0VCUG9ydF0nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdFQkhUVFBTUG9ydE5vdEVxdWFsVG9XRUJQb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGlmZmVyZW50W0FKQU1Qb3J0VExTXScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCSFRUUFNQb3J0Tm90RXF1YWxUb0FqYW1Qb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGlmZmVyZW50W0FKQU1Qb3J0XScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV0VCSFRUUFNQb3J0Tm90RXF1YWxUb0FqYW1UTFNQb3J0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgICBBSkFNUG9ydDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ0FKQU1Qb3J0JyxcbiAgICAgICAgICAgIHJ1bGVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnaW50ZWdlclsxLi42NTUzNV0nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZUFKQU1Qb3J0T3V0T2ZSYW5nZSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2RpZmZlcmVudFtBSkFNUG9ydFRMU10nLFxuICAgICAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZUFKQU1Qb3J0T3V0T2ZSYW5nZSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICB9LFxuXG4gICAgLy8gUnVsZXMgZm9yIHRoZSB3ZWIgYWRtaW4gcGFzc3dvcmQgZmllbGQgd2hlbiBpdCBub3QgZXF1YWwgdG8gaGlkZGVuUGFzc3dvcmRcbiAgICB3ZWJBZG1pblBhc3N3b3JkUnVsZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ2VtcHR5JyxcbiAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlRW1wdHlXZWJQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ21pbkxlbmd0aFs1XScsXG4gICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdlYWtXZWJQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ25vdFJlZ0V4cCcsXG4gICAgICAgICAgICB2YWx1ZTogL1thLXpdLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmRzICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb0xvd1NpbXZvbFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAnbm90UmVnRXhwJyxcbiAgICAgICAgICAgIHZhbHVlOiAvXFxkLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmRzICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb051bWJlcnNcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ25vdFJlZ0V4cCcsXG4gICAgICAgICAgICB2YWx1ZTogL1tBLVpdLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmRzICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb1VwcGVyU2ltdm9sXG4gICAgICAgIH1cbiAgICBdLFxuICAgIC8vIFJ1bGVzIGZvciB0aGUgU1NIIHBhc3N3b3JkIGZpZWxkIHdoZW4gU1NIIGxvZ2luIHRocm91Z2ggdGhlIHBhc3N3b3JkIGVuYWJsZWQsIGFuZCBpdCBub3QgZXF1YWwgdG8gaGlkZGVuUGFzc3dvcmRcbiAgICBhZGRpdGlvbmFsU3NoVmFsaWRSdWxlc1Bhc3M6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ2VtcHR5JyxcbiAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlRW1wdHlTU0hQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ21pbkxlbmd0aFs1XScsXG4gICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS5nc19WYWxpZGF0ZVdlYWtTU0hQYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdHlwZTogJ25vdFJlZ0V4cCcsXG4gICAgICAgICAgICB2YWx1ZTogL1thLXpdLyxcbiAgICAgICAgICAgIHByb21wdDogJzxiPicgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfU1NIUGFzc3dvcmQgKyAnPC9iPjogJyArIGdsb2JhbFRyYW5zbGF0ZS5nc19QYXNzd29yZE5vTG93U2ltdm9sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHR5cGU6ICdub3RSZWdFeHAnLFxuICAgICAgICAgICAgdmFsdWU6IC9cXGQvLFxuICAgICAgICAgICAgcHJvbXB0OiAnPGI+JyArIGdsb2JhbFRyYW5zbGF0ZS5nc19TU0hQYXNzd29yZCArICc8L2I+OiAnICsgZ2xvYmFsVHJhbnNsYXRlLmdzX1Bhc3N3b3JkTm9OdW1iZXJzXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHR5cGU6ICdub3RSZWdFeHAnLFxuICAgICAgICAgICAgdmFsdWU6IC9bQS1aXS8sXG4gICAgICAgICAgICBwcm9tcHQ6ICc8Yj4nICsgZ2xvYmFsVHJhbnNsYXRlLmdzX1NTSFBhc3N3b3JkICsgJzwvYj46ICcgKyBnbG9iYWxUcmFuc2xhdGUuZ3NfUGFzc3dvcmROb1VwcGVyU2ltdm9sXG4gICAgICAgIH1cbiAgICBdLFxuXG4gICAgLy8gUnVsZXMgZm9yIHRoZSBTU0ggcGFzc3dvcmQgZmllbGQgd2hlbiBTU0ggbG9naW4gdGhyb3VnaCB0aGUgcGFzc3dvcmQgZGlzYWJsZWRcbiAgICBhZGRpdGlvbmFsU3NoVmFsaWRSdWxlc05vUGFzczogW1xuICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAnZW1wdHknLFxuICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUuZ3NfVmFsaWRhdGVFbXB0eVNTSFBhc3N3b3JkLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICB0eXBlOiAnbWluTGVuZ3RoWzVdJyxcbiAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLmdzX1ZhbGlkYXRlV2Vha1NTSFBhc3N3b3JkLFxuICAgICAgICB9XG4gICAgXSxcblxuICAgIC8qKlxuICAgICAqICBJbml0aWFsaXplIG1vZHVsZSB3aXRoIGV2ZW50IGJpbmRpbmdzIGFuZCBjb21wb25lbnQgaW5pdGlhbGl6YXRpb25zLlxuICAgICAqL1xuICAgIGluaXRpYWxpemUoKSB7XG5cbiAgICAgICAgLy8gV2hlbiBXZWJBZG1pblBhc3N3b3JkIGlucHV0IGlzIGNoYW5nZWQsIHJlY2FsY3VsYXRlIHRoZSBwYXNzd29yZCBzdHJlbmd0aFxuICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHdlYkFkbWluUGFzc3dvcmQub24oJ2tleXVwJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kd2ViQWRtaW5QYXNzd29yZC52YWwoKSAhPT0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmhpZGRlblBhc3N3b3JkKSB7XG4gICAgICAgICAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRSdWxlcygpO1xuICAgICAgICAgICAgICAgIFBhc3N3b3JkU2NvcmUuY2hlY2tQYXNzU3RyZW5ndGgoe1xuICAgICAgICAgICAgICAgICAgICBwYXNzOiBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHdlYkFkbWluUGFzc3dvcmQudmFsKCksXG4gICAgICAgICAgICAgICAgICAgIGJhcjogJCgnLnBhc3N3b3JkLXNjb3JlJyksXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246ICQoJy5wYXNzd29yZC1zY29yZS1zZWN0aW9uJyksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFdoZW4gU1NIUGFzc3dvcmQgaW5wdXQgaXMgY2hhbmdlZCwgcmVjYWxjdWxhdGUgdGhlIHBhc3N3b3JkIHN0cmVuZ3RoXG4gICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kc3NoUGFzc3dvcmQub24oJ2tleXVwJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kc3NoUGFzc3dvcmQudmFsKCkgIT09IGdlbmVyYWxTZXR0aW5nc01vZGlmeS5oaWRkZW5QYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS5pbml0UnVsZXMoKTtcbiAgICAgICAgICAgICAgICBQYXNzd29yZFNjb3JlLmNoZWNrUGFzc1N0cmVuZ3RoKHtcbiAgICAgICAgICAgICAgICAgICAgcGFzczogZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRzc2hQYXNzd29yZC52YWwoKSxcbiAgICAgICAgICAgICAgICAgICAgYmFyOiAkKCcuc3NoLXBhc3N3b3JkLXNjb3JlJyksXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246ICQoJy5zc2gtcGFzc3dvcmQtc2NvcmUtc2VjdGlvbicpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBFbmFibGUgdGFiIG5hdmlnYXRpb24gd2l0aCBoaXN0b3J5IHN1cHBvcnRcbiAgICAgICAgJCgnI2dlbmVyYWwtc2V0dGluZ3MtbWVudScpLmZpbmQoJy5pdGVtJykudGFiKHtcbiAgICAgICAgICAgIGhpc3Rvcnk6IHRydWUsXG4gICAgICAgICAgICBoaXN0b3J5VHlwZTogJ2hhc2gnLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBFbmFibGUgZHJvcGRvd25zIG9uIHRoZSBmb3JtXG4gICAgICAgICQoJyNnZW5lcmFsLXNldHRpbmdzLWZvcm0gLmRyb3Bkb3duJykuZHJvcGRvd24oKTtcblxuICAgICAgICAvLyBFbmFibGUgY2hlY2tib3hlcyBvbiB0aGUgZm9ybVxuICAgICAgICAkKCcjZ2VuZXJhbC1zZXR0aW5ncy1mb3JtIC5jaGVja2JveCcpLmNoZWNrYm94KCk7XG5cbiAgICAgICAgLy8gRW5hYmxlIHRhYmxlIGRyYWctbi1kcm9wIGZ1bmN0aW9uYWxpdHlcbiAgICAgICAgJCgnI2F1ZGlvLWNvZGVjcy10YWJsZSwgI3ZpZGVvLWNvZGVjcy10YWJsZScpLnRhYmxlRG5EKHtcbiAgICAgICAgICAgIG9uRHJvcCgpIHtcbiAgICAgICAgICAgICAgICAvLyBUcmlnZ2VyIGNoYW5nZSBldmVudCB0byBhY2tub3dsZWRnZSB0aGUgbW9kaWZpY2F0aW9uXG4gICAgICAgICAgICAgICAgRm9ybS5kYXRhQ2hhbmdlZCgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uRHJhZ0NsYXNzOiAnaG92ZXJpbmdSb3cnLFxuICAgICAgICAgICAgZHJhZ0hhbmRsZTogJy5kcmFnSGFuZGxlJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gRW5hYmxlIGRyb3Bkb3duIHdpdGggc291bmQgZmlsZSBzZWxlY3Rpb25cbiAgICAgICAgJCgnI2dlbmVyYWwtc2V0dGluZ3MtZm9ybSAuYXVkaW8tbWVzc2FnZS1zZWxlY3QnKS5kcm9wZG93bihTb3VuZEZpbGVzU2VsZWN0b3IuZ2V0RHJvcGRvd25TZXR0aW5nc1dpdGhFbXB0eSgpKTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHJlY29yZHMgc2F2ZSBwZXJpb2Qgc2xpZGVyXG4gICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kcmVjb3Jkc1NhdmVQZXJpb2RTbGlkZXJcbiAgICAgICAgICAgIC5zbGlkZXIoe1xuICAgICAgICAgICAgICAgIG1pbjogMCxcbiAgICAgICAgICAgICAgICBtYXg6IDUsXG4gICAgICAgICAgICAgICAgc3RlcDogMSxcbiAgICAgICAgICAgICAgICBzbW9vdGg6IHRydWUsXG4gICAgICAgICAgICAgICAgaW50ZXJwcmV0TGFiZWw6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgbGFiZWxzID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsVHJhbnNsYXRlLmdzX1N0b3JlMU1vbnRoT2ZSZWNvcmRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsVHJhbnNsYXRlLmdzX1N0b3JlM01vbnRoc09mUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbFRyYW5zbGF0ZS5nc19TdG9yZTZNb250aHNPZlJlY29yZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWxUcmFuc2xhdGUuZ3NfU3RvcmUxWWVhck9mUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbFRyYW5zbGF0ZS5nc19TdG9yZTNZZWFyc09mUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbFRyYW5zbGF0ZS5nc19TdG9yZUFsbFBvc3NpYmxlUmVjb3JkcyxcbiAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxhYmVsc1t2YWx1ZV07XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBvbkNoYW5nZTogZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNiQWZ0ZXJTZWxlY3RTYXZlUGVyaW9kU2xpZGVyLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGZvcm1cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRpYWxpemVGb3JtKCk7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBhZGRpdGlvbmFsIHZhbGlkYXRpb24gcnVsZXNcbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRSdWxlcygpO1xuXG4gICAgICAgIC8vIFNob3csIGhpZGUgc3NoIHBhc3N3b3JkIHNlZ21lbnRcbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRkaXNhYmxlU1NIUGFzc3dvcmQuY2hlY2tib3goe1xuICAgICAgICAgICAgJ29uQ2hhbmdlJzogZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LnNob3dIaWRlU1NIUGFzc3dvcmRcbiAgICAgICAgfSk7XG4gICAgICAgIGdlbmVyYWxTZXR0aW5nc01vZGlmeS5zaG93SGlkZVNTSFBhc3N3b3JkKCk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBpbml0aWFsIHZhbHVlIGZvciB0aGUgcmVjb3JkcyBzYXZlIHBlcmlvZCBzbGlkZXJcbiAgICAgICAgY29uc3QgcmVjb3JkU2F2ZVBlcmlvZCA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnUEJYUmVjb3JkU2F2ZVBlcmlvZCcpO1xuICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHJlY29yZHNTYXZlUGVyaW9kU2xpZGVyXG4gICAgICAgICAgICAuc2xpZGVyKCdzZXQgdmFsdWUnLCBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuc2F2ZVJlY29yZHNQZXJpb2QuaW5kZXhPZihyZWNvcmRTYXZlUGVyaW9kKSwgZmFsc2UpO1xuXG4gICAgICAgIC8vIEFkZCBldmVudCBsaXN0ZW5lciB0byBoYW5kbGUgdGFiIGFjdGl2YXRpb25cbiAgICAgICAgJCh3aW5kb3cpLm9uKCdHUy1BY3RpdmF0ZVRhYicsIChldmVudCwgbmFtZVRhYikgPT4ge1xuICAgICAgICAgICAgJCgnI2dlbmVyYWwtc2V0dGluZ3MtbWVudScpLmZpbmQoJy5pdGVtJykudGFiKCdjaGFuZ2UgdGFiJywgbmFtZVRhYik7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTaG93LCBoaWRlIHNzaCBwYXNzd29yZCBzZWdtZW50IGFjY29yZGluZyB0byB0aGUgdmFsdWUgb2YgdXNlIFNTSCBwYXNzd29yZCBjaGVja2JveC5cbiAgICAgKi9cbiAgICBzaG93SGlkZVNTSFBhc3N3b3JkKCl7XG4gICAgICAgIGlmIChnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJGRpc2FibGVTU0hQYXNzd29yZC5jaGVja2JveCgnaXMgY2hlY2tlZCcpKSB7XG4gICAgICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHNzaFBhc3N3b3JkU2VnbWVudC5oaWRlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuJHNzaFBhc3N3b3JkU2VnbWVudC5zaG93KCk7XG4gICAgICAgIH1cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRSdWxlcygpO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGNvbmRpdGlvbnMgZm9yIGRlbGV0aW5nIGFsbCByZWNvcmRzLlxuICAgICAqIENvbXBhcmVzIHRoZSB2YWx1ZSBvZiB0aGUgJ2RlbGV0ZUFsbElucHV0JyBmaWVsZCB3aXRoIGEgcGhyYXNlLlxuICAgICAqIElmIHRoZXkgbWF0Y2gsIGl0IHRyaWdnZXJzIGEgc3lzdGVtIHJlc3RvcmUgdG8gZGVmYXVsdCBzZXR0aW5ncy5cbiAgICAgKi9cbiAgICBjaGVja0RlbGV0ZUFsbENvbmRpdGlvbnMoKSB7XG5cbiAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZSBvZiAnZGVsZXRlQWxsSW5wdXQnIGZpZWxkLlxuICAgICAgICBjb25zdCBkZWxldGVBbGxJbnB1dCA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnZGVsZXRlQWxsSW5wdXQnKTtcblxuICAgICAgICAvLyBJZiB0aGUgZW50ZXJlZCBwaHJhc2UgbWF0Y2hlcyB0aGUgcGhyYXNlIGluICdnbG9iYWxUcmFuc2xhdGUuZ3NfRW50ZXJEZWxldGVBbGxQaHJhc2UnLFxuICAgICAgICAvLyBjYWxsICdQYnhBcGkuU3lzdGVtUmVzdG9yZURlZmF1bHRTZXR0aW5ncycgdG8gcmVzdG9yZSBkZWZhdWx0IHNldHRpbmdzLlxuICAgICAgICBpZiAoZGVsZXRlQWxsSW5wdXQgPT09IGdsb2JhbFRyYW5zbGF0ZS5nc19FbnRlckRlbGV0ZUFsbFBocmFzZSkge1xuICAgICAgICAgICAgUGJ4QXBpLlN5c3RlbVJlc3RvcmVEZWZhdWx0U2V0dGluZ3MoZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNiQWZ0ZXJSZXN0b3JlRGVmYXVsdFNldHRpbmdzKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgcmVzcG9uc2UgYWZ0ZXIgcmVzdG9yaW5nIGRlZmF1bHQgc2V0dGluZ3MuXG4gICAgICogQHBhcmFtIHtib29sZWFufHN0cmluZ30gcmVzcG9uc2UgLSBSZXNwb25zZSBmcm9tIHRoZSBzZXJ2ZXIgYWZ0ZXIgcmVzdG9yaW5nIGRlZmF1bHQgc2V0dGluZ3MuXG4gICAgICovXG4gICAgY2JBZnRlclJlc3RvcmVEZWZhdWx0U2V0dGluZ3MocmVzcG9uc2UpIHtcblxuICAgICAgICAvLyBDaGVjayBpZiB0aGUgcmVzcG9uc2UgaXMgdHJ1ZSwgZGlzcGxheSBhIHN1Y2Nlc3MgbWVzc2FnZVxuICAgICAgICAvLyBvdGhlcndpc2UsIGRpc3BsYXkgdGhlIHJlc3BvbnNlIG1lc3NhZ2UuXG4gICAgICAgIGlmIChyZXNwb25zZSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd0luZm9ybWF0aW9uKGdsb2JhbFRyYW5zbGF0ZS5nc19BbGxTZXR0aW5nc0RlbGV0ZWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVXNlck1lc3NhZ2Uuc2hvd011bHRpU3RyaW5nKHJlc3BvbnNlKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgZXZlbnQgYWZ0ZXIgdGhlIHNlbGVjdCBzYXZlIHBlcmlvZCBzbGlkZXIgaXMgY2hhbmdlZC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgc2VsZWN0ZWQgdmFsdWUgZnJvbSB0aGUgc2xpZGVyLlxuICAgICAqL1xuICAgIGNiQWZ0ZXJTZWxlY3RTYXZlUGVyaW9kU2xpZGVyKHZhbHVlKSB7XG5cbiAgICAgICAgLy8gR2V0IHRoZSBzYXZlIHBlcmlvZCBjb3JyZXNwb25kaW5nIHRvIHRoZSBzbGlkZXIgdmFsdWUuXG4gICAgICAgIGNvbnN0IHNhdmVQZXJpb2QgPSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuc2F2ZVJlY29yZHNQZXJpb2RbdmFsdWVdO1xuXG4gICAgICAgIC8vIFNldCB0aGUgZm9ybSB2YWx1ZSBmb3IgJ1BCWFJlY29yZFNhdmVQZXJpb2QnIHRvIHRoZSBzZWxlY3RlZCBzYXZlIHBlcmlvZC5cbiAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRmb3JtT2JqLmZvcm0oJ3NldCB2YWx1ZScsICdQQlhSZWNvcmRTYXZlUGVyaW9kJywgc2F2ZVBlcmlvZCk7XG5cbiAgICAgICAgLy8gVHJpZ2dlciBjaGFuZ2UgZXZlbnQgdG8gYWNrbm93bGVkZ2UgdGhlIG1vZGlmaWNhdGlvblxuICAgICAgICBGb3JtLmRhdGFDaGFuZ2VkKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBiZWZvcmUgdGhlIGZvcm0gaXMgc2VudFxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBjdXJyZW50IHNldHRpbmdzIG9mIHRoZSBmb3JtXG4gICAgICogQHJldHVybnMge09iamVjdH0gLSBUaGUgdXBkYXRlZCBzZXR0aW5ncyBvZiB0aGUgZm9ybVxuICAgICAqL1xuICAgIGNiQmVmb3JlU2VuZEZvcm0oc2V0dGluZ3MpIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gc2V0dGluZ3M7XG4gICAgICAgIHJlc3VsdC5kYXRhID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZXMnKTtcbiAgICAgICAgY29uc3QgYXJyQ29kZWNzID0gW107XG4gICAgICAgICQoJyNhdWRpby1jb2RlY3MtdGFibGUgLmNvZGVjLXJvdywgI3ZpZGVvLWNvZGVjcy10YWJsZSAuY29kZWMtcm93JykuZWFjaCgoaW5kZXgsIG9iaikgPT4ge1xuICAgICAgICAgICAgaWYgKCQob2JqKS5hdHRyKCdpZCcpKSB7XG4gICAgICAgICAgICAgICAgYXJyQ29kZWNzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBjb2RlY0lkOiAkKG9iaikuYXR0cignaWQnKSxcbiAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQ6ICQob2JqKS5maW5kKCcuY2hlY2tib3gnKS5jaGVja2JveCgnaXMgdW5jaGVja2VkJyksXG4gICAgICAgICAgICAgICAgICAgIHByaW9yaXR5OiBpbmRleCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3VsdC5kYXRhLmNvZGVjcyA9IEpTT04uc3RyaW5naWZ5KGFyckNvZGVjcyk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGFmdGVyIHRoZSBmb3JtIGhhcyBiZWVuIHNlbnQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZlciBhZnRlciB0aGUgZm9ybSBpcyBzZW50XG4gICAgICovXG4gICAgY2JBZnRlclNlbmRGb3JtKHJlc3BvbnNlKSB7XG4gICAgICAgICQoXCIjZXJyb3ItbWVzc2FnZXNcIikucmVtb3ZlKCk7XG4gICAgICAgIGlmICghcmVzcG9uc2Uuc3VjY2Vzcykge1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnJlbW92ZUNsYXNzKCdkaXNhYmxlZCcpO1xuICAgICAgICAgICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmdlbmVyYXRlRXJyb3JNZXNzYWdlSHRtbChyZXNwb25zZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAkKCcucGFzc3dvcmQtdmFsaWRhdGUnKS5yZW1vdmUoKTtcbiAgICAgICAgfVxuICAgICAgICBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuY2hlY2tEZWxldGVBbGxDb25kaXRpb25zKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBmdW5jdGlvbiBjb2xsZWN0cyBhbiBpbmZvcm1hdGlvbiBtZXNzYWdlIGFib3V0IGEgZGF0YSBzYXZpbmcgZXJyb3JcbiAgICAgKiBAcGFyYW0gcmVzcG9uc2VcbiAgICAgKi9cbiAgICBnZW5lcmF0ZUVycm9yTWVzc2FnZUh0bWwocmVzcG9uc2UpIHtcbiAgICAgICAgaWYgKHJlc3BvbnNlLm1lc3NhZ2VzICYmIHJlc3BvbnNlLm1lc3NhZ2VzLmVycm9yKSB7XG4gICAgICAgICAgICBjb25zdCAkZGl2ID0gJCgnPGRpdj4nLCB7IGNsYXNzOiAndWkgbmVnYXRpdmUgbWVzc2FnZScsIGlkOiAnZXJyb3ItbWVzc2FnZXMnIH0pO1xuICAgICAgICAgICAgY29uc3QgJGhlYWRlciA9ICQoJzxkaXY+JywgeyBjbGFzczogJ2hlYWRlcicgfSkudGV4dChnbG9iYWxUcmFuc2xhdGUuZ3NfRXJyb3JTYXZlU2V0dGluZ3MpO1xuICAgICAgICAgICAgJGRpdi5hcHBlbmQoJGhlYWRlcik7XG4gICAgICAgICAgICBjb25zdCAkdWwgPSAkKCc8dWw+JywgeyBjbGFzczogJ2xpc3QnIH0pO1xuICAgICAgICAgICAgY29uc3QgbWVzc2FnZXNTZXQgPSBuZXcgU2V0KCk7XG4gICAgICAgICAgICByZXNwb25zZS5tZXNzYWdlcy5lcnJvci5mb3JFYWNoKGVycm9yQXJyYXkgPT4ge1xuICAgICAgICAgICAgICAgIGVycm9yQXJyYXkuZm9yRWFjaChlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGxldCB0ZXh0Q29udGVudCA9Jyc7XG4gICAgICAgICAgICAgICAgICAgIGlmKGdsb2JhbFRyYW5zbGF0ZVtlcnJvci5tZXNzYWdlXSA9PT0gdW5kZWZpbmVkKXtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHRDb250ZW50ID0gZXJyb3IubWVzc2FnZTtcbiAgICAgICAgICAgICAgICAgICAgfWVsc2V7XG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0Q29udGVudCA9IGdsb2JhbFRyYW5zbGF0ZVtlcnJvci5tZXNzYWdlXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAobWVzc2FnZXNTZXQuaGFzKHRleHRDb250ZW50KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2VzU2V0LmFkZChlcnJvci5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgJHVsLmFwcGVuZCgkKCc8bGk+JykudGV4dCh0ZXh0Q29udGVudCkpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAkZGl2LmFwcGVuZCgkdWwpO1xuICAgICAgICAgICAgJCgnI3N1Ym1pdGJ1dHRvbicpLmJlZm9yZSgkZGl2KTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSB2YWxpZGF0aW9uIHJ1bGVzIG9mIHRoZSBmb3JtXG4gICAgICovXG4gICAgaW5pdFJ1bGVzKCkge1xuICAgICAgICAvLyBTU0hQYXNzd29yZFxuICAgICAgICBpZiAoZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRkaXNhYmxlU1NIUGFzc3dvcmQuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLlNTSFBhc3N3b3JkLnJ1bGVzID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmFkZGl0aW9uYWxTc2hWYWxpZFJ1bGVzTm9QYXNzO1xuICAgICAgICB9IGVsc2UgaWYgKGdlbmVyYWxTZXR0aW5nc01vZGlmeS4kc3NoUGFzc3dvcmQudmFsKCkgPT09IGdlbmVyYWxTZXR0aW5nc01vZGlmeS5oaWRkZW5QYXNzd29yZCkge1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLlNTSFBhc3N3b3JkLnJ1bGVzID0gW107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMuU1NIUGFzc3dvcmQucnVsZXMgPSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuYWRkaXRpb25hbFNzaFZhbGlkUnVsZXNQYXNzO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV2ViQWRtaW5QYXNzd29yZFxuICAgICAgICBpZiAoZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiR3ZWJBZG1pblBhc3N3b3JkLnZhbCgpID09PSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkuaGlkZGVuUGFzc3dvcmQpIHtcbiAgICAgICAgICAgIEZvcm0udmFsaWRhdGVSdWxlcy5XZWJBZG1pblBhc3N3b3JkLnJ1bGVzID0gW107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMuV2ViQWRtaW5QYXNzd29yZC5ydWxlcyA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS53ZWJBZG1pblBhc3N3b3JkUnVsZXM7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZSB0aGUgZm9ybSB3aXRoIGN1c3RvbSBzZXR0aW5nc1xuICAgICAqL1xuICAgIGluaXRpYWxpemVGb3JtKCkge1xuICAgICAgICBGb3JtLiRmb3JtT2JqID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LiRmb3JtT2JqO1xuICAgICAgICBGb3JtLnVybCA9IGAke2dsb2JhbFJvb3RVcmx9Z2VuZXJhbC1zZXR0aW5ncy9zYXZlYDsgLy8gRm9ybSBzdWJtaXNzaW9uIFVSTFxuICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMgPSBnZW5lcmFsU2V0dGluZ3NNb2RpZnkudmFsaWRhdGVSdWxlczsgLy8gRm9ybSB2YWxpZGF0aW9uIHJ1bGVzXG4gICAgICAgIEZvcm0uY2JCZWZvcmVTZW5kRm9ybSA9IGdlbmVyYWxTZXR0aW5nc01vZGlmeS5jYkJlZm9yZVNlbmRGb3JtOyAvLyBDYWxsYmFjayBiZWZvcmUgZm9ybSBpcyBzZW50XG4gICAgICAgIEZvcm0uY2JBZnRlclNlbmRGb3JtID0gZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmNiQWZ0ZXJTZW5kRm9ybTsgLy8gQ2FsbGJhY2sgYWZ0ZXIgZm9ybSBpcyBzZW50XG4gICAgICAgIEZvcm0uaW5pdGlhbGl6ZSgpO1xuICAgIH1cbn07XG5cbi8vIFdoZW4gdGhlIGRvY3VtZW50IGlzIHJlYWR5LCBpbml0aWFsaXplIHRoZSBnZW5lcmFsU2V0dGluZ3MgbWFuYWdlbWVudCBpbnRlcmZhY2UuXG4kKGRvY3VtZW50KS5yZWFkeSgoKSA9PiB7XG4gICAgZ2VuZXJhbFNldHRpbmdzTW9kaWZ5LmluaXRpYWxpemUoKTtcbn0pOyJdfQ==
\ No newline at end of file
diff --git a/sites/admin-cabinet/assets/js/pbx/OutOffWorkTime/out-of-work-time-modify.js b/sites/admin-cabinet/assets/js/pbx/OutOffWorkTime/out-of-work-time-modify.js
index 79a801bba..26f3cd2fb 100644
--- a/sites/admin-cabinet/assets/js/pbx/OutOffWorkTime/out-of-work-time-modify.js
+++ b/sites/admin-cabinet/assets/js/pbx/OutOffWorkTime/out-of-work-time-modify.js
@@ -372,7 +372,7 @@ var outOfWorkTimeRecord = {
} // Check all fields
- if ($('#calType').parent().dropdown('get value') !== 'caldav' && result.data.time_from === '' && result.data.time_to === '' && result.data.weekday_from === '-1' && result.data.weekday_to === '-1' && result.data.date_from === '' && result.data.date_to === '') {
+ if ($('#calType').parent().dropdown('get value') === 'none' && result.data.time_from === '' && result.data.time_to === '' && result.data.weekday_from === '-1' && result.data.weekday_to === '-1' && result.data.date_from === '' && result.data.date_to === '') {
$('.form .error.message').html(globalTranslate.tf_ValidateNoRulesSelected).show();
Form.$submitButton.transition('shake').removeClass('loading disabled');
return false;
@@ -396,12 +396,12 @@ var outOfWorkTimeRecord = {
var serverOffset = parseInt(outOfWorkTimeRecord.$formObj.form('get value', 'serverOffset'));
var offsetDiff = serverOffset + currentOffset;
- if ($('#calType').parent().dropdown('get value') === 'caldav') {
- Form.validateRules.timefrom.rules = [];
- Form.validateRules.timeto.rules = [];
- } else {
+ if ($('#calType').parent().dropdown('get value') === 'none') {
Form.validateRules.timefrom.rules = outOfWorkTimeRecord.additionalTimeIntervalRules;
Form.validateRules.timeto.rules = outOfWorkTimeRecord.additionalTimeIntervalRules;
+ } else {
+ Form.validateRules.timefrom.rules = [];
+ Form.validateRules.timeto.rules = [];
}
if (dateFrom) {
@@ -483,4 +483,4 @@ $.fn.form.settings.rules.customNotEmptyIfCalType = function (value) {
$(document).ready(function () {
outOfWorkTimeRecord.initialize();
});
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9PdXRPZmZXb3JrVGltZS9vdXQtb2Ytd29yay10aW1lLW1vZGlmeS5qcyJdLCJuYW1lcyI6WyJvdXRPZldvcmtUaW1lUmVjb3JkIiwiJGZvcm1PYmoiLCIkIiwiJGRlZmF1bHREcm9wZG93biIsIiRyYW5nZURheXNTdGFydCIsIiRyYW5nZURheXNFbmQiLCIkcmFuZ2VUaW1lU3RhcnQiLCIkcmFuZ2VUaW1lRW5kIiwiJGRhdGVfZnJvbSIsIiRkYXRlX3RvIiwiJHRpbWVfdG8iLCIkZm9yd2FyZGluZ1NlbGVjdERyb3Bkb3duIiwiYWRkaXRpb25hbFRpbWVJbnRlcnZhbFJ1bGVzIiwidHlwZSIsInZhbHVlIiwicHJvbXB0IiwiZ2xvYmFsVHJhbnNsYXRlIiwidGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCIsInZhbGlkYXRlUnVsZXMiLCJhdWRpb19tZXNzYWdlX2lkIiwiaWRlbnRpZmllciIsInJ1bGVzIiwidGZfVmFsaWRhdGVBdWRpb01lc3NhZ2VFbXB0eSIsImNhbFVybCIsInRmX1ZhbGlkYXRlQ2FsVXJpIiwiZXh0ZW5zaW9uIiwidGZfVmFsaWRhdGVFeHRlbnNpb25FbXB0eSIsInRpbWVmcm9tIiwib3B0aW9uYWwiLCJ0aW1ldG8iLCJpbml0aWFsaXplIiwidGFiIiwiZHJvcGRvd24iLCJjYWxlbmRhciIsImZpcnN0RGF5T2ZXZWVrIiwiU2VtYW50aWNMb2NhbGl6YXRpb24iLCJjYWxlbmRhckZpcnN0RGF5T2ZXZWVrIiwidGV4dCIsImNhbGVuZGFyVGV4dCIsImVuZENhbGVuZGFyIiwiaW5saW5lIiwibW9udGhGaXJzdCIsInJlZ0V4cCIsInN0YXJ0Q2FsZW5kYXIiLCJvbkNoYW5nZSIsIm5ld0RhdGVUbyIsIm9sZERhdGVUbyIsImF0dHIiLCJEYXRlIiwidHJpZ2dlciIsIkZvcm0iLCJkYXRhQ2hhbmdlZCIsImRpc2FibGVNaW51dGUiLCJhbXBtIiwibmV3VGltZVRvIiwib2xkVGltZVRvIiwidG9nZ2xlRGlzYWJsZWRGaWVsZENsYXNzIiwiZnJvbSIsImZvcm0iLCJ0byIsIm9uIiwiZSIsImRhdGVfZnJvbSIsImRhdGVfdG8iLCJwcmV2ZW50RGVmYXVsdCIsIndlZWtkYXlfZnJvbSIsIndlZWtkYXlfdG8iLCJTb3VuZEZpbGVzU2VsZWN0b3IiLCJnZXREcm9wZG93blNldHRpbmdzV2l0aEVtcHR5IiwiY2hhbmdlRGF0ZUZvcm1hdCIsImluaXRpYWxpemVGb3JtIiwiRXh0ZW5zaW9ucyIsImdldERyb3Bkb3duU2V0dGluZ3NXaXRob3V0RW1wdHkiLCJjaGVja2JveCIsIm5ld1N0YXRlIiwicGFyZW50IiwiZGlkIiwiZmlsdGVyIiwiY2hhbmdlUmVzdHJpY3Rpb24iLCJzaG93IiwiaGlkZSIsImRhdGVGcm9tIiwiZGF0ZVRvIiwiY3VycmVudE9mZnNldCIsImdldFRpbWV6b25lT2Zmc2V0Iiwic2VydmVyT2Zmc2V0IiwicGFyc2VJbnQiLCJvZmZzZXREaWZmIiwidW5kZWZpbmVkIiwibGVuZ3RoIiwiZGF0ZUZyb21JbkJyb3dzZXJUWiIsImRhdGVUb0luQnJvd3NlclRaIiwiY3VzdG9tVmFsaWRhdGVGb3JtIiwicmVzdWx0IiwiZGF0YSIsImh0bWwiLCJ0Zl9WYWxpZGF0ZUNoZWNrRGF0ZUludGVydmFsIiwiJHN1Ym1pdEJ1dHRvbiIsInRyYW5zaXRpb24iLCJyZW1vdmVDbGFzcyIsInRmX1ZhbGlkYXRlQ2hlY2tXZWVrRGF5SW50ZXJ2YWwiLCJ0aW1lX2Zyb20iLCJ0aW1lX3RvIiwidGZfVmFsaWRhdGVOb1J1bGVzU2VsZWN0ZWQiLCJjYkJlZm9yZVNlbmRGb3JtIiwic2V0dGluZ3MiLCJzZXRIb3VycyIsIk1hdGgiLCJmbG9vciIsImdldFRpbWUiLCJjYkFmdGVyU2VuZEZvcm0iLCJyZXNwb25zZSIsInVybCIsImdsb2JhbFJvb3RVcmwiLCJmbiIsImN1c3RvbU5vdEVtcHR5SWZBY3Rpb25SdWxlIiwiYWN0aW9uIiwidmFsIiwiY3VzdG9tTm90RW1wdHlJZkNhbFR5cGUiLCJVUkwiLCJfIiwiZG9jdW1lbnQiLCJyZWFkeSJd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QUFPLElBQVA7QUFDSCxDQVZEO0FBYUE7QUFDQTtBQUNBOzs7QUFDQXRILENBQUMsQ0FBQ3VILFFBQUQsQ0FBRCxDQUFZQyxLQUFaLENBQWtCLFlBQU07QUFDcEIxSCxFQUFBQSxtQkFBbUIsQ0FBQzhCLFVBQXBCO0FBQ0gsQ0FGRCIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBNaWtvUEJYIC0gZnJlZSBwaG9uZSBzeXN0ZW0gZm9yIHNtYWxsIGJ1c2luZXNzXG4gKiBDb3B5cmlnaHQgwqkgMjAxNy0yMDIzIEFsZXhleSBQb3J0bm92IGFuZCBOaWtvbGF5IEJla2V0b3ZcbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gKiAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4gKlxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uXG4gKiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuICovXG5cbi8qIGdsb2JhbCBnbG9iYWxSb290VXJsLGdsb2JhbFRyYW5zbGF0ZSwgRXh0ZW5zaW9ucywgRm9ybSwgU2VtYW50aWNMb2NhbGl6YXRpb24sIFNvdW5kRmlsZXNTZWxlY3RvciAqL1xuXG5cbi8qKlxuICogT2JqZWN0IGZvciBtYW5hZ2luZyBPdXQtb2YtV29yayBUaW1lIHNldHRpbmdzXG4gKlxuICogQG1vZHVsZSBvdXRPZldvcmtUaW1lUmVjb3JkXG4gKi9cbmNvbnN0IG91dE9mV29ya1RpbWVSZWNvcmQgPSB7XG4gICAgLyoqXG4gICAgICogalF1ZXJ5IG9iamVjdCBmb3IgdGhlIGZvcm0uXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkZm9ybU9iajogJCgnI3NhdmUtb3V0b2Zmd29yay1mb3JtJyksXG5cbiAgICAkZGVmYXVsdERyb3Bkb3duOiAkKCcjc2F2ZS1vdXRvZmZ3b3JrLWZvcm0gLmRyb3Bkb3duLWRlZmF1bHQnKSxcbiAgICAkcmFuZ2VEYXlzU3RhcnQ6ICQoJyNyYW5nZS1kYXlzLXN0YXJ0JyksXG4gICAgJHJhbmdlRGF5c0VuZDogJCgnI3JhbmdlLWRheXMtZW5kJyksXG4gICAgJHJhbmdlVGltZVN0YXJ0OiAkKCcjcmFuZ2UtdGltZS1zdGFydCcpLFxuICAgICRyYW5nZVRpbWVFbmQ6ICQoJyNyYW5nZS10aW1lLWVuZCcpLFxuICAgICRkYXRlX2Zyb206ICQoJyNkYXRlX2Zyb20nKSxcbiAgICAkZGF0ZV90bzogJCgnI2RhdGVfdG8nKSxcbiAgICAkdGltZV90bzogJCgnI3RpbWVfdG8nKSxcbiAgICAkZm9yd2FyZGluZ1NlbGVjdERyb3Bkb3duOiAkKCcjc2F2ZS1vdXRvZmZ3b3JrLWZvcm0gLmZvcndhcmRpbmctc2VsZWN0JyksXG5cblxuICAgIC8qKlxuICAgICAqIEFkZGl0aW9uYWwgY29uZGl0aW9uIGZvciB0aGUgdGltZSBpbnRlcnZhbFxuICAgICAqIEB0eXBlIHthcnJheX1cbiAgICAgKi9cbiAgICBhZGRpdGlvbmFsVGltZUludGVydmFsUnVsZXM6IFt7XG4gICAgICAgIHR5cGU6ICdyZWdFeHAnLFxuICAgICAgICB2YWx1ZTogL14oMlswLTNdfDE/WzAtOV0pOihbMC01XT9bMC05XSkkLyxcbiAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCxcbiAgICB9XSxcblxuICAgIC8qKlxuICAgICAqIFZhbGlkYXRpb24gcnVsZXMgZm9yIHRoZSBmb3JtIGZpZWxkcyBiZWZvcmUgc3VibWlzc2lvbi5cbiAgICAgKlxuICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICovXG4gICAgdmFsaWRhdGVSdWxlczoge1xuICAgICAgICBhdWRpb19tZXNzYWdlX2lkOiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnYXVkaW9fbWVzc2FnZV9pZCcsXG4gICAgICAgICAgICBydWxlczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2N1c3RvbU5vdEVtcHR5SWZBY3Rpb25SdWxlW3BsYXltZXNzYWdlXScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLnRmX1ZhbGlkYXRlQXVkaW9NZXNzYWdlRW1wdHksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIGNhbFVybDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ2NhbFVybCcsXG4gICAgICAgICAgICBydWxlczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZSAgIDogJ2N1c3RvbU5vdEVtcHR5SWZDYWxUeXBlJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0IDogZ2xvYmFsVHJhbnNsYXRlLnRmX1ZhbGlkYXRlQ2FsVXJpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXVxuICAgICAgICB9LFxuICAgICAgICBleHRlbnNpb246IHtcbiAgICAgICAgICAgIGlkZW50aWZpZXI6ICdleHRlbnNpb24nLFxuICAgICAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdjdXN0b21Ob3RFbXB0eUlmQWN0aW9uUnVsZVtleHRlbnNpb25dJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVFeHRlbnNpb25FbXB0eSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgdGltZWZyb206IHtcbiAgICAgICAgICAgIG9wdGlvbmFsOiB0cnVlLFxuICAgICAgICAgICAgaWRlbnRpZmllcjogJ3RpbWVfZnJvbScsXG4gICAgICAgICAgICBydWxlczogW3tcbiAgICAgICAgICAgICAgICB0eXBlOiAncmVnRXhwJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogL14oMlswLTNdfDE/WzAtOV0pOihbMC01XT9bMC05XSkkLyxcbiAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrVGltZUludGVydmFsLFxuICAgICAgICAgICAgfV0sXG4gICAgICAgIH0sXG4gICAgICAgIHRpbWV0bzoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ3RpbWVfdG8nLFxuICAgICAgICAgICAgb3B0aW9uYWw6IHRydWUsXG4gICAgICAgICAgICBydWxlczogW3tcbiAgICAgICAgICAgICAgICB0eXBlOiAncmVnRXhwJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogL14oMlswLTNdfDE/WzAtOV0pOihbMC01XT9bMC05XSkkLyxcbiAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrVGltZUludGVydmFsLFxuICAgICAgICAgICAgfV0sXG4gICAgICAgIH0sXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemVzIHRoZSBvdXQgb2Ygd29yayB0aW1lIHJlY29yZCBmb3JtLlxuICAgICAqL1xuICAgIGluaXRpYWxpemUoKSB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgdGFiIGJlaGF2aW9yIGZvciB0aGUgb3V0LXRpbWUtbW9kaWZ5LW1lbnVcbiAgICAgICAgJCgnI291dC10aW1lLW1vZGlmeS1tZW51IC5pdGVtJykudGFiKCk7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgZGVmYXVsdCBkcm9wZG93blxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRkZWZhdWx0RHJvcGRvd24uZHJvcGRvd24oKTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjYWxlbmRhciBmb3IgcmFuZ2UgZGF5cyBzdGFydFxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC5jYWxlbmRhcih7XG4gICAgICAgICAgICAvLyBDYWxlbmRhciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICAgIGZpcnN0RGF5T2ZXZWVrOiBTZW1hbnRpY0xvY2FsaXphdGlvbi5jYWxlbmRhckZpcnN0RGF5T2ZXZWVrLFxuICAgICAgICAgICAgdGV4dDogU2VtYW50aWNMb2NhbGl6YXRpb24uY2FsZW5kYXJUZXh0LFxuICAgICAgICAgICAgZW5kQ2FsZW5kYXI6IG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c0VuZCxcbiAgICAgICAgICAgIHR5cGU6ICdkYXRlJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBtb250aEZpcnN0OiBmYWxzZSxcbiAgICAgICAgICAgIHJlZ0V4cDogU2VtYW50aWNMb2NhbGl6YXRpb24ucmVnRXhwLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjYWxlbmRhciBmb3IgcmFuZ2UgZGF5cyBlbmRcbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kcmFuZ2VEYXlzRW5kLmNhbGVuZGFyKHtcbiAgICAgICAgICAgIC8vIENhbGVuZGFyIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAgICAgZmlyc3REYXlPZldlZWs6IFNlbWFudGljTG9jYWxpemF0aW9uLmNhbGVuZGFyRmlyc3REYXlPZldlZWssXG4gICAgICAgICAgICB0ZXh0OiBTZW1hbnRpY0xvY2FsaXphdGlvbi5jYWxlbmRhclRleHQsXG4gICAgICAgICAgICBzdGFydENhbGVuZGFyOiBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydCxcbiAgICAgICAgICAgIHR5cGU6ICdkYXRlJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBtb250aEZpcnN0OiBmYWxzZSxcbiAgICAgICAgICAgIHJlZ0V4cDogU2VtYW50aWNMb2NhbGl6YXRpb24ucmVnRXhwLFxuICAgICAgICAgICAgb25DaGFuZ2U6IChuZXdEYXRlVG8pID0+IHtcbiAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgcmFuZ2UgdGltZSBlbmRcbiAgICAgICAgICAgICAgICBsZXQgb2xkRGF0ZVRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZGF0ZV90by5hdHRyKCd2YWx1ZScpO1xuICAgICAgICAgICAgICAgIGlmIChuZXdEYXRlVG8gIT09IG51bGwgJiYgb2xkRGF0ZVRvICE9PSAnJykge1xuICAgICAgICAgICAgICAgICAgICBvbGREYXRlVG8gPSBuZXcgRGF0ZShvbGREYXRlVG8gKiAxMDAwKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKChuZXdEYXRlVG8gLSBvbGREYXRlVG8pICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRkYXRlX2Zyb20udHJpZ2dlcignY2hhbmdlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBGb3JtLmRhdGFDaGFuZ2VkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjYWxlbmRhciBmb3IgcmFuZ2UgdGltZSBzdGFydFxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZVRpbWVTdGFydC5jYWxlbmRhcih7XG4gICAgICAgICAgICAvLyBDYWxlbmRhciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICAgIGZpcnN0RGF5T2ZXZWVrOiBTZW1hbnRpY0xvY2FsaXphdGlvbi5jYWxlbmRhckZpcnN0RGF5T2ZXZWVrLFxuICAgICAgICAgICAgdGV4dDogU2VtYW50aWNMb2NhbGl6YXRpb24uY2FsZW5kYXJUZXh0LFxuICAgICAgICAgICAgZW5kQ2FsZW5kYXI6IG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlVGltZUVuZCxcbiAgICAgICAgICAgIHR5cGU6ICd0aW1lJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBkaXNhYmxlTWludXRlOiB0cnVlLFxuICAgICAgICAgICAgYW1wbTogZmFsc2UsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGNhbGVuZGFyIGZvciByYW5nZSB0aW1lIGVuZFxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZVRpbWVFbmQuY2FsZW5kYXIoe1xuICAgICAgICAgICAgLy8gQ2FsZW5kYXIgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAgICBmaXJzdERheU9mV2VlazogU2VtYW50aWNMb2NhbGl6YXRpb24uY2FsZW5kYXJGaXJzdERheU9mV2VlayxcbiAgICAgICAgICAgIHRleHQ6IFNlbWFudGljTG9jYWxpemF0aW9uLmNhbGVuZGFyVGV4dCxcbiAgICAgICAgICAgIHR5cGU6ICd0aW1lJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBkaXNhYmxlTWludXRlOiB0cnVlLFxuICAgICAgICAgICAgYW1wbTogZmFsc2UsXG4gICAgICAgICAgICBvbkNoYW5nZTogKG5ld1RpbWVUbykgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSB0aGUgY2hhbmdlIGV2ZW50IGZvciByYW5nZSB0aW1lIGVuZFxuICAgICAgICAgICAgICAgIGxldCBvbGRUaW1lVG8gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiR0aW1lX3RvLmF0dHIoJ3ZhbHVlJyk7XG4gICAgICAgICAgICAgICAgaWYgKG5ld1RpbWVUbyAhPT0gbnVsbCAmJiBvbGRUaW1lVG8gIT09ICcnKSB7XG4gICAgICAgICAgICAgICAgICAgIG9sZFRpbWVUbyA9IG5ldyBEYXRlKG9sZFRpbWVUbyAqIDEwMDApO1xuICAgICAgICAgICAgICAgICAgICBpZiAoKG5ld1RpbWVUbyAtIG9sZFRpbWVUbykgIT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJHRpbWVfdG8udHJpZ2dlcignY2hhbmdlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBGb3JtLmRhdGFDaGFuZ2VkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBhY3Rpb24gZHJvcGRvd25cbiAgICAgICAgJCgnI2FjdGlvbicpXG4gICAgICAgICAgICAuZHJvcGRvd24oe1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgdGhlIGFjdGlvbiBkcm9wZG93blxuICAgICAgICAgICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLnRvZ2dsZURpc2FibGVkRmllbGRDbGFzcygpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgY2FsVHlwZSBkcm9wZG93blxuICAgICAgICAkKCcjY2FsVHlwZScpXG4gICAgICAgICAgICAuZHJvcGRvd24oe1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgdGhlIGFjdGlvbiBkcm9wZG93blxuICAgICAgICAgICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLnRvZ2dsZURpc2FibGVkRmllbGRDbGFzcygpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSB3ZWVrZGF5X2Zyb20gZHJvcGRvd25cbiAgICAgICAgJCgnI3dlZWtkYXlfZnJvbScpXG4gICAgICAgICAgICAuZHJvcGRvd24oe1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgdGhlIHdlZWtkYXlfZnJvbSBkcm9wZG93blxuICAgICAgICAgICAgICAgICAgICBjb25zdCBmcm9tID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnd2Vla2RheV9mcm9tJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnd2Vla2RheV90bycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZnJvbSA8IHRvIHx8IHRvID09PSAtMSB8fCBmcm9tID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdzZXQgdmFsdWUnLCAnd2Vla2RheV90bycsIGZyb20pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIHdlZWtkYXlfdG8gZHJvcGRvd25cbiAgICAgICAgJCgnI3dlZWtkYXlfdG8nKVxuICAgICAgICAgICAgLmRyb3Bkb3duKHtcbiAgICAgICAgICAgICAgICBvbkNoYW5nZSgpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSGFuZGxlIHRoZSBjaGFuZ2UgZXZlbnQgZm9yIHRoZSB3ZWVrZGF5X3RvIGRyb3Bkb3duXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZyb20gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICd3ZWVrZGF5X2Zyb20nKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdG8gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICd3ZWVrZGF5X3RvJyk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0byA8IGZyb20gfHwgZnJvbSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmouZm9ybSgnc2V0IHZhbHVlJywgJ3dlZWtkYXlfZnJvbScsIHRvKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAvLyBCaW5kIGNsaWNrIGV2ZW50IHRvIGVyYXNlLWRhdGVzIGJ1dHRvblxuICAgICAgICAkKCcjZXJhc2UtZGF0ZXMnKS5vbignY2xpY2snLCAoZSkgPT4ge1xuICAgICAgICAgICAgLy8gSGFuZGxlIHRoZSBjbGljayBldmVudCBmb3IgZXJhc2UtZGF0ZXMgYnV0dG9uXG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC5jYWxlbmRhcignY2xlYXInKTtcbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c0VuZC5jYWxlbmRhcignY2xlYXInKTtcbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmpcbiAgICAgICAgICAgICAgICAuZm9ybSgnc2V0IHZhbHVlcycsIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0ZV9mcm9tOiAnJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0ZV90bzogJycsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEJpbmQgY2xpY2sgZXZlbnQgdG8gZXJhc2Utd2Vla2RheXMgYnV0dG9uXG4gICAgICAgICQoJyNlcmFzZS13ZWVrZGF5cycpLm9uKCdjbGljaycsIChlKSA9PiB7XG4gICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNsaWNrIGV2ZW50IGZvciBlcmFzZS13ZWVrZGF5cyBidXR0b25cbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmpcbiAgICAgICAgICAgICAgICAuZm9ybSgnc2V0IHZhbHVlcycsIHtcbiAgICAgICAgICAgICAgICAgICAgd2Vla2RheV9mcm9tOiAtMSxcbiAgICAgICAgICAgICAgICAgICAgd2Vla2RheV90bzogLTEsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC50cmlnZ2VyKCdjaGFuZ2UnKTtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQmluZCBjbGljayBldmVudCB0byBlcmFzZS10aW1lcGVyaW9kIGJ1dHRvblxuICAgICAgICAkKCcjZXJhc2UtdGltZXBlcmlvZCcpLm9uKCdjbGljaycsIChlKSA9PiB7XG4gICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNsaWNrIGV2ZW50IGZvciBlcmFzZS10aW1lcGVyaW9kIGJ1dHRvblxuICAgICAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kcmFuZ2VUaW1lU3RhcnQuY2FsZW5kYXIoJ2NsZWFyJyk7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZVRpbWVFbmQuY2FsZW5kYXIoJ2NsZWFyJyk7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiR0aW1lX3RvLnRyaWdnZXIoJ2NoYW5nZScpO1xuICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIGF1ZGlvLW1lc3NhZ2Utc2VsZWN0IGRyb3Bkb3duXG4gICAgICAgICQoJyNzYXZlLW91dG9mZndvcmstZm9ybSAuYXVkaW8tbWVzc2FnZS1zZWxlY3QnKS5kcm9wZG93bihTb3VuZEZpbGVzU2VsZWN0b3IuZ2V0RHJvcGRvd25TZXR0aW5nc1dpdGhFbXB0eSgpKTtcblxuICAgICAgICAvLyBDaGFuZ2UgdGhlIGRhdGUgZm9ybWF0IGZyb20gbGludXh0aW1lIHRvIGxvY2FsIHJlcHJlc2VudGF0aW9uXG4gICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuY2hhbmdlRGF0ZUZvcm1hdCgpO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGZvcm1cbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC5pbml0aWFsaXplRm9ybSgpO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGZvcndhcmRpbmdTZWxlY3REcm9wZG93blxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3J3YXJkaW5nU2VsZWN0RHJvcGRvd24uZHJvcGRvd24oRXh0ZW5zaW9ucy5nZXREcm9wZG93blNldHRpbmdzV2l0aG91dEVtcHR5KCkpO1xuXG4gICAgICAgIC8vIFRvZ2dsZSBkaXNhYmxlZCBmaWVsZCBjbGFzcyBiYXNlZCBvbiBhY3Rpb24gdmFsdWVcbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC50b2dnbGVEaXNhYmxlZEZpZWxkQ2xhc3MoKTtcblxuICAgICAgICAvLyBCaW5kIGNoZWNrYm94IGNoYW5nZSBldmVudCBmb3IgaW5ib3VuZCBydWxlcyB0YWJsZVxuICAgICAgICAkKCcjaW5ib3VuZC1ydWxlcy10YWJsZSAudWkuY2hlY2tib3gnKS5jaGVja2JveCh7XG4gICAgICAgICAgICBvbkNoYW5nZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGxldCBuZXdTdGF0ZSA9ICd1bmNoZWNrZWQnO1xuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSB0aGUgY2hhbmdlIGV2ZW50IGZvciBpbmJvdW5kIHJ1bGVzIHRhYmxlIGNoZWNrYm94XG4gICAgICAgICAgICAgICAgaWYgKCQodGhpcykucGFyZW50KCkuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuICAgICAgICAgICAgICAgICAgICBuZXdTdGF0ZSA9ICdjaGVja2VkJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbGV0IGRpZCA9ICQodGhpcykucGFyZW50KCkuYXR0cignZGF0YS1kaWQnKTtcbiAgICAgICAgICAgICAgICBsZXQgZmlsdGVyID0gJyNpbmJvdW5kLXJ1bGVzLXRhYmxlIC51aS5jaGVja2JveFtkYXRhLWNvbnRleHQtaWQ9JyArICQodGhpcykucGFyZW50KCkuYXR0cignZGF0YS1jb250ZXh0LWlkJykgKyAnXSc7XG4gICAgICAgICAgICAgICAgaWYoZGlkICE9PSAnJyAmJiBuZXdTdGF0ZSA9PT0gJ2NoZWNrZWQnKXtcbiAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyICsgJy51aS5jaGVja2JveFtkYXRhLWRpZD0nK2RpZCsnXSc7XG4gICAgICAgICAgICAgICAgfWVsc2UgaWYoZGlkID09PSAnJyAmJiBuZXdTdGF0ZSA9PT0gJ3VuY2hlY2tlZCcpe1xuICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBmaWx0ZXIgKyAnLnVpLmNoZWNrYm94W2RhdGEtZGlkPVwiXCJdJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJChmaWx0ZXIpLmNoZWNrYm94KCdzZXQgJytuZXdTdGF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEJpbmQgY2hlY2tib3ggY2hhbmdlIGV2ZW50IGZvciBhbGxvd1Jlc3RyaWN0aW9uIGNoZWNrYm94XG4gICAgICAgICQoJyNhbGxvd1Jlc3RyaWN0aW9uJykucGFyZW50KCkuY2hlY2tib3goe1xuICAgICAgICAgICAgb25DaGFuZ2U6IG91dE9mV29ya1RpbWVSZWNvcmQuY2hhbmdlUmVzdHJpY3Rpb25cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQ2FsbCBjaGFuZ2VSZXN0cmljdGlvbiBtZXRob2RcbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC5jaGFuZ2VSZXN0cmljdGlvbigpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDaGFuZ2VzIHRoZSB2aXNpYmlsaXR5IG9mIHRoZSAncnVsZXMnIHRhYiBiYXNlZCBvbiB0aGUgY2hlY2tlZCBzdGF0dXMgb2YgdGhlICdhbGxvd1Jlc3RyaWN0aW9uJyBjaGVja2JveC5cbiAgICAgKi9cbiAgICBjaGFuZ2VSZXN0cmljdGlvbigpIHtcbiAgICAgICAgaWYgKCQoJyNhbGxvd1Jlc3RyaWN0aW9uJykucGFyZW50KCkuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuICAgICAgICAgICAgJChcImFbZGF0YS10YWI9J3J1bGVzJ11cIikuc2hvdygpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJChcImFbZGF0YS10YWI9J3J1bGVzJ11cIikuaGlkZSgpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIHRoZSBkYXRlIGZvcm1hdCBmcm9tIGxpbnV4dGltZSB0byB0aGUgbG9jYWwgcmVwcmVzZW50YXRpb24uXG4gICAgICovXG4gICAgY2hhbmdlRGF0ZUZvcm1hdCgpIHtcbiAgICAgICAgY29uc3QgZGF0ZUZyb20gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRkYXRlX2Zyb20uYXR0cigndmFsdWUnKTtcbiAgICAgICAgY29uc3QgZGF0ZVRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZGF0ZV90by5hdHRyKCd2YWx1ZScpO1xuICAgICAgICBjb25zdCBjdXJyZW50T2Zmc2V0ID0gbmV3IERhdGUoKS5nZXRUaW1lem9uZU9mZnNldCgpO1xuICAgICAgICBjb25zdCBzZXJ2ZXJPZmZzZXQgPSBwYXJzZUludChvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICdzZXJ2ZXJPZmZzZXQnKSk7XG4gICAgICAgIGNvbnN0IG9mZnNldERpZmYgPSBzZXJ2ZXJPZmZzZXQgKyBjdXJyZW50T2Zmc2V0O1xuICAgICAgICBpZiAoZGF0ZUZyb20gIT09IHVuZGVmaW5lZCAmJiBkYXRlRnJvbS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBkYXRlRnJvbUluQnJvd3NlclRaID0gZGF0ZUZyb20gKiAxMDAwICsgb2Zmc2V0RGlmZiAqIDYwICogMTAwMDtcbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c1N0YXJ0LmNhbGVuZGFyKCdzZXQgZGF0ZScsIG5ldyBEYXRlKGRhdGVGcm9tSW5Ccm93c2VyVFopKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGF0ZVRvICE9PSB1bmRlZmluZWQgJiYgZGF0ZVRvLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGRhdGVUb0luQnJvd3NlclRaID0gZGF0ZVRvICogMTAwMCArIG9mZnNldERpZmYgKiA2MCAqIDEwMDA7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNFbmQuY2FsZW5kYXIoJ3NldCBkYXRlJywgbmV3IERhdGUoZGF0ZVRvSW5Ccm93c2VyVFopKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHRoZSB2aXNpYmlsaXR5IG9mIGNlcnRhaW4gZmllbGQgZ3JvdXBzIGJhc2VkIG9uIHRoZSBzZWxlY3RlZCBhY3Rpb24gdmFsdWUuXG4gICAgICovXG4gICAgdG9nZ2xlRGlzYWJsZWRGaWVsZENsYXNzKCkge1xuICAgICAgICBpZihvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICdhY3Rpb24nKSA9PT0gJ2V4dGVuc2lvbicpIHtcbiAgICAgICAgICAgICQoJyNleHRlbnNpb24tZ3JvdXAnKS5zaG93KCk7XG4gICAgICAgICAgICAkKCcjYXVkaW8tZmlsZS1ncm91cCcpLmhpZGUoKTtcbiAgICAgICAgICAgICQoJyNhdWRpb19tZXNzYWdlX2lkJykuZHJvcGRvd24oJ2NsZWFyJyk7XG4gICAgICAgIH1lbHNle1xuICAgICAgICAgICAgJCgnI2V4dGVuc2lvbi1ncm91cCcpLmhpZGUoKTtcbiAgICAgICAgICAgICQoJyNhdWRpby1maWxlLWdyb3VwJykuc2hvdygpO1xuICAgICAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdzZXQgdmFsdWUnLCAnZXh0ZW5zaW9uJywgLTEpO1xuICAgICAgICB9XG4gICAgICAgIGlmKG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmouZm9ybSgnZ2V0IHZhbHVlJywgJ2NhbFR5cGUnKSA9PT0gJ25vbmUnKXtcbiAgICAgICAgICAgICQoJyNjYWxsLXR5cGUtbWFpbi10YWInKS5zaG93KCk7XG4gICAgICAgICAgICAkKCcjY2FsbC10eXBlLWNhbGVuZGFyLXRhYicpLmhpZGUoKTtcbiAgICAgICAgfWVsc2V7XG4gICAgICAgICAgICAkKCcjY2FsbC10eXBlLW1haW4tdGFiJykuaGlkZSgpO1xuICAgICAgICAgICAgJCgnI2NhbGwtdHlwZS1jYWxlbmRhci10YWInKS5zaG93KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3VzdG9tIGZvcm0gdmFsaWRhdGlvbiBmb3IgdmFsaWRhdGluZyBzcGVjaWZpYyBmaWVsZHMgaW4gYSBmb3JtLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHJlc3VsdCAtIFRoZSByZXN1bHQgb2JqZWN0IGNvbnRhaW5pbmcgZm9ybSBkYXRhLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufE9iamVjdH0gUmV0dXJucyBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLCBvciB0aGUgcmVzdWx0IG9iamVjdCBpZiB2YWxpZGF0aW9uIHBhc3Nlcy5cbiAgICAgKi9cbiAgICBjdXN0b21WYWxpZGF0ZUZvcm0ocmVzdWx0KSB7XG4gICAgICAgIC8vIENoZWNrIGRhdGUgZmllbGRzXG4gICAgICAgIGlmICgocmVzdWx0LmRhdGEuZGF0ZV9mcm9tICE9PSAnJyAmJiByZXN1bHQuZGF0YS5kYXRlX3RvID09PSAnJylcbiAgICAgICAgICAgIHx8IChyZXN1bHQuZGF0YS5kYXRlX3RvICE9PSAnJyAmJiByZXN1bHQuZGF0YS5kYXRlX2Zyb20gPT09ICcnKSkge1xuICAgICAgICAgICAgJCgnLmZvcm0gLmVycm9yLm1lc3NhZ2UnKS5odG1sKGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrRGF0ZUludGVydmFsKS5zaG93KCk7XG4gICAgICAgICAgICBGb3JtLiRzdWJtaXRCdXR0b24udHJhbnNpdGlvbignc2hha2UnKS5yZW1vdmVDbGFzcygnbG9hZGluZyBkaXNhYmxlZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgd2Vla2RheSBmaWVsZHNcbiAgICAgICAgaWYgKChyZXN1bHQuZGF0YS53ZWVrZGF5X2Zyb20gPiAwICYmIHJlc3VsdC5kYXRhLndlZWtkYXlfdG8gPT09ICctMScpXG4gICAgICAgICAgICB8fCAocmVzdWx0LmRhdGEud2Vla2RheV90byA+IDAgJiYgcmVzdWx0LmRhdGEud2Vla2RheV9mcm9tID09PSAnLTEnKSkge1xuICAgICAgICAgICAgJCgnLmZvcm0gLmVycm9yLm1lc3NhZ2UnKS5odG1sKGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrV2Vla0RheUludGVydmFsKS5zaG93KCk7XG4gICAgICAgICAgICBGb3JtLiRzdWJtaXRCdXR0b24udHJhbnNpdGlvbignc2hha2UnKS5yZW1vdmVDbGFzcygnbG9hZGluZyBkaXNhYmxlZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgdGltZSBmaWVsZHNcbiAgICAgICAgaWYgKChyZXN1bHQuZGF0YS50aW1lX2Zyb20ubGVuZ3RoID4gMCAmJiByZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHx8IChyZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA+IDAgJiYgcmVzdWx0LmRhdGEudGltZV9mcm9tLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgICAgICQoJy5mb3JtIC5lcnJvci5tZXNzYWdlJykuaHRtbChnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCkuc2hvdygpO1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnRyYW5zaXRpb24oJ3NoYWtlJykucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcgZGlzYWJsZWQnKTtcblxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgdGltZSBmaWVsZCBmb3JtYXRcbiAgICAgICAgaWYgKChyZXN1bHQuZGF0YS50aW1lX2Zyb20ubGVuZ3RoID4gMCAmJiByZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHx8IChyZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA+IDAgJiYgcmVzdWx0LmRhdGEudGltZV9mcm9tLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgICAgICQoJy5mb3JtIC5lcnJvci5tZXNzYWdlJykuaHRtbChnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCkuc2hvdygpO1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnRyYW5zaXRpb24oJ3NoYWtlJykucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcgZGlzYWJsZWQnKTtcblxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgYWxsIGZpZWxkc1xuICAgICAgICBpZiAoJCgnI2NhbFR5cGUnKS5wYXJlbnQoKS5kcm9wZG93bignZ2V0IHZhbHVlJykgIT09ICdjYWxkYXYnXG4gICAgICAgICAgICAmJiByZXN1bHQuZGF0YS50aW1lX2Zyb20gPT09ICcnXG4gICAgICAgICAgICAmJiByZXN1bHQuZGF0YS50aW1lX3RvID09PSAnJ1xuICAgICAgICAgICAgJiYgcmVzdWx0LmRhdGEud2Vla2RheV9mcm9tID09PSAnLTEnXG4gICAgICAgICAgICAmJiByZXN1bHQuZGF0YS53ZWVrZGF5X3RvID09PSAnLTEnXG4gICAgICAgICAgICAmJiByZXN1bHQuZGF0YS5kYXRlX2Zyb20gPT09ICcnXG4gICAgICAgICAgICAmJiByZXN1bHQuZGF0YS5kYXRlX3RvID09PSAnJykge1xuICAgICAgICAgICAgJCgnLmZvcm0gLmVycm9yLm1lc3NhZ2UnKS5odG1sKGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZU5vUnVsZXNTZWxlY3RlZCkuc2hvdygpO1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnRyYW5zaXRpb24oJ3NoYWtlJykucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcgZGlzYWJsZWQnKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYmVmb3JlIHRoZSBmb3JtIGlzIHNlbnRcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgY3VycmVudCBzZXR0aW5ncyBvZiB0aGUgZm9ybVxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIHVwZGF0ZWQgc2V0dGluZ3Mgb2YgdGhlIGZvcm1cbiAgICAgKi9cbiAgICBjYkJlZm9yZVNlbmRGb3JtKHNldHRpbmdzKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHNldHRpbmdzO1xuICAgICAgICAkKCcuZm9ybSAuZXJyb3IubWVzc2FnZScpLmh0bWwoJycpLmhpZGUoKTtcbiAgICAgICAgcmVzdWx0LmRhdGEgPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZXMnKTtcbiAgICAgICAgY29uc3QgZGF0ZUZyb20gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC5jYWxlbmRhcignZ2V0IGRhdGUnKTtcbiAgICAgICAgY29uc3QgZGF0ZVRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kcmFuZ2VEYXlzRW5kLmNhbGVuZGFyKCdnZXQgZGF0ZScpO1xuICAgICAgICBjb25zdCBjdXJyZW50T2Zmc2V0ID0gbmV3IERhdGUoKS5nZXRUaW1lem9uZU9mZnNldCgpO1xuICAgICAgICBjb25zdCBzZXJ2ZXJPZmZzZXQgPSBwYXJzZUludChvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICdzZXJ2ZXJPZmZzZXQnKSk7XG4gICAgICAgIGNvbnN0IG9mZnNldERpZmYgPSBzZXJ2ZXJPZmZzZXQgKyBjdXJyZW50T2Zmc2V0O1xuXG4gICAgICAgIGlmKCQoJyNjYWxUeXBlJykucGFyZW50KCkuZHJvcGRvd24oJ2dldCB2YWx1ZScpID09PSAnY2FsZGF2Jyl7XG4gICAgICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMudGltZWZyb20ucnVsZXMgPSBbXTtcbiAgICAgICAgICAgIEZvcm0udmFsaWRhdGVSdWxlcy50aW1ldG8ucnVsZXMgPSBbXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIEZvcm0udmFsaWRhdGVSdWxlcy50aW1lZnJvbS5ydWxlcyA9IG91dE9mV29ya1RpbWVSZWNvcmQuYWRkaXRpb25hbFRpbWVJbnRlcnZhbFJ1bGVzO1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLnRpbWV0by5ydWxlcyA9IG91dE9mV29ya1RpbWVSZWNvcmQuYWRkaXRpb25hbFRpbWVJbnRlcnZhbFJ1bGVzO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRhdGVGcm9tKSB7XG4gICAgICAgICAgICBkYXRlRnJvbS5zZXRIb3VycygwLCAwLCAwLCAwKTtcbiAgICAgICAgICAgIHJlc3VsdC5kYXRhLmRhdGVfZnJvbSA9IE1hdGguZmxvb3IoZGF0ZUZyb20uZ2V0VGltZSgpLzEwMDApIC0gb2Zmc2V0RGlmZiAqIDYwO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkYXRlVG8pIHtcbiAgICAgICAgICAgIGRhdGVUby5zZXRIb3VycygyMywgNTksIDU5LCAwKTtcbiAgICAgICAgICAgIHJlc3VsdC5kYXRhLmRhdGVfdG8gPSBNYXRoLmZsb29yKGRhdGVUby5nZXRUaW1lKCkvMTAwMCkgLSBvZmZzZXREaWZmICogNjA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG91dE9mV29ya1RpbWVSZWNvcmQuY3VzdG9tVmFsaWRhdGVGb3JtKHJlc3VsdCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgZm9ybSBoYXMgYmVlbiBzZW50LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSByZXNwb25zZSAtIFRoZSByZXNwb25zZSBmcm9tIHRoZSBzZXJ2ZXIgYWZ0ZXIgdGhlIGZvcm0gaXMgc2VudFxuICAgICAqL1xuICAgIGNiQWZ0ZXJTZW5kRm9ybShyZXNwb25zZSkge1xuXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgdGhlIGZvcm0gd2l0aCBjdXN0b20gc2V0dGluZ3NcbiAgICAgKi9cbiAgICBpbml0aWFsaXplRm9ybSgpIHtcbiAgICAgICAgRm9ybS4kZm9ybU9iaiA9IG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmo7XG4gICAgICAgIEZvcm0udXJsID0gYCR7Z2xvYmFsUm9vdFVybH1vdXQtb2ZmLXdvcmstdGltZS9zYXZlYDsgLy8gRm9ybSBzdWJtaXNzaW9uIFVSTFxuICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMgPSBvdXRPZldvcmtUaW1lUmVjb3JkLnZhbGlkYXRlUnVsZXM7IC8vIEZvcm0gdmFsaWRhdGlvbiBydWxlc1xuICAgICAgICBGb3JtLmNiQmVmb3JlU2VuZEZvcm0gPSBvdXRPZldvcmtUaW1lUmVjb3JkLmNiQmVmb3JlU2VuZEZvcm07IC8vIENhbGxiYWNrIGJlZm9yZSBmb3JtIGlzIHNlbnRcbiAgICAgICAgRm9ybS5jYkFmdGVyU2VuZEZvcm0gPSBvdXRPZldvcmtUaW1lUmVjb3JkLmNiQWZ0ZXJTZW5kRm9ybTsgLy8gQ2FsbGJhY2sgYWZ0ZXIgZm9ybSBpcyBzZW50XG4gICAgICAgIEZvcm0uaW5pdGlhbGl6ZSgpO1xuICAgIH0sXG59O1xuXG4vKipcbiAqIEN1c3RvbSBmb3JtIHZhbGlkYXRpb24gcnVsZSB0aGF0IGNoZWNrcyBpZiBhIHZhbHVlIGlzIG5vdCBlbXB0eSBiYXNlZCBvbiBhIHNwZWNpZmljIGFjdGlvbi5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgdmFsaWRhdGVkLlxuICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvbiAtIFRoZSBhY3Rpb24gdG8gY29tcGFyZSBhZ2FpbnN0LlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgdmFsdWUgaXMgbm90IGVtcHR5IG9yIHRoZSBhY3Rpb24gZG9lcyBub3QgbWF0Y2gsIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuJC5mbi5mb3JtLnNldHRpbmdzLnJ1bGVzLmN1c3RvbU5vdEVtcHR5SWZBY3Rpb25SdWxlID0gKHZhbHVlLCBhY3Rpb24pID0+IHtcbiAgICBpZiAodmFsdWUubGVuZ3RoID09PSAwICYmICQoJyNhY3Rpb24nKS52YWwoKSA9PT0gYWN0aW9uKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59O1xuXG4vKipcbiAqIEN1c3RvbSBmb3JtIHZhbGlkYXRpb24gcnVsZSB0aGF0IGNoZWNrcyBpZiBhIHZhbHVlIGlzIG5vdCBlbXB0eSBiYXNlZCBvbiBhIHNwZWNpZmljIGFjdGlvbi5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgdmFsaWRhdGVkLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgdmFsdWUgaXMgbm90IGVtcHR5IG9yIHRoZSBhY3Rpb24gZG9lcyBub3QgbWF0Y2gsIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuJC5mbi5mb3JtLnNldHRpbmdzLnJ1bGVzLmN1c3RvbU5vdEVtcHR5SWZDYWxUeXBlID0gKHZhbHVlKSA9PiB7XG4gICAgaWYgKCQoJyNjYWxUeXBlJykudmFsKCkgPT09ICdub25lJykge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgbGV0IHVybCA9IG5ldyBVUkwodmFsdWUpO1xuICAgIH0gY2F0Y2ggKF8pIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cblxuLyoqXG4gKiAgSW5pdGlhbGl6ZSBvdXQgb2Ygd29yayBmb3JtIG9uIGRvY3VtZW50IHJlYWR5XG4gKi9cbiQoZG9jdW1lbnQpLnJlYWR5KCgpID0+IHtcbiAgICBvdXRPZldvcmtUaW1lUmVjb3JkLmluaXRpYWxpemUoKTtcbn0pO1xuIl19
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9PdXRPZmZXb3JrVGltZS9vdXQtb2Ytd29yay10aW1lLW1vZGlmeS5qcyJdLCJuYW1lcyI6WyJvdXRPZldvcmtUaW1lUmVjb3JkIiwiJGZvcm1PYmoiLCIkIiwiJGRlZmF1bHREcm9wZG93biIsIiRyYW5nZURheXNTdGFydCIsIiRyYW5nZURheXNFbmQiLCIkcmFuZ2VUaW1lU3RhcnQiLCIkcmFuZ2VUaW1lRW5kIiwiJGRhdGVfZnJvbSIsIiRkYXRlX3RvIiwiJHRpbWVfdG8iLCIkZm9yd2FyZGluZ1NlbGVjdERyb3Bkb3duIiwiYWRkaXRpb25hbFRpbWVJbnRlcnZhbFJ1bGVzIiwidHlwZSIsInZhbHVlIiwicHJvbXB0IiwiZ2xvYmFsVHJhbnNsYXRlIiwidGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCIsInZhbGlkYXRlUnVsZXMiLCJhdWRpb19tZXNzYWdlX2lkIiwiaWRlbnRpZmllciIsInJ1bGVzIiwidGZfVmFsaWRhdGVBdWRpb01lc3NhZ2VFbXB0eSIsImNhbFVybCIsInRmX1ZhbGlkYXRlQ2FsVXJpIiwiZXh0ZW5zaW9uIiwidGZfVmFsaWRhdGVFeHRlbnNpb25FbXB0eSIsInRpbWVmcm9tIiwib3B0aW9uYWwiLCJ0aW1ldG8iLCJpbml0aWFsaXplIiwidGFiIiwiZHJvcGRvd24iLCJjYWxlbmRhciIsImZpcnN0RGF5T2ZXZWVrIiwiU2VtYW50aWNMb2NhbGl6YXRpb24iLCJjYWxlbmRhckZpcnN0RGF5T2ZXZWVrIiwidGV4dCIsImNhbGVuZGFyVGV4dCIsImVuZENhbGVuZGFyIiwiaW5saW5lIiwibW9udGhGaXJzdCIsInJlZ0V4cCIsInN0YXJ0Q2FsZW5kYXIiLCJvbkNoYW5nZSIsIm5ld0RhdGVUbyIsIm9sZERhdGVUbyIsImF0dHIiLCJEYXRlIiwidHJpZ2dlciIsIkZvcm0iLCJkYXRhQ2hhbmdlZCIsImRpc2FibGVNaW51dGUiLCJhbXBtIiwibmV3VGltZVRvIiwib2xkVGltZVRvIiwidG9nZ2xlRGlzYWJsZWRGaWVsZENsYXNzIiwiZnJvbSIsImZvcm0iLCJ0byIsIm9uIiwiZSIsImRhdGVfZnJvbSIsImRhdGVfdG8iLCJwcmV2ZW50RGVmYXVsdCIsIndlZWtkYXlfZnJvbSIsIndlZWtkYXlfdG8iLCJTb3VuZEZpbGVzU2VsZWN0b3IiLCJnZXREcm9wZG93blNldHRpbmdzV2l0aEVtcHR5IiwiY2hhbmdlRGF0ZUZvcm1hdCIsImluaXRpYWxpemVGb3JtIiwiRXh0ZW5zaW9ucyIsImdldERyb3Bkb3duU2V0dGluZ3NXaXRob3V0RW1wdHkiLCJjaGVja2JveCIsIm5ld1N0YXRlIiwicGFyZW50IiwiZGlkIiwiZmlsdGVyIiwiY2hhbmdlUmVzdHJpY3Rpb24iLCJzaG93IiwiaGlkZSIsImRhdGVGcm9tIiwiZGF0ZVRvIiwiY3VycmVudE9mZnNldCIsImdldFRpbWV6b25lT2Zmc2V0Iiwic2VydmVyT2Zmc2V0IiwicGFyc2VJbnQiLCJvZmZzZXREaWZmIiwidW5kZWZpbmVkIiwibGVuZ3RoIiwiZGF0ZUZyb21JbkJyb3dzZXJUWiIsImRhdGVUb0luQnJvd3NlclRaIiwiY3VzdG9tVmFsaWRhdGVGb3JtIiwicmVzdWx0IiwiZGF0YSIsImh0bWwiLCJ0Zl9WYWxpZGF0ZUNoZWNrRGF0ZUludGVydmFsIiwiJHN1Ym1pdEJ1dHRvbiIsInRyYW5zaXRpb24iLCJyZW1vdmVDbGFzcyIsInRmX1ZhbGlkYXRlQ2hlY2tXZWVrRGF5SW50ZXJ2YWwiLCJ0aW1lX2Zyb20iLCJ0aW1lX3RvIiwidGZfVmFsaWRhdGVOb1J1bGVzU2VsZWN0ZWQiLCJjYkJlZm9yZVNlbmRGb3JtIiwic2V0dGluZ3MiLCJzZXRIb3VycyIsIk1hdGgiLCJmbG9vciIsImdldFRpbWUiLCJjYkFmdGVyU2VuZEZvcm0iLCJyZXNwb25zZSIsInVybCIsImdsb2JhbFJvb3RVcmwiLCJmbiIsImN1c3RvbU5vdEVtcHR5SWZBY3Rpb25SdWxlIiwiYWN0aW9uIiwidmFsIiwiY3VzdG9tTm90RW1wdHlJZkNhbFR5cGUiLCJVUkwiLCJfIiwiZG9jdW1lbnQiLCJyZWFkeSJd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QUFPLElBQVA7QUFDSCxDQVZEO0FBYUE7QUFDQTtBQUNBOzs7QUFDQXRILENBQUMsQ0FBQ3VILFFBQUQsQ0FBRCxDQUFZQyxLQUFaLENBQWtCLFlBQU07QUFDcEIxSCxFQUFBQSxtQkFBbUIsQ0FBQzhCLFVBQXBCO0FBQ0gsQ0FGRCIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBNaWtvUEJYIC0gZnJlZSBwaG9uZSBzeXN0ZW0gZm9yIHNtYWxsIGJ1c2luZXNzXG4gKiBDb3B5cmlnaHQgwqkgMjAxNy0yMDIzIEFsZXhleSBQb3J0bm92IGFuZCBOaWtvbGF5IEJla2V0b3ZcbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gKiAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4gKlxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uXG4gKiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuICovXG5cbi8qIGdsb2JhbCBnbG9iYWxSb290VXJsLGdsb2JhbFRyYW5zbGF0ZSwgRXh0ZW5zaW9ucywgRm9ybSwgU2VtYW50aWNMb2NhbGl6YXRpb24sIFNvdW5kRmlsZXNTZWxlY3RvciAqL1xuXG5cbi8qKlxuICogT2JqZWN0IGZvciBtYW5hZ2luZyBPdXQtb2YtV29yayBUaW1lIHNldHRpbmdzXG4gKlxuICogQG1vZHVsZSBvdXRPZldvcmtUaW1lUmVjb3JkXG4gKi9cbmNvbnN0IG91dE9mV29ya1RpbWVSZWNvcmQgPSB7XG4gICAgLyoqXG4gICAgICogalF1ZXJ5IG9iamVjdCBmb3IgdGhlIGZvcm0uXG4gICAgICogQHR5cGUge2pRdWVyeX1cbiAgICAgKi9cbiAgICAkZm9ybU9iajogJCgnI3NhdmUtb3V0b2Zmd29yay1mb3JtJyksXG5cbiAgICAkZGVmYXVsdERyb3Bkb3duOiAkKCcjc2F2ZS1vdXRvZmZ3b3JrLWZvcm0gLmRyb3Bkb3duLWRlZmF1bHQnKSxcbiAgICAkcmFuZ2VEYXlzU3RhcnQ6ICQoJyNyYW5nZS1kYXlzLXN0YXJ0JyksXG4gICAgJHJhbmdlRGF5c0VuZDogJCgnI3JhbmdlLWRheXMtZW5kJyksXG4gICAgJHJhbmdlVGltZVN0YXJ0OiAkKCcjcmFuZ2UtdGltZS1zdGFydCcpLFxuICAgICRyYW5nZVRpbWVFbmQ6ICQoJyNyYW5nZS10aW1lLWVuZCcpLFxuICAgICRkYXRlX2Zyb206ICQoJyNkYXRlX2Zyb20nKSxcbiAgICAkZGF0ZV90bzogJCgnI2RhdGVfdG8nKSxcbiAgICAkdGltZV90bzogJCgnI3RpbWVfdG8nKSxcbiAgICAkZm9yd2FyZGluZ1NlbGVjdERyb3Bkb3duOiAkKCcjc2F2ZS1vdXRvZmZ3b3JrLWZvcm0gLmZvcndhcmRpbmctc2VsZWN0JyksXG5cblxuICAgIC8qKlxuICAgICAqIEFkZGl0aW9uYWwgY29uZGl0aW9uIGZvciB0aGUgdGltZSBpbnRlcnZhbFxuICAgICAqIEB0eXBlIHthcnJheX1cbiAgICAgKi9cbiAgICBhZGRpdGlvbmFsVGltZUludGVydmFsUnVsZXM6IFt7XG4gICAgICAgIHR5cGU6ICdyZWdFeHAnLFxuICAgICAgICB2YWx1ZTogL14oMlswLTNdfDE/WzAtOV0pOihbMC01XT9bMC05XSkkLyxcbiAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCxcbiAgICB9XSxcblxuICAgIC8qKlxuICAgICAqIFZhbGlkYXRpb24gcnVsZXMgZm9yIHRoZSBmb3JtIGZpZWxkcyBiZWZvcmUgc3VibWlzc2lvbi5cbiAgICAgKlxuICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICovXG4gICAgdmFsaWRhdGVSdWxlczoge1xuICAgICAgICBhdWRpb19tZXNzYWdlX2lkOiB7XG4gICAgICAgICAgICBpZGVudGlmaWVyOiAnYXVkaW9fbWVzc2FnZV9pZCcsXG4gICAgICAgICAgICBydWxlczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2N1c3RvbU5vdEVtcHR5SWZBY3Rpb25SdWxlW3BsYXltZXNzYWdlXScsXG4gICAgICAgICAgICAgICAgICAgIHByb21wdDogZ2xvYmFsVHJhbnNsYXRlLnRmX1ZhbGlkYXRlQXVkaW9NZXNzYWdlRW1wdHksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIGNhbFVybDoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ2NhbFVybCcsXG4gICAgICAgICAgICBydWxlczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZSAgIDogJ2N1c3RvbU5vdEVtcHR5SWZDYWxUeXBlJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0IDogZ2xvYmFsVHJhbnNsYXRlLnRmX1ZhbGlkYXRlQ2FsVXJpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXVxuICAgICAgICB9LFxuICAgICAgICBleHRlbnNpb246IHtcbiAgICAgICAgICAgIGlkZW50aWZpZXI6ICdleHRlbnNpb24nLFxuICAgICAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdjdXN0b21Ob3RFbXB0eUlmQWN0aW9uUnVsZVtleHRlbnNpb25dJyxcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0OiBnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVFeHRlbnNpb25FbXB0eSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgdGltZWZyb206IHtcbiAgICAgICAgICAgIG9wdGlvbmFsOiB0cnVlLFxuICAgICAgICAgICAgaWRlbnRpZmllcjogJ3RpbWVfZnJvbScsXG4gICAgICAgICAgICBydWxlczogW3tcbiAgICAgICAgICAgICAgICB0eXBlOiAncmVnRXhwJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogL14oMlswLTNdfDE/WzAtOV0pOihbMC01XT9bMC05XSkkLyxcbiAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrVGltZUludGVydmFsLFxuICAgICAgICAgICAgfV0sXG4gICAgICAgIH0sXG4gICAgICAgIHRpbWV0bzoge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ3RpbWVfdG8nLFxuICAgICAgICAgICAgb3B0aW9uYWw6IHRydWUsXG4gICAgICAgICAgICBydWxlczogW3tcbiAgICAgICAgICAgICAgICB0eXBlOiAncmVnRXhwJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogL14oMlswLTNdfDE/WzAtOV0pOihbMC01XT9bMC05XSkkLyxcbiAgICAgICAgICAgICAgICBwcm9tcHQ6IGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrVGltZUludGVydmFsLFxuICAgICAgICAgICAgfV0sXG4gICAgICAgIH0sXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemVzIHRoZSBvdXQgb2Ygd29yayB0aW1lIHJlY29yZCBmb3JtLlxuICAgICAqL1xuICAgIGluaXRpYWxpemUoKSB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgdGFiIGJlaGF2aW9yIGZvciB0aGUgb3V0LXRpbWUtbW9kaWZ5LW1lbnVcbiAgICAgICAgJCgnI291dC10aW1lLW1vZGlmeS1tZW51IC5pdGVtJykudGFiKCk7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgZGVmYXVsdCBkcm9wZG93blxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRkZWZhdWx0RHJvcGRvd24uZHJvcGRvd24oKTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjYWxlbmRhciBmb3IgcmFuZ2UgZGF5cyBzdGFydFxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC5jYWxlbmRhcih7XG4gICAgICAgICAgICAvLyBDYWxlbmRhciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICAgIGZpcnN0RGF5T2ZXZWVrOiBTZW1hbnRpY0xvY2FsaXphdGlvbi5jYWxlbmRhckZpcnN0RGF5T2ZXZWVrLFxuICAgICAgICAgICAgdGV4dDogU2VtYW50aWNMb2NhbGl6YXRpb24uY2FsZW5kYXJUZXh0LFxuICAgICAgICAgICAgZW5kQ2FsZW5kYXI6IG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c0VuZCxcbiAgICAgICAgICAgIHR5cGU6ICdkYXRlJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBtb250aEZpcnN0OiBmYWxzZSxcbiAgICAgICAgICAgIHJlZ0V4cDogU2VtYW50aWNMb2NhbGl6YXRpb24ucmVnRXhwLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjYWxlbmRhciBmb3IgcmFuZ2UgZGF5cyBlbmRcbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kcmFuZ2VEYXlzRW5kLmNhbGVuZGFyKHtcbiAgICAgICAgICAgIC8vIENhbGVuZGFyIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAgICAgZmlyc3REYXlPZldlZWs6IFNlbWFudGljTG9jYWxpemF0aW9uLmNhbGVuZGFyRmlyc3REYXlPZldlZWssXG4gICAgICAgICAgICB0ZXh0OiBTZW1hbnRpY0xvY2FsaXphdGlvbi5jYWxlbmRhclRleHQsXG4gICAgICAgICAgICBzdGFydENhbGVuZGFyOiBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydCxcbiAgICAgICAgICAgIHR5cGU6ICdkYXRlJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBtb250aEZpcnN0OiBmYWxzZSxcbiAgICAgICAgICAgIHJlZ0V4cDogU2VtYW50aWNMb2NhbGl6YXRpb24ucmVnRXhwLFxuICAgICAgICAgICAgb25DaGFuZ2U6IChuZXdEYXRlVG8pID0+IHtcbiAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgcmFuZ2UgdGltZSBlbmRcbiAgICAgICAgICAgICAgICBsZXQgb2xkRGF0ZVRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZGF0ZV90by5hdHRyKCd2YWx1ZScpO1xuICAgICAgICAgICAgICAgIGlmIChuZXdEYXRlVG8gIT09IG51bGwgJiYgb2xkRGF0ZVRvICE9PSAnJykge1xuICAgICAgICAgICAgICAgICAgICBvbGREYXRlVG8gPSBuZXcgRGF0ZShvbGREYXRlVG8gKiAxMDAwKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKChuZXdEYXRlVG8gLSBvbGREYXRlVG8pICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRkYXRlX2Zyb20udHJpZ2dlcignY2hhbmdlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBGb3JtLmRhdGFDaGFuZ2VkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjYWxlbmRhciBmb3IgcmFuZ2UgdGltZSBzdGFydFxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZVRpbWVTdGFydC5jYWxlbmRhcih7XG4gICAgICAgICAgICAvLyBDYWxlbmRhciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICAgIGZpcnN0RGF5T2ZXZWVrOiBTZW1hbnRpY0xvY2FsaXphdGlvbi5jYWxlbmRhckZpcnN0RGF5T2ZXZWVrLFxuICAgICAgICAgICAgdGV4dDogU2VtYW50aWNMb2NhbGl6YXRpb24uY2FsZW5kYXJUZXh0LFxuICAgICAgICAgICAgZW5kQ2FsZW5kYXI6IG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlVGltZUVuZCxcbiAgICAgICAgICAgIHR5cGU6ICd0aW1lJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBkaXNhYmxlTWludXRlOiB0cnVlLFxuICAgICAgICAgICAgYW1wbTogZmFsc2UsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGNhbGVuZGFyIGZvciByYW5nZSB0aW1lIGVuZFxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZVRpbWVFbmQuY2FsZW5kYXIoe1xuICAgICAgICAgICAgLy8gQ2FsZW5kYXIgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAgICBmaXJzdERheU9mV2VlazogU2VtYW50aWNMb2NhbGl6YXRpb24uY2FsZW5kYXJGaXJzdERheU9mV2VlayxcbiAgICAgICAgICAgIHRleHQ6IFNlbWFudGljTG9jYWxpemF0aW9uLmNhbGVuZGFyVGV4dCxcbiAgICAgICAgICAgIHR5cGU6ICd0aW1lJyxcbiAgICAgICAgICAgIGlubGluZTogZmFsc2UsXG4gICAgICAgICAgICBkaXNhYmxlTWludXRlOiB0cnVlLFxuICAgICAgICAgICAgYW1wbTogZmFsc2UsXG4gICAgICAgICAgICBvbkNoYW5nZTogKG5ld1RpbWVUbykgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSB0aGUgY2hhbmdlIGV2ZW50IGZvciByYW5nZSB0aW1lIGVuZFxuICAgICAgICAgICAgICAgIGxldCBvbGRUaW1lVG8gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiR0aW1lX3RvLmF0dHIoJ3ZhbHVlJyk7XG4gICAgICAgICAgICAgICAgaWYgKG5ld1RpbWVUbyAhPT0gbnVsbCAmJiBvbGRUaW1lVG8gIT09ICcnKSB7XG4gICAgICAgICAgICAgICAgICAgIG9sZFRpbWVUbyA9IG5ldyBEYXRlKG9sZFRpbWVUbyAqIDEwMDApO1xuICAgICAgICAgICAgICAgICAgICBpZiAoKG5ld1RpbWVUbyAtIG9sZFRpbWVUbykgIT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJHRpbWVfdG8udHJpZ2dlcignY2hhbmdlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBGb3JtLmRhdGFDaGFuZ2VkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBhY3Rpb24gZHJvcGRvd25cbiAgICAgICAgJCgnI2FjdGlvbicpXG4gICAgICAgICAgICAuZHJvcGRvd24oe1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgdGhlIGFjdGlvbiBkcm9wZG93blxuICAgICAgICAgICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLnRvZ2dsZURpc2FibGVkRmllbGRDbGFzcygpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgY2FsVHlwZSBkcm9wZG93blxuICAgICAgICAkKCcjY2FsVHlwZScpXG4gICAgICAgICAgICAuZHJvcGRvd24oe1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgdGhlIGFjdGlvbiBkcm9wZG93blxuICAgICAgICAgICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLnRvZ2dsZURpc2FibGVkRmllbGRDbGFzcygpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSB3ZWVrZGF5X2Zyb20gZHJvcGRvd25cbiAgICAgICAgJCgnI3dlZWtkYXlfZnJvbScpXG4gICAgICAgICAgICAuZHJvcGRvd24oe1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNoYW5nZSBldmVudCBmb3IgdGhlIHdlZWtkYXlfZnJvbSBkcm9wZG93blxuICAgICAgICAgICAgICAgICAgICBjb25zdCBmcm9tID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnd2Vla2RheV9mcm9tJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnd2Vla2RheV90bycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZnJvbSA8IHRvIHx8IHRvID09PSAtMSB8fCBmcm9tID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdzZXQgdmFsdWUnLCAnd2Vla2RheV90bycsIGZyb20pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIHdlZWtkYXlfdG8gZHJvcGRvd25cbiAgICAgICAgJCgnI3dlZWtkYXlfdG8nKVxuICAgICAgICAgICAgLmRyb3Bkb3duKHtcbiAgICAgICAgICAgICAgICBvbkNoYW5nZSgpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSGFuZGxlIHRoZSBjaGFuZ2UgZXZlbnQgZm9yIHRoZSB3ZWVrZGF5X3RvIGRyb3Bkb3duXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZyb20gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICd3ZWVrZGF5X2Zyb20nKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdG8gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICd3ZWVrZGF5X3RvJyk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0byA8IGZyb20gfHwgZnJvbSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmouZm9ybSgnc2V0IHZhbHVlJywgJ3dlZWtkYXlfZnJvbScsIHRvKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAvLyBCaW5kIGNsaWNrIGV2ZW50IHRvIGVyYXNlLWRhdGVzIGJ1dHRvblxuICAgICAgICAkKCcjZXJhc2UtZGF0ZXMnKS5vbignY2xpY2snLCAoZSkgPT4ge1xuICAgICAgICAgICAgLy8gSGFuZGxlIHRoZSBjbGljayBldmVudCBmb3IgZXJhc2UtZGF0ZXMgYnV0dG9uXG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC5jYWxlbmRhcignY2xlYXInKTtcbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c0VuZC5jYWxlbmRhcignY2xlYXInKTtcbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmpcbiAgICAgICAgICAgICAgICAuZm9ybSgnc2V0IHZhbHVlcycsIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0ZV9mcm9tOiAnJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0ZV90bzogJycsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEJpbmQgY2xpY2sgZXZlbnQgdG8gZXJhc2Utd2Vla2RheXMgYnV0dG9uXG4gICAgICAgICQoJyNlcmFzZS13ZWVrZGF5cycpLm9uKCdjbGljaycsIChlKSA9PiB7XG4gICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNsaWNrIGV2ZW50IGZvciBlcmFzZS13ZWVrZGF5cyBidXR0b25cbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmpcbiAgICAgICAgICAgICAgICAuZm9ybSgnc2V0IHZhbHVlcycsIHtcbiAgICAgICAgICAgICAgICAgICAgd2Vla2RheV9mcm9tOiAtMSxcbiAgICAgICAgICAgICAgICAgICAgd2Vla2RheV90bzogLTEsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNTdGFydC50cmlnZ2VyKCdjaGFuZ2UnKTtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQmluZCBjbGljayBldmVudCB0byBlcmFzZS10aW1lcGVyaW9kIGJ1dHRvblxuICAgICAgICAkKCcjZXJhc2UtdGltZXBlcmlvZCcpLm9uKCdjbGljaycsIChlKSA9PiB7XG4gICAgICAgICAgICAvLyBIYW5kbGUgdGhlIGNsaWNrIGV2ZW50IGZvciBlcmFzZS10aW1lcGVyaW9kIGJ1dHRvblxuICAgICAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kcmFuZ2VUaW1lU3RhcnQuY2FsZW5kYXIoJ2NsZWFyJyk7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZVRpbWVFbmQuY2FsZW5kYXIoJ2NsZWFyJyk7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiR0aW1lX3RvLnRyaWdnZXIoJ2NoYW5nZScpO1xuICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIGF1ZGlvLW1lc3NhZ2Utc2VsZWN0IGRyb3Bkb3duXG4gICAgICAgICQoJyNzYXZlLW91dG9mZndvcmstZm9ybSAuYXVkaW8tbWVzc2FnZS1zZWxlY3QnKS5kcm9wZG93bihTb3VuZEZpbGVzU2VsZWN0b3IuZ2V0RHJvcGRvd25TZXR0aW5nc1dpdGhFbXB0eSgpKTtcblxuICAgICAgICAvLyBDaGFuZ2UgdGhlIGRhdGUgZm9ybWF0IGZyb20gbGludXh0aW1lIHRvIGxvY2FsIHJlcHJlc2VudGF0aW9uXG4gICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuY2hhbmdlRGF0ZUZvcm1hdCgpO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGZvcm1cbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC5pbml0aWFsaXplRm9ybSgpO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGZvcndhcmRpbmdTZWxlY3REcm9wZG93blxuICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3J3YXJkaW5nU2VsZWN0RHJvcGRvd24uZHJvcGRvd24oRXh0ZW5zaW9ucy5nZXREcm9wZG93blNldHRpbmdzV2l0aG91dEVtcHR5KCkpO1xuXG4gICAgICAgIC8vIFRvZ2dsZSBkaXNhYmxlZCBmaWVsZCBjbGFzcyBiYXNlZCBvbiBhY3Rpb24gdmFsdWVcbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC50b2dnbGVEaXNhYmxlZEZpZWxkQ2xhc3MoKTtcblxuICAgICAgICAvLyBCaW5kIGNoZWNrYm94IGNoYW5nZSBldmVudCBmb3IgaW5ib3VuZCBydWxlcyB0YWJsZVxuICAgICAgICAkKCcjaW5ib3VuZC1ydWxlcy10YWJsZSAudWkuY2hlY2tib3gnKS5jaGVja2JveCh7XG4gICAgICAgICAgICBvbkNoYW5nZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGxldCBuZXdTdGF0ZSA9ICd1bmNoZWNrZWQnO1xuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSB0aGUgY2hhbmdlIGV2ZW50IGZvciBpbmJvdW5kIHJ1bGVzIHRhYmxlIGNoZWNrYm94XG4gICAgICAgICAgICAgICAgaWYgKCQodGhpcykucGFyZW50KCkuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuICAgICAgICAgICAgICAgICAgICBuZXdTdGF0ZSA9ICdjaGVja2VkJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbGV0IGRpZCA9ICQodGhpcykucGFyZW50KCkuYXR0cignZGF0YS1kaWQnKTtcbiAgICAgICAgICAgICAgICBsZXQgZmlsdGVyID0gJyNpbmJvdW5kLXJ1bGVzLXRhYmxlIC51aS5jaGVja2JveFtkYXRhLWNvbnRleHQtaWQ9JyArICQodGhpcykucGFyZW50KCkuYXR0cignZGF0YS1jb250ZXh0LWlkJykgKyAnXSc7XG4gICAgICAgICAgICAgICAgaWYoZGlkICE9PSAnJyAmJiBuZXdTdGF0ZSA9PT0gJ2NoZWNrZWQnKXtcbiAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyICsgJy51aS5jaGVja2JveFtkYXRhLWRpZD0nK2RpZCsnXSc7XG4gICAgICAgICAgICAgICAgfWVsc2UgaWYoZGlkID09PSAnJyAmJiBuZXdTdGF0ZSA9PT0gJ3VuY2hlY2tlZCcpe1xuICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBmaWx0ZXIgKyAnLnVpLmNoZWNrYm94W2RhdGEtZGlkPVwiXCJdJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJChmaWx0ZXIpLmNoZWNrYm94KCdzZXQgJytuZXdTdGF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEJpbmQgY2hlY2tib3ggY2hhbmdlIGV2ZW50IGZvciBhbGxvd1Jlc3RyaWN0aW9uIGNoZWNrYm94XG4gICAgICAgICQoJyNhbGxvd1Jlc3RyaWN0aW9uJykucGFyZW50KCkuY2hlY2tib3goe1xuICAgICAgICAgICAgb25DaGFuZ2U6IG91dE9mV29ya1RpbWVSZWNvcmQuY2hhbmdlUmVzdHJpY3Rpb25cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQ2FsbCBjaGFuZ2VSZXN0cmljdGlvbiBtZXRob2RcbiAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC5jaGFuZ2VSZXN0cmljdGlvbigpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDaGFuZ2VzIHRoZSB2aXNpYmlsaXR5IG9mIHRoZSAncnVsZXMnIHRhYiBiYXNlZCBvbiB0aGUgY2hlY2tlZCBzdGF0dXMgb2YgdGhlICdhbGxvd1Jlc3RyaWN0aW9uJyBjaGVja2JveC5cbiAgICAgKi9cbiAgICBjaGFuZ2VSZXN0cmljdGlvbigpIHtcbiAgICAgICAgaWYgKCQoJyNhbGxvd1Jlc3RyaWN0aW9uJykucGFyZW50KCkuY2hlY2tib3goJ2lzIGNoZWNrZWQnKSkge1xuICAgICAgICAgICAgJChcImFbZGF0YS10YWI9J3J1bGVzJ11cIikuc2hvdygpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJChcImFbZGF0YS10YWI9J3J1bGVzJ11cIikuaGlkZSgpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIHRoZSBkYXRlIGZvcm1hdCBmcm9tIGxpbnV4dGltZSB0byB0aGUgbG9jYWwgcmVwcmVzZW50YXRpb24uXG4gICAgICovXG4gICAgY2hhbmdlRGF0ZUZvcm1hdCgpIHtcbiAgICAgICAgY29uc3QgZGF0ZUZyb20gPSBvdXRPZldvcmtUaW1lUmVjb3JkLiRkYXRlX2Zyb20uYXR0cigndmFsdWUnKTtcbiAgICAgICAgY29uc3QgZGF0ZVRvID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZGF0ZV90by5hdHRyKCd2YWx1ZScpO1xuICAgICAgICBjb25zdCBjdXJyZW50T2Zmc2V0ID0gbmV3IERhdGUoKS5nZXRUaW1lem9uZU9mZnNldCgpO1xuICAgICAgICBjb25zdCBzZXJ2ZXJPZmZzZXQgPSBwYXJzZUludChvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICdzZXJ2ZXJPZmZzZXQnKSk7XG4gICAgICAgIGNvbnN0IG9mZnNldERpZmYgPSBzZXJ2ZXJPZmZzZXQgKyBjdXJyZW50T2Zmc2V0O1xuICAgICAgICBpZiAoZGF0ZUZyb20gIT09IHVuZGVmaW5lZCAmJiBkYXRlRnJvbS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBkYXRlRnJvbUluQnJvd3NlclRaID0gZGF0ZUZyb20gKiAxMDAwICsgb2Zmc2V0RGlmZiAqIDYwICogMTAwMDtcbiAgICAgICAgICAgIG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c1N0YXJ0LmNhbGVuZGFyKCdzZXQgZGF0ZScsIG5ldyBEYXRlKGRhdGVGcm9tSW5Ccm93c2VyVFopKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGF0ZVRvICE9PSB1bmRlZmluZWQgJiYgZGF0ZVRvLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGRhdGVUb0luQnJvd3NlclRaID0gZGF0ZVRvICogMTAwMCArIG9mZnNldERpZmYgKiA2MCAqIDEwMDA7XG4gICAgICAgICAgICBvdXRPZldvcmtUaW1lUmVjb3JkLiRyYW5nZURheXNFbmQuY2FsZW5kYXIoJ3NldCBkYXRlJywgbmV3IERhdGUoZGF0ZVRvSW5Ccm93c2VyVFopKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHRoZSB2aXNpYmlsaXR5IG9mIGNlcnRhaW4gZmllbGQgZ3JvdXBzIGJhc2VkIG9uIHRoZSBzZWxlY3RlZCBhY3Rpb24gdmFsdWUuXG4gICAgICovXG4gICAgdG9nZ2xlRGlzYWJsZWRGaWVsZENsYXNzKCkge1xuICAgICAgICBpZihvdXRPZldvcmtUaW1lUmVjb3JkLiRmb3JtT2JqLmZvcm0oJ2dldCB2YWx1ZScsICdhY3Rpb24nKSA9PT0gJ2V4dGVuc2lvbicpIHtcbiAgICAgICAgICAgICQoJyNleHRlbnNpb24tZ3JvdXAnKS5zaG93KCk7XG4gICAgICAgICAgICAkKCcjYXVkaW8tZmlsZS1ncm91cCcpLmhpZGUoKTtcbiAgICAgICAgICAgICQoJyNhdWRpb19tZXNzYWdlX2lkJykuZHJvcGRvd24oJ2NsZWFyJyk7XG4gICAgICAgIH1lbHNle1xuICAgICAgICAgICAgJCgnI2V4dGVuc2lvbi1ncm91cCcpLmhpZGUoKTtcbiAgICAgICAgICAgICQoJyNhdWRpby1maWxlLWdyb3VwJykuc2hvdygpO1xuICAgICAgICAgICAgb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdzZXQgdmFsdWUnLCAnZXh0ZW5zaW9uJywgLTEpO1xuICAgICAgICB9XG4gICAgICAgIGlmKG91dE9mV29ya1RpbWVSZWNvcmQuJGZvcm1PYmouZm9ybSgnZ2V0IHZhbHVlJywgJ2NhbFR5cGUnKSA9PT0gJ25vbmUnKXtcbiAgICAgICAgICAgICQoJyNjYWxsLXR5cGUtbWFpbi10YWInKS5zaG93KCk7XG4gICAgICAgICAgICAkKCcjY2FsbC10eXBlLWNhbGVuZGFyLXRhYicpLmhpZGUoKTtcbiAgICAgICAgfWVsc2V7XG4gICAgICAgICAgICAkKCcjY2FsbC10eXBlLW1haW4tdGFiJykuaGlkZSgpO1xuICAgICAgICAgICAgJCgnI2NhbGwtdHlwZS1jYWxlbmRhci10YWInKS5zaG93KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3VzdG9tIGZvcm0gdmFsaWRhdGlvbiBmb3IgdmFsaWRhdGluZyBzcGVjaWZpYyBmaWVsZHMgaW4gYSBmb3JtLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHJlc3VsdCAtIFRoZSByZXN1bHQgb2JqZWN0IGNvbnRhaW5pbmcgZm9ybSBkYXRhLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufE9iamVjdH0gUmV0dXJucyBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLCBvciB0aGUgcmVzdWx0IG9iamVjdCBpZiB2YWxpZGF0aW9uIHBhc3Nlcy5cbiAgICAgKi9cbiAgICBjdXN0b21WYWxpZGF0ZUZvcm0ocmVzdWx0KSB7XG4gICAgICAgIC8vIENoZWNrIGRhdGUgZmllbGRzXG4gICAgICAgIGlmICgocmVzdWx0LmRhdGEuZGF0ZV9mcm9tICE9PSAnJyAmJiByZXN1bHQuZGF0YS5kYXRlX3RvID09PSAnJylcbiAgICAgICAgICAgIHx8IChyZXN1bHQuZGF0YS5kYXRlX3RvICE9PSAnJyAmJiByZXN1bHQuZGF0YS5kYXRlX2Zyb20gPT09ICcnKSkge1xuICAgICAgICAgICAgJCgnLmZvcm0gLmVycm9yLm1lc3NhZ2UnKS5odG1sKGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrRGF0ZUludGVydmFsKS5zaG93KCk7XG4gICAgICAgICAgICBGb3JtLiRzdWJtaXRCdXR0b24udHJhbnNpdGlvbignc2hha2UnKS5yZW1vdmVDbGFzcygnbG9hZGluZyBkaXNhYmxlZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgd2Vla2RheSBmaWVsZHNcbiAgICAgICAgaWYgKChyZXN1bHQuZGF0YS53ZWVrZGF5X2Zyb20gPiAwICYmIHJlc3VsdC5kYXRhLndlZWtkYXlfdG8gPT09ICctMScpXG4gICAgICAgICAgICB8fCAocmVzdWx0LmRhdGEud2Vla2RheV90byA+IDAgJiYgcmVzdWx0LmRhdGEud2Vla2RheV9mcm9tID09PSAnLTEnKSkge1xuICAgICAgICAgICAgJCgnLmZvcm0gLmVycm9yLm1lc3NhZ2UnKS5odG1sKGdsb2JhbFRyYW5zbGF0ZS50Zl9WYWxpZGF0ZUNoZWNrV2Vla0RheUludGVydmFsKS5zaG93KCk7XG4gICAgICAgICAgICBGb3JtLiRzdWJtaXRCdXR0b24udHJhbnNpdGlvbignc2hha2UnKS5yZW1vdmVDbGFzcygnbG9hZGluZyBkaXNhYmxlZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgdGltZSBmaWVsZHNcbiAgICAgICAgaWYgKChyZXN1bHQuZGF0YS50aW1lX2Zyb20ubGVuZ3RoID4gMCAmJiByZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHx8IChyZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA+IDAgJiYgcmVzdWx0LmRhdGEudGltZV9mcm9tLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgICAgICQoJy5mb3JtIC5lcnJvci5tZXNzYWdlJykuaHRtbChnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCkuc2hvdygpO1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnRyYW5zaXRpb24oJ3NoYWtlJykucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcgZGlzYWJsZWQnKTtcblxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgdGltZSBmaWVsZCBmb3JtYXRcbiAgICAgICAgaWYgKChyZXN1bHQuZGF0YS50aW1lX2Zyb20ubGVuZ3RoID4gMCAmJiByZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHx8IChyZXN1bHQuZGF0YS50aW1lX3RvLmxlbmd0aCA+IDAgJiYgcmVzdWx0LmRhdGEudGltZV9mcm9tLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgICAgICAgICQoJy5mb3JtIC5lcnJvci5tZXNzYWdlJykuaHRtbChnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVDaGVja1RpbWVJbnRlcnZhbCkuc2hvdygpO1xuICAgICAgICAgICAgRm9ybS4kc3VibWl0QnV0dG9uLnRyYW5zaXRpb24oJ3NoYWtlJykucmVtb3ZlQ2xhc3MoJ2xvYWRpbmcgZGlzYWJsZWQnKTtcblxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgYWxsIGZpZWxkc1xuICAgICAgICBpZiAoJCgnI2NhbFR5cGUnKS5wYXJlbnQoKS5kcm9wZG93bignZ2V0IHZhbHVlJykgPT09ICdub25lJ1xuICAgICAgICAgICAgJiYgcmVzdWx0LmRhdGEudGltZV9mcm9tID09PSAnJ1xuICAgICAgICAgICAgJiYgcmVzdWx0LmRhdGEudGltZV90byA9PT0gJydcbiAgICAgICAgICAgICYmIHJlc3VsdC5kYXRhLndlZWtkYXlfZnJvbSA9PT0gJy0xJ1xuICAgICAgICAgICAgJiYgcmVzdWx0LmRhdGEud2Vla2RheV90byA9PT0gJy0xJ1xuICAgICAgICAgICAgJiYgcmVzdWx0LmRhdGEuZGF0ZV9mcm9tID09PSAnJ1xuICAgICAgICAgICAgJiYgcmVzdWx0LmRhdGEuZGF0ZV90byA9PT0gJycpIHtcbiAgICAgICAgICAgICQoJy5mb3JtIC5lcnJvci5tZXNzYWdlJykuaHRtbChnbG9iYWxUcmFuc2xhdGUudGZfVmFsaWRhdGVOb1J1bGVzU2VsZWN0ZWQpLnNob3coKTtcbiAgICAgICAgICAgIEZvcm0uJHN1Ym1pdEJ1dHRvbi50cmFuc2l0aW9uKCdzaGFrZScpLnJlbW92ZUNsYXNzKCdsb2FkaW5nIGRpc2FibGVkJyk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGJlZm9yZSB0aGUgZm9ybSBpcyBzZW50XG4gICAgICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIGN1cnJlbnQgc2V0dGluZ3Mgb2YgdGhlIGZvcm1cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSB1cGRhdGVkIHNldHRpbmdzIG9mIHRoZSBmb3JtXG4gICAgICovXG4gICAgY2JCZWZvcmVTZW5kRm9ybShzZXR0aW5ncykge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBzZXR0aW5ncztcbiAgICAgICAgJCgnLmZvcm0gLmVycm9yLm1lc3NhZ2UnKS5odG1sKCcnKS5oaWRlKCk7XG4gICAgICAgIHJlc3VsdC5kYXRhID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWVzJyk7XG4gICAgICAgIGNvbnN0IGRhdGVGcm9tID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kcmFuZ2VEYXlzU3RhcnQuY2FsZW5kYXIoJ2dldCBkYXRlJyk7XG4gICAgICAgIGNvbnN0IGRhdGVUbyA9IG91dE9mV29ya1RpbWVSZWNvcmQuJHJhbmdlRGF5c0VuZC5jYWxlbmRhcignZ2V0IGRhdGUnKTtcbiAgICAgICAgY29uc3QgY3VycmVudE9mZnNldCA9IG5ldyBEYXRlKCkuZ2V0VGltZXpvbmVPZmZzZXQoKTtcbiAgICAgICAgY29uc3Qgc2VydmVyT2Zmc2V0ID0gcGFyc2VJbnQob3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iai5mb3JtKCdnZXQgdmFsdWUnLCAnc2VydmVyT2Zmc2V0JykpO1xuICAgICAgICBjb25zdCBvZmZzZXREaWZmID0gc2VydmVyT2Zmc2V0ICsgY3VycmVudE9mZnNldDtcblxuICAgICAgICBpZigkKCcjY2FsVHlwZScpLnBhcmVudCgpLmRyb3Bkb3duKCdnZXQgdmFsdWUnKSA9PT0gJ25vbmUnKXtcbiAgICAgICAgICAgIEZvcm0udmFsaWRhdGVSdWxlcy50aW1lZnJvbS5ydWxlcyA9IG91dE9mV29ya1RpbWVSZWNvcmQuYWRkaXRpb25hbFRpbWVJbnRlcnZhbFJ1bGVzO1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLnRpbWV0by5ydWxlcyA9IG91dE9mV29ya1RpbWVSZWNvcmQuYWRkaXRpb25hbFRpbWVJbnRlcnZhbFJ1bGVzO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgRm9ybS52YWxpZGF0ZVJ1bGVzLnRpbWVmcm9tLnJ1bGVzID0gW107XG4gICAgICAgICAgICBGb3JtLnZhbGlkYXRlUnVsZXMudGltZXRvLnJ1bGVzID0gW107XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZGF0ZUZyb20pIHtcbiAgICAgICAgICAgIGRhdGVGcm9tLnNldEhvdXJzKDAsIDAsIDAsIDApO1xuICAgICAgICAgICAgcmVzdWx0LmRhdGEuZGF0ZV9mcm9tID0gTWF0aC5mbG9vcihkYXRlRnJvbS5nZXRUaW1lKCkvMTAwMCkgLSBvZmZzZXREaWZmICogNjA7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRhdGVUbykge1xuICAgICAgICAgICAgZGF0ZVRvLnNldEhvdXJzKDIzLCA1OSwgNTksIDApO1xuICAgICAgICAgICAgcmVzdWx0LmRhdGEuZGF0ZV90byA9IE1hdGguZmxvb3IoZGF0ZVRvLmdldFRpbWUoKS8xMDAwKSAtIG9mZnNldERpZmYgKiA2MDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0T2ZXb3JrVGltZVJlY29yZC5jdXN0b21WYWxpZGF0ZUZvcm0ocmVzdWx0KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGFmdGVyIHRoZSBmb3JtIGhhcyBiZWVuIHNlbnQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZlciBhZnRlciB0aGUgZm9ybSBpcyBzZW50XG4gICAgICovXG4gICAgY2JBZnRlclNlbmRGb3JtKHJlc3BvbnNlKSB7XG5cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZSB0aGUgZm9ybSB3aXRoIGN1c3RvbSBzZXR0aW5nc1xuICAgICAqL1xuICAgIGluaXRpYWxpemVGb3JtKCkge1xuICAgICAgICBGb3JtLiRmb3JtT2JqID0gb3V0T2ZXb3JrVGltZVJlY29yZC4kZm9ybU9iajtcbiAgICAgICAgRm9ybS51cmwgPSBgJHtnbG9iYWxSb290VXJsfW91dC1vZmYtd29yay10aW1lL3NhdmVgOyAvLyBGb3JtIHN1Ym1pc3Npb24gVVJMXG4gICAgICAgIEZvcm0udmFsaWRhdGVSdWxlcyA9IG91dE9mV29ya1RpbWVSZWNvcmQudmFsaWRhdGVSdWxlczsgLy8gRm9ybSB2YWxpZGF0aW9uIHJ1bGVzXG4gICAgICAgIEZvcm0uY2JCZWZvcmVTZW5kRm9ybSA9IG91dE9mV29ya1RpbWVSZWNvcmQuY2JCZWZvcmVTZW5kRm9ybTsgLy8gQ2FsbGJhY2sgYmVmb3JlIGZvcm0gaXMgc2VudFxuICAgICAgICBGb3JtLmNiQWZ0ZXJTZW5kRm9ybSA9IG91dE9mV29ya1RpbWVSZWNvcmQuY2JBZnRlclNlbmRGb3JtOyAvLyBDYWxsYmFjayBhZnRlciBmb3JtIGlzIHNlbnRcbiAgICAgICAgRm9ybS5pbml0aWFsaXplKCk7XG4gICAgfSxcbn07XG5cbi8qKlxuICogQ3VzdG9tIGZvcm0gdmFsaWRhdGlvbiBydWxlIHRoYXQgY2hlY2tzIGlmIGEgdmFsdWUgaXMgbm90IGVtcHR5IGJhc2VkIG9uIGEgc3BlY2lmaWMgYWN0aW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSB2YWxpZGF0ZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gYWN0aW9uIC0gVGhlIGFjdGlvbiB0byBjb21wYXJlIGFnYWluc3QuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyB0cnVlIGlmIHRoZSB2YWx1ZSBpcyBub3QgZW1wdHkgb3IgdGhlIGFjdGlvbiBkb2VzIG5vdCBtYXRjaCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG4kLmZuLmZvcm0uc2V0dGluZ3MucnVsZXMuY3VzdG9tTm90RW1wdHlJZkFjdGlvblJ1bGUgPSAodmFsdWUsIGFjdGlvbikgPT4ge1xuICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDAgJiYgJCgnI2FjdGlvbicpLnZhbCgpID09PSBhY3Rpb24pIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8qKlxuICogQ3VzdG9tIGZvcm0gdmFsaWRhdGlvbiBydWxlIHRoYXQgY2hlY2tzIGlmIGEgdmFsdWUgaXMgbm90IGVtcHR5IGJhc2VkIG9uIGEgc3BlY2lmaWMgYWN0aW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSB2YWxpZGF0ZWQuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyB0cnVlIGlmIHRoZSB2YWx1ZSBpcyBub3QgZW1wdHkgb3IgdGhlIGFjdGlvbiBkb2VzIG5vdCBtYXRjaCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG4kLmZuLmZvcm0uc2V0dGluZ3MucnVsZXMuY3VzdG9tTm90RW1wdHlJZkNhbFR5cGUgPSAodmFsdWUpID0+IHtcbiAgICBpZiAoJCgnI2NhbFR5cGUnKS52YWwoKSA9PT0gJ25vbmUnKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICBsZXQgdXJsID0gbmV3IFVSTCh2YWx1ZSk7XG4gICAgfSBjYXRjaCAoXykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufTtcblxuXG4vKipcbiAqICBJbml0aWFsaXplIG91dCBvZiB3b3JrIGZvcm0gb24gZG9jdW1lbnQgcmVhZHlcbiAqL1xuJChkb2N1bWVudCkucmVhZHkoKCkgPT4ge1xuICAgIG91dE9mV29ya1RpbWVSZWNvcmQuaW5pdGlhbGl6ZSgpO1xufSk7XG4iXX0=
\ No newline at end of file
diff --git a/sites/admin-cabinet/assets/js/src/GeneralSettings/general-settings-modify.js b/sites/admin-cabinet/assets/js/src/GeneralSettings/general-settings-modify.js
index 9344f8f7b..220bf610f 100644
--- a/sites/admin-cabinet/assets/js/src/GeneralSettings/general-settings-modify.js
+++ b/sites/admin-cabinet/assets/js/src/GeneralSettings/general-settings-modify.js
@@ -418,14 +418,47 @@ const generalSettingsModify = {
* @param {Object} response - The response from the server after the form is sent
*/
cbAfterSendForm(response) {
+ $("#error-messages").remove();
if (!response.success) {
Form.$submitButton.removeClass('disabled');
+ generalSettingsModify.generateErrorMessageHtml(response);
} else {
$('.password-validate').remove();
}
generalSettingsModify.checkDeleteAllConditions();
},
+ /**
+ * The function collects an information message about a data saving error
+ * @param response
+ */
+ generateErrorMessageHtml(response) {
+ if (response.messages && response.messages.error) {
+ const $div = $('
', { class: 'ui negative message', id: 'error-messages' });
+ const $header = $('
', { class: 'header' }).text(globalTranslate.gs_ErrorSaveSettings);
+ $div.append($header);
+ const $ul = $('
', { class: 'list' });
+ const messagesSet = new Set();
+ response.messages.error.forEach(errorArray => {
+ errorArray.forEach(error => {
+ let textContent ='';
+ if(globalTranslate[error.message] === undefined){
+ textContent = error.message;
+ }else{
+ textContent = globalTranslate[error.message];
+ }
+ if (messagesSet.has(textContent)) {
+ return;
+ }
+ messagesSet.add(error.message);
+ $ul.append($('- ').text(textContent));
+ });
+ });
+ $div.append($ul);
+ $('#submitbutton').before($div);
+ }
+ },
+
/**
* Initialize the validation rules of the form
*/
diff --git a/sites/admin-cabinet/assets/js/src/OutOffWorkTime/out-of-work-time-modify.js b/sites/admin-cabinet/assets/js/src/OutOffWorkTime/out-of-work-time-modify.js
index 97d316add..9cbc4f427 100644
--- a/sites/admin-cabinet/assets/js/src/OutOffWorkTime/out-of-work-time-modify.js
+++ b/sites/admin-cabinet/assets/js/src/OutOffWorkTime/out-of-work-time-modify.js
@@ -398,7 +398,7 @@ const outOfWorkTimeRecord = {
}
// Check all fields
- if ($('#calType').parent().dropdown('get value') !== 'caldav'
+ if ($('#calType').parent().dropdown('get value') === 'none'
&& result.data.time_from === ''
&& result.data.time_to === ''
&& result.data.weekday_from === '-1'
@@ -427,12 +427,12 @@ const outOfWorkTimeRecord = {
const serverOffset = parseInt(outOfWorkTimeRecord.$formObj.form('get value', 'serverOffset'));
const offsetDiff = serverOffset + currentOffset;
- if($('#calType').parent().dropdown('get value') === 'caldav'){
- Form.validateRules.timefrom.rules = [];
- Form.validateRules.timeto.rules = [];
- } else {
+ if($('#calType').parent().dropdown('get value') === 'none'){
Form.validateRules.timefrom.rules = outOfWorkTimeRecord.additionalTimeIntervalRules;
Form.validateRules.timeto.rules = outOfWorkTimeRecord.additionalTimeIntervalRules;
+ } else {
+ Form.validateRules.timefrom.rules = [];
+ Form.validateRules.timeto.rules = [];
}
if (dateFrom) {
diff --git a/src/AdminCabinet/Controllers/OutOffWorkTimeController.php b/src/AdminCabinet/Controllers/OutOffWorkTimeController.php
index 29a70c168..e4b72a968 100644
--- a/src/AdminCabinet/Controllers/OutOffWorkTimeController.php
+++ b/src/AdminCabinet/Controllers/OutOffWorkTimeController.php
@@ -196,7 +196,7 @@ public function modifyAction(string $id = ''): void
if($providerData['registration_type'] === Sip::REG_TYPE_INBOUND || empty($providerData['host'])){
$providersId[$providerData['uniqid']] = $providerData['uniqid'];
}else{
- $providersId[$providerData['uniqid']] = SIPConf::getContextId($providerData['host'] . $providerData['port']);
+ $providersId[$providerData['uniqid']] = SIPConf::getContextId($providerData['host'] , $providerData['port']);
}
}
unset($data);
diff --git a/src/Common/Messages/az.php b/src/Common/Messages/az.php
index 02ceeba9e..364cea563 100644
--- a/src/Common/Messages/az.php
+++ b/src/Common/Messages/az.php
@@ -1279,4 +1279,7 @@
'nw_NATInfo6OR' => 'YA',
'nw_NATInfo2' => '1:1 NAT istifadə edilmirsə, marşrutlaşdırıcının parametrlərində aşağıdakı portları ictimai IP-dən PBX-in daxili IP ünvanına yönləndirin.',
'nw_PublicSIPPort' => 'SIP port nömrəsi daxili %SIP_PORT% PBX-ə yönləndirildi',
+ 'gs_ErrorSaveSettings' => 'Parametrləri yadda saxlama xətası',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Göstərilən artırma nömrəsi artıq istifadə olunur',
+ 'fw_iaxDescription' => 'IAX - telefon qeydiyyatı və səs trafiki',
];
diff --git a/src/Common/Messages/cs.php b/src/Common/Messages/cs.php
index 1bc3eeb4e..3b389fe4e 100644
--- a/src/Common/Messages/cs.php
+++ b/src/Common/Messages/cs.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo6OR' => 'NEBO',
'nw_PublicSIPPort' => 'Číslo SIP portu přesměrováno na interní %SIP_PORT% PBX',
'nw_PublicTLSPort' => 'Číslo portu SIP TLS přesměrováno na interní %TLS_PORT% PBX',
+ 'gs_ErrorSaveSettings' => 'Při ukládání nastavení došlo k chybě',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Zadané číslo pobočky se již používá',
+ 'fw_iaxDescription' => 'IAX - registrace telefonu a hlasový provoz',
];
diff --git a/src/Common/Messages/da.php b/src/Common/Messages/da.php
index bb21dd3fc..c02097bac 100644
--- a/src/Common/Messages/da.php
+++ b/src/Common/Messages/da.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo2' => 'Hvis 1:1 NAT ikke bruges, skal du omdirigere følgende porte fra den offentlige IP til den interne IP-adresse på PBX\'en i dine routerindstillinger.',
'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO% UDP',
'nw_NATInfo5' => 'Hvis et eksternt værtsnavn er angivet, vil det blive brugt frem for den eksterne IP-adresse.',
+ 'gs_ErrorSaveSettings' => 'Fejl under lagring af indstillinger',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Det angivne lokalnummer er allerede i brug',
+ 'fw_iaxDescription' => 'IAX - telefonregistrering og taletrafik',
];
diff --git a/src/Common/Messages/de.php b/src/Common/Messages/de.php
index c54ec14ba..510a62255 100644
--- a/src/Common/Messages/de.php
+++ b/src/Common/Messages/de.php
@@ -1283,4 +1283,7 @@
'nw_NATInfo1' => 'Wenn Ihr Netzwerk für die Unterstützung von 1:1-NAT konfiguriert ist (normalerweise die Standardeinstellung in Clouds), müssen Sie keine zusätzlichen Einstellungen an Ihrem Router vornehmen.',
'nw_NATInfo2' => 'Wenn 1:1 NAT nicht verwendet wird, leiten Sie in Ihren Router-Einstellungen die folgenden Ports von der öffentlichen IP auf die interne IP-Adresse der TK-Anlage um.',
'nw_PublicSIPPort' => 'SIP-Portnummer, die an die interne %SIP_PORT%-PBX weitergeleitet wird',
+ 'gs_ErrorSaveSettings' => 'Fehler beim Speichern der Einstellungen',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Die angegebene Nebenstellennummer wird bereits verwendet',
+ 'fw_iaxDescription' => 'IAX – Telefonregistrierung und Sprachverkehr',
];
diff --git a/src/Common/Messages/el.php b/src/Common/Messages/el.php
index c1536316c..296335d7d 100644
--- a/src/Common/Messages/el.php
+++ b/src/Common/Messages/el.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo2' => 'Εάν δεν χρησιμοποιείται NAT 1:1, ανακατευθύνετε τις ακόλουθες θύρες από τη δημόσια IP στην εσωτερική διεύθυνση IP του PBX στις ρυθμίσεις του δρομολογητή σας.',
'nw_PublicSIPPort' => 'Ο αριθμός θύρας SIP προωθείται στο εσωτερικό PBX %SIP_PORT%',
'nw_PublicTLSPort' => 'Ο αριθμός θύρας SIP TLS προωθείται στο εσωτερικό PBX %TLS_PORT%',
+ 'gs_ErrorSaveSettings' => 'Σφάλμα αποθήκευσης ρυθμίσεων',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Ο καθορισμένος αριθμός επέκτασης χρησιμοποιείται ήδη',
+ 'fw_iaxDescription' => 'IAX - εγγραφή τηλεφώνου και φωνητική κίνηση',
];
diff --git a/src/Common/Messages/en.php b/src/Common/Messages/en.php
index 328d6e08f..eb349cdbd 100644
--- a/src/Common/Messages/en.php
+++ b/src/Common/Messages/en.php
@@ -1283,4 +1283,7 @@
'nw_NATInfo6OR' => 'OR',
'nw_PublicSIPPort' => 'SIP port number forwarded to internal %SIP_PORT% PBX',
'nw_PublicTLSPort' => 'SIP TLS port number forwarded to internal %TLS_PORT% PBX',
+ 'gs_ErrorSaveSettings' => 'Error saving settings',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'The specified extension number is already in use',
+ 'fw_iaxDescription' => 'IAX - Phone Registration and Voice Traffic',
];
diff --git a/src/Common/Messages/es.php b/src/Common/Messages/es.php
index 6f929df81..9ed41544b 100644
--- a/src/Common/Messages/es.php
+++ b/src/Common/Messages/es.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo3' => '%SIP_PORT% TCP/UDP y %TLS_PORT% TCP',
'nw_NATInfo5' => 'Si se especifica un nombre de host externo, se utilizará con preferencia a la dirección IP externa.',
'nw_PublicTLSPort' => 'Número de puerto SIP TLS reenviado al PBX interno %TLS_PORT%',
+ 'gs_ErrorSaveSettings' => 'Error al guardar la configuración',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'El número de extensión especificado ya está en uso',
+ 'fw_iaxDescription' => 'IAX: registro telefónico y tráfico de voz',
];
diff --git a/src/Common/Messages/fi.php b/src/Common/Messages/fi.php
new file mode 100644
index 000000000..79c451197
--- /dev/null
+++ b/src/Common/Messages/fi.php
@@ -0,0 +1,1237 @@
+ 'Palomuurin määrittäminen',
+ 'BreadcrumbFirewallmodify' => 'Säännön määrittäminen',
+ 'SubHeaderFirewall' => 'Aseman pääsyn rajoittaminen liikennetyypin ja aliverkkojen mukaan',
+ 'BreadcrumbGeneralSettings' => 'Järjestelmäasetukset',
+ 'SubHeaderIvrMenu' => 'Saapuvien puhelujen reititysmallin ja asetusten määrittäminen',
+ 'BreadcrumbDialplanApplications' => 'Dialplan-sovellukset',
+ 'BreadcrumbDialplanApplicationsmodify' => 'Sovelluksen määrittäminen',
+ 'SubHeaderDialplanApplications' => 'Ohjelmoitavat puhesovellukset PHP:ssä ja Asterisk Dialplanissa',
+ 'BreadcrumbConferenceRooms' => 'Konferenssit',
+ 'SubHeaderConferenceRooms' => 'Huoneiden perustaminen usean osapuolen äänikonferensseja varten',
+ 'BreadcrumbConferenceRoomsmodify' => 'Asetusvaihtoehdot',
+ 'BreadcrumbCallDetailRecords' => 'Puheluhistoria',
+ 'SubHeaderCallDetailRecords' => 'Keskusteluloki ja puheluloki',
+ 'BreadcrumbCustomFilesmodify' => 'Muokkaus',
+ 'BreadcrumbCustomFiles' => 'Järjestelmätiedostot',
+ 'SubHeaderCustomFiles' => 'Järjestelmän ja Asterisk-määritystiedostojen mukauttaminen',
+ 'BreadcrumbSoundFiles' => 'Äänitiedostot',
+ 'SubHeaderSoundFiles' => 'Käytetään erilaisissa puheluskenaarioissa ja interaktiivisissa äänivalikoissa',
+ 'BreadcrumbLicensing' => 'Lisensointi',
+ 'SubHeaderLicensing' => 'Rekisteröidy Marketplacessa saadaksesi uusia laajennuksia ja moduuleja',
+ 'BreadcrumbErrors' => 'Virheilmoitus',
+ 'SubHeaderErrors' => 'Jos tämä virhe on toistettavissa, ota yhteyttä kehittäjään.',
+ 'BreadcrumbRestart' => 'Käynnistä järjestelmä uudelleen',
+ 'BreadcrumbRestartmanage' => 'Käynnistä järjestelmä uudelleen',
+ 'SubHeaderRestart' => 'Moduulien uudelleenkäynnistys, täydellinen uudelleenkäynnistys tai sammutus',
+ 'BreadcrumbSession' => 'Valtuutus',
+ 'BreadcrumbSessionend' => 'Valtuutus',
+ 'BreadcrumbSystemDiagnostic' => 'Järjestelmän diagnostiikka',
+ 'SubHeaderSystemDiagnostic' => 'Järjestelmälokien kokoelma MikoPBX-toiminnan virheiden yksityiskohtaista analysointia varten',
+ 'BreadcrumbFail2Ban' => 'Hakkerointisuojaus',
+ 'SubHeaderFail2Ban' => 'Automaattinen esto, kun salasanat valitaan',
+ 'BreadcrumbUpdate' => 'Järjestelmän päivitys',
+ 'SubHeaderUpdate' => 'Virheenkorjauksia, suorituskyvyn parannuksia, uusia toimintoja',
+ 'BreadcrumbPbxExtensionModules' => 'Moduulien ja laajennusten hallinta MikoPBX:lle',
+ 'SubHeaderPbxExtensionModules' => 'Lataa omasi tai lataa moduuleja markkinapaikaltamme',
+ 'mm_Setup' => 'Puhelimet',
+ 'mm_Extensions' => 'Työntekijät',
+ 'mm_CallQueues' => 'Puhelujonot',
+ 'mm_DialplanApplications' => 'Dialplan-sovellukset',
+ 'mm_Routing' => 'Reititys',
+ 'mm_Providers' => 'Puhelinpalvelujen tarjoajat',
+ 'mm_IncomingRoutes' => 'Saapuvat reitit',
+ 'mm_OutboundRoutes' => 'Lähtevät reitit',
+ 'mm_OutOffWorkTime' => 'Vapaat työajat',
+ 'mm_System' => 'Järjestelmä',
+ 'mm_GeneralSettings' => 'Yleiset asetukset',
+ 'mm_TimeSettings' => 'Päivämäärä ja aika',
+ 'mm_Network' => 'Verkkoliitännät',
+ 'mm_Firewall' => 'Palomuuri',
+ 'mm_MailSettings' => 'Posti ja ilmoitukset',
+ 'mm_AsteriskManagers' => 'Pääsy AMI:hen',
+ 'mm_IvrMenu' => 'IVR-valikko',
+ 'mm_ConferenceRooms' => 'Konferenssit',
+ 'mm_CallDetailRecords' => 'Puheluhistoria',
+ 'mm_CustomFiles' => 'Järjestelmätiedostojen mukauttaminen',
+ 'mm_SoundFiles' => 'Äänitiedostot',
+ 'mm_Restart' => 'Käynnistä uudelleen',
+ 'mm_PbxExtensionModules' => 'Moduulit',
+ 'mm_Maintenance' => 'Palvelu',
+ 'mm_Logout' => 'Poistu',
+ 'mm_SystemDiagnostic' => 'Järjestelmälokit',
+ 'mm_Fail2Ban' => 'Hakkerointisuojaus',
+ 'mm_Update' => 'PBX-päivitys',
+ 'mm_ModuleManager' => 'Moduulien markkinapaikka',
+ 'mm_SSHConsole' => 'SSH-konsoli',
+ 'mm_Integrations' => 'Integraatiot',
+ 'bt_Edit' => 'Muuttaa',
+ 'bt_Clear' => 'Selkeä',
+ 'bt_Delete' => 'Poistaa',
+ 'bt_SaveSettings' => 'Tallentaa',
+ 'bt_SaveSettingsAndAddNew' => 'Tallenna ja lisää',
+ 'bt_SaveSettingsAndExit' => 'Tallenna ja sulje',
+ 'bt_ApplyChangesToPBX' => 'Ota muutokset käyttöön',
+ 'bt_BackToList' => 'Takaisin luetteloon',
+ 'bt_Back' => 'Takaisin',
+ 'bt_ToolTipCopyPassword' => 'Salasana kopioitu leikepöydälle',
+ 'bt_ToolTipEdit' => 'Muuttaa',
+ 'pr_ProviderName' => 'Palveluntarjoajan nimi',
+ 'pr_ProviderLogin' => 'Kirjaudu sisään',
+ 'pr_ProviderPassword' => 'Salasana',
+ 'pr_ProviderHostOrIPAddress' => 'Isäntä tai IP-osoite',
+ 'pr_DTMFMode' => 'DTMF-tila',
+ 'pr_RegistrationSettings' => 'Rekisteröintiasetukset',
+ 'pr_RedefinitionFromUser' => 'SIP-otsikon "From" uudelleenmäärittely',
+ 'pr_FromUser_v2' => 'Käyttäjä',
+ 'pr_ValidationProviderNameIsEmpty' => 'Anna palveluntarjoajan nimi',
+ 'pr_ValidationProviderHostIsEmpty' => 'Anna palvelimen nimi tai palveluntarjoajan IP-osoite',
+ 'pr_ValidationProviderLoginIsEmpty' => 'Anna kirjautumistunnuksesi valtuuttaaksesi palveluntarjoajan kanssa',
+ 'pr_ValidationProviderLoginNotSingleSimbol' => 'Kirjautumisen tulee olla pidempi kuin yksi merkki',
+ 'pr_DisableFromUser' => 'Poista käyttäjäkentän käyttö käytöstä',
+ 'pr_NoRegister' => 'Poista rekisteröinti käytöstä',
+ 'pr_ManualAdditionalAtributes' => 'Lisävaihtoehdot',
+ 'pr_UpdateStatus' => 'Tilan päivitys',
+ 'pr_Online' => 'Yhteys muodostettu',
+ 'pr_Offline' => 'Ei käytössä',
+ 'pr_WithoutRegistration' => 'Rekisteröinti poistettu käytöstä',
+ 'pr_TableColumnProviderLogin' => 'Kirjaudu sisään',
+ 'pr_TableColumnProviderHostName' => 'Isäntä',
+ 'pr_TableColumnProviderType' => 'Tyyppi',
+ 'pr_TableColumnProviderName' => 'Palveluntarjoaja',
+ 'pr_TableColumnProviderStatus' => 'Status',
+ 'pr_ValidateRTPOutOfRange' => 'RTP-porttien alue on väärä. Arvojen on oltava välillä {ruleValue}',
+ 'pr_RTPPortRange' => 'RTP-porttialue',
+ 'pr_RTPPortFrom' => 'KANSSA',
+ 'pr_RTPPortTo' => 'Tekijä:',
+ 'pr_Note' => 'Huomautus tai hyödyllistä tietoa palveluntarjoajasta',
+ 'gs_RTPStunServer' => 'STUN-palvelimen osoite (esimerkki: stun.test.net:10000)',
+ 'gs_UseWebRTC' => 'Käytä WebRTC:tä',
+ 'gs_Store1MonthOfRecords' => '1 kuukausi',
+ 'gs_Store3MonthsOfRecords' => '3 kuukautta',
+ 'gs_Store6MonthsOfRecords' => '6 kuukautta',
+ 'gs_Store1YearOfRecords' => '1 vuosi',
+ 'gs_Store3YearsOfRecords' => '3 vuotta',
+ 'gs_PBXRecordSavePeriodLabel' => 'Puhelutallenteiden säilytysaika',
+ 'gs_StoreAllPossibleRecords' => '∞',
+ 'gs_DisableAllModules' => 'Poista markkinapaikka käytöstä',
+ 'gs_ErrorSaveSettings' => 'Virhe asetusten tallentamisessa',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Määritetty alanumero on jo käytössä',
+ 'pr_AddSIPProvider' => 'Yhdistä SIP',
+ 'pr_AddIAXProvider' => 'Yhdistä IAX',
+ 'pr_QualifyInstructionsIAX' => 'Kun tämä vaihtoehto on käytössä, Asterisk lähettää SIP-asetukset-paketteja. Tämä on tarpeen NAT-tunneloinnin tukemiseksi reitittimessäsi.',
+ 'pr_CustomFieldsDescriptions' => 'Useimmissa tapauksissa ohituskentät tulee jättää tyhjiksi.
+ Vain jos puhelut eivät toimi sinulle ja palveluntarjoaja vaatii erityisiä asetuksia, nämä kentät on täytettävä palveluntarjoajan suositusten mukaisesti.',
+ 'pr_ReceiveCallsWithoutAuth' => 'Vastaanota puheluita ilman todennusta',
+ 'pr_ValidationProviderPortRange' => 'Palveluntarjoajan portin on oltava alueella {ruleValue}',
+ 'pr_DeleteTitle' => 'Palveluntarjoajan poistaminen',
+ 'pr_DeleteDescription' => 'Yhdessä palveluntarjoajan kanssa kaikki siihen liittyvät lähtevän liikenteen reitityssäännöt poistetaan, ja saapuvan liikenteen reitityssäännöissä kaikki linkit korvataan sanoilla "Kaikki toimittajat".',
+ 'pr_DeleteDescription_v2' => 'Yhdessä palveluntarjoajan kanssa kaikki siihen liittyvät lähtevän liikenteen reitityssäännöt poistetaan, ja saapuvien reitityssäännöissä kaikki linkit korvataan tekstillä "Ei yhteyttä palveluntarjoajaan, ei valtuutusta".',
+ 'pr_Delete' => 'Poistaa',
+ 'pr_EnterHostOrIp' => 'Palveluntarjoajan lisäosoitteet',
+ 'pr_EnterHostOrIpPlaceholder' => 'Anna IP-osoite tai aliverkko ja paina Enter',
+ 'pr_NoAnyAdditionalHosts' => 'Tälle palveluntarjoajalle ei ole määritetty muita osoitteita',
+ 'or_RuleName' => 'Säännön nimi',
+ 'or_Note' => 'Huom',
+ 'or_PatternToMatch' => 'Sääntö toimii, jos',
+ 'or_NumberBeginsWithTheDigits' => 'Numero alkaa kirjaimella',
+ 'or_TheRestOfTheNumberMustBe' => 'Loput numerosta koostuu määritetystä määrästä numeroita',
+ 'or_ReformatNumber' => 'Muunna numero',
+ 'or_BeforeConnectingTheCallTrim' => 'Ennen kuin aloitamme puhelun, lopetimme',
+ 'or_digitsFromTheFrontAndThenPrependTheDigits' => 'numerot luvun alussa ja lisää sitten alkuun',
+ 'or_CallThrough' => 'Suora puhelu',
+ 'or_Provider' => 'palveluntarjoajan kautta',
+ 'or_ValidationPleaseEnterRuleName' => 'Anna säännön nimi',
+ 'or_ValidateBeginPattern' => 'Virhe numerosuodatinkentässä. Se voi sisältää numeroita ja merkkejä :)|',
+ 'or_ValidateRestNumbers' => 'Numeron vähimmäispituuden on oltava suurempi kuin 2',
+ 'or_ValidateTrimFromBegin' => 'Väärä arvo numeron alussa olevien merkkien katkaisulle',
+ 'or_ValidatePrepend' => 'Virhe lisättäessä luvun alkuun. Kenttä voi sisältää numeroita ja merkkejä: * # +. Arvon enimmäispituus on 20 merkkiä.',
+ 'or_AddNewRule' => 'Lisää uusi sääntö',
+ 'or_TableColumnName' => 'Nimi',
+ 'or_TableColumnRule' => 'Sääntö',
+ 'or_TableColumnProvider' => 'Palveluntarjoaja',
+ 'or_RuleDescriptionFullMatch' => 'Vain numerolle %numberbeginswith%',
+ 'or_RuleDescriptionBeginMatch' => 'Minkä tahansa pituisille numeroille, jotka alkavat %numberbeginswith%',
+ 'or_TableColumnNote' => 'Huom',
+ 'or_ValidationPleaseSelectProvider' => 'Valitse palveluntarjoaja, jota tämä sääntö koskee.',
+ 'ir_Provider' => 'Palveluntarjoaja',
+ 'ir_RuleName' => 'Säännön nimi',
+ 'or_RuleDescription' => '%numberbeginswith% alussa ja sitten %restnumbers% numeroa',
+ 'or_RuleDescriptionBeginEmpty' => 'Numero koostuu %restnumbers% numeroista',
+ 'or_RuleNotConfigured' => 'Sääntöä ei ole määritetty',
+ 'ir_Note' => 'Huom',
+ 'ir_TableColumnNote' => 'Huom',
+ 'ir_TableColumnName' => 'Nimi',
+ 'ir_TableColumnDetails' => 'Sääntö',
+ 'ir_RuleDescriptionWithNumberAndWithProvider' => 'Puhelu numeroon %number%   %provider% kautta siirretään numeroon   %callerid%',
+ 'ir_RuleDescriptionWithoutNumber' => 'Puhelu   %provider% kautta siirretään osoitteeseen   %callerid%',
+ 'ir_RuleDescriptionWithoutProvider' => 'Puhelu numeroon %number% siirretään numeroon   %callerid%',
+ 'ir_RuleDescriptionWithoutNumberAndWithoutProvider' => 'Minkä tahansa palveluntarjoajan kautta tuleva puhelu siirretään osoitteeseen   %callerid%',
+ 'ir_DefaultRoute' => 'Oletustuloreitti',
+ 'ir_ActionSelect' => 'Jos mikään säännöistä ei vastaa',
+ 'ir_busy_signal' => 'Toista varattu-ääni',
+ 'ir_hangup' => 'Katkaise puhelu',
+ 'ir_extension' => 'Siirrä puhelu',
+ 'ir_playback' => 'Toista mediatiedosto',
+ 'ir_ExtensionSelect' => 'Numeroon',
+ 'ir_RuleAssignIf' => 'Sääntö toimii soitettaessa',
+ 'ir_DidNumber' => 'Lisänumero (DID)',
+ 'ir_CallTransferTo' => 'Puhelu siirretään osoitteeseen',
+ 'ir_Extension' => 'määrä',
+ 'ir_ValidateForwardingToBeFilled' => 'Edelleenlähetysnumeroa ei ole määritetty',
+ 'ir_ValidateForwardingDefaultToBeFilled' => 'Oletussoitonsiirtonumeroa ei ole määritetty',
+ 'ir_ValidationPleaseEnterRuleName' => 'Anna säännön nimi',
+ 'ir_ValidateTimeoutOutOfRange' => 'Uudelleenohjauksen aikakatkaisu on määritetty väärin. Sen pitäisi olla välillä {ruleValue}',
+ 'ir_DidNumberDescription' => 'Palveluntarjoaja voi välittää lisänumeron, tämä on valinnainen kenttä, mutta joissakin tapauksissa se voi reitittää puhelut tarkemmin.',
+ 'ir_TimeoutToTransferDefault' => 'Aika sekunneissa, jonka jälkeen puhelu reititetään seuraavaan prioriteettisääntöön',
+ 'ir_AddNewRule' => 'Lisää uusi sääntö',
+ 'ir_AnyProvider' => 'Mikä tahansa palveluntarjoaja',
+ 'ir_AnyProvider_v2' => 'Ei yhteyttä palveluntarjoajaan, ei valtuutusta',
+ 'cq_Extension' => 'Jonon numero',
+ 'cq_Name' => 'Jonon nimi',
+ 'cq_Note' => 'Huom',
+ 'cq_Description' => 'Huom',
+ 'cq_AddNewQueue' => 'Luo uusi jono',
+ 'cq_StaticAgents' => 'Osallistujat',
+ 'cq_QueueMembersColumnName' => 'Operaattori',
+ 'cq_QueueMembersColumnExtension' => 'Määrä',
+ 'cq_ringall' => 'Puhelu saapuu samanaikaisesti kaikille jonossa oleville osallistujille, mukaan lukien varatut (oletusarvoisesti)',
+ 'cq_leastrecent' => 'Puhelu saapuu jonon jäsenelle, joka ei ole saanut puheluita pisimpään aikaan',
+ 'cq_fewestcalls' => 'Puhelu menee jonon jäsenelle, joka on käsitellyt vähiten puheluita ',
+ 'cq_random' => 'Puhelu saapuu kenelle tahansa jonossa olevalle vapaalle osallistujalle',
+ 'cq_rrmemory' => 'Puhelu saapuu kenelle tahansa jonossa olevalle vapaalle osallistujalle paitsi osallistujalle, joka käsitteli viimeisen puhelun',
+ 'cq_linear' => 'Kutsu saapuu jokaiselle jonoon osallistujalle järjestyksessä',
+ 'cd_Extensions' => 'Tämän jonon puhelinnumero',
+ 'cq_QueueStrategy' => 'Soittostrategia operaattoreille',
+ 'cd_Description' => 'Kommentti',
+ 'cq_QueueMembers' => 'Jonooperaattorit',
+ 'cq_SelectAgentForAddToQueue' => 'Valitse nykyiseen jonoon lisättävä työntekijä',
+ 'cq_AddQueueMembers' => 'Ei valittuja operaattoreita',
+ 'cq_QueueMemberSettings' => 'Operaattoreiden jonoasetukset',
+ 'cq_SecRingToEachMembers' => 'Soittoyritysten aika operaattoreille',
+ 'cq_WrapupTime' => 'Operaattorin lepoaika puhelun käsittelyn jälkeen ennen uusien puheluiden vastaanottamista',
+ 'cq_ReciveCallWhileOnCall' => 'Vastaanota uusia puheluita puhelun aikana',
+ 'cq_QueueCallerSettings' => 'Soittajajonon asetukset',
+ 'cq_CallerHearOnQueued' => 'Mitä tilaaja kuulee odottaessaan',
+ 'cq_ringing' => 'Soittoäänet',
+ 'cq_moh' => 'Musiikki',
+ 'cq_AnnoncePosition' => 'Ilmoita nykyisestä sijainnista jonossa',
+ 'cq_AnnonceHoldTime' => 'Ilmoita arvioidusta odotusajasta',
+ 'cq_PereodicAnonceSoundFile' => 'Mainoslause tai lisäilmoitus',
+ 'cq_PereodicAnonceMohSoundFile' => 'Taustamusiikki (MOH)',
+ 'gs_SSHDisablePasswordLogins' => 'Poista salasanatodennus käytöstä',
+ 'cq_PereodicAnonceFrequency' => 'Aika sekunteina toistaa säännöllisesti kaikki hälytykset',
+ 'cq_CallRouting' => 'Puhelun reititys vikojen aikana',
+ 'cq_ScenaryOne' => 'Skenaario #1',
+ 'cq_ScenaryTwo' => 'Skenaario #2',
+ 'cq_ScenaryThree' => 'Skenaario #3',
+ 'cq_ScenaryFour' => 'Skenaario #4',
+ 'cq_IfQueueNotAnsweredFor' => 'Jos tilaaja odottaa jonossa yli ',
+ 'cq_SecondsCallWillBeRoutedTo' => ' sekuntia, siirrä puhelu numeroon ',
+ 'cq_RedirectToExtensionIfEmtyQueue' => 'Jos jonossa ei ole operaattoreita, siirrä puhelu numeroon ',
+ 'cq_IfQueueNotAnsweredNumberCalls' => 'Jos kukaan operaattori ei vastaa puheluun sisällä ',
+ 'cq_ImpossibleToDeleteCallQueue' => 'Puhelujonon poistaminen on mahdotonta, koska siellä on seuraavat linkit',
+ 'dt_Info' => 'Merkinnät _START_–_END_ alkaen _TOTAL_',
+ 'dt_InfoEmpty' => 'Valintakriteerit täyttäviä tietueita ei ole',
+ 'dt_InfoFiltered' => '(valittu _MAX_ tietueesta)',
+ 'dt_Previous' => 'Edellinen',
+ 'dt_Next' => 'Seuraavaksi',
+ 'dt_Search' => 'Haku',
+ 'dt_TableIsEmpty' => 'Ei näytettävää dataa',
+ 'ml_EmailNotSended' => 'Viestiä ei lähetetty',
+ 'ml_EmailSendedSuccess' => 'Kirje lähetetty',
+ 'ml_EmailTestSubject' => 'Testaa sähköposti puhelinjärjestelmästäsi',
+ 'ml_EmailTestBody' => 'Hei, jos sinulla on tämä kirje postissasi, asetukset ovat oikein.',
+ 'er_Unauthorized' => 'Valtuutusvirhe',
+ 'er_InternalServerErrorDescription' => 'Jotain meni pieleen. Tällaisia virheitä ei pitäisi olla.',
+ 'ex_enableRecording' => 'Salli',
+ 'ex_ThisUserIdNotExistInUsersModel' => 'Tätä käyttäjää ei ole olemassa',
+ 'ex_ThisNumberNotExistInSipModel' => 'Tällä numerolla ei ole vastaavia SIP-asetuksia',
+ 'ex_NoNetworkFilter' => 'Yhteydet mistä tahansa osoitteesta ovat sallittuja',
+ 'ex_PermitNetwork' => 'Sallittu verkko',
+ 'ex_DenyNetwork' => 'Kielletty verkko',
+ 'ex_GeneralSettings' => 'Perusparametrit',
+ 'ex_RoutingSettings' => 'Reititysasetukset',
+ 'ex_Username' => 'Käyttäjän koko nimi',
+ 'ex_EmailAddress' => 'Sähköpostiosoite',
+ 'ex_ThisEmailAlreadyRegisteredForOtherUser' => 'Annettu osoite on jo rekisteröity',
+ 'ex_Language' => 'Käyttöliittymä ja ilmoituskieli',
+ 'ex_Number' => 'Laajennusnumero',
+ 'ex_ThisNumberIsNotFree' => 'Numero on jo tietokannassa',
+ 'ex_ThisNumberOverlapWithParkingSlots' => 'Risteys, jossa on useita pysäköintinumeroita',
+ 'ex_MobileNumber' => 'Matkapuhelinnumero',
+ 'ex_Secret' => 'SIP-salasana',
+ 'ex_ChangeAvatar' => 'Vaihda avataria',
+ 'ex_UserPhotography' => 'Työntekijän kuva',
+ 'ex_MobileSettings' => 'Lisäasetukset mobiililaitteille',
+ 'ex_MobileDialstring' => 'Valintamerkkijonon ohitus',
+ 'ex_SipSettings' => 'SIP-asetukset',
+ 'ex_BusyLevel' => 'Rinnakkaisten keskustelujen enimmäismäärä',
+ 'ex_BusyLevelInfo' => 'Kun määritetty määrä puheluita saavutetaan, työntekijän puhelin katsotaan varattuksi.',
+ 'ex_DTMFMode' => 'DTMF-tila',
+ 'ex_NetworkFilter' => 'Ylijännitesuodatin',
+ 'ex_NatMode' => 'NAT-tila',
+ 'gs_CallRecordTab' => 'Keskustelujen tallentaminen',
+ 'ex_ManualAdditionalAttributes' => 'Lisävaihtoehdot',
+ 'ex_RingMainExtension' => 'varten',
+ 'ex_SecondsAndThenRedirectCallTo' => 'Yritämme soittaa päänumeroon sekuntia, sitten siirrymme numeroon',
+ 'ex_IfMainExtensionIsBusyRedirectCallTo' => 'Jos päänumero on varattu, siirrämme puhelun numeroon',
+ 'ex_IfMainExtensionIsUnavailableRedirectCallTo' => 'Jos päänumero ei ole käytettävissä, siirrämme puhelun numeroon',
+ 'ex_ValidateMobileIsNotCorrect' => 'Tarkista, että matkapuhelinnumerosi on syötetty oikein',
+ 'ex_ValidateEmailEmpty' => 'Todennäköisesti sähköpostiosoite on syötetty väärin',
+ 'ex_ValidateUsernameEmpty' => 'Kirjoita työntekijän koko nimi',
+ 'ex_ValidateUsernameSpecialCharacters' => 'Koko nimi ei saa sisältää erikoismerkkejä',
+ 'ex_ValidateSecretEmpty' => 'SIP-salasana ei voi olla tyhjä',
+ 'ex_ValidateSecretWeak' => 'SIP-salasanan on oltava yli 4 merkkiä pitkä',
+ 'ex_PasswordNoLowSimvol' => 'Salasanan tulee sisältää kirjaimia',
+ 'ex_RegeneratePassword' => 'Luo uusi salasana',
+ 'ex_PasswordNoNumbers' => 'Salasanan tulee sisältää numeroita',
+ 'ex_ValidateExtensionNumber' => 'Alanumerossa saa olla vain numeroita',
+ 'ex_AddNewExtension' => 'Lisää työntekijä',
+ 'ex_Name' => 'Työntekijä',
+ 'ex_Transport' => 'Kuljetusprotokolla',
+ 'ex_Extension' => 'Laajennusnumero',
+ 'ex_OutboundProxy' => 'Lähtevä välityspalvelin (esimerkki: pbx.yandex.net:5080)',
+ 'ex_Mobile' => 'mobiili',
+ 'ex_Email' => 'Sähköposti',
+ 'ex_Status' => 'Status',
+ 'ex_ValidateForwardingToBeFilled' => 'Aikakatkaisun edelleenlähetysnumeroa ei täytetty reititysasetuksissa',
+ 'ex_ValidateForwardingToBeDifferent' => 'Et voi määrittää edelleenlähetystä omaan numeroosi',
+ 'ex_ValidateMobileNumberIsDouble' => 'Matkapuhelinnumero on jo toisen työntekijän käytössä',
+ 'ex_ValidateNumberIsDouble' => 'Alanumero on jo varattu',
+ 'ex_UpdateStatus' => 'Tilan päivitys',
+ 'ex_Online' => 'Yhdistetty',
+ 'ex_Offline' => 'Ei käytössä',
+ 'ex_SelectNumber' => 'Valitse numero',
+ 'ex_dropdownCategory_CONFERENCE' => 'Konferenssit',
+ 'ex_dropdownCategory_USER' => 'Työntekijät',
+ 'ex_dropdownCategory_USERS' => 'Työntekijät',
+ 'ex_dropdownCategory_DIALPLAN_APPLICATION' => 'Dialplan-sovellukset',
+ 'ex_dropdownCategory_IVR_MENU' => 'Interaktiiviset äänivalikot IVR',
+ 'ex_dropdownCategory_CALLQUEUES' => 'Puhelujonot',
+ 'ex_dropdownCategory_IVRMENU' => 'Interaktiiviset äänivalikot IVR',
+ 'ex_dropdownCategory_PBXEXTENSIONMODULES' => 'Lisämoduulit',
+ 'ex_dropdownCategory_CONFERENCEROOMS' => 'Konferenssit',
+ 'ex_dropdownCategory_DIALPLANAPPLICATIONS' => 'Dialplan-sovellukset',
+ 'ex_dropdownCategory_NETWORKFILTERS' => 'Aliverkot',
+ 'ex_dropdownCategory_QUEUE' => 'Puhelujonot',
+ 'ex_dropdownCategory_MODULES' => 'Lisämoduulit',
+ 'ex_dropdownCategory_PROVIDERS' => 'Palveluntarjoajat',
+ 'ex_dropdownCategory_OUTWORKTIMES' => 'Vapaat työajat',
+ 'ex_dropdownCategory_ASTERISKMANAGERUSERS' => 'AMI-käyttäjät',
+ 'ex_dropdownCategory_CUSTOMFILES' => 'Asetustiedostot',
+ 'ex_dropdownCategory_MENUITEMS' => 'Valikkokohteet',
+ 'ex_dropdownCategory_SYSTEM' => 'Palvelunumerot',
+ 'ex_dropdownCategory_PARKING' => 'Parkkipaikat',
+ 'ex_ImpossibleToDeleteExtension' => 'Työntekijän poistaminen on mahdotonta, koska siellä on seuraavat linkit',
+ 'ex_ImpossibleToGetSecret' => 'Käyttäjän salasanan saaminen epäonnistui',
+ 'am_TableColumnName' => 'Nimi',
+ 'am_TableColumnRead' => 'Lukuoikeus',
+ 'am_TableColumnWrite' => 'Kirjoitusoikeus',
+ 'am_TableColumnDescription' => 'Huomautuksia',
+ 'am_AddNewUser' => 'Lisää käyttäjä AMI',
+ 'am_TableColumnNetworkFilter' => 'Ylijännitesuodatin',
+ 'am_Read' => 'lukeminen',
+ 'am_Write' => 'tallentaa',
+ 'am_Username' => 'Käyttäjätunnus',
+ 'am_Secret' => 'Salasana',
+ 'am_NetworkFilter' => 'Ylijännitesuodatin',
+ 'am_UserRights' => 'Käyttäjän oikeudet',
+ 'am_Description' => 'Kommentti',
+ 'am_ValidationAMINameIsEmpty' => 'Tilin nimeä ei ole määritetty',
+ 'am_ValidationAMISecretIsEmpty' => 'Salasanaa ei ole täytetty',
+ 'am_ErrorThisUsernameInNotAvailable' => 'Samanniminen merkintä on jo olemassa',
+ 'am_NoAnyServersYet' => 'Täällä ei ole vielä AMI-käyttäjiä',
+ 'tf_TableColumnNotes' => 'Huom',
+ 'tf_AddNewTimeFrame' => 'Lisää aikaväli',
+ 'tf_DateDaysFrom' => 'Kausi',
+ 'tf_WeekDaysFrom' => 'Viikon päivät',
+ 'tf_TimePeriodFrom' => 'Aikajakso',
+ 'tf_PeriodAction' => 'Saapuva puhelutoiminto',
+ 'tf_ValidateCheckWeekDayInterval' => 'Tarkista viikonpäivien väli',
+ 'tf_ValidateCheckTimeInterval' => 'Tarkista aikaväli',
+ 'tf_ValidateAudioMessageEmpty' => 'Valitse äänitallenne',
+ 'tf_ValidateExtensionEmpty' => 'Valitse alanumero edelleenlähetystä varten',
+ 'tf_ValidateNoRulesSelected' => 'Aikaa ei täytetä',
+ 'tf_TabGeneralSettings' => 'Perusasetukset',
+ 'tf_TabRoutsRestriction' => 'Voimassa valituille reiteille',
+ 'tf_calUrl' => 'Kalenterin URL-osoite',
+ 'tf_calUser' => 'Käyttäjätunnus',
+ 'tf_calSecret' => 'Salasana',
+ 'tf_calType' => 'Tyyppi',
+ 'tf_CAL_TYPE_NONE' => 'Tavallinen',
+ 'tf_CAL_TYPE_CALDAV' => 'CalDAV',
+ 'tf_CAL_TYPE_ICAL' => 'iCal',
+ 'tf_ValidateCalUri' => 'Kalenterin URL-osoite -kentässä on virheellinen arvo.',
+ 'Mon' => 'maanantai',
+ 'Tue' => 'tiistai',
+ 'Wed' => 'keskiviikko',
+ 'Thu' => 'torstai',
+ 'Fri' => 'perjantai',
+ 'Sat' => 'lauantai',
+ 'Sun' => 'sunnuntai',
+ 'fw_AddNewRule' => 'Lisää uusi aliverkko',
+ 'fw_TableColumnDescription' => 'Nimi',
+ 'fw_TableColumnNetwork' => 'Aliverkko/osoite',
+ 'fw_Description' => 'Nimi',
+ 'fw_Permit' => 'Aliverkko',
+ 'fw_Rules' => 'Käytettävissä olevat palvelut',
+ 'fw_webDescription' => 'WEB - pääsy hallinnolliseen käyttöliittymään',
+ 'fw_amiDescription' => 'AMI - pääsy Asterisk Manager -sovellusliittymään Telnetin kautta',
+ 'fw_ctiDescription' => 'CTI - puhelinpaneelin kytkeminen',
+ 'fw_ajamDescription' => 'AJAM – pääsy tähtienhallintasovellusliittymään http/https:n kautta',
+ 'fw_sshDescription' => 'SSH - pääkäyttäjän oikeudet järjestelmään',
+ 'fw_icmpDescription' => 'ICMP - yhteyden tarkistus ping-komennolla',
+ 'fw_ValidatePermitAddress' => 'Määritetty aliverkon osoite on virheellinen. Kokeile mallia, joka on samanlainen kuin 192.168.1.0/24',
+ 'fw_ValidateRuleName' => 'Anna aliverkolle nimi',
+ 'fw_NewerBlockIp' => 'Älä koskaan estä osoitteita tästä verkosta, ohita puhelimen valtuutusvirheet ja salasanan syöttövirheet verkkoliittymässä',
+ 'fw_ItIsLocalNetwork' => 'Tämä on VPN tai paikallinen verkko, tämän verkon puhelimet muodostavat yhteyden suoraan asemaan ilman NAT-reititystä',
+ 'fw_AllNetworksRule' => 'Kaikki saatavilla olevat verkot',
+ 'fw_LocalNetworksRule' => 'Aliverkko, jossa MikoPBX sijaitsee',
+ 'fw_DenyNetwork' => 'Kielletty aliverkko',
+ 'fw_PermitNetwork' => 'aliverkko',
+ 'fw_Subnet' => 'Aliverkon maski',
+ 'fw_AdditionalRules' => 'Lisävaihtoehdot',
+ 'fw_StatusEnabled' => 'Mukana palomuuri ja hakkeroinnin esto',
+ 'fw_StatusDisabled' => 'Palomuuri ja hakkerointisuoja on poistettu käytöstä',
+ 'fw_NeedConfigureRule' => 'Vaatii asennuksen',
+ 'mo_BeforeDeleteNetworkFilterDeleteAsteriskManagerUsersFirst' => 'Linkki tähän sääntöön löytyi Asterisk Managers -luettelosta käyttäjälle %username%',
+ 'mo_BeforeDeleteNetworkFilterDeleteSipFirst' => 'Linkki tähän sääntöön löytyi työntekijäluettelosta osoitteessa %extension%',
+ 'mo_ThisVlanIdNotUniqueForLanInterfacesModels' => 'Järjestelmässä on jo liitäntä samaan VLAN-verkkoon',
+ 'mo_Disabled' => 'pois',
+ 'mo_RightNumber' => 'Sääntö nro.%id%',
+ 'mo_NewElement' => 'Uuden luominen',
+ 'mo_NewElementNetworkFilters' => 'Uusi palomuurisääntö aliverkolle/osoitteelle',
+ 'mo_NewElementSip' => 'Uusi SIP-palveluntarjoaja',
+ 'mo_NewElementIncomingRoutingTable' => 'Uusi sääntö saapuvien puhelujen käsittelyyn',
+ 'mo_NewElementOutgoingRoutingTable' => 'Uusi sääntö lähtevien puhelujen käsittelylle',
+ 'mo_NewElementOutWorkTimes' => 'Uusi sääntö työajan jälkeen',
+ 'mo_NewElementDialplanApplications' => 'Uusi sovellus/soittosuunnitelma',
+ 'mo_NewElementAsteriskManagerUsers' => 'Uusi tili AMI-käyttäjälle',
+ 'mo_NewElementSoundFiles' => 'Uusi äänitiedosto',
+ 'nw_PublicHostName' => 'Reitittimesi ulkoinen isäntänimi',
+ 'nw_ValidateDHCPOnVlansDontSupport' => 'DHCP:tä ei tueta VLAN-aliverkoissa',
+ 'nw_ValidateNameIsNotBeEmpty' => 'Käyttöliittymän nimi on tyhjä',
+ 'nw_ValidateVlanRange' => 'VLAN-arvo on täytetty väärin. Valitse {ruleValue}',
+ 'nw_Hostname' => 'Paikallinen isäntänimi',
+ 'nw_ValidateExtIppaddrNotRight' => 'Virhe täytettäessä reitittimen ulkoista IP-osoitetta',
+ 'nw_ValidateExtIppaddrOrHostIsEmpty' => 'Sinun on täytettävä joko reitittimen ulkoinen IP-osoite tai sen DNS-nimi',
+ 'nw_ValidateVlanCross' => 'Virheet rajapintojen VLAN-asetuksissa, tarkista parametrien leikkauskohta',
+ 'nw_ValidateIppaddrIsEmpty' => 'Verkkoliitännän IP-osoitetta ei ole täytetty',
+ 'nw_ValidateIppaddrNotRight' => 'Verkkoliitännän IP-osoite on määritetty väärin',
+ 'nw_GatewayAddress' => 'Yhdyskäytävän osoite',
+ 'nw_DNSAddresses' => 'DNS-palvelinosoitteet',
+ 'nw_PublicAddress' => 'Reitittimesi ulkoinen IP-osoite',
+ 'nw_InternetInterface' => 'Verkkoliitäntä Internet-yhteydellä',
+ 'nw_NetworkInterfaces' => 'Verkkoliitännät',
+ 'nw_InterfaceName' => 'Nimi',
+ 'nw_IPAddress' => 'IP-osoite',
+ 'nw_NetworkMask' => 'Aliverkon peite (CIDR)',
+ 'nw_VlanID' => 'VLAN ID',
+ 'nw_SelectInterface' => 'Valitse verkkoliitäntä',
+ 'nw_AllowNatPortForwarding' => 'Tämä asema sijaitsee NAT-reitittimen takana',
+ 'nw_NATInfo1' => 'Jos verkkosi on määritetty tukemaan 1:1 NAT:ia (yleensä oletusarvo pilvissä), sinun ei tarvitse tehdä lisäasetuksia reitittimellesi.',
+ 'nw_NATInfo2' => 'Jos 1:1 NAT ei ole käytössä, ohjaa seuraavat portit julkisesta IP-osoitteesta PBX:n sisäiseen IP-osoitteeseen reitittimen asetuksissa.',
+ 'nw_NATInfo3' => '%SIP_PORT% TCP/UDP ja %TLS_PORT% TCP',
+ 'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO% UDP',
+ 'nw_NATInfo5' => 'Jos ulkoinen isäntänimi on määritetty, sitä käytetään ulkoisen IP-osoitteen sijaan.',
+ 'nw_NATInfo6OR' => 'TAI',
+ 'nw_PublicSIPPort' => 'SIP-portin numero välitetty sisäiseen %SIP_PORT% PBX:ään',
+ 'nw_PublicTLSPort' => 'SIP TLS -portin numero välitetty sisäiseen %TLS_PORT% PBX:ään',
+ 'nw_UseDHCP' => 'Käytä DHCP:tä verkkoasetusten hakemiseen',
+ 'nw_LookUpExternalIp' => 'Ota selvää ulkoisesta IP-osoitteesta',
+ 'nw_DeleteCurrentInterface' => 'Poista tämä käyttöliittymä',
+ 'nw_NetworkAddressTranslations' => 'Verkkotopologia',
+ 'nw_UpdateExternalIPAutomaticallyOnReboot' => 'Päivitä ulkoinen IP-osoite aina, kun käynnistät uudelleen',
+ 'gs_MainTab' => 'Perus',
+ 'gs_FeaturesTab' => 'Puhelujen siirrot',
+ 'gs_SIPTab' => 'SIEMAILLA',
+ 'gs_AMITab' => 'AMI&AJAM',
+ 'gs_SSHTab' => 'SSH',
+ 'gs_WebTab' => 'Web-käyttöliittymä',
+ 'gs_PBXName' => 'PBX-järjestelmän nimi',
+ 'gs_PBXDescription' => 'Lisäkuvaus',
+ 'gs_NeedRestartPBX' => 'Kun muutos tehdään, tähtipalvelu käynnistyy uudelleen',
+ 'gs_PBXLanguage' => 'Järjestelmän äänen kieli',
+ 'gs_PBXInternalExtensionLength' => 'Sisäisten numeroiden enimmäispituus',
+ 'gs_PBXRecordCalls' => 'Keskustelujen tallentaminen',
+ 'gs_PBXRecordCallsInner' => 'Sisäisten keskustelujen tallennus',
+ 'gs_RestartEveryNight' => 'Käynnistä PBX uudelleen joka ilta',
+ 'gs_PBXCallParkingExt' => 'Soita puiston numeroon',
+ 'gs_PBXCallParkingSlotRange' => 'Parkkipaikkavalikoima',
+ 'gs_PBXFeatureAttendedTransfer' => 'Konsultoiva käännösyhdistelmä',
+ 'gs_PBXFeatureBlindTransfer' => 'Yhdistelmä ehdottomaan siirtoon',
+ 'gs_PBXFeatureDigitTimeout' => 'Suurin välinumeroiden aikakatkaisu alanumeroa syötettäessä (millisekunteina)',
+ 'gs_PBXFeaturePickupExten' => 'Yhdistelmä saapuvien puhelujen sieppaamiseen',
+ 'gs_PBXSplitAudioThread' => 'Tallenna äänitykset stereotilassa',
+ 'gs_PBXAllowGuestCalls' => 'Salli saapuvat puhelut kaikilta palvelimilta',
+ 'gs_SIPPort' => 'SIP-portti puhelimien rekisteröintiä varten tälle asemalle',
+ 'gs_TLS_PORT' => 'SIP TLS -portti (salatut puhelut)',
+ 'gs_KeepAliveHeader' => 'Rekisteröinnin keston asetukset',
+ 'gs_SIPDefaultExpiry' => 'Normaali aika sekunneissa Säilytä elossa -viestin lähettämiseen',
+ 'gs_SIPExpiryRange' => 'Minimi- ja enimmäisaika sekunneissa',
+ 'gs_SIPPortSettings' => 'Porttiasetukset SIP-signalointia ja RTP-aluetta varten',
+ 'gs_RTPPortRange' => 'RTP-porttialue',
+ 'gs_AMIEnabled' => 'Käytä AMI-liitäntää',
+ 'gs_AMIPort' => 'AMI-portti',
+ 'gs_AJAMEnabled' => 'Käytä AJAM-käyttöliittymää',
+ 'gs_AJAMPort' => 'Port AJAM',
+ 'gs_AJAMPortTLS' => 'Salattu AJAM-portti',
+ 'gs_SSHPort' => 'SSH-portti',
+ 'adv_SSHPPasswordCorrupt' => 'Verkkoliittymässä asetettu SSH-salasana ei vastaa järjestelmän nykyistä salasanaa. korjaus',
+ 'gs_SSHLogin' => 'Kirjaudu SSH-konsoliin',
+ 'gs_SSHPassword' => 'SSH-salasana',
+ 'gs_SSHAuthorizedKeys' => 'Valtuutetut SSH-avaimet',
+ 'gs_SSHecdsaKey' => 'SSH ECDSA -avain',
+ 'gs_SSHRsaKey' => 'SSH RSA avain',
+ 'gs_SSHDssKey' => 'SSH DSS avain',
+ 'gs_PasswordSimple' => 'Määrittämäsi salasana on liian yksinkertainen.',
+ 'gs_SetPasswordError' => 'Salasana - %password% ei voi käyttää, se on yksinkertaisten salasanojen sanakirjassa.',
+ 'gs_SetPasswordInfo' => 'Määritettyä salasanaa ei voi käyttää, se on yksinkertaisessa salasanasanakirjassa.',
+ 'gs_PasswordNoNumbers' => 'Salasanan tulee sisältää numeroita',
+ 'gs_PasswordNoLowSimvol' => 'Salasanan tulee sisältää pieniä kirjaimia',
+ 'gs_PasswordNoUpperSimvol' => 'Salasanan tulee sisältää isoja kirjaimia',
+ 'gs_WebPort' => 'HTTP-portti',
+ 'gs_WebHTTPSPort' => 'HTTPs-portti',
+ 'gs_WEBHTTPSPrivateKey' => 'HTTPs yksityinen avain',
+ 'gs_WEBHTTPSPublicKey' => 'HTTPs julkinen avain',
+ 'gs_ValidateEmptyPBXName' => 'Aseman nimeä ei ole määritetty',
+ 'gs_TwoDigthts' => '2 numeroa',
+ 'gs_ThreeDigthts' => '3 numeroa',
+ 'gs_FourDigthts' => '4 numeroa',
+ 'gs_FiveDigthts' => '5 numeroa',
+ 'gs_SixDigthts' => '6 numeroa',
+ 'gs_SevenDigthts' => '7 numeroa',
+ 'gs_ElevenDigthts' => '11 numeroa',
+ 'gs_WebAdminLogin' => 'Kirjaudu sisään',
+ 'gs_WebAdminPassword' => 'Salasana',
+ 'gs_WebAdminPasswordRepeat' => 'Kirjoita salasanasi uudelleen',
+ 'gs_SSHPasswordRepeat' => 'Kirjoita salasanasi uudelleen',
+ 'gs_Passwords' => 'WEB-käyttöliittymän salasana',
+ 'gs_DefaultPasswordWarning' => 'Älä käytä tavallista järjestelmänvalvojan kirjautumistunnusta ja salasanaa',
+ 'gs_ValidateEmptyWebPassword' => 'Järjestelmänvalvojan salasana ei voi olla tyhjä',
+ 'gs_ValidateWeakWebPassword' => 'WEB-salasanan on oltava yli 4 merkkiä pitkä',
+ 'gs_ValidateWebPasswordsFieldDifferent' => 'Verkkokäyttöliittymän salasana syötettiin väärin',
+ 'gs_ValidateEmptySSHPassword' => 'SSH-salasana ei voi olla tyhjä',
+ 'gs_ValidateWeakSSHPassword' => 'SSH-salasanan on oltava yli 4 merkkiä pitkä',
+ 'gs_ValidateSSHPasswordsFieldDifferent' => 'SSH-salasana syötettiin väärin. Kirjoita salasanasi uudelleen.',
+ 'gs_ValidateWEBPortOutOfRange' => 'HTTP-porttikenttä on virheellinen. Valitse arvo väliltä {ruleValue}.',
+ 'gs_ValidateWEBHTTPSPortOutOfRange' => 'HTTPS-porttikenttä on virheellinen. Valitse arvo väliltä {ruleValue}.',
+ 'gs_ValidateWEBHTTPSPortNotEqualToWEBPort' => 'HTTP- ja HTTPS-porttien on oltava erilaiset',
+ 'gs_ValidateWEBPortNotEqualToAjamPort' => 'HTTP- ja AJAM-porttien on oltava erilaisia',
+ 'gs_ValidateWEBPortNotEqualToAjamTLSPort' => 'HTTP- ja AJAM-porttien on oltava erilaisia',
+ 'gs_ValidateWEBHTTPSPortNotEqualToAjamPort' => 'HTTPS- ja AJAM-porttien on oltava erilaisia',
+ 'gs_ValidateWEBHTTPSPortNotEqualToAjamTLSPort' => 'HTTPS- ja AJAM-porttien on oltava erilaisia',
+ 'gs_SendAnonymousMetrics' => 'Lähetä kaatumistiedot kehittäjille',
+ 'gs_WebAdminLanguage' => 'Web-käyttöliittymän kieli',
+ 'gs_CodecsTab' => 'Audio/video koodekit',
+ 'gs_AudioCodecs' => 'Äänikoodekit',
+ 'gs_VideoCodecs' => 'Videokoodekit',
+ 'gs_CodecsOrder' => 'Kodekin prioriteetti',
+ 'gs_DangerZone' => 'Järjestelmäasetusten poistaminen',
+ 'gs_RestoreAllSettingsHeader' => 'Huomio!',
+ 'gs_RestoreAllSettingsMessage' => 'Kaikki asetukset, puheluhistoria, puhelujen tallennustiedostot ja asennetut laajennukset poistetaan.',
+ 'gs_EnterDeleteAllPhrasePreText' => 'Puhdista järjestelmä kirjoittamalla syöttökenttään seuraava lause:',
+ 'gs_EnterDeleteAllPhrase' => 'poista kaikki',
+ 'gs_AllSettingsDeleted' => 'Kaikki asetukset poistetaan',
+ 'gs_PBXRecordAnnouncementIn' => 'Valitse puhelun tallennushälytys saapuville puheluille',
+ 'gs_PBXRecordAnnouncementOut' => 'Valitse lähteville puheluille puhelun tallennushälytys',
+ 'ts_CurrentSettings' => 'Nykyiset asetukset',
+ 'ts_SystemTime' => 'Järjestelmän aika',
+ 'ts_TimeZone' => 'Aikavyöhyke',
+ 'ts_ModifySettings' => 'Uudet asetukset',
+ 'ms_SentTestEmailAfterSaveTo' => 'Lähetä testisähköposti tähän osoitteeseen',
+ 'ms_MissedCallSubject' => 'Vastaamaton puhelu - sähköpostin aihe',
+ 'ms_MissedCallBody' => 'Vastaamaton puhelu - kirjeen teksti',
+ 'ms_MissedCallFooter' => 'Vastaamaton puhelu - kellari',
+ 'ms_VoicemailSubject' => 'Vastaaja - aiherivi',
+ 'ms_VoicemailBody' => 'Vastaaja - kirjeen teksti',
+ 'ms_VoicemailFooter' => 'Vastaaja - kellari',
+ 'ms_MailSysadminEmail' => 'Järjestelmänvalvojan sähköposti',
+ 'ms_SystemEmailForMissed' => 'Sähköposti jääneistä ilmoituksista',
+ 'ms_TestEmailSubject' => 'Testataan postin lähetystä',
+ 'ms_TestEmailSentSuccessfully' => 'Kirje lähetetty',
+ 'ms_TestEmailBody' => 'Jos sait tämän kirjeen, sähköpostiasetukset ovat oikein.',
+ 'ms_MissedCalls' => 'Vastaamattomat puhelut',
+ 'ms_Voicemail' => 'Vastaaja',
+ 'ms_VoicemailCommonEmail' => 'Yksittäinen sähköposti vastaajaviestien lähettämiseen',
+ 'iv_ValidateDigitsIsNotCorrect' => 'Koodikenttää ei ole täytetty oikein',
+ 'iv_ValidateExtensionIsNotCorrect' => 'Tilaajanumeroa ei ole valittu',
+ 'iv_ValidateExtensionIsEmpty' => 'IVR-valikon numeroa ei ole määritetty',
+ 'iv_ValidateAudioFileIsEmpty' => 'Äänitiedostoa ei ole valittu äänitervehdystä varten',
+ 'iv_ValidateNameIsEmpty' => 'IVR-valikon nimeä ei ole määritetty',
+ 'iv_ValidateNoIVRExtensions' => 'IVR-valikon lisävalinnan toimintoja ei ole määritetty',
+ 'iv_ValidateTimeoutExtensionIsEmpty' => 'Aikakatkaisun edelleenlähetysnumeroa ei ole määritetty',
+ 'iv_ValidateExtensionIsDouble' => 'Määritetty IVR-valikkonumero on varattu',
+ 'iv_ValidateRepeatNumberOutOfRange' => 'Valikon toistojen määrä on väärä',
+ 'iv_ValidateTimeoutOutOfRange' => 'Alanumeron odottamisen aikakatkaisu on syötetty väärin',
+ 'iv_Name' => 'Valikon nimi',
+ 'iv_Description' => 'Kommentti',
+ 'iv_Extensions' => 'IVR-valikon numero',
+ 'iv_PlaySound' => 'Äänitervehdys',
+ 'iv_Actions' => 'Toimenpiteet lisärekrytoimiseksi',
+ 'iv_DeleteRow' => 'Poistaa',
+ 'iv_AddNewRow' => 'Lisätä',
+ 'iv_TimeoutExtension' => 'Oletusnumero',
+ 'iv_Extension' => 'IVR-valikon numero',
+ 'iv_Note' => 'Huomautuksia',
+ 'iv_AddNewIvrMenu' => 'Luo uusi IVR-valikko',
+ 'iv_ThisNumberIsNotFree' => 'Tämä numero on varattu',
+ 'iv_NumberOfRepeat' => 'Uudelleenyritysten määrä ennen siirtoa oletusnumeroon',
+ 'iv_ImpossibleToDeleteIVRMenu' => 'IVR-valikkoa ei voi poistaa, siihen on aktiivisia linkkejä',
+ 'da_Main' => 'Sovellusasetukset',
+ 'da_Applicationlogic' => 'Ohjelmakoodi',
+ 'da_Hint' => 'Vihje',
+ 'da_Description' => 'Kommentti',
+ 'da_Name' => 'Nimi',
+ 'da_Extensions' => 'Hakemuksen puhelinnumero',
+ 'da_ThisNumberIsNotFree' => 'Tämä numero on varattu',
+ 'da_Type' => 'Koodityyppi',
+ 'da_ColumnExtension' => 'Määrä',
+ 'da_ColumnName' => 'Nimi',
+ 'da_ColumnNote' => 'Kuvaus',
+ 'da_ValidateNameIsEmpty' => 'Hakemuksen nimeä ei ole täytetty',
+ 'da_ValidateExtensionIsEmpty' => 'Hakemuksen numeroa ei ole täytetty',
+ 'da_ValidateExtensionDouble' => 'Tälle sovellukselle määritetty alanumero on varattu',
+ 'da_AddNewDialplanApp' => 'Lisää uusi',
+ 'da_TypePhp' => 'PHP-AGI-skripti',
+ 'da_TypePlaintext' => 'Tähtivalintasuunnitelma',
+ 'da_ValidateExtensionNumber' => 'Alanumerossa saa olla vain numeroita',
+ 'da_ImpossibleToDeleteDialplanApplication' => 'Dialplans-sovellusta ei voi poistaa, sillä siinä on linkkejä',
+ 'cr_AddNewConferenceRoom' => 'Lisää konferenssi',
+ 'cr_ColumnExtension' => 'Määrä',
+ 'cr_pinCode' => 'Konferenssin PIN-koodi',
+ 'cr_Extensions' => 'Määrä',
+ 'cr_ThisNumberIsNotFree' => 'Tämä numero on varattu',
+ 'cr_ValidateExtensionDouble' => 'Tälle konferenssille määritetty alanumero on varattu',
+ 'cr_ValidateExtensionEmpty' => 'Sisäistä neuvottelunumeroa ei ole määritetty',
+ 'cr_ValidateNameEmpty' => 'Konferenssin nimeä ei ole määritelty',
+ 'cr_ValidateExtensionNumber' => 'Alanumerossa saa olla vain numeroita',
+ 'cr_ValidateExtensionLen' => 'Alanumeron tulee koostua kahdesta tai useammasta numerosta',
+ 'cr_ValidatePinNumber' => 'PIN-koodi saa sisältää vain numeroita',
+ 'cr_ImpossibleToDeleteConferenceRoom' => 'Tätä kokoushuonetta ei voi poistaa',
+ 'cdr_ColumnDate' => 'Soittopäivä',
+ 'cdr_ColumnFrom' => 'WHO',
+ 'cdr_ColumnTo' => 'Kenelle',
+ 'cdr_ColumnDuration' => 'Kesto',
+ 'cdr_ColumnRecordings' => 'Puhelujen tallenteet',
+ 'cdr_And' => 'Ja',
+ 'cf_ColumnPath' => 'Tiedoston polku',
+ 'cf_ColumnMode' => 'tila',
+ 'cf_ColumnNote' => 'Huom',
+ 'cf_FileActionsNone' => 'Älä vaihda',
+ 'cf_FileActionsAppend' => 'Liitä tiedoston loppuun',
+ 'cf_FileActionsOverride' => 'Vaihda kokonaan',
+ 'cf_FileActionsScript' => 'Prosessi skriptillä',
+ 'cf_Main' => 'Kommentoi muutoksia',
+ 'cf_Content' => 'Ohjelmakoodi tai kokoonpano',
+ 'cf_Path' => 'Tiedoston polku',
+ 'cf_Description' => 'Kommentoi miksi muutokset tehtiin',
+ 'cf_Mode' => 'tila',
+ 'cf_OriginalFileHeader' => 'Järjestelmän luoma alkuperäinen tiedostosisältö',
+ 'cf_UserEditHeader' => 'Editor muutosten tekemiseen',
+ 'cf_ResultFileHeader' => 'Tiedoston sisältö muutoksineen',
+ 'mo_BeforeDeleteFirst' => 'Objektiin on linkkejä - %represent%',
+ 'ConstraintViolation' => 'Loogisen eheyden rikkominen',
+ 'repAsteriskManagerUsers' => 'AMI-merkintä - %represent%',
+ 'repCallQueues' => 'Puhelujono - %represent%',
+ 'repCallQueueMembers' => 'Puhelujonon jäsen - %represent%',
+ 'repConferenceRooms' => 'Konferenssi – %represent%',
+ 'repCustomFiles' => 'Järjestelmätiedosto - %represent%',
+ 'repDialplanApplications' => 'Dialplan-sovellus - %represent%',
+ 'repExtensionForwardingRights' => 'Työntekijän reititysasetukset - %represent%',
+ 'repExtensions' => 'Laajennuksen numero - %represent%',
+ 'repExternalPhones' => 'Ulkoinen numero - %represent%',
+ 'repFail2BanRules' => 'Fail2Ban-sääntö – %represent%',
+ 'repSoundFiles' => 'Äänitiedosto - %represent%',
+ 'repIvrMenu' => 'IVR-valikko – %represent%',
+ 'repIvrMenuActions' => 'IVR-menun osallistuja - %represent%',
+ 'repLink' => 'linkki',
+ 'sf_ValidationFileNameIsEmpty' => 'Tiedoston nimeä ei ole määritetty',
+ 'sf_Filename' => 'Tallennustiedoston nimi',
+ 'sf_UploadNewSoundFile' => 'Lataa uusi tiedosto',
+ 'sf_RecordNewSoundFile' => 'Nauhoita mikrofonilla',
+ 'sf_UploadSoundFileButton' => 'Lataa',
+ 'sf_StartRecordSoundFileButton' => 'Aloita tallennus',
+ 'sf_StopRecordSoundFileButton' => 'Stop',
+ 'sf_ColumnFile' => 'Nimi',
+ 'sf_ColumnPlayer' => 'Pelaaja',
+ 'sf_AddNewSoundFile' => 'Lisää uusi äänitiedosto',
+ 'sf_FileNotFound' => 'Virhe - tiedostoa ei voi toistaa',
+ 'sf_SelectAudioFile' => 'Valitse äänitiedosto',
+ 'sf_ValidationFileNotSelected' => 'Lataa ensin äänitiedosto',
+ 'sf_CustomSounds' => 'Äänitiedostot',
+ 'sf_MusicOnHold' => 'Musiikki pidossa',
+ 'sf_UploadError' => 'Virhe ladattaessa äänitiedostoa',
+ 'lic_ValidateCompanyNameEmpty' => 'Pakollinen kenttä ei täytetty - yrityksen nimi',
+ 'lic_ValidateContactEmail' => 'Pakollinen kenttä ei täytetty - yhteyshenkilön sähköpostiosoite',
+ 'lic_ValidateContactName' => 'Pakollinen kenttä ei täytetty - yhteyshenkilö',
+ 'lic_ValidateCouponEmpty' => 'Pakollinen kenttä ei täytetty - kuponki',
+ 'lic_ValidateLicenseKeyEmpty' => 'Pakollinen kenttä ei täytetty - Lisenssiavain',
+ 'lic_GetKeyForm' => 'Rekisteröinti',
+ 'lic_ActivateCoupon' => 'Kupongin aktivointi',
+ 'lic_LicenseKey' => 'Lisenssiavain',
+ 'lic_CompanyName' => 'Organisaation nimi',
+ 'lic_Email' => 'Yhteyshenkilön sähköpostiosoite',
+ 'lic_Contact' => 'Yhteyshenkilö',
+ 'lic_Phone' => 'Yhteydenotto puhelinnumero',
+ 'lic_Inn' => 'Yksilöllinen yrityksen tunniste (TIN, IIN, UNP jne.)',
+ 'lic_Coupon' => 'Lisenssin uusimiskuponki',
+ 'lic_SuccessfulCouponActivation' => 'Kuponki aktivoitu onnistuneesti',
+ 'lic_SuccessfulActivation' => 'Onnistunut järjestelmän rekisteröinti',
+ 'lic_WrongLicenseKeyOrEmpty' => 'Lisenssiavain syötettiin väärin',
+ 'lic_LicenseKeyMessage' => 'Lisenssiavainta käytetään kaikkien MIKO-tuotteiden lisenssien tallentamiseen.
+Jos sinulla on jo avain, voit kirjoittaa sen tähän kenttään.
+Jos sinulla oli avain, mutta unohdit sen, etsi saapuvat kirjeet osoitteesta lic@miko.ru
+Voit saada uuden avaimen automaattisesti täyttämällä rekisteröintilomakkeen.
',
+ 'lic_CouponMessage' => 'Kuponkia käytetään tilausten, kokeilujen uusimiseen ja laajennusmoduulien lisenssien aktivoimiseen.
+Kupongin voi aktivoida kerran, jonka jälkeen se lunastetaan.',
+ 'lic_CurrentLicenseInfo' => 'Yksityiskohtaiset tiedot lisenssiavaimen tuotteista',
+ 'lic_Expired' => 'Tuote on vanhentunut, ota yhteyttä lic@mikopbx.com',
+ 'lic_ExpiredAfter' => 'Lisenssi vanhenee %expired% jälkeen',
+ 'lic_Product' => 'Tuote',
+ 'lic_FeatureInfo' => 'Yhteensä %count% lisenssiä kohteelle %name%, joista käytössä %captured%',
+ 'lic_LicenseKeyProducts' => 'Aktivoidut tuotteet',
+ 'lic_LicenseKeyOwner' => 'Lisenssin haltija',
+ 'lic_ResetLicenseSettings' => 'Nollaa avaimen sidonta',
+ 'lic_LicenseKeyValid' => 'Ohjelma on rekisteröity',
+ 'lic_FailedToGetTrialKey2051' => '(2051) Tätä kopiota ei voitu rekisteröidä, koska olet jo käyttänyt rekisteröintinumeroa toisessa sähköpostissa tällä koneella.
+ Käytä avainta, joka lähetettiin sinulle aiemmin osoitteesta lic@miko.ru',
+ 'lic_FailedToGetTrialKey2022' => '(2022) Tämän kopion rekisteröinti epäonnistui. Toisen yrityksen rekisteröintinumero on jo luotu määritettyyn sähköpostiosoitteeseen.
+ Käytä avainta, joka lähetettiin sinulle aiemmin osoitteesta lic@miko.ru tai ilmoita oikea yrityksen nimi.',
+ 'lic_FailedActivateCoupon2057' => '(2057) Tämä kuponki on estetty',
+ 'lic_FailedActivateCoupon2040' => '(2040) Tätä kuponkia ei ole olemassa, tarkista syöttämäsi oikeellisuus',
+ 'lic_FailedActivateCoupon2041' => '(2041) Tämä kuponki on aktivoitu jo aiemmin',
+ 'lic_FailedActivateCoupon2037' => '(2037) Virhe määritettäessä rekisterinumeroa',
+ 'lic_FailedCheckLicense2026' => '(2026) Virhe määritettäessä lisenssinumeroa',
+ 'lic_FailedToCaptureFeature2008' => '(2008) Ei vaadita lisenssiä tai se on sidottu toiseen MikoPBX:ään',
+ 'lic_InvalidLicenseKey2009' => '(2009) Lisenssiavaimen virhe',
+ 'lic_FeatureExpired2011' => '(2011) Moduulilisenssi on vanhentunut, ota yhteyttä sale@mikopbx.com',
+ 'lic_FailedCheckLicenseNotPbxResponse' => 'MikoPBX ei vastannut lupatietopyyntöön. Palvelu ei ole saatavilla.',
+ 'lic_UnknownLicenseMessage' => 'Ei vastausta lupajärjestelmästä',
+ 'lic_IntroductionTabHeader' => 'Tietoja markkinapaikan lisensoinnista',
+ 'lic_ManagementTabHeader' => 'Rekisteröinti ja lisenssien hallinta',
+ 'lic_FirstQuestionHeader' => 'Onko rekisteröityminen tarpeellista?',
+ 'lic_FirstQuestionAnswer' => 'MikoPBX:n perustoiminnot ovat täysin ilmaisia, eikä niitä rajoita lisenssi. Lisenssin puute ei vaikuta puheluihin millään tavalla.
Voit rekisteröityä Marketplaceen ja peruuttaa sen milloin tahansa.',
+ 'lic_MarketplaceHeader' => 'Marketplace tarjoaa lisämahdollisuuksia',
+ 'f2b_Reason' => 'Aiheuttaa',
+ 'f2b_IpAddres' => 'IP-osoite',
+ 'f2b_BanedTime' => 'Päivämäärä',
+ 'f2b_TableBannedHeader' => 'Estetyt osoitteet',
+ 'f2b_Unban' => 'Kumoa esto',
+ 'f2b_Jail_asterisk_ami_v2' => 'AMI- tai AJAM-valtuutusvirheet',
+ 'f2b_Jail_asterisk_v2' => 'SIP-valtuutusvirheet',
+ 'f2b_Jail_asterisk_security_log_v2' => 'SIP-valtuutusvirheet (security_log)',
+ 'f2b_Jail_asterisk_public_v2' => 'SIP-valtuutusvirheet (julkinen)',
+ 'f2b_Jail_dropbear' => 'SSH-istunnon valtuutusvirheet',
+ 'f2b_Jail_mikopbx-www' => 'Valtuutusvirheet PBX-hallintaliittymässä',
+ 'f2b_WhiteList' => 'Luettelo osoitteista, joita ei koskaan estetä',
+ 'f2b_MaxRetry' => 'Yritysten lukumäärä ennen estoa',
+ 'f2b_FindTime' => '(sekunnissa)',
+ 'f2b_BanTime' => 'Estä (sekuntia)',
+ 'f2b_Fail2BanSwitch' => 'Käytä Fail2Ban aktiivista estojärjestelmää',
+ 'f2b_ValidateMaxRetryRange' => 'Yritysten lukumäärän parametria ei ole asetettu oikein',
+ 'f2b_ValidateFindTimeRange' => 'Valtuutusyritysten analyysijaksoa ei ole asetettu oikein',
+ 'f2b_ValidateBanTimeRange' => 'Estoaika on väärä',
+ 'f2b_TableBannedEmpty' => 'Tietoja ei ole saatavilla',
+ 'f2b_SettingsTabHeader' => 'Suojauksen asettaminen',
+ 'f2b_BannedIpTabHeader' => 'Estetyt osoitteet',
+ 'upd_FileName' => 'Valitse päivitystiedosto',
+ 'upd_UpdateSystem' => 'Ota päivitys käyttöön',
+ 'upd_VersionColumn' => 'Versio',
+ 'upd_DescriptionColumn' => 'Kuvaus',
+ 'upd_AvailableUpdates' => 'Online-päivitykset saatavilla',
+ 'upd_DownloadUpgradeError' => 'Virhe päivityksen lataamisessa. Yritä myöhemmin uudelleen',
+ 'upd_UploadError' => 'Virhe päivityksen lataamisessa',
+ 'upd_UpdateTitle' => 'PBX-päivitys',
+ 'upd_Cancel' => 'Peruuttaa',
+ 'upd_UploadInProgress' => 'Päivitystiedostoa ladataan…',
+ 'upd_UpgradeInProgress' => 'Järjestelmätiedostoja päivitetään…',
+ 'upd_UpgradeError' => 'Virhe päivitettäessä MikoPBX:ää',
+ 'upd_UpdateDescription' => 'Päivityksen lataamisen jälkeen MikoPBX käynnistyy automaattisesti uudelleen ja kaikki nykyiset puhelut katkeavat. Muista varmuuskopioida MikoPBX ennen päivittämistä.',
+ 'upd_EnterIHaveBackupPhrasePreText' => 'Päivitä järjestelmä kirjoittamalla syöttökenttään seuraava lause:',
+ 'upd_EnterIHaveBackupPhrase' => 'Kyllä minulla on varmuuskopio',
+ 'upd_UpdateDockerHeader' => 'Säilön päivityssäännöt',
+ 'upd_UpdateDockerText' => 'Pysäytä säilö, poista se, lataa uusin versio ja aloita uudelleen säilyttäen tallennustilan asennusasetukset ja ympäristömuuttujat. Prosessi on kuvattu tarkemmin dokumentaatiossa.',
+ 'ext_TableColumnDescription' => 'Moduulin nimi',
+ 'ext_TableColumnVersion' => 'Versio',
+ 'ext_UpdateModule' => 'Päivitä moduuli',
+ 'ext_UpdateModuleError' => 'Virhe moduulin asennuksessa',
+ 'ext_DeleteModuleError' => 'Virhe poistettaessa moduulia',
+ 'ext_Available' => 'voidaan päivittää',
+ 'ext_InstallModule' => 'Asenna moduuli',
+ 'ext_AvailableModules' => 'Moduulit saatavilla asennettavaksi',
+ 'ext_ModuleDisabledStatusDisabled' => 'Moduuli poistettu käytöstä',
+ 'ext_ModuleDisabledStatusEnabled' => 'Moduuli käytössä',
+ 'ext_ModuleStatusChanging' => 'Muutetaan moduulin tiloja…',
+ 'ext_Delete' => 'Poistaa',
+ 'ext_GetLinkError' => 'Virhe vastaanotettaessa moduulin jakelusarjaa sivustolta. Yritä myöhemmin uudelleen.',
+ 'ext_NoLicenseAvailable' => 'Tämän moduulin asentamiseen tai päivittämiseen ei ole lisenssiä.',
+ 'ext_ValidateCaptionEmpty' => 'Valikkokohdan nimi on tyhjä',
+ 'ext_ShowModuleItemAtMainMenu' => 'Näytä moduuli sivuvalikossa',
+ 'ext_SelectMenuGroup' => 'Valitse sivuvalikosta kohta',
+ 'ext_SettingsForModule' => 'Moduulin asetukset:',
+ 'ext_Caption' => 'Valikkokohdan nimi',
+ 'ext_AddNewExtension' => 'Lataa uusi moduuli',
+ 'ext_CreateNewExtension' => 'Luo oma moduulisi',
+ 'ext_UploadError' => 'Moduulin latausvirhe',
+ 'ext_UploadInProgress' => 'Ladataan moduulia…',
+ 'ext_InstallationInProgress' => 'Moduulia asennetaan…',
+ 'ext_GetReleaseInProgress' => 'Pyydetään tietoja arkistosta…',
+ 'ext_DownloadInProgress' => 'Ladataan moduulia…',
+ 'ext_CheckLicenseInProgress' => 'Lisenssin tarkistus…',
+ 'ext_ModuleChangeStatusError' => 'Ongelmia vaihdettaessa moduulin tilaa',
+ 'ext_InstallationError' => 'Virhe moduulin asennuksessa',
+ 'ext_InstalledModules' => 'Asennetut moduulit',
+ 'ext_Marketplace' => 'Markkinapaikka',
+ 'ext_Licensing' => 'Lisenssien hallinta',
+ 'ext_NoAvailableModules' => 'Asennettavia moduuleja ei ole saatavana',
+ 'ext_ModuleDependsHigherVersion' => 'Moduulin asentamiseen tarvitset %version% tai uudemman version MikoPBX:stä',
+ 'ext_UninstallDBError' => 'Virhe poistettaessa moduulitietokantaa',
+ 'ext_UnInstallFiles' => 'Virhe poistettaessa moduulitiedostoja',
+ 'ext_EmptyLicenseKey' => 'Lisenssiavainta moduulin lisenssin aktivoimiseksi ei ole asennettu',
+ 'ext_ErrorOnAppliesFilesRights' => 'Virhe määritettäessä oikeuksia moduulitiedostoille',
+ 'ext_ErrorOnInstallDB' => 'Virhe määritettäessä moduulitietokantaa',
+ 'ext_ErrorOnInstallFiles' => 'Virheitä kopioitaessa moduulitiedostoja',
+ 'ext_ErrorOnLicenseActivation' => 'Virheet lisenssin aktivoinnissa',
+ 'ext_NoInstalledModules' => 'Ei asennettuja moduuleja',
+ 'ext_GoToMarketplace' => 'Mene torille',
+ 'ext_GoToRegistration' => 'Ilmoittautuminen torilla',
+ 'ext_LicenseProblemHeader' => 'Lisenssi ongelma',
+ 'ext_ErrorOnDecodeModuleJson' => 'Virhe jäsennettäessä moduulin määritystiedostoa %filename%',
+ 'ext_ErrorOnEnableFirewallSettings' => 'Virhe otettaessa käyttöön moduulin palomuuriasetuksia',
+ 'ext_ErrorOnDisableFirewallSettings' => 'Virhe suljettaessa pois palomuuriasetuksia moduulista',
+ 'ext_ErrorOnModuleBeforeEnable' => 'Virheitä tarkistettaessa, voidaanko moduuli ottaa käyttöön',
+ 'ext_ErrorOnModuleBeforeDisable' => 'Virheitä tarkistettaessa, voidaanko moduuli sammuttaa',
+ 'ext_ModuleLicenseProblem' => 'Laajennusmoduulin lisenssiongelma',
+ 'ext_ModuleExecutionProblem' => 'Tapahtui vakava virhe:',
+ 'ext_DisableReasonHeader' => 'Moduuli poistettiin käytöstä automaattisesti',
+ 'ext_UpdateAllModules' => 'Päivitä kaikki asennetut moduulit',
+ 'ext_EmptyRepoAnswer' => 'Moduulin asentamiseen ei ole saatavilla julkaisuja',
+ 'ext_ErrDownloadTimeout' => 'Moduulipäivityksen lataaminen epäonnistui. Toiminnan aikakatkaisu.',
+ 'ext_ErrUploadTimeout' => 'Moduulitiedoston lataaminen epäonnistui. Toiminnan aikakatkaisu.',
+ 'ext_ErrInstallationTimeout' => 'Moduulin asennus epäonnistui. Toiminnan aikakatkaisu.',
+ 'ext_ModuleLastRelease' => 'Nykyinen julkaisu',
+ 'ext_ModulePublisher' => 'Kehittäjä',
+ 'ext_ModuleDescriptionTab' => 'Moduulin kuvaus',
+ 'ext_ModuleChangelogTab' => 'Versiohistoria',
+ 'ext_UsefulLinks' => 'Hyödyllisiä linkkejä',
+ 'ext_ExternalDescription' => 'Yksityiskohtainen kuvaus, dokumentaatio',
+ 'ext_CommercialModule' => 'Maksullinen moduuli',
+ 'ext_UpdateModuleShort' => 'Päivittää',
+ 'ext_InstallModuleReleaseTag' => 'Vapauta',
+ 'ext_InstallModuleVersion' => 'Asenna versio',
+ 'ext_FreeModule' => 'Ilmainen moduuli',
+ 'ext_ShowModuleRepoDetails' => 'Avaa moduulin yksityiskohtainen kuvaus',
+ 'ext_ModuleEulaTab' => 'Lisenssisopimus',
+ 'ext_FromDate' => 'vapautettu',
+ 'ext_InstallModuleTitle' => 'Moduulin asennus',
+ 'ext_ModuleInstallDescription' => 'Moduulia asennettaessa järjestelmä tarkistaa lisenssin. Maksullisille moduuleille tarjotaan mahdollisuuksien mukaan kokeiluversio. Ilmaiset moduulit asennetaan ilman ehtoja. Jos moduuli on aiemmin poistettu asetusten tallennuksen aikana, ne palautetaan. Moduulia asennettaessa on parempi olla suorittamatta muita toimintoja järjestelmässä.',
+ 'ext_UpdateAllModulesTitle' => 'Päivitetään kaikki moduulit',
+ 'ext_UpdateAllModulesDescription' => 'Järjestelmä päivittää kaikki asennetut moduulit uusimpiin versioihin säilyttäen nykyiset asetukset. On suositeltavaa, että et suorita muita toimintoja järjestelmässä päivitysprosessin aikana.',
+ 'ext_UpdateModuleTitle' => 'Moduulin päivitys',
+ 'ext_ModuleUpdateDescription' => 'Valittu moduuli päivitetään arkistosta uusimpaan versioon ja kaikki asetukset tallennetaan. Maksullisten moduulien lisenssi tarkistetaan ensin. Päivityksen aikana on suositeltavaa pidättäytyä muista toiminnoista järjestelmässä.',
+ 'ext_DowngradeModuleTitle' => 'Moduuliversion palautus',
+ 'ext_ModuleDowngradeDescription' => 'Moduuli palautetaan edelliseen versioon. Asetukset tallennetaan, mutta maksullisten moduulien lisenssi tarkistetaan ensin. Huomaa, että palautus voi muuttaa tietorakennetta ja moduuli on ehkä määritettävä uudelleen. Vältä muiden toimintojen suorittamista järjestelmässä palautuksen aikana.',
+ 'ext_SystemVersionRequired' => 'Vähintään yhteensopiva MikoPBX-versio',
+ 'DimmerWaitForPBXIsOnline' => 'Yhteys PBX-ytimen kanssa katkesi…',
+ 'DimmerWaitForPBXOnlineDescription' => 'On normaalia, että asema käynnistyy uudelleen.
Heti kun yhteys on palautettu, sivu päivittyy automaattisesti!',
+ 'loc_NoResult' => 'Mitään ei löytynyt',
+ 'mo_CallQueueShort4Dropdown' => 'Jonottaa',
+ 'mo_ConferenceRoomsShort4Dropdown' => 'Konferenssi',
+ 'mo_ApplicationShort4Dropdown' => 'Sovellus',
+ 'mo_IVRMenuShort4Dropdown' => 'IVR-valikko',
+ 'mo_ModuleShort4Dropdown' => 'Moduuli',
+ 'mo_SystemExten_hangup' => 'Lopeta puhelu',
+ 'mo_SystemExten_busy' => 'Toista varattu-ääni',
+ 'mo_SystemExten_did2user' => 'Suoraan työntekijälle (vastaa DID)',
+ 'mo_SystemExten_voicemail' => 'Vastaaja',
+ 'GoToWikiDocumentation' => 'Siirry online-dokumentaatioon',
+ 'mo_ModuleSettingsError' => 'Virheet moduulin asetuksissa - %modulename%',
+ 'adv_MessagesHeader' => 'Huomaa',
+ 'adv_MessagesHeaderError' => 'Vakava virhe',
+ 'adv_YouUseDefaultWebPassword' => 'Käytät oletussalasanaa kirjautuaksesi hallintaliittymään - muokkaa',
+ 'adv_YouUseDefaultSSHPassword' => 'Käytät oletussalasanaa käyttääksesi SSH:ta - muokkaa',
+ 'adv_WebPasswordWeak' => 'Yksinkertainen järjestelmänvalvojan salasana verkkoliittymässä muuta',
+ 'adv_SshPasswordWeak' => 'Yksinkertainen SSH-tilin salasana muutos',
+ 'adv_SipPasswordWeak' => 'Yksinkertainen SIP-salasana: %record%',
+ 'adv_AmiPasswordWeak' => 'Yksinkertainen salasana AMI-käyttäjälle %record%',
+ 'adv_PopupHeader' => 'Seuraavat ongelmat havaittiin:',
+ 'pass_CheckWebAdminPasswordSimple' => 'WEB-salasana on liian yksinkertainen.',
+ 'pass_CheckWebAdminPasswordDontMatch' => 'Annetut WEB-salasanat eivät täsmää',
+ 'pass_CheckWebAdminPasswordEmpty' => 'Kenttä on tyhjä: WEB-salasana',
+ 'pass_CheckWebPassErrorChange' => 'Salasanan vaihto epäonnistui',
+ 'pass_CheckSSHPasswordDontMatch' => 'Annetut SSH-salasanat eivät täsmää',
+ 'pass_CheckSSHPasswordEmpty' => 'Kenttä on tyhjä: SSH',
+ 'pass_CheckSSHPasswordSimple' => 'SSH-salasana on liian yksinkertainen.',
+ 'adv_FirewallDisabled' => 'Palomuuri on poistettu käytöstä järjestelmässä - muokkaa',
+ 'adv_NetworksNotConfigured' => 'Sallittujen aliverkkojen parametreja ei ole määritetty - muuta',
+ 'adv_AvailableNewVersionPBX' => 'Uusi versio PBX:stä saatavilla - %ver%',
+ 'adv_ThisCopyIsNotRegistered' => 'Tämä ohjelman kopio ei ole lisensoitu - Ilmainen aktivointi',
+ 'adv_StorageDiskRunningOutOfFreeSpace' => 'Tallennuslevyltä on loppumassa vapaa tila (%free% Mt)',
+ 'adv_ThisCopyHasLicensingTroubles' => 'PBX-lisenssiongelma: %error% - kuinka korjata ',
+ 'adv_ProblemWithInternetConnection' => 'Internet-yhteyttä ei ole. Maksullisten moduulien toiminnassa voi esiintyä ongelmia.',
+ 'cal_Yesterday' => 'Eilen',
+ 'cal_LastWeek' => 'Viimeiset 7 päivää',
+ 'cal_Last30Days' => 'Viimeiset 30 päivää',
+ 'cal_ThisMonth' => 'Nykyinen kuukausi',
+ 'cal_LastMonth' => 'Viime kuussa',
+ 'cal_ApplyBtn' => 'Käytä',
+ 'cal_CancelBtn' => 'Peruuttaa',
+ 'cal_from' => 'Kanssa',
+ 'cal_to' => 'Tekijä:',
+ 'cal_CustomPeriod' => 'Mielivaltainen',
+ 'sntry_Title' => 'Jotain meni pieleen!',
+ 'sntry_Subtitle' => 'Virheestä on ilmoitettu kehittäjälle.',
+ 'sntry_Subtitle2' => 'Kuvaile toimintasi, jotka johtivat tähän virheeseen.',
+ 'sntry_LabelComments' => 'Mitä sinä teit?',
+ 'sntry_LabelClose' => 'Lähellä',
+ 'sntry_LabelSubmit' => 'Lähetä',
+ 'sntry_ErrorGeneric' => 'Tuntematon virhe lähetettäessä. Yritä uudelleen!',
+ 'sntry_ErrorFormEntry' => 'Kenttiä ei ole täytetty, korjaa ne ja yritä lähettää uudelleen!',
+ 'sntry_SuccessMessage' => 'Kiitos avustasi!',
+ 'lang_HelpWithTranslateIt' => 'Apua kääntämiseen MikoPBX',
+ 'topMenu_Support' => 'Tukea',
+ 'topMenu_SearchPlaceholder' => 'Kirjoita hakutermi',
+ 'topMenu_SidebarButton' => 'Valikko',
+ 'MIKO_PBX' => 'MIKO PBX',
+ 'PBX is running in Live or Recovery mode' => 'Järjestelmä käynnistetty palautustilaan (Live CD)',
+ 'LAN IP address assigned via DHCP' => 'LAN IP määritetty DHCP-palvelimen kautta',
+ 'LAN IP address' => 'LAN IP asetettu manuaalisesti',
+ 'VLAN IP address assigned via' => 'VLAN IP: toimii kautta',
+ 'The integrity of the system is broken' => 'Järjestelmän eheys on vaarassa',
+ 'adv_SystemBrokenComment' => 'Järjestelmätiedostoja on muokattu. Suorita järjestelmän palautus/päivitys.',
+ 'PBX console setup' => 'MikoPBX konsoli',
+ 'Install or recover' => 'Suorita asennus/palautus',
+ 'Install on Hard Drive' => 'Suorita asennus',
+ 'Set up LAN IP address' => 'Määritä LAN IP-osoite',
+ 'Reboot system' => 'Käynnistä järjestelmä uudelleen',
+ 'Ping host' => 'Ping osoitteita',
+ 'Firewall' => 'Ota palomuuri käyttöön/poista käytöstä',
+ 'Connect storage' => 'Liitä levy tietojen tallentamista varten',
+ 'Reset admin password' => 'Palauta verkkokäyttöliittymän salasana',
+ 'Enter a number' => 'Syötä joukkueen numero',
+ 'Press ENTER to continue.' => 'Paina ENTER jatkaaksesi…',
+ 'version' => 'versio',
+ 'this_is' => 'Tämä on ',
+ 'Do you want to use DHCP to configure your LAN interface?' => 'Pitäisikö minun käyttää DHCP-palvelinta LAN-liitännän määrittämiseen?',
+ 'The LAN interface will now be configured via DHCP...' => "LAN-liitäntä konfiguroidaan DHCP:n avulla…",
+ 'The LAN interface will now be configured ...' => "Asetetaan LAN-liitäntää…",
+ 'Enter the new LAN IP address: ' => 'Anna uusi LAN-IP-osoite:',
+ 'Subnet masks are to be entered as bit counts (as in CIDR notation).' => 'Aliverkon peite CIDR-muodossa (1-32)',
+ 'Enter the new LAN subnet bit count: ' => "Anna maskin arvo:",
+ 'Enter the LAN gateway IP address: ' => "Anna yhdyskäytävän osoite (LAN-yhdyskäytävän IP-osoite):",
+ 'Enter the LAN DNS IP address: ' => 'Anna DNS-palvelimen osoite:',
+ 'The system will reboot. This may take a minute.' => 'Järjestelmä käynnistyy uudelleen. Tämä kestää muutaman minuutin.',
+ 'Do you want to proceed? (y/n): ' => 'Jatketaanko prosessia? (y/n):',
+ 'The system is rebooting now...' => 'Käynnistä uudelleen…',
+ 'Enter a host name or IP address: ' => 'Anna palvelimen osoite:',
+ 'disable' => 'poistaa käytöstä',
+ 'enable' => 'kytke päälle',
+ 'running' => 'mukana',
+ 'stopped' => 'pois käytöstä',
+ 'Firewall is now' => 'Palomuuri nyt',
+ 'Firewall disabled' => 'Palomuuri poistettu käytöstä',
+ 'Do you want disable firewall now? (y/n): ' => 'Poistetaanko käytöstä? (y/n):',
+ 'Do you want enable firewall now? (y/n): ' => 'Laitetaanko päälle? (y/n):',
+ 'Storage disk is already mounted...' => 'Tallennuslevy on jo asennettu',
+ 'Storage disk was mounted successfully...' => 'Tallennuslevy on asennettu onnistuneesti',
+ 'Valid disks not found...' => 'Vastaavia asemia ei löytynyt',
+ 'Valid disks are:' => 'Luettelo sopivista levyistä:',
+ 'Enter the device name:' => 'Anna laitteen nimi:',
+ 'Do you want reset password? (y/n): ' => 'Haluatko varmasti palauttaa verkkosalasanasi tehdasasetuksiin? (y/n):',
+ 'Password successfully reset. New login: admin. New password: admin.' => "Salasanan palautus onnistui. Käyttäjätunnus: admin Salasana: admin",
+ 'Error resetting password.' => "Salasanan palautusvirhe",
+ 'Install or recovery' => "Asennus/palautus",
+ 'All settings will be lost!' => 'Palaa tehdasasetuksiin!',
+ 'All settings will be kept!' => 'Nykyiset asetukset tallennetaan!',
+ 'Cancel' => 'Peruuttaa',
+ 'Install' => 'Asentaa',
+ 'Reinstall to' => 'Päivitä versioon',
+ 'Firmware version on this system:' => 'Nykyinen järjestelmän laiteohjelmistoversio:',
+ 'WARNING' => 'HUOMIO',
+ 'The PBX will reboot after installation.' => 'Järjestelmä käynnistyy uudelleen, kun asennus on valmis',
+ 'The PBX is about to be installed onto the' => 'MikoPBX asennetaan levylle:',
+ 'everything on this device will be erased!' => 'kaikki laitteen tiedot poistetaan!',
+ 'this cannot be undone!' => 'Operaatio on peruuttamaton!',
+ 'Change language' => 'Vaihda kieli / Muuta käyttöliittymän kieltä',
+ 'Select the drive to install the system.' => 'Valitse levy järjestelmän asentamista varten',
+ 'Selected disk:' => 'Valittu asema:',
+ '(default value = ' => '(oletus = ',
+ 'Select the drive to store the data.' => 'Valitse levy tietojen tallentamista varten',
+ 'Partitioning and formatting storage disk' => 'Luo osio ja alusta levy tietojen tallentamiseksi laitteeseen',
+ 'Update storage partition 4 on disk' => 'Neljännen osion päivittäminen tietojen tallentamiseksi levylle',
+ 'Installing PBX...' => 'Asennetaan MikoPBX:ää…',
+ ' - Unmounting partitions...' => 'Poistetaan asennettuja levyosioita…',
+ ' - Unpacking img...' => 'Päivitetään järjestelmäosiota…',
+ 'Copying configuration...' => 'Alkumääritysasetuksia täytetään…',
+ 'Save storage disk settings' => 'Tallennetaan levyasetuksia tallennusta varten',
+ 'Formatting storage partition 4 on disk' => 'Neljännen osion alustaminen tietojen tallentamiseksi levylle',
+ 'Warning! Selected disk will be formatted!' => 'Huomio! Valittu levy alustetaan ja kaikki tiedot tuhotaan!',
+ 'user' => 'käyttäjä',
+ 'Reboot' => 'Käynnistä MikoPBX uudelleen',
+ 'Power off' => 'Sammuta',
+ 'Choose action' => 'Valitse toiminto',
+ 'Пропущенный вызов' => 'Sinulla on vastaamaton puhelu',
+ 'Console' => 'Konsoli (Shell)',
+ 'Failed to mount the disc...' => 'Levyn asentaminen epäonnistui',
+ 'All processes will be completed. Continue? (y/n):' => 'Kaikki prosessit suoritetaan loppuun. Jatkaa? (y/n):',
+ 'Configuring using DHCP' => 'Konfigurointi DHCP-palvelimella',
+ 'Manual setting' => 'Manuaalinen asetus',
+ 'Storage' => 'Tietojen tallennus',
+ 'Resize storage' => 'Suurenna levyn kokoa tietojen tallennusta varten käyttämällä koko varaamatonta aluetta',
+ 'Check storage' => 'Tarkista levy virheiden varalta',
+ 'Storage unmounted' => 'Tallennuslevyä ei ole kytketty',
+ 'sd_Filename' => 'Tiedosto',
+ 'sd_filter' => 'Suodattaa',
+ 'sd_offset' => 'Offset',
+ 'sd_lines' => 'Rajoittaa',
+ 'sd_ShowLog' => 'Lokien katselu',
+ 'sd_CapturePcap' => 'Kaappaa verkkopaketteja',
+ 'sd_DownloadPcapFileError' => 'Virhe luotaessa lokiarkistoa',
+ 'sd_SystemInformation' => 'Järjestelmätiedot',
+ 'sd_CollectingInfo' => 'Palvelutietojen kerääminen',
+ 'sd_CollectingLogsInfo' => 'Lokitiedostojen luettelon hakeminen',
+ 'sd_PackingLogFiles' => 'Kerättyjen tietojen pakkaaminen',
+ 'sd_ToolTipDownload' => 'Lataa lokitiedosto',
+ 'sd_ToolTipRefresh' => 'Hanki uusin versio lokitiedostosta',
+ 'sd_ToolTipAutoUpdate' => 'Päivitä sisältö automaattisesti näytöllä',
+ 'sd_ToolTipErase' => 'Tyhjennä tiedosto',
+ 'msg_ErrorHeader' => 'Virhe',
+ 'msg_WarningHeader' => 'Huomio',
+ 'msg_infoHeader' => 'Tiedot',
+ 'adv_SSHPasswordWasChangedSubject' => "Huomio! SSH-salasana on vaihdettu!",
+ 'adv_SSHPasswordWasChangedBody' => "MikoPBX:n SSH-salasana on vaihdettu!",
+ 'adv_SSHPasswordWasCompromisedSubject' => 'Huomio! SSH-salasana vaihdettiin ilman kirjautumista MikoPBX-liittymään!',
+ 'adv_SSHPasswordMismatchStringsHash' => 'SSH-salasana vaihdettiin MikoPBX-verkkoliittymän ulkopuolella',
+ 'adv_SSHPasswordMismatchFilesHash' => 'MikoPBX SSH -salasana eroaa asetustiedostossa määritetystä salasanasta. Se on saatettu muuttaa manuaalisesti MikoPBX-konsolista.',
+ 'adv_ThereIsSomeTroublesWithMikoPBX' => 'Huomio! MikoPBX:ssäsi on havaittu ongelmia!',
+ 'ex_English' => 'englanti',
+ 'ex_EnglishUK' => 'englanti (UK)',
+ 'March' => 'maaliskuuta',
+ 'April' => 'huhtikuu',
+ 'May' => 'toukokuuta',
+ 'June' => 'kesäkuuta',
+ 'Jan' => 'tammikuu',
+ 'ShortDaySunday' => 'Vos',
+ 'BreadcrumbTimeSettings' => 'Järjestelmän aika',
+ 'SubHeaderCallQueues' => 'Puhelut asetetaan pitoon ja jaetaan sitten osallistujien kesken strategian mukaisesti',
+ 'BreadcrumbCallQueuesmodify' => 'Jonon asettaminen',
+ 'BreadcrumbOutOffWorkTime' => 'Vapaat työajat',
+ 'SubHeaderGeneralSettings' => 'Järjestelmän perusparametrien määrittäminen',
+ 'BreadcrumbIvrMenu' => 'Interaktiiviset äänivalikot - IVR',
+ 'BreadcrumbIvrMenumodify' => 'IVR-valikon määrittäminen',
+ 'mm_NetworkSettings' => 'Verkko ja palomuuri',
+ 'bt_ToolTipRestore' => 'Palauttaa',
+ 'bt_ToolTipDownload' => 'Lataa',
+ 'bt_ToolTipCopy' => 'Kopioida',
+ 'bt_ToolTipDelete' => 'Poistaa',
+ 'bt_ToolTipUpgradeOnline' => 'Päivitä verkossa',
+ 'ms_SuccessfulSaved' => 'Asetukset tallennettu',
+ 'ms_SuccessfulDeleted' => 'Tiedot poistettu',
+ 'Codecs' => 'koodekit',
+ 'sip_registration_type' => 'Tilin tyyppi',
+ 'sip_REG_TYPE_OUTBOUND' => 'Lähtevä rekisteröinti',
+ 'sip_REG_TYPE_INBOUND' => 'Saapuva rekisteröinti',
+ 'sip_REG_TYPE_NONE' => 'Todennus IP-osoitteella, ilman salasanaa',
+ 'pr_SIPPort' => 'SIP-liitäntäportti',
+ 'pr_Cancel' => 'Peruuttaa',
+ 'or_RuleAnyNumbers' => 'Kaikki numerot',
+ 'cq_QueueSetup' => 'Perusparametrit',
+ 'cq_CallsCallWillBeRoutedTo' => 'puhelut, siirrä kaikki uudet puhelut numeroon ',
+ 'cq_IfQueueNotAnsweredRepeat' => 'Jos jonoa ei käsitelty peräkkäin ',
+ 'cq_ThisNumberIsNotFree' => 'Tämä numero on varattu',
+ 'cq_ValidateNameEmpty' => 'Anna jonon nimi',
+ 'cq_ValidateExtensionEmpty' => 'Jonon alanumeroa ei ole määritetty',
+ 'cq_ValidateExtensionDouble' => 'Tälle jonolle määritetty alanumero on jo käytössä',
+ 'cq_ValidateExtensionNumber' => 'Alanumerossa saa olla vain numeroita',
+ 'cq_ValidateNoExtensions' => 'Jonon jäseniä ei ole valittu',
+ 'cq_CallerIDPrefix' => 'Jonon lyhyt nimi, joka näytetään ennen tilaajan soittajatunnusta, esimerkiksi "Myynti"',
+ 'er_UnauthorizedDescription' => 'Sinulla ei ole pääsyä tälle sivulle.',
+ 'er_PageNotFound' => 'Sivua ei löydy',
+ 'er_PageNotFoundDescription' => 'Tätä sivua ei ole olemassa.',
+ 'er_InternalServerError' => 'Sisäinen palvelinvirhe',
+ 'ex_CallRecording' => 'Keskustelujen tallentaminen',
+ 'ex_ValidateRingingBeforeForwardOutOfRange' => 'Reititysasetukset osoittavat, että aika ennen siirtoa on virheellinen. Valitse arvo väliltä {ruleValue}.',
+ 'ex_ValidateNumberIsEmpty' => 'Työntekijän sisäistä numeroa ei täytetty',
+ 'tf_ActionPlayMessage' => 'Toista tiedosto %message%',
+ 'tf_ActionTransferToExtension' => 'Siirrä puhelu numeroon %extension%',
+ 'tf_TableColumnDatePeriod' => 'Kausi',
+ 'tf_TableColumnTimePeriod' => 'Aika',
+ 'tf_TableColumnWeekDaysPeriod' => 'Viikon päivät',
+ 'tf_TableColumnAction' => 'Toiminta',
+ 'tf_AllowRestriction' => 'Käytä vain tiettyjä saapuvia reittejä',
+ 'tf_Description' => 'Kommentti',
+ 'tf_SelectActionPlayMessage' => 'Toista äänitiedosto',
+ 'tf_SelectActionRedirectToExtension' => 'Siirrä puhelu',
+ 'tf_SelectAudioMessage' => 'Valitse äänitiedosto',
+ 'tf_SelectExtension' => 'Valitse alaliittymän numero',
+ 'tf_ValidateCheckDateInterval' => 'Tarkista ajanjakso',
+ 'fw_sipDescription' => 'SIP & RTP - puhelimen rekisteröinti ja puheliikenne',
+ 'fw_iaxDescription' => 'IAX - puhelimen rekisteröinti ja puheliikenne',
+ 'mo_NewElementExtensions' => 'Uusi työntekijä',
+ 'mo_NewElementCallQueues' => 'Uusi soittojono',
+ 'mo_NewElementIvrMenu' => 'Uusi IVR-valikko',
+ 'mo_NewElementConferenceRooms' => 'Uusi kokoushuone',
+ 'mo_NewElementIax' => 'Uusi IAX-toimittaja',
+ 'gs_SetPassword' => 'Aseta uusi salasana',
+ 'gs_RedirectToHttps' => 'Ohjaa HTTPS:ään',
+ 'ts_ManualAdjustDateTime' => 'Säädä aika manuaalisesti',
+ 'ts_CurrentSystemTime' => 'Nykyinen aika',
+ 'ts_NTPServer' => 'NTP-palvelimet',
+ 'ts_ValidateDateTime' => 'Väärä päivämäärä',
+ 'ms_SMTPSettings' => 'Viestien lähetysasetukset',
+ 'ms_NotificationTemplatesMissed' => 'Malli - vastaamattomat puhelut',
+ 'ms_NotificationTemplatesVoicemail' => 'Malli - vastaaja',
+ 'ms_SMTPHost' => 'SMTP-isäntä',
+ 'ms_SMTPPort' => 'SMTP-portti',
+ 'ms_SMTPUsername' => 'SMTP-kirjautuminen',
+ 'ms_SMTPPassword' => 'SMTP-salasana',
+ 'ms_SMTPSenderAddress' => 'Lähettäjän osoite',
+ 'ms_SMTPFromUsername' => 'Lähettäjän nimi',
+ 'ms_SMTPUseTLS' => 'Käytä TLS:ää',
+ 'ms_SMTPCertCheck' => 'Tarkista palvelimen varmenne',
+ 'ms_MailEnableNotifications' => 'Käytä hälytyksiä',
+ 'iv_TimeoutToRedirect' => 'Alaliittymän numeron syöttämisen odottamisen aikakatkaisu, jonka jälkeen äänitervehdys toistetaan',
+ 'iv_AllowEnterAnyInternalExtension' => 'Salli minkä tahansa sisäisen numeron lisävalinta',
+ 'cr_ColumnName' => 'Nimi',
+ 'cr_Name' => 'Kokoushuoneen nimi',
+ 'repFirewallRules' => 'Palomuurisääntö - %represent%',
+ 'repIax' => 'IAX-tili – %represent%',
+ 'repIncomingRoutingTable' => '%represent%',
+ 'repIncomingRoutingTableNumber' => 'Saapuvien viestien käsittelysääntö - N%represent%',
+ 'repLanInterfaces' => 'Järjestelmätiedosto - %represent%',
+ 'repNetworkFilters' => 'Viivasuodatin - %represent%',
+ 'repOutgoingRoutingTable' => '%represent%',
+ 'repOutgoingRoutingTableNumber' => 'Lähtevän postin käsittelysääntö - N%represent%',
+ 'repOutWorkTimes' => 'Tuntien jälkeen – %represent%',
+ 'repPbxSettings' => 'Asemaasetukset - %represent%',
+ 'repSip' => 'SIP-tili - %represent%',
+ 'lic_ActivateCouponButton' => 'Aktivoi kuponki',
+ 'lic_RegisterTheSystemButton' => 'Rekisteröidy',
+ 'lic_SaveLicenseKeyButton' => 'Tallenna avain',
+ 'lic_GetTrialErrorCheckInternet' => 'Rekisteröinti epäonnistui, tarkista Internetin saatavuus MikoPBX:stä',
+ 'ex_Japanese' => '日本語',
+ 'ex_Deutsch' => 'Deutsch',
+ 'ex_Spanish' => 'Espanol',
+ 'ex_French' => 'Le français',
+ 'ex_PortugueseBrazil' => 'Portugali (Brasilia)',
+ 'ex_Vietnamese' => 'Tiếng việt',
+ 'ex_Chinese' => '中国人',
+ 'ex_Dutch' => 'Alankomaat',
+ 'ex_Georgian' => 'ქართველი',
+ 'January' => 'tammikuu',
+ 'February' => 'helmikuu',
+ 'July' => 'heinäkuu',
+ 'August' => 'elokuu',
+ 'September' => 'syyskuu',
+ 'October' => 'lokakuu',
+ 'November' => 'marraskuu',
+ 'December' => 'joulukuu',
+ 'Feb' => 'helmikuuta',
+ 'Mar' => 'maaliskuu',
+ 'Apr' => 'huhtikuu',
+ 'Jun' => 'kesäkuuta',
+ 'Jul' => 'heinäkuuta',
+ 'Aug' => 'elokuu',
+ 'Sep' => 'syyskuu',
+ 'Oct' => 'lokakuu',
+ 'Nov' => 'marraskuu',
+ 'Dec' => 'joulukuuta',
+ 'ShortDayMonday' => 'ma',
+ 'ShortDayTuesday' => 'W',
+ 'ShortDayWednesday' => 'ke',
+ 'ShortDayThursday' => 'to',
+ 'ShortDayFriday' => 'pe',
+ 'ShortDaySaturday' => 'la',
+ 'Today' => 'Tänään',
+ 'Now' => 'Nyt',
+ 'MetaTegHeadDescription' => 'Yrityspuhelinjärjestelmä',
+ 'Loading' => 'Ladataan',
+ 'qf_Qualify' => 'Tuki NAT-istuntoon',
+ 'qf_Frequency' => 'Lähetystaajuus sekunneissa:',
+ 'qf_QualifyInstructions' => 'Kun tämä vaihtoehto on käytössä, MikoPBX lähettää SIP OPTIONS -paketteja määritetyllä taajuudella. Tämä on tarpeen NAT-tunneloinnin tukemiseksi reitittimessäsi.',
+ 'AdvancedOptions' => 'Lisäasetukset',
+ 'ConnectionSettings' => 'Yhteysasetukset',
+ 'BreadcrumbAdminCabinet' => 'Hallinnollinen käyttöliittymä',
+ 'BreadcrumbPBXCoreREST' => 'REST API',
+ 'BreadcrumbHome' => 'Alkuun',
+ 'BreadcrumbProviders' => 'Puhelinpalvelujen tarjoajat',
+ 'SubHeaderProviders' => 'Tilien perustaminen ulkoisten saapuvien ja lähtevien yhteyksien järjestämistä varten',
+ 'BreadcrumbAsteriskManagers' => 'Asterisk Manager Interface (AMI)',
+ 'SubHeaderAsteriskManagers' => 'Aseman AMI-rajapinnan käyttöoikeuksien asettaminen',
+ 'BreadcrumbAsteriskManagersmodify' => 'Tilin asetukset',
+ 'BreadcrumbProvidersmodifysip' => 'SIP-palveluntarjoajan määrittäminen',
+ 'BreadcrumbProvidersmodifyiax' => 'IAX-palveluntarjoajan määrittäminen',
+ 'SubHeaderTimeSettings' => 'Kellon ja kalenterin asettaminen',
+ 'BreadcrumbMailSettings' => 'Sähköpostiasetukset',
+ 'lic_FailedCheckLicense' => 'Lisenssipalvelin ei vastannut, tarkista Internet-asetukset',
+ 'SubHeaderMailSettings' => 'Sähköpostipalvelimen määrittäminen lähettämään ilmoituksia käyttäjille ja järjestelmänvalvojille',
+ 'BreadcrumbNetwork' => 'Verkkoasetukset',
+ 'SubHeaderNetwork' => 'Verkkokorttien määrittäminen (DHCP, DNS, GATEWAY, VLAN)',
+ 'BreadcrumbModify' => 'Säännön määrittäminen',
+ 'BreadcrumbOutboundRoutes' => 'Lähtevän liikenteen reititys',
+ 'SubHeaderOutboundRoutes' => 'Säännöt ja mallit puheluiden jakamiseen palveluntarjoajien kautta',
+ 'BreadcrumbOutboundRoutesmodify' => 'Säännön määrittäminen',
+ 'BreadcrumbIncomingRoutes' => 'Saapuvan reitityksen',
+ 'SubHeaderIncomingRoutes' => 'Säännöt ja mallit saapuvien puheluiden jakamiseen',
+ 'BreadcrumbIncomingRoutesmodify' => 'Säännön määrittäminen',
+ 'BreadcrumbExtensions' => 'Työntekijät',
+ 'SubHeaderExtensions' => 'Ensisijaisten puhelinnumeroiden ja henkilökohtaisten edelleenlähetyssääntöjen määrittäminen',
+ 'BreadcrumbExtensionsmodify' => 'Asetusten muuttaminen',
+ 'BreadcrumbCallQueues' => 'Puhelujonot',
+ 'lic_NoInetHeader' => 'Ei pääsyä lisenssipalvelimeen.',
+ 'lic_GeneralError' => 'Virhe yritettäessä aktivoida lisenssiä',
+ 'lic_HostLookupFailed' => 'Ei yhteyttä lisenssipalvelimeen, DNS-ongelma',
+ 'er_Home' => 'Siirry alkuun',
+ 'rs_RestartPhoneSystem' => 'Käynnistä MikoPBX uudelleen',
+ 'rs_ShutDownPhoneSystem' => 'Sammuta MikoPBX',
+ 'auth_ValidatePasswordNotEmpty' => 'Kirjoita salasanasi',
+ 'auth_ValidateLoginNotEmpty' => 'Anna kirjautumistunnuksesi',
+ 'auth_SubmitButton' => 'Kirjaudu sisään',
+ 'auth_WrongLoginPassword' => 'Valtuutus epäonnistui, sinulla on %attempts% yritystä jäljellä',
+ 'auth_TooManyLoginAttempts' => 'Liian monta kirjautumisyritystä. IP-osoitteesi on estetty %interval% sekunniksi.',
+ 'log_StartCapturePCAP' => 'Aloita',
+ 'f2b_Jail_asterisk_error_v2' => 'SIP-valtuutusvirheet (virhe)',
+ 'upd_Update' => 'Päivittää',
+ 'ext_TableColumnDeveloper' => 'Kehittäjä',
+ 'ext_ModuleChangedObjects' => 'Seuraavat kohteet on muutettu',
+ 'ext_DeleteTitle' => 'Laajennusmoduulin poistaminen',
+ 'ext_DeleteDescription' => 'Ennen moduulin poistamista se tarkistaa ristiviittaukset muiden moduulien ja järjestelmäasetusten välillä.',
+ 'ext_KeepModuleSettings' => 'Tallenna nykyiset moduuliasetukset',
+ 'ext_Cancel' => 'Peruuttaa',
+ 'ext_Version' => 'Versio',
+ 'ext_InstallModuleShort' => 'Asentaa',
+ 'ext_InstallUpdateAction' => 'Suorittaa',
+ 'adv_StorageDiskUnMounted' => 'Asetusten ja tietojen tallennuslevyä ei ole kytketty!',
+ 'cal_Today' => 'Tänään',
+ 'SubHeaderOutOffWorkTime' => 'Aseman toiminnan säännöt aukioloaikojen, pyhäpäivien ja viikonloppujen jälkeen',
+ 'BreadcrumbOutOffWorkTimemodify' => 'Säännön määrittäminen',
+ 'lic_MarketplaceText' => 'Rekisteröitymällä Marketplaceen saat käyttöösi lisämoduuleja ja laajennuksia.
On olemassa ilmaisia moduuleja, jotka olemme poistaneet perustoiminnoista alkuasennuksen yksinkertaistamiseksi, sekä maksullisia moduuleja meiltä ja muilta kehittäjiltä.
Jos olet kehittäjä, voit ottaa yhteyttä ottaa meihin yhteyttä saadaksesi ohjeet oman moduulin kehittämiseen ja sen lisäämiseen Marketplaceen.',
+ 'lic_LastQuestionAnswer' => 'Lisenssiin liittyviä usein kysyttyjä kysymyksiä löytyy osoitteesta osoitteessa .',
+ 'lic_NoInet' => 'Ehkä MikoPBX-palvelimelta ei ole Internet-yhteyttä',
+ 'lic_NoInetLicMiko' => 'Mahdollisesti rajoitettu pääsy resurssiin lic.mikopbx.com',
+ 'lic_NoInetNetSettings' => "Tarkista DNS- ja Gateway-asetukset verkkoasetuksista",
+ 'lic_ReloadPage' => 'Päivitä sivu…',
+ 'lic_LicenseProblem' => 'Ongelma Marketplacen rekisteröinnissä',
+ 'lic_ManageLicense' => 'Voit hallita lisenssiäsi, nollata sidoksia ja analysoida ongelmia siirtymällä verkkosivustolle ',
+ 'lic_ManageLicenseKeyOnSitePreLinkText' => 'Hallitse lisenssiä nollaamalla isäntäsidokset ja tarkastelemalla tilastoja',
+ 'lic_ManageLicenseKeyOnSiteLinkText' => 'seuraa linkkiä',
+ 'lic_ManageLicenseKey' => 'Lisenssien hallinta',
+ 'rs_CurrentCalls' => 'Aktiiviset puhelut',
+ 'rs_DateCall' => 'aloituspäivämäärä',
+ 'rs_Src' => 'WHO',
+ 'rs_Dst' => 'Kenelle',
+ 'rs_ShutdownRebootMessage' => 'Kun käynnistetään uudelleen tai sammutetaan, kaikki käynnissä olevat puhelut keskeytyvät.',
+ 'auth_Login' => 'Kirjaudu sisään',
+ 'auth_Password' => 'Salasana',
+ 'auth_RememberMe' => 'Muista minut',
+ 'auth_DefaultCloudPasswordInstructions' => 'Oletussalasana on sama kuin pilvessä olevan virtuaalikoneen yksilöllinen tunniste',
+ 'log_CaptureMessage' => 'Aloita verkkopakettien kerääminen ja soita puhelu tai muu toiminta, joka aiheuttaa epäonnistumisen.
+
Järjestelmä tallentaa kaikki tällä hetkellä verkkokortin läpi kulkevat paketit lisäanalyysiä varten.',
+ 'log_StopCapturePCAP' => 'Pysäytä ja lataa',
+ 'log_DownloadLogs' => 'Lataa kaikki järjestelmälokit',
+ 'dbg_NoDebugInformation' => 'Ei tietoa',
+ 'dbg_Header' => 'Virheenkorjaustiedot',
+];
diff --git a/src/Common/Messages/fr.php b/src/Common/Messages/fr.php
index 529625e53..29ab2694b 100644
--- a/src/Common/Messages/fr.php
+++ b/src/Common/Messages/fr.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo2' => 'Si le NAT 1:1 n\'est pas utilisé, redirigez les ports suivants de l\'adresse IP publique vers l\'adresse IP interne du PBX dans les paramètres de votre routeur.',
'nw_NATInfo3' => '%SIP_PORT% TCP/UDP et %TLS_PORT% TCP',
'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO%UDP',
+ 'gs_ErrorSaveSettings' => 'Erreur lors de l\'enregistrement des paramètres',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Le numéro de poste spécifié est déjà utilisé',
+ 'fw_iaxDescription' => 'IAX - enregistrement téléphonique et trafic vocal',
];
diff --git a/src/Common/Messages/hu.php b/src/Common/Messages/hu.php
new file mode 100644
index 000000000..11d77cd76
--- /dev/null
+++ b/src/Common/Messages/hu.php
@@ -0,0 +1,1237 @@
+ 'NAT mód',
+ 'ext_Available' => '-re frissíthető',
+ 'ext_InstallModule' => 'Modul telepítése',
+ 'ext_FreeModule' => 'Ingyenes modul',
+ 'gs_PBXName' => 'PBX rendszernév',
+ 'mo_ApplicationShort4Dropdown' => 'Alkalmazás',
+ 'mo_IVRMenuShort4Dropdown' => 'IVR menü',
+ 'mo_ModuleShort4Dropdown' => 'Modul',
+ 'lic_ReloadPage' => 'Frissítsd az oldalt…',
+ 'auth_ValidateLoginNotEmpty' => 'Adja meg a bejelentkezést',
+ 'auth_SubmitButton' => 'Belépés',
+ 'auth_WrongLoginPassword' => 'Az engedélyezés nem sikerült, még %attempts% próbálkozása van hátra',
+ 'BreadcrumbFirewallmodify' => 'Szabály felállítása',
+ 'SubHeaderFirewall' => 'Az állomáshoz való hozzáférés korlátozása forgalomtípus és alhálózatok szerint',
+ 'BreadcrumbGeneralSettings' => 'Rendszerbeállítások',
+ 'bt_ToolTipUpgradeOnline' => 'Frissítés online',
+ 'ms_SuccessfulSaved' => 'A beállítások elmentve',
+ 'ms_SuccessfulDeleted' => 'Adatok törölve',
+ 'Codecs' => 'Kodekek',
+ 'sip_registration_type' => 'Fiók Típus',
+ 'sip_REG_TYPE_OUTBOUND' => 'Kimenő regisztráció',
+ 'sip_REG_TYPE_INBOUND' => 'Bejövő regisztráció',
+ 'gs_CallRecordTab' => 'Beszélgetések rögzítése',
+ 'ex_ManualAdditionalAttributes' => 'Extra lehetőségek',
+ 'ex_SecondsAndThenRedirectCallTo' => 'Másodpercig próbáljuk hívni a fő számot, majd áttérünk a számra',
+ 'ext_ShowModuleItemAtMainMenu' => 'Modul megjelenítése az oldalmenüben',
+ 'ext_Marketplace' => 'Piactér',
+ 'ext_ModuleLicenseProblem' => 'Probléma a bővítőmodul licencével',
+ 'ex_PortugueseBrazil' => 'Portugália (Brazília)',
+ 'ex_Vietnamese' => 'Tiếng việt',
+ 'ex_Chinese' => '中国人',
+ 'May' => 'Lehet',
+ 'June' => 'június',
+ 'July' => 'július',
+ 'August' => 'augusztus',
+ 'September' => 'szeptember',
+ 'ShortDayTuesday' => 'W',
+ 'Now' => 'Most',
+ 'ex_dropdownCategory_CALLQUEUES' => 'Hívási sorok',
+ 'tf_WeekDaysFrom' => 'A hét napjai',
+ 'tf_TimePeriodFrom' => 'Időtartam',
+ 'tf_PeriodAction' => 'Bejövő hívás művelet',
+ 'tf_AllowRestriction' => 'Csak meghatározott bejövő útvonalakra vonatkozik',
+ 'tf_Description' => 'Egy komment',
+ 'tf_SelectActionPlayMessage' => 'Hangfájl lejátszása',
+ 'tf_SelectActionRedirectToExtension' => 'Hívás átadása',
+ 'tf_SelectAudioMessage' => 'Válassza ki a hangfájlt',
+ 'tf_SelectExtension' => 'Válassza ki a mellékállomás számát',
+ 'gs_PBXDescription' => 'További leírás',
+ 'gs_NeedRestartPBX' => 'A módosítás után a csillag szolgáltatás újraindul',
+ 'gs_PBXLanguage' => 'A rendszer hangjának nyelve',
+ 'gs_PBXInternalExtensionLength' => 'A belső számok maximális hossza',
+ 'f2b_BanedTime' => 'dátum',
+ 'f2b_TableBannedHeader' => 'Letiltott címek',
+ 'f2b_Unban' => 'Blokkolás feloldása',
+ 'BreadcrumbHome' => 'Az elejére',
+ 'BreadcrumbProvidersmodifysip' => 'SIP-szolgáltató beállítása',
+ 'mm_CustomFiles' => 'A rendszerfájlok testreszabása',
+ 'bt_Delete' => 'Töröl',
+ 'bt_SaveSettings' => 'Megment',
+ 'bt_SaveSettingsAndAddNew' => 'Mentse el és adja hozzá',
+ 'bt_SaveSettingsAndExit' => 'Mentés és bezárás',
+ 'bt_ApplyChangesToPBX' => 'Módosítások elfogadása',
+ 'bt_BackToList' => 'Vissza a listához',
+ 'pr_RedefinitionFromUser' => 'A "From" SIP-fejléc újradefiniálása',
+ 'pr_FromUser_v2' => 'Felhasználó',
+ 'pr_ValidationProviderNameIsEmpty' => 'Írja be a szolgáltató nevét',
+ 'pr_DisableFromUser' => 'Tiltsa le a fromuser mező használatát',
+ 'pr_TableColumnProviderLogin' => 'Belépés',
+ 'pr_TableColumnProviderHostName' => 'Házigazda',
+ 'gs_UseWebRTC' => 'Használja a WebRTC-t',
+ 'gs_Store1MonthOfRecords' => '1 hónap',
+ 'gs_Store3MonthsOfRecords' => '3 hónap',
+ 'pr_DeleteDescription_v2' => 'A szolgáltatóval együtt az összes kapcsolódó kimenő útválasztási szabály törlődik, és a bejövő forgalomirányítási szabályokban az összes hivatkozás helyére a „Nincs kapcsolat a szolgáltatóhoz, nincs jogosultság” szövegre.',
+ 'gs_PBXRecordCalls' => 'Beszélgetések rögzítése',
+ 'gs_PBXRecordCallsInner' => 'Belső beszélgetések rögzítése',
+ 'gs_RestartEveryNight' => 'Indítsa újra az alközpontot minden este',
+ 'gs_PBXCallParkingExt' => 'Hívja a Park számát',
+ 'gs_PBXCallParkingSlotRange' => 'Parkolóhelyek választéka',
+ 'gs_PBXFeatureAttendedTransfer' => 'Tanácsadó fordítási kombináció',
+ 'gs_PBXFeatureBlindTransfer' => 'Kombináció a feltétel nélküli átvitelhez',
+ 'mo_SystemExten_busy' => 'Foglalt hang lejátszása',
+ 'cal_ThisMonth' => 'Jelenlegi hónap',
+ 'cal_LastMonth' => 'Múlt hónap',
+ 'cal_ApplyBtn' => 'Alkalmaz',
+ 'cal_CancelBtn' => 'Megszünteti',
+ 'cal_from' => 'Val vel',
+ 'f2b_Jail_asterisk_ami_v2' => 'AMI vagy AJAM engedélyezési hibák',
+ 'f2b_Jail_asterisk_v2' => 'SIP hitelesítési hibák',
+ 'f2b_Jail_asterisk_security_log_v2' => 'SIP engedélyezési hibák (security_log)',
+ 'f2b_Jail_asterisk_error_v2' => 'SIP engedélyezési hibák (hiba)',
+ 'cal_to' => 'Által',
+ 'ir_hangup' => 'Tedd le a telefont',
+ 'ir_Extension' => 'szám',
+ 'cal_CustomPeriod' => 'Tetszőleges',
+ 'sntry_Title' => 'Valami elromlott!',
+ 'sntry_Subtitle' => 'A hibát jelezték a fejlesztőnek.',
+ 'sntry_Subtitle2' => 'Kérjük, írja le azokat a lépéseket, amelyek ehhez a hibához vezettek.',
+ 'sntry_LabelComments' => 'Mit csináltál?',
+ 'cq_StaticAgents' => 'Résztvevők',
+ 'gs_WEBHTTPSPublicKey' => 'HTTPs nyilvános kulcs',
+ 'gs_ValidateEmptyPBXName' => 'Az állomás neve nincs megadva',
+ 'gs_TwoDigthts' => '2 számjegy',
+ 'gs_ThreeDigthts' => '3 számjegy',
+ 'gs_FourDigthts' => '4 számjegy',
+ 'cq_AddQueueMembers' => 'Nincsenek kiválasztva operátorok',
+ 'gs_FiveDigthts' => '5 számjegy',
+ 'gs_SixDigthts' => '6 szám',
+ 'gs_SevenDigthts' => '7 számjegy',
+ 'gs_ElevenDigthts' => '11 számjegy',
+ 'gs_WebAdminLogin' => 'Belépés',
+ 'gs_WebAdminPassword' => 'Jelszó',
+ 'gs_WebAdminPasswordRepeat' => 'Írja be újra a jelszavát',
+ 'sntry_LabelClose' => 'Bezárás',
+ 'sntry_LabelSubmit' => 'Küld',
+ 'gs_SSHPasswordRepeat' => 'Írja be újra a jelszavát',
+ 'gs_Passwords' => 'WEB interfész jelszó',
+ 'gs_DefaultPasswordWarning' => 'Ne használja a szokásos rendszergazdai bejelentkezést és jelszót',
+ 'gs_ValidateEmptyWebPassword' => 'Az adminisztrátori jelszó nem lehet üres',
+ 'gs_ValidateWeakWebPassword' => 'A WEB jelszónak 4 karakternél hosszabbnak kell lennie',
+ 'gs_ValidateWebPasswordsFieldDifferent' => 'A webes felület jelszava helytelenül lett megadva',
+ 'ms_SMTPPassword' => 'SMTP jelszó',
+ 'ms_SMTPSenderAddress' => 'A feladó címe',
+ 'ms_SMTPFromUsername' => 'Küldő neve',
+ 'ms_SMTPUseTLS' => 'Használja a TLS-t',
+ 'ms_SMTPCertCheck' => 'Ellenőrizze a kiszolgáló tanúsítványát',
+ 'ms_MailEnableNotifications' => 'Figyelmeztetések használata',
+ 'ex_ThisUserIdNotExistInUsersModel' => 'Ez a felhasználó nem létezik',
+ 'ex_ThisNumberNotExistInSipModel' => 'Ez a szám nem rendelkezik a megfelelő SIP-beállításokkal',
+ 'ex_NoNetworkFilter' => 'Bármilyen címről engedélyezett a csatlakozás',
+ 'ex_PermitNetwork' => 'Engedélyezett hálózat',
+ 'ex_Username' => 'A felhasználó teljes neve',
+ 'ex_EmailAddress' => 'Email cím',
+ 'ex_ThisEmailAlreadyRegisteredForOtherUser' => 'A megadott cím már regisztrálva van',
+ 'ex_Language' => 'Interfész és értesítési nyelv',
+ 'ex_Number' => 'Mellék számát',
+ 'ex_RingMainExtension' => 'Alatt',
+ 'ex_IfMainExtensionIsBusyRedirectCallTo' => 'Ha a fő szám foglalt, átirányítjuk a hívást a számra',
+ 'ex_IfMainExtensionIsUnavailableRedirectCallTo' => 'Ha a fő szám nem elérhető, átirányítjuk a hívást a számra',
+ 'ex_ValidateMobileIsNotCorrect' => 'Ellenőrizze, hogy helyesen adta-e meg mobilszámát',
+ 'ex_Name' => 'Munkavállaló',
+ 'f2b_Jail_asterisk_public_v2' => 'SIP engedélyezési hibák (nyilvános)',
+ 'ex_Offline' => 'Tiltva',
+ 'tf_TableColumnAction' => 'Akció',
+ 'tf_ValidateCheckWeekDayInterval' => 'Ellenőrizze a hét napjait',
+ 'fw_ValidateRuleName' => 'Adjon nevet az alhálózatnak',
+ 'nw_DNSAddresses' => 'DNS szerver címek',
+ 'nw_PublicAddress' => 'Az útválasztó külső IP-címe',
+ 'nw_InternetInterface' => 'Hálózati interfész Internet hozzáféréssel',
+ 'nw_NetworkInterfaces' => 'Hálózati interfészek',
+ 'nw_InterfaceName' => 'Név',
+ 'nw_SelectInterface' => 'Válassza ki a hálózati interfészt',
+ 'nw_AllowNatPortForwarding' => 'Ez az állomás egy NAT router mögött található',
+ 'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO% UDP',
+ 'repFail2BanRules' => 'Fail2Ban szabály – %represent%',
+ 'repFirewallRules' => 'Tűzfalszabály – %represent%',
+ 'repIax' => 'IAX-fiók – %represent%',
+ 'repIncomingRoutingTable' => '%represent%',
+ 'repIncomingRoutingTableNumber' => 'Bejövő feldolgozási szabály – N%represent%',
+ 'repLanInterfaces' => 'Rendszerfájl – %represent%',
+ 'repNetworkFilters' => 'Vonalszűrő – %represent%',
+ 'repOutgoingRoutingTable' => '%represent%',
+ 'repOutgoingRoutingTableNumber' => 'Kimenő feldolgozási szabály – N%represent%',
+ 'repOutWorkTimes' => 'Nyitvatartás után – %represent%',
+ 'repPbxSettings' => 'Állomásbeállítások - %represent%',
+ 'repSip' => 'SIP-fiók – %represent%',
+ 'repSoundFiles' => 'Hangfájl - %represent%',
+ 'repIvrMenu' => 'IVR menü – %represent%',
+ 'f2b_Jail_dropbear' => 'SSH munkamenet engedélyezési hibák',
+ 'f2b_Jail_mikopbx-www' => 'Engedélyezési hibák az alközpont adminisztrációs felületén',
+ 'f2b_WhiteList' => 'A soha nem blokkolt címek listája',
+ 'f2b_MaxRetry' => 'A blokkolás előtti próbálkozások száma',
+ 'f2b_FindTime' => 'Másodperceken belül)',
+ 'f2b_BanTime' => 'Letiltás (másodperc)',
+ 'gs_SSHecdsaKey' => 'SSH ECDSA kulcs',
+ 'gs_SSHRsaKey' => 'SSH RSA kulcs',
+ 'gs_SSHDssKey' => 'SSH DSS kulcs',
+ 'gs_RedirectToHttps' => 'Átirányítás HTTPS-re',
+ 'gs_CodecsOrder' => 'Codec prioritás',
+ 'gs_DangerZone' => 'Rendszerbeállítások eltávolítása',
+ 'gs_RestoreAllSettingsHeader' => 'Figyelem!',
+ 'gs_EnterDeleteAllPhrase' => 'törölj mindent',
+ 'gs_AllSettingsDeleted' => 'Minden beállítás törlődik',
+ 'gs_PBXRecordAnnouncementIn' => 'Válassza ki a hívásrögzítési figyelmeztetést a bejövő hívásokhoz',
+ 'da_Type' => 'Kód típusa',
+ 'da_ColumnExtension' => 'Szám',
+ 'sf_StartRecordSoundFileButton' => 'Felvétel megkezdése',
+ 'sf_StopRecordSoundFileButton' => 'Állj meg',
+ 'sf_ColumnFile' => 'Név',
+ 'sf_ColumnPlayer' => 'Játékos',
+ 'sf_AddNewSoundFile' => 'Új hangfájl hozzáadása',
+ 'sf_UploadError' => 'Hiba az audiofájl betöltésekor',
+ 'lic_ValidateCompanyNameEmpty' => 'A kötelező mező nincs kitöltve - cégnév',
+ 'lic_ValidateLicenseKeyEmpty' => 'A kötelező mező nincs kitöltve - Licenckulcs',
+ 'mo_SystemExten_hangup' => 'Hívás befejezése',
+ 'pass_CheckSSHPasswordEmpty' => 'A mező üres: SSH',
+ 'pass_CheckSSHPasswordSimple' => 'Az SSH jelszó túl egyszerű.',
+ 'adv_ThisCopyIsNotRegistered' => 'A program ezen példánya nem licencelt – Ingyenes aktiválás',
+ 'cal_Today' => 'Ma',
+ 'disable' => 'letiltása',
+ 'Error resetting password.' => "Jelszó visszaállítási hiba",
+ 'sd_ToolTipErase' => 'Fájl törlése',
+ 'ext_DeleteModuleError' => 'Hiba a modul eltávolításakor',
+ 'lic_LastQuestionAnswer' => 'A licencekkel kapcsolatos gyakran ismételt kérdések az címen, az címen találhatók.',
+ 'lic_NoInetHeader' => 'Nincs hozzáférés a licencszerverhez.',
+ 'lic_NoInet' => 'Talán nincs internet-hozzáférés a MikoPBX szerverről',
+ 'lic_NoInetLicMiko' => 'Valószínűleg korlátozott hozzáférés az erőforráshoz lic.mikopbx.com',
+ 'lic_NoInetNetSettings' => "Ellenőrizze a DNS és az Gateway beállításait a hálózati beállításokban",
+ 'lic_LicenseProblem' => 'Probléma a Marketplace regisztrációjával',
+ 'lic_ManageLicense' => 'A licenc kezeléséhez, a kötések visszaállításához és a problémák elemzéséhez látogasson el a webhelyre ',
+ 'lic_ManageLicenseKeyOnSitePreLinkText' => 'A licenc kezeléséhez állítsa vissza a gazdagép-összerendeléseket, tekintse meg a statisztikákat',
+ 'lic_ManageLicenseKeyOnSiteLinkText' => 'link',
+ 'lic_ManageLicenseKey' => 'Licenckezelés',
+ 'lic_GeneralError' => 'Hiba történt a licenc aktiválásakor',
+ 'lic_HostLookupFailed' => 'Nincs kapcsolat a licencszerverrel, DNS probléma',
+ 'er_Home' => 'Ugrás a tetejére',
+ 'rs_RestartPhoneSystem' => 'Indítsa újra a MikoPBX-et',
+ 'rs_ShutDownPhoneSystem' => 'Kapcsolja ki a MikoPBX-et',
+ 'rs_CurrentCalls' => 'Aktív hívások',
+ 'rs_DateCall' => 'kezdő dátum',
+ 'rs_Src' => 'WHO',
+ 'rs_Dst' => 'Kinek',
+ 'rs_ShutdownRebootMessage' => 'Újraindításkor vagy leállításkor minden folyamatban lévő hívás megszakad.',
+ 'auth_Login' => 'Belépés',
+ 'auth_Password' => 'Jelszó',
+ 'auth_ValidatePasswordNotEmpty' => 'írd be a jelszót',
+ 'auth_TooManyLoginAttempts' => 'Túl sok bejelentkezési kísérlet. Az Ön IP-címe %interval% másodpercig blokkolva van.',
+ 'auth_RememberMe' => 'Emlékezz rám',
+ 'auth_DefaultCloudPasswordInstructions' => 'Az alapértelmezett jelszó megegyezik a felhőben lévő virtuális gép egyedi azonosítójával',
+ 'log_CaptureMessage' => 'Kezdje el gyűjteni a hálózati csomagokat, és indítson hívást vagy más műveletet, amely a hibát okozza.
+
A rendszer elmenti a hálózati kártyán jelenleg áthaladó összes csomagot további elemzés céljából.',
+ 'log_StartCapturePCAP' => 'Rajt',
+ 'log_StopCapturePCAP' => 'Állj le és töltsd le',
+ 'log_DownloadLogs' => 'Töltse le az összes rendszernaplót',
+ 'dbg_NoDebugInformation' => 'Nincs információ',
+ 'dbg_Header' => 'Hibakeresési információk',
+ 'f2b_Reason' => 'Ok',
+ 'f2b_IpAddres' => 'IP-cím',
+ 'f2b_Fail2BanSwitch' => 'Használja a Fail2Ban aktív blokkoló rendszert',
+ 'f2b_ValidateMaxRetryRange' => 'A kísérletek számának paramétere nincs megfelelően beállítva',
+ 'f2b_ValidateFindTimeRange' => 'Az engedélyezési kísérletek elemzési időszaka nincs megfelelően beállítva',
+ 'f2b_ValidateBanTimeRange' => 'A blokkolási időszak helytelen',
+ 'f2b_TableBannedEmpty' => 'Nincs adat',
+ 'f2b_SettingsTabHeader' => 'A védelem beállítása',
+ 'f2b_BannedIpTabHeader' => 'Letiltott címek',
+ 'upd_FileName' => 'Válassza ki a frissítési fájlt',
+ 'upd_UpdateSystem' => 'Frissítés alkalmazása',
+ 'upd_VersionColumn' => 'Változat',
+ 'upd_DescriptionColumn' => 'Leírás',
+ 'upd_AvailableUpdates' => 'Online frissítések elérhetők',
+ 'upd_DownloadUpgradeError' => 'Hiba történt a frissítés letöltése során, próbálkozzon újra később',
+ 'upd_UploadError' => 'Hiba a frissítés letöltése közben',
+ 'upd_UpdateTitle' => 'PBX frissítés',
+ 'upd_Cancel' => 'Megszünteti',
+ 'upd_Update' => 'Frissítés',
+ 'upd_UploadInProgress' => 'A frissítési fájl letöltése folyamatban van…',
+ 'upd_UpgradeInProgress' => 'A rendszerfájlok frissítése folyamatban van…',
+ 'upd_UpgradeError' => 'Hiba történt a MikoPBX frissítésekor',
+ 'upd_UpdateDescription' => 'A frissítés letöltése után a MikoPBX automatikusan újraindul, és minden aktuális hívás megszakad. Frissítés előtt mindenképpen készítsen biztonsági másolatot a MikoPBX-ről.',
+ 'upd_EnterIHaveBackupPhrasePreText' => 'A rendszer frissítéséhez írja be a következő kifejezést a beviteli mezőbe:',
+ 'upd_EnterIHaveBackupPhrase' => 'Igen van tartalékom',
+ 'upd_UpdateDockerHeader' => 'Tároló frissítési szabályok',
+ 'upd_UpdateDockerText' => 'Állítsa le a tárolót, törölje azt, töltse le a legújabb verziót, és indítsa újra, megőrizve a tárhely-beillesztési beállításokat és a környezeti változókat. A folyamatot részletesebben a dokumentáció írja le.',
+ 'ext_TableColumnDescription' => 'Modul neve',
+ 'ext_TableColumnDeveloper' => 'Fejlesztő',
+ 'ext_TableColumnVersion' => 'Változat',
+ 'ext_UpdateModule' => 'Modul frissítése',
+ 'ext_UpdateModuleError' => 'Hiba a modul telepítésekor',
+ 'ext_AvailableModules' => 'Modulok beépíthetők',
+ 'ext_ModuleDisabledStatusDisabled' => 'Modul letiltva',
+ 'ext_ModuleDisabledStatusEnabled' => 'Modul engedélyezve',
+ 'ext_ModuleStatusChanging' => 'Modulállapotok módosítása…',
+ 'ext_ModuleChangedObjects' => 'A következő objektumok módosultak',
+ 'ext_DeleteTitle' => 'Bővítő modul eltávolítása',
+ 'ext_DeleteDescription' => 'A modul törlése előtt ellenőrzi, hogy vannak-e kereszthivatkozások a többi modul és a rendszerbeállítások között.',
+ 'ext_KeepModuleSettings' => 'Mentse el az aktuális modulbeállításokat',
+ 'ext_Cancel' => 'Megszünteti',
+ 'ext_Delete' => 'Töröl',
+ 'ext_GetLinkError' => 'Hiba történt a modulelosztó készlet webhelyről történő fogadásakor. Kérlek, próbáld újra később.',
+ 'ext_NoLicenseAvailable' => 'Nincs engedély a modul telepítésére vagy frissítésére.',
+ 'ext_Version' => 'Változat',
+ 'ext_ValidateCaptionEmpty' => 'A menüelem neve üres',
+ 'ext_SelectMenuGroup' => 'Válasszon egy oldalmenüszakaszt',
+ 'ext_SettingsForModule' => 'Modul beállítások:',
+ 'ext_Caption' => 'A menüelem neve',
+ 'ext_AddNewExtension' => 'Új modul betöltése',
+ 'ext_CreateNewExtension' => 'Készítse el saját modulját',
+ 'ext_UploadError' => 'Modul letöltési hiba',
+ 'ext_UploadInProgress' => 'Modul betöltése…',
+ 'ext_InstallationInProgress' => 'Modul telepítése…',
+ 'ext_GetReleaseInProgress' => 'Adatkérés az adattárból…',
+ 'ext_DownloadInProgress' => 'Modul letöltése…',
+ 'ext_CheckLicenseInProgress' => 'A jogosítvány ellenőrzése…',
+ 'ext_ModuleChangeStatusError' => 'Problémák a modulállapot megváltoztatásakor',
+ 'ext_InstallationError' => 'Hiba a modul telepítésekor',
+ 'ext_InstalledModules' => 'Telepített modulok',
+ 'ext_Licensing' => 'Licenckezelés',
+ 'ext_NoAvailableModules' => 'Nincsenek telepíthető modulok',
+ 'ext_NoInstalledModules' => 'Nincsenek telepítve modulok',
+ 'ext_GoToMarketplace' => 'Menj a piactérre',
+ 'ext_GoToRegistration' => 'Regisztráció a piacon',
+ 'ext_LicenseProblemHeader' => 'Licenc probléma',
+ 'ext_ModuleDependsHigherVersion' => 'A modul telepítéséhez %version% vagy a MikoPBX újabb verziója szükséges',
+ 'ext_UninstallDBError' => 'Hiba a modul adatbázis törlésekor',
+ 'ext_UnInstallFiles' => 'Hiba a modulfájlok törlésekor',
+ 'ext_EmptyLicenseKey' => 'A modul licencének aktiválásához szükséges licenckulcs nincs telepítve',
+ 'ext_ErrorOnAppliesFilesRights' => 'Hiba a modulfájlokhoz való jogok hozzárendelése során',
+ 'ext_ErrorOnInstallDB' => 'Hiba a moduladatbázis beállítása közben',
+ 'ext_ErrorOnInstallFiles' => 'Hibák a modulfájlok másolásakor',
+ 'ext_ErrorOnLicenseActivation' => 'Hibák a licenc aktiválásakor',
+ 'ext_ErrorOnDecodeModuleJson' => 'Hiba a modul konfigurációs fájljának elemzésekor %filename%',
+ 'ext_ErrorOnEnableFirewallSettings' => 'Hiba a modul tűzfalbeállításainak engedélyezésekor',
+ 'ext_ErrorOnDisableFirewallSettings' => 'Hiba a modul tűzfalbeállításainak kizárásakor',
+ 'ext_ErrorOnModuleBeforeEnable' => 'Hibák annak ellenőrzése során, hogy a modul engedélyezhető-e',
+ 'ext_ErrorOnModuleBeforeDisable' => 'Hibák az ellenőrzés során, hogy a modul kikapcsolható-e',
+ 'ext_ModuleExecutionProblem' => 'Súlyos hiba történt:',
+ 'ext_DisableReasonHeader' => 'A modul automatikusan letiltásra került',
+ 'ext_UpdateAllModules' => 'Frissítse az összes telepített modult',
+ 'ext_EmptyRepoAnswer' => 'A modul telepítéséhez nem érhető el kiadás',
+ 'ext_ErrDownloadTimeout' => 'Nem sikerült letölteni a modul frissítését. Időtúllépés a működéshez.',
+ 'ext_ErrUploadTimeout' => 'Nem sikerült feltölteni a modulfájlt. Időtúllépés a működéshez.',
+ 'ext_ErrInstallationTimeout' => 'Nem sikerült telepíteni a modult. Időtúllépés a működéshez.',
+ 'ext_ModuleLastRelease' => 'Jelenlegi kiadás',
+ 'ext_ModulePublisher' => 'Fejlesztő',
+ 'ext_ModuleDescriptionTab' => 'Modul leírása',
+ 'ext_ModuleChangelogTab' => 'Verziótörténet',
+ 'ext_UsefulLinks' => 'Hasznos Linkek',
+ 'ext_ExternalDescription' => 'Részletes leírás, dokumentáció',
+ 'ext_CommercialModule' => 'Fizetett modul',
+ 'ext_InstallModuleShort' => 'Telepítés',
+ 'ext_UpdateModuleShort' => 'Frissítés',
+ 'ext_InstallModuleReleaseTag' => 'Kiadás',
+ 'ext_InstallModuleVersion' => 'Verzió telepítése',
+ 'ext_ShowModuleRepoDetails' => 'Nyissa meg a modul részletes leírását',
+ 'ext_ModuleEulaTab' => 'Licencszerződés',
+ 'ext_FromDate' => 'kiadták',
+ 'ext_InstallModuleTitle' => 'A modul telepítése',
+ 'ex_English' => 'angol',
+ 'ex_EnglishUK' => 'angol (UK)',
+ 'ex_Japanese' => '日本語',
+ 'ex_Deutsch' => 'Deutsch',
+ 'ex_Spanish' => 'Espanol',
+ 'ex_French' => 'Francia',
+ 'ex_Dutch' => 'Hollandia',
+ 'ex_Georgian' => 'ქართველი',
+ 'January' => 'január',
+ 'February' => 'február',
+ 'March' => 'március',
+ 'April' => 'április',
+ 'October' => 'október',
+ 'November' => 'november',
+ 'December' => 'december',
+ 'Jan' => 'jan',
+ 'Feb' => 'Február',
+ 'Mar' => 'márc',
+ 'Apr' => 'Április',
+ 'Jun' => 'Június',
+ 'Jul' => 'Július',
+ 'Aug' => 'Augusztus',
+ 'Sep' => 'szept',
+ 'Oct' => 'Október',
+ 'Nov' => 'De én',
+ 'Dec' => 'December',
+ 'ShortDaySunday' => 'Vos',
+ 'ShortDayMonday' => 'Hétfő',
+ 'ShortDayWednesday' => 'Házasodik',
+ 'ShortDayThursday' => 'cs',
+ 'ShortDayFriday' => 'Péntek',
+ 'ShortDaySaturday' => 'Ült',
+ 'Today' => 'Ma',
+ 'MetaTegHeadDescription' => 'Üzleti telefon rendszer',
+ 'Loading' => 'Betöltés',
+ 'qf_Qualify' => 'NAT munkamenet támogatása',
+ 'qf_Frequency' => 'Küldési gyakoriság másodpercben:',
+ 'qf_QualifyInstructions' => 'Ha ez az opció engedélyezve van, a MikoPBX SIP OPTIONS csomagokat küld a megadott gyakorisággal. Erre azért van szükség, hogy támogassa a NAT alagútkezelést az útválasztón.',
+ 'AdvancedOptions' => 'További beállítások',
+ 'ConnectionSettings' => 'Csatlakozási beállítások',
+ 'BreadcrumbAdminCabinet' => 'Adminisztrációs felület',
+ 'BreadcrumbPBXCoreREST' => 'REST API',
+ 'BreadcrumbProviders' => 'Telefonszolgáltatók',
+ 'SubHeaderProviders' => 'Fiókok létrehozása külső bejövő és kimenő kapcsolatok szervezéséhez',
+ 'BreadcrumbAsteriskManagers' => 'Asterisk Manager Interface (AMI)',
+ 'SubHeaderAsteriskManagers' => 'Hozzáférési jogok beállítása az állomás AMI interfészéhez',
+ 'BreadcrumbAsteriskManagersmodify' => 'Fiók beállítása',
+ 'BreadcrumbProvidersmodifyiax' => 'IAX szolgáltató beállítása',
+ 'BreadcrumbTimeSettings' => 'rendszeridő',
+ 'SubHeaderTimeSettings' => 'Az óra és a naptár beállítása',
+ 'BreadcrumbMailSettings' => 'Levelezési beállítások',
+ 'SubHeaderMailSettings' => 'Levelezőszerver beállítása értesítések küldésére a felhasználóknak és a rendszergazdáknak',
+ 'BreadcrumbNetwork' => 'Hálózati beállítások',
+ 'SubHeaderNetwork' => 'Hálózati kártyák konfigurálása (DHCP, DNS, GATEWAY, VLAN)',
+ 'BreadcrumbModify' => 'Szabály felállítása',
+ 'BreadcrumbOutboundRoutes' => 'Kimenő útválasztás',
+ 'SubHeaderOutboundRoutes' => 'A szolgáltatókon keresztüli híváselosztás szabályai és sablonjai',
+ 'BreadcrumbOutboundRoutesmodify' => 'Szabály felállítása',
+ 'BreadcrumbIncomingRoutes' => 'Bejövő útválasztás',
+ 'SubHeaderIncomingRoutes' => 'A bejövő hívások elosztásának szabályai és sablonjai',
+ 'BreadcrumbIncomingRoutesmodify' => 'Szabály felállítása',
+ 'BreadcrumbExtensions' => 'Alkalmazottak',
+ 'SubHeaderExtensions' => 'Elsődleges telefonszámok és személyes továbbítási szabályok beállítása',
+ 'BreadcrumbExtensionsmodify' => 'Beállítások módosítása',
+ 'BreadcrumbCallQueues' => 'Hívási sorok',
+ 'SubHeaderCallQueues' => 'A hívások tartásba kerülnek, majd stratégia szerint szétosztják a résztvevők között',
+ 'BreadcrumbCallQueuesmodify' => 'Sor felállítása',
+ 'BreadcrumbOutOffWorkTime' => 'Nem munkaidő',
+ 'SubHeaderOutOffWorkTime' => 'Az állomás munkaidőn túli, ünnepnapokon és hétvégén történő üzemeltetésének szabályai',
+ 'BreadcrumbOutOffWorkTimemodify' => 'Szabály felállítása',
+ 'BreadcrumbFirewall' => 'Tűzfal beállítása',
+ 'SubHeaderGeneralSettings' => 'Alapvető rendszerparaméterek konfigurálása',
+ 'BreadcrumbIvrMenu' => 'Interaktív hangmenük – IVR',
+ 'BreadcrumbIvrMenumodify' => 'Az IVR menü beállítása',
+ 'SubHeaderIvrMenu' => 'A bejövő hívások irányításának sémájának és opcióinak konfigurálása',
+ 'BreadcrumbDialplanApplications' => 'Dialplan alkalmazások',
+ 'BreadcrumbDialplanApplicationsmodify' => 'Az alkalmazás beállítása',
+ 'SubHeaderDialplanApplications' => 'Programozható hangalkalmazások PHP-ben és Asterisk Dialplanban',
+ 'BreadcrumbConferenceRooms' => 'Konferenciák',
+ 'SubHeaderConferenceRooms' => 'Szobák kialakítása több résztvevős audiokonferenciákhoz',
+ 'BreadcrumbConferenceRoomsmodify' => 'Beállítások',
+ 'BreadcrumbCallDetailRecords' => 'Híváslista',
+ 'SubHeaderCallDetailRecords' => 'Beszélgetési napló és hívásnapló',
+ 'BreadcrumbCustomFilesmodify' => 'Szerkesztés',
+ 'BreadcrumbCustomFiles' => 'Rendszerfájlok',
+ 'SubHeaderCustomFiles' => 'A rendszer és az Asterisk konfigurációs fájlok testreszabása',
+ 'BreadcrumbSoundFiles' => 'Hangfájlok',
+ 'SubHeaderSoundFiles' => 'Különféle hívási helyzetekben és interaktív hangmenükben használható',
+ 'BreadcrumbLicensing' => 'Engedélyezés',
+ 'SubHeaderLicensing' => 'Új bővítmények és modulok eléréséhez regisztráljon a Piactéren',
+ 'BreadcrumbErrors' => 'Hiba üzenet',
+ 'SubHeaderErrors' => 'Ha ez a hiba reprodukálható, forduljon a fejlesztőhöz.',
+ 'BreadcrumbRestart' => 'Indítsa újra a rendszert',
+ 'BreadcrumbRestartmanage' => 'Indítsa újra a rendszert',
+ 'SubHeaderRestart' => 'Modulok újraindítása, teljes újraindítás vagy leállítás',
+ 'BreadcrumbSession' => 'Engedélyezés',
+ 'BreadcrumbSessionend' => 'Engedélyezés',
+ 'BreadcrumbSystemDiagnostic' => 'Rendszerdiagnosztika',
+ 'SubHeaderSystemDiagnostic' => 'Rendszernaplók gyűjtése a MikoPBX működési hibáinak részletes elemzéséhez',
+ 'BreadcrumbFail2Ban' => 'Hackelés elleni védelem',
+ 'SubHeaderFail2Ban' => 'Automatikus blokkolás jelszavak kiválasztásakor',
+ 'BreadcrumbUpdate' => 'Rendszerfrissítés',
+ 'SubHeaderUpdate' => 'Hibajavítások, teljesítményjavítások, új funkciók',
+ 'BreadcrumbPbxExtensionModules' => 'Modulok és bővítmények kezelése MikoPBX-hez',
+ 'SubHeaderPbxExtensionModules' => 'Töltsd fel saját vagy tölts le modulokat piacterünkről',
+ 'mm_Setup' => 'Telefonálás',
+ 'mm_Extensions' => 'Alkalmazottak',
+ 'mm_CallQueues' => 'Hívási sorok',
+ 'mm_DialplanApplications' => 'Dialplan alkalmazások',
+ 'mm_Routing' => 'útvonalválasztás',
+ 'mm_Providers' => 'Telefonszolgáltatók',
+ 'mm_IncomingRoutes' => 'Bejövő útvonalak',
+ 'mm_OutboundRoutes' => 'Kimenő útvonalak',
+ 'mm_OutOffWorkTime' => 'Nem munkaidő',
+ 'mm_System' => 'Rendszer',
+ 'mm_NetworkSettings' => 'Hálózat és tűzfal',
+ 'mm_GeneralSettings' => 'Általános beállítások',
+ 'mm_TimeSettings' => 'dátum és idő',
+ 'mm_Network' => 'Hálózati interfészek',
+ 'mm_Firewall' => 'Tűzfal',
+ 'mm_MailSettings' => 'Levél és értesítések',
+ 'mm_AsteriskManagers' => 'Hozzáférés az AMI-hez',
+ 'mm_IvrMenu' => 'IVR menü',
+ 'mm_ConferenceRooms' => 'Konferenciák',
+ 'mm_CallDetailRecords' => 'Híváslista',
+ 'mm_SoundFiles' => 'Hangfájlok',
+ 'mm_Restart' => 'Indítsa újra',
+ 'mm_PbxExtensionModules' => 'Modulok',
+ 'mm_Maintenance' => 'Szolgáltatás',
+ 'mm_Logout' => 'Kijárat',
+ 'mm_SystemDiagnostic' => 'Rendszernaplók',
+ 'mm_Fail2Ban' => 'Hackelés elleni védelem',
+ 'mm_Update' => 'PBX frissítés',
+ 'mm_ModuleManager' => 'Modulok piactere',
+ 'mm_SSHConsole' => 'SSH konzol',
+ 'mm_Integrations' => 'Integrációk',
+ 'bt_Edit' => 'változás',
+ 'bt_Clear' => 'Egyértelmű',
+ 'bt_Back' => 'Vissza',
+ 'bt_ToolTipCopyPassword' => 'A jelszó a vágólapra másolva',
+ 'bt_ToolTipEdit' => 'változás',
+ 'bt_ToolTipRestore' => 'visszaállítás',
+ 'bt_ToolTipDownload' => 'Letöltés',
+ 'bt_ToolTipCopy' => 'Másolat',
+ 'bt_ToolTipDelete' => 'Töröl',
+ 'sip_REG_TYPE_NONE' => 'Hitelesítés IP címmel, jelszó nélkül',
+ 'pr_ProviderName' => 'Szolgáltató neve',
+ 'pr_ProviderLogin' => 'Belépés',
+ 'pr_ProviderPassword' => 'Jelszó',
+ 'pr_ProviderHostOrIPAddress' => 'Gazda vagy IP-cím',
+ 'pr_DTMFMode' => 'DTMF mód',
+ 'pr_RegistrationSettings' => 'Regisztrációs beállítások',
+ 'pr_ValidationProviderHostIsEmpty' => 'Adja meg a szerver nevét vagy a szolgáltató IP-címét',
+ 'pr_ValidationProviderLoginIsEmpty' => 'Adja meg bejelentkezési adatait, hogy engedélyezze a szolgáltatóval',
+ 'pr_ValidationProviderLoginNotSingleSimbol' => 'A bejelentkezésnek egy karakternél hosszabbnak kell lennie',
+ 'pr_SIPPort' => 'SIP csatlakozási port',
+ 'pr_NoRegister' => 'Regisztráció letiltása',
+ 'pr_ManualAdditionalAtributes' => 'Extra lehetőségek',
+ 'pr_UpdateStatus' => 'Állapotfrissítés',
+ 'pr_Online' => 'A kapcsolat létrejött',
+ 'pr_Offline' => 'Tiltva',
+ 'pr_WithoutRegistration' => 'A regisztráció letiltva',
+ 'pr_TableColumnProviderType' => 'típus',
+ 'pr_TableColumnProviderName' => 'Szolgáltató',
+ 'pr_TableColumnProviderStatus' => 'Állapot',
+ 'pr_ValidateRTPOutOfRange' => 'Az RTP-portok tartománya nem megfelelő. Az értékeknek {ruleValue} között kell lenniük',
+ 'pr_RTPPortRange' => 'RTP port tartomány',
+ 'pr_RTPPortFrom' => 'VAL VEL',
+ 'pr_RTPPortTo' => 'Által',
+ 'pr_Note' => 'Megjegyzés vagy hasznos információ a szolgáltatóról',
+ 'gs_RTPStunServer' => 'STUN szerver címe (például: stun.test.net:10000)',
+ 'gs_Store6MonthsOfRecords' => '6 hónap',
+ 'gs_Store1YearOfRecords' => '1 év',
+ 'gs_Store3YearsOfRecords' => '3 év',
+ 'gs_PBXRecordSavePeriodLabel' => 'A hívásfelvételek tárolási ideje',
+ 'gs_StoreAllPossibleRecords' => '∞',
+ 'gs_DisableAllModules' => 'Piactér letiltása',
+ 'gs_ErrorSaveSettings' => 'Hiba a beállítások mentésekor',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'A megadott mellékszám már használatban van',
+ 'pr_AddSIPProvider' => 'Csatlakoztassa a SIP-t',
+ 'pr_AddIAXProvider' => 'Csatlakoztassa az IAX-et',
+ 'ir_CallTransferTo' => 'A hívás a következő címre lesz átirányítva',
+ 'pr_QualifyInstructionsIAX' => 'Ha ez az opció engedélyezve van, az Asterisk SIP Options csomagokat küld. Erre azért van szükség, hogy támogassa a NAT alagútkezelést az útválasztón.',
+ 'pr_CustomFieldsDescriptions' => 'A legtöbb esetben a felülbírálási mezőket üresen kell hagyni.
+ Csak ha a hívások nem működnek az Ön számára, és a szolgáltató speciális beállításokat igényel, akkor ezeket a mezőket a szolgáltató ajánlása szerint kell kitölteni.',
+ 'pr_ReceiveCallsWithoutAuth' => 'Hívások fogadása hitelesítés nélkül',
+ 'pr_ValidationProviderPortRange' => 'A szolgáltató portjának a következőn belül kell lennie: {ruleValue}',
+ 'pr_DeleteTitle' => 'Szolgáltató eltávolítása',
+ 'pr_DeleteDescription' => 'A szolgáltatóval együtt az összes kapcsolódó kimenő útválasztási szabály törlődik, és a bejövő forgalomirányítási szabályokban az összes hivatkozás helyére "Bármely szolgáltató" kerül.',
+ 'pr_Cancel' => 'Megszünteti',
+ 'pr_Delete' => 'Töröl',
+ 'pr_EnterHostOrIp' => 'További szolgáltatói címek',
+ 'pr_EnterHostOrIpPlaceholder' => 'Írja be az IP-címet vagy az alhálózatot, és nyomja meg az Enter billentyűt',
+ 'pr_NoAnyAdditionalHosts' => 'Nincsenek megadva további címek ehhez a szolgáltatóhoz',
+ 'or_RuleName' => 'Szabály neve',
+ 'or_Note' => 'A jegyzet',
+ 'or_PatternToMatch' => 'A szabály működni fog, ha',
+ 'or_NumberBeginsWithTheDigits' => 'A szám ezzel kezdődik',
+ 'or_TheRestOfTheNumberMustBe' => 'A szám többi része a megadott számú számjegyből áll',
+ 'or_ReformatNumber' => 'Szám konvertálása',
+ 'or_BeforeConnectingTheCallTrim' => 'Mielőtt elkezdenénk a hívást, megszakítjuk',
+ 'or_digitsFromTheFrontAndThenPrependTheDigits' => 'számokat a szám elejére, majd adja hozzá az elejéhez',
+ 'or_CallThrough' => 'Irányítsa a hívást',
+ 'or_Provider' => 'a szolgáltatón keresztül',
+ 'or_ValidationPleaseEnterRuleName' => 'Adja meg a szabály nevét',
+ 'or_ValidateBeginPattern' => 'Hiba a számszűrő mezőben. Lehet benne számok és jelek :)|',
+ 'or_ValidateRestNumbers' => 'A szám minimális hosszának 2-nél nagyobbnak kell lennie',
+ 'or_ValidateTrimFromBegin' => 'Helytelen érték a szám elején lévő karakterek csonkolásához',
+ 'ir_ValidateForwardingToBeFilled' => 'Az átirányítási szám nincs megadva',
+ 'or_ValidatePrepend' => 'Hiba történt a szám elejéhez való hozzáadáskor. A mező tartalmazhat számokat és jeleket: * # +. Az érték maximális hossza 20 karakter.',
+ 'or_AddNewRule' => 'Új szabály hozzáadása',
+ 'or_TableColumnName' => 'Név',
+ 'or_TableColumnRule' => 'Szabály',
+ 'or_TableColumnProvider' => 'Szolgáltató',
+ 'or_TableColumnNote' => 'A jegyzet',
+ 'or_RuleDescription' => '%numberbeginswith% az elején, majd %restnumbers% számjegy',
+ 'or_RuleDescriptionBeginEmpty' => 'A szám %restnumbers% számjegyekből áll',
+ 'or_RuleNotConfigured' => 'A szabály nincs konfigurálva',
+ 'or_RuleAnyNumbers' => 'Bármilyen szám',
+ 'or_RuleDescriptionFullMatch' => 'Csak a %numberbeginswith% számhoz',
+ 'or_RuleDescriptionBeginMatch' => 'Bármilyen hosszúságú, %numberbeginswith% karakterrel kezdődő számokhoz',
+ 'or_ValidationPleaseSelectProvider' => 'Válassza ki azt a szolgáltatót, amelyre ez a szabály vonatkozik.',
+ 'ir_Provider' => 'Szolgáltató',
+ 'ir_RuleName' => 'Szabály neve',
+ 'ir_Note' => 'A jegyzet',
+ 'ir_TableColumnNote' => 'A jegyzet',
+ 'ir_TableColumnName' => 'Név',
+ 'ir_TableColumnDetails' => 'Szabály',
+ 'ir_RuleDescriptionWithNumberAndWithProvider' => 'A(z) %number% számra   %provider% keresztül érkező hívást a(z)   %callerid% címre irányítjuk.',
+ 'ir_RuleDescriptionWithoutNumber' => 'A   %provider%-on keresztül érkező hívás a következőre lesz átirányítva:   %callerid%',
+ 'ir_RuleDescriptionWithoutProvider' => 'A(z) %number% számra érkező hívást a(z)   %callerid% számra irányítjuk',
+ 'ir_RuleDescriptionWithoutNumberAndWithoutProvider' => 'A bármely szolgáltatón keresztül érkező hívást a rendszer a következő címre irányítja:   %callerid%',
+ 'ir_DefaultRoute' => 'Alapértelmezett bejövő útvonal',
+ 'ir_ActionSelect' => 'Ha egyik szabály sem egyezik',
+ 'ir_busy_signal' => 'Foglalt hang lejátszása',
+ 'ir_extension' => 'Hívás átadása',
+ 'ir_playback' => 'Médiafájl lejátszása',
+ 'ir_ExtensionSelect' => 'Számhoz',
+ 'ir_RuleAssignIf' => 'A szabály híváskor működni fog',
+ 'ir_DidNumber' => 'Kiegészítő szám (DID)',
+ 'ex_DTMFMode' => 'DTMF mód',
+ 'ir_ValidateForwardingDefaultToBeFilled' => 'Az alapértelmezett átirányítási szám nincs megadva',
+ 'ir_ValidationPleaseEnterRuleName' => 'Adja meg a szabály nevét',
+ 'ir_ValidateTimeoutOutOfRange' => 'Az átirányítási időtúllépés helytelenül van megadva. {ruleValue} között kell lennie',
+ 'ir_DidNumberDescription' => 'A szolgáltató továbbadhat egy további számot, ez egy opcionális mező, de bizonyos esetekben pontosabban irányíthatja a hívásokat.',
+ 'ir_TimeoutToTransferDefault' => 'Az az idő másodpercben, amely után a hívás a következő prioritási szabályhoz lesz irányítva',
+ 'ir_AddNewRule' => 'Új szabály hozzáadása',
+ 'ir_AnyProvider' => 'Bármilyen szolgáltató',
+ 'ir_AnyProvider_v2' => 'Nincs kapcsolat szolgáltatóval, nincs jogosultság',
+ 'cq_Extension' => 'Sorszám',
+ 'cq_Name' => 'Sor neve',
+ 'cq_Note' => 'A jegyzet',
+ 'cq_Description' => 'A jegyzet',
+ 'cq_AddNewQueue' => 'Hozzon létre egy új sort',
+ 'cq_QueueMembersColumnName' => 'Operátor',
+ 'cq_QueueMembersColumnExtension' => 'Szám',
+ 'cq_ringall' => 'A hívás egyszerre érkezik a sorban lévő összes résztvevőhöz, beleértve azokat is, akik foglaltak (alapértelmezés szerint)',
+ 'cq_leastrecent' => 'A hívás ahhoz a sortaghoz érkezik, aki a leghosszabb ideig nem fogadott hívásokat',
+ 'cq_fewestcalls' => 'A hívás annak a sortagnak szól, aki a legkevesebb hívást kezelte ',
+ 'cq_random' => 'A hívás a sorban álló bármely ingyenes résztvevőhöz érkezik',
+ 'cq_rrmemory' => 'A hívás a sorban lévő bármely ingyenes résztvevőhöz érkezik, kivéve azt a résztvevőt, aki az utolsó hívást feldolgozta',
+ 'cq_linear' => 'A hívás minden sor résztvevőhöz sorrendben érkezik',
+ 'cq_QueueSetup' => 'Fő beállítások',
+ 'cd_Extensions' => 'A sor telefonszáma',
+ 'cq_QueueStrategy' => 'Hívásstratégia szolgáltatók számára',
+ 'cd_Description' => 'Egy komment',
+ 'cq_QueueMembers' => 'Soroperátorok',
+ 'cq_SelectAgentForAddToQueue' => 'Válasszon ki egy alkalmazottat, akit hozzá szeretne adni az aktuális sorhoz',
+ 'cq_QueueMemberSettings' => 'Sorbeállítások az operátorok számára',
+ 'cq_SecRingToEachMembers' => 'Hívási kísérleti idő az operátorok számára',
+ 'cq_WrapupTime' => 'A kezelő pihenőideje a hívás kezelése után, mielőtt új hívások fogadását kezdené',
+ 'cq_ReciveCallWhileOnCall' => 'Új hívások fogadása hívás közben',
+ 'cq_QueueCallerSettings' => 'Hívósor beállításai',
+ 'cq_CallerHearOnQueued' => 'Mit hall az előfizető várakozás közben',
+ 'cq_ringing' => 'Híváshangok',
+ 'cq_moh' => 'Zene',
+ 'cq_AnnoncePosition' => 'Értesítés az aktuális pozícióról a sorban',
+ 'cq_AnnonceHoldTime' => 'Értesítés a becsült várakozási időről',
+ 'cq_PereodicAnonceSoundFile' => 'Promóciós kifejezés vagy kiegészítő értesítés',
+ 'cq_PereodicAnonceMohSoundFile' => 'Háttérzene (MOH)',
+ 'gs_SSHDisablePasswordLogins' => 'Jelszavas hitelesítés letiltása',
+ 'cq_PereodicAnonceFrequency' => 'Az összes figyelmeztetés időszakos ismétlésének ideje másodpercben',
+ 'cq_CallRouting' => 'Hívásirányítás hiba esetén',
+ 'cq_ScenaryOne' => '1. forgatókönyv',
+ 'cq_ScenaryTwo' => '2. forgatókönyv',
+ 'cq_ScenaryThree' => '3. forgatókönyv',
+ 'cq_ScenaryFour' => '4. forgatókönyv',
+ 'cq_IfQueueNotAnsweredFor' => 'Ha egy előfizető többet vár a sorban ',
+ 'cq_SecondsCallWillBeRoutedTo' => ' másodpercig, átirányítja a hívást a következőre ',
+ 'cq_RedirectToExtensionIfEmtyQueue' => 'Ha nincs operátor a sorban, vigye át a hívást a következőre ',
+ 'cq_IfQueueNotAnsweredNumberCalls' => 'Ha belül egyik kezelő sem veszi fel a hívást ',
+ 'cq_CallsCallWillBeRoutedTo' => 'hívások, az összes új hívás átirányítása ide ',
+ 'cq_IfQueueNotAnsweredRepeat' => 'Ha a sor feldolgozása nem szekvenciálisan történt ',
+ 'cq_ThisNumberIsNotFree' => 'Ez a szám foglalt',
+ 'cq_ValidateNameEmpty' => 'Kérjük, adja meg a sor nevét',
+ 'cq_ValidateExtensionEmpty' => 'A sor mellékszáma nincs megadva',
+ 'cq_ValidateExtensionDouble' => 'A sorhoz megadott mellékszám már használatban van',
+ 'cq_ValidateExtensionNumber' => 'A mellékszám csak számokból állhat',
+ 'cq_ValidateNoExtensions' => 'Nincsenek kiválasztva a sor tagjai',
+ 'cq_CallerIDPrefix' => 'A sor rövid neve, amelyet az előfizető hívóazonosítója előtt kell megjeleníteni, például "Értékesítés"',
+ 'ex_NetworkFilter' => 'Hálózati szűrő',
+ 'cq_ImpossibleToDeleteCallQueue' => 'Lehetetlen törölni egy hívási sort, mert a következő linkek vannak',
+ 'dt_Info' => '_START_-_END_ bejegyzések _TOTAL_',
+ 'dt_InfoEmpty' => 'Nincsenek a kiválasztási kritériumoknak megfelelő rekordok',
+ 'dt_InfoFiltered' => '(_MAX_ rekord közül kiválasztva)',
+ 'dt_Previous' => 'Előző',
+ 'dt_Next' => 'Következő',
+ 'dt_Search' => 'Keresés',
+ 'dt_TableIsEmpty' => 'nincs megjeleníthető adat',
+ 'ml_EmailNotSended' => 'Az üzenetet nem küldték el',
+ 'ml_EmailSendedSuccess' => 'Levél elküldve',
+ 'ml_EmailTestSubject' => 'Tesztelje az e-maileket a telefonrendszeréből',
+ 'ml_EmailTestBody' => 'Üdvözöljük, ha ez a levél van a levelében, akkor a beállítások helyesek.',
+ 'er_Unauthorized' => 'Engedélyezési hiba',
+ 'er_UnauthorizedDescription' => 'Nincs hozzáférése ehhez az oldalhoz.',
+ 'er_PageNotFound' => 'Az oldal nem található',
+ 'er_PageNotFoundDescription' => 'Ez az oldal nem létezik.',
+ 'er_InternalServerError' => 'Belső Szerverhiba',
+ 'er_InternalServerErrorDescription' => 'Valami elromlott. Ilyen hibák nem létezhetnek.',
+ 'ex_CallRecording' => 'Beszélgetések rögzítése',
+ 'ex_enableRecording' => 'Lehetővé teszi',
+ 'ex_DenyNetwork' => 'Tiltott hálózat',
+ 'ex_GeneralSettings' => 'Fő beállítások',
+ 'ex_RoutingSettings' => 'Útválasztási beállítások',
+ 'ex_ThisNumberIsNotFree' => 'A szám már benne van az adatbázisban',
+ 'ex_ThisNumberOverlapWithParkingSlots' => 'Kereszteződés számos parkolószámmal',
+ 'ex_MobileNumber' => 'Mobil szám',
+ 'ex_Secret' => 'SIP jelszó',
+ 'ex_ChangeAvatar' => 'Avatar módosítása',
+ 'ex_UserPhotography' => 'Alkalmazotti fotó',
+ 'ex_MobileSettings' => 'További beállítások a mobilhoz',
+ 'ex_MobileDialstring' => 'Tárcsázási karakterlánc felülbírálása',
+ 'ex_SipSettings' => 'SIP beállítások',
+ 'ex_BusyLevel' => 'A párhuzamos beszélgetések maximális száma',
+ 'ex_BusyLevelInfo' => 'A megadott számú hívás elérésekor az alkalmazott telefonja foglaltnak minősül.',
+ 'ex_ValidateEmailEmpty' => 'Valószínűleg rosszul adta meg az e-mail címet',
+ 'ex_ValidateUsernameEmpty' => 'Adja meg az alkalmazott teljes nevét',
+ 'ex_ValidateUsernameSpecialCharacters' => 'A teljes név nem tartalmazhat speciális karaktereket',
+ 'ex_ValidateSecretEmpty' => 'A SIP jelszó nem lehet üres',
+ 'ex_ValidateSecretWeak' => 'A SIP jelszónak 4 karakternél hosszabbnak kell lennie',
+ 'ex_PasswordNoLowSimvol' => 'A jelszónak betűket kell tartalmaznia',
+ 'ex_PasswordNoNumbers' => 'A jelszónak számokat kell tartalmaznia',
+ 'ex_ValidateExtensionNumber' => 'A mellékszám csak számokból állhat',
+ 'ex_AddNewExtension' => 'Alkalmazott hozzáadása',
+ 'ex_Transport' => 'Szállítási protokoll',
+ 'ex_Extension' => 'Mellék számát',
+ 'ex_OutboundProxy' => 'Kimenő proxy (például: pbx.yandex.net:5080)',
+ 'ex_Mobile' => 'Mobil',
+ 'ex_Email' => 'Email',
+ 'ex_Status' => 'Állapot',
+ 'ex_RegeneratePassword' => 'Hozzon létre egy új jelszót',
+ 'ex_ValidateForwardingToBeFilled' => 'Az időtúllépési továbbítási szám nincs kitöltve az útválasztási beállításokban',
+ 'ex_ValidateRingingBeforeForwardOutOfRange' => 'Az útválasztási beállítások azt jelzik, hogy az átvitel előtti idő nem megfelelő. Válasszon egy értéket a {ruleValue} közül.',
+ 'ex_ValidateNumberIsEmpty' => 'Az alkalmazotti belső szám nincs kitöltve',
+ 'ex_ValidateForwardingToBeDifferent' => 'A saját számra történő továbbítást nem állíthatja be',
+ 'ex_ValidateMobileNumberIsDouble' => 'A mobilszámot már egy másik alkalmazott használja',
+ 'ex_ValidateNumberIsDouble' => 'A mellékszám már foglalt',
+ 'ex_UpdateStatus' => 'Állapotfrissítés',
+ 'ex_Online' => 'csatlakoztatva',
+ 'ex_SelectNumber' => 'Válassza ki a számot',
+ 'ex_dropdownCategory_CONFERENCE' => 'Konferenciák',
+ 'ex_dropdownCategory_USER' => 'Alkalmazottak',
+ 'ex_dropdownCategory_USERS' => 'Alkalmazottak',
+ 'ex_dropdownCategory_DIALPLAN_APPLICATION' => 'Dialplan alkalmazások',
+ 'ex_dropdownCategory_IVR_MENU' => 'Interaktív hangmenük IVR',
+ 'ex_dropdownCategory_QUEUE' => 'Hívási sorok',
+ 'ex_dropdownCategory_MODULES' => 'További modulok',
+ 'ex_dropdownCategory_PROVIDERS' => 'Szolgáltatók',
+ 'ex_dropdownCategory_IVRMENU' => 'Interaktív hangmenük IVR',
+ 'ex_dropdownCategory_PBXEXTENSIONMODULES' => 'További modulok',
+ 'ex_dropdownCategory_CONFERENCEROOMS' => 'Konferenciák',
+ 'ex_dropdownCategory_DIALPLANAPPLICATIONS' => 'Dialplan alkalmazások',
+ 'ex_dropdownCategory_NETWORKFILTERS' => 'Alhálózatok',
+ 'ex_dropdownCategory_OUTWORKTIMES' => 'Nem munkaidő',
+ 'ex_dropdownCategory_ASTERISKMANAGERUSERS' => 'AMI felhasználók',
+ 'ex_dropdownCategory_CUSTOMFILES' => 'Konfigurációs fájlok',
+ 'ex_dropdownCategory_MENUITEMS' => 'Menüpontok',
+ 'ex_dropdownCategory_SYSTEM' => 'Szolgáltatási számok',
+ 'ex_dropdownCategory_PARKING' => 'Parkolóhelyek',
+ 'ex_ImpossibleToDeleteExtension' => 'Lehetetlen törölni egy alkalmazottat, mert a következő linkek vannak',
+ 'ex_ImpossibleToGetSecret' => 'Nem sikerült megszerezni a felhasználói jelszót',
+ 'am_TableColumnName' => 'Név',
+ 'am_TableColumnRead' => 'Olvasási hozzáférés',
+ 'am_TableColumnWrite' => 'Írási hozzáférés',
+ 'am_TableColumnDescription' => 'Megjegyzések',
+ 'am_AddNewUser' => 'AMI felhasználó hozzáadása',
+ 'am_TableColumnNetworkFilter' => 'Hálózati szűrő',
+ 'am_Read' => 'olvasás',
+ 'am_Write' => 'rekord',
+ 'am_Username' => 'Felhasználónév',
+ 'am_Secret' => 'Jelszó',
+ 'am_NetworkFilter' => 'Hálózati szűrő',
+ 'am_UserRights' => 'Felhasználói jogok',
+ 'am_Description' => 'Egy komment',
+ 'am_ValidationAMINameIsEmpty' => 'A fiók neve nincs megadva',
+ 'am_ValidationAMISecretIsEmpty' => 'A jelszó nincs kitöltve',
+ 'am_ErrorThisUsernameInNotAvailable' => 'Már létezik azonos nevű bejegyzés',
+ 'am_NoAnyServersYet' => 'Itt még nincsenek AMI-felhasználók',
+ 'tf_ActionPlayMessage' => 'Fájl lejátszása %message%',
+ 'tf_ActionTransferToExtension' => 'Hívás átirányítása ide: %extension%',
+ 'tf_TableColumnDatePeriod' => 'Időszak',
+ 'tf_TableColumnTimePeriod' => 'Idő',
+ 'tf_TableColumnWeekDaysPeriod' => 'A hét napjai',
+ 'tf_TableColumnNotes' => 'A jegyzet',
+ 'tf_AddNewTimeFrame' => 'Időintervallum hozzáadása',
+ 'tf_DateDaysFrom' => 'Időszak',
+ 'tf_ValidateCheckDateInterval' => 'Ellenőrizze a dátumtartományt',
+ 'tf_ValidateCheckTimeInterval' => 'Ellenőrizze az időintervallumot',
+ 'tf_ValidateAudioMessageEmpty' => 'Válassza ki a hangfelvételt',
+ 'tf_ValidateExtensionEmpty' => 'Válassza ki a mellékállomás számát a továbbításhoz',
+ 'tf_ValidateNoRulesSelected' => 'Nincs kitöltött időszak',
+ 'tf_TabGeneralSettings' => 'alapbeállítások',
+ 'tf_TabRoutsRestriction' => 'A kiválasztott útvonalakra érvényes',
+ 'tf_calUrl' => 'A naptár URL-je',
+ 'tf_calUser' => 'Felhasználónév',
+ 'tf_calSecret' => 'Jelszó',
+ 'tf_calType' => 'típus',
+ 'tf_CAL_TYPE_NONE' => 'Rendes',
+ 'tf_CAL_TYPE_CALDAV' => 'CalDAV',
+ 'tf_CAL_TYPE_ICAL' => 'iCal',
+ 'tf_ValidateCalUri' => 'A „Naptár URL-címe” mező helytelen értéket tartalmaz.',
+ 'Mon' => 'hétfő',
+ 'Tue' => 'kedd',
+ 'Wed' => 'szerda',
+ 'Thu' => 'csütörtök',
+ 'Fri' => 'péntek',
+ 'Sat' => 'szombat',
+ 'Sun' => 'vasárnap',
+ 'fw_AddNewRule' => 'Új alhálózat hozzáadása',
+ 'fw_TableColumnDescription' => 'Név',
+ 'fw_TableColumnNetwork' => 'Alhálózat/Cím',
+ 'fw_Description' => 'Név',
+ 'fw_Permit' => 'Alhálózat',
+ 'fw_Rules' => 'Elérhető szolgáltatások',
+ 'fw_sipDescription' => 'SIP & RTP - telefon regisztráció és hangforgalom',
+ 'fw_webDescription' => 'WEB - hozzáférés az adminisztrációs felülethez',
+ 'fw_amiDescription' => 'AMI – hozzáférés az Asterisk Manager API-hoz Telneten keresztül',
+ 'fw_ctiDescription' => 'CTI - telefonpanel csatlakoztatása',
+ 'fw_ajamDescription' => 'AJAM – hozzáférés a csillagkezelő API-hoz a http/https-n keresztül',
+ 'fw_sshDescription' => 'SSH - root hozzáférés a rendszerhez',
+ 'fw_icmpDescription' => 'ICMP - kapcsolat ellenőrzése ping paranccsal',
+ 'fw_ValidatePermitAddress' => 'A megadott alhálózati cím helytelen. Próbálja ki a 192.168.1.0/24-hez hasonló kialakítást',
+ 'nw_ValidateDHCPOnVlansDontSupport' => 'A DHCP nem támogatott VLAN-alhálózatok esetén',
+ 'fw_NewerBlockIp' => 'Soha ne blokkoljon címeket erről a hálózatról, hagyja figyelmen kívül a telefon engedélyezési és jelszóbeviteli hibákat a webes felületen',
+ 'fw_ItIsLocalNetwork' => 'Ez egy VPN vagy helyi hálózat, a hálózat telefonjai közvetlenül csatlakoznak az állomáshoz NAT-útválasztás nélkül',
+ 'fw_AllNetworksRule' => 'Minden elérhető hálózat',
+ 'fw_LocalNetworksRule' => 'Alhálózat, ahol a MikoPBX található',
+ 'fw_DenyNetwork' => 'Tiltott alhálózat',
+ 'fw_PermitNetwork' => 'alhálózat',
+ 'fw_Subnet' => 'Alhálózati maszk',
+ 'fw_AdditionalRules' => 'Extra lehetőségek',
+ 'fw_StatusEnabled' => 'Tűzfal és hackelés elleni védelem',
+ 'fw_StatusDisabled' => 'A tűzfal és a feltörés elleni védelem le van tiltva',
+ 'fw_NeedConfigureRule' => 'Beállítást igényel',
+ 'mo_BeforeDeleteNetworkFilterDeleteAsteriskManagerUsersFirst' => 'Talált linket erre a szabályra az Asterisk Managers listában az %username% felhasználóhoz',
+ 'mo_BeforeDeleteNetworkFilterDeleteSipFirst' => 'Találtam egy linket erre a szabályra az alkalmazottak listájában a %extension% címen',
+ 'mo_ThisVlanIdNotUniqueForLanInterfacesModels' => 'A rendszer már rendelkezik interfésszel ugyanazzal a VLAN-nal',
+ 'mo_Disabled' => 'kikapcsolva',
+ 'mo_RightNumber' => 'számú szabály.%id%',
+ 'mo_NewElement' => 'Új létrehozása',
+ 'mo_NewElementNetworkFilters' => 'Új tűzfalszabály az alhálózathoz/címhez',
+ 'mo_NewElementExtensions' => 'Új alkalmazott',
+ 'mo_NewElementCallQueues' => 'Új hívási sor',
+ 'mo_NewElementIvrMenu' => 'Új IVR menü',
+ 'mo_NewElementConferenceRooms' => 'Új konferenciaterem',
+ 'mo_NewElementIax' => 'Új IAX szolgáltató',
+ 'mo_NewElementSip' => 'Új SIP szolgáltató',
+ 'mo_NewElementIncomingRoutingTable' => 'Új szabály a bejövő hívások feldolgozására',
+ 'mo_NewElementOutgoingRoutingTable' => 'Új szabály a kimenő hívások feldolgozására',
+ 'mo_NewElementOutWorkTimes' => 'Új szabály a munkaidőn túli munkavégzésre',
+ 'mo_NewElementDialplanApplications' => 'Új alkalmazás/tárcsázási terv',
+ 'mo_NewElementAsteriskManagerUsers' => 'Új fiók az AMI-felhasználó számára',
+ 'mo_NewElementSoundFiles' => 'Új hangfájl',
+ 'nw_PublicHostName' => 'Az útválasztó külső gazdagépneve',
+ 'nw_ValidateNameIsNotBeEmpty' => 'Az interfész neve üres',
+ 'nw_ValidateVlanRange' => 'A VLAN értéke hibásan van kitöltve. Válasszon a {ruleValue} közül',
+ 'nw_Hostname' => 'Helyi gazdagépnév',
+ 'nw_ValidateExtIppaddrNotRight' => 'Hiba az útválasztó külső IP-címének kitöltésekor',
+ 'nw_ValidateExtIppaddrOrHostIsEmpty' => 'Meg kell adnia az útválasztó külső IP-címét vagy DNS-nevét',
+ 'nw_ValidateVlanCross' => 'Hibák az interfészek VLAN-beállításaiban, ellenőrizze a paraméterek metszetét',
+ 'nw_ValidateIppaddrIsEmpty' => 'A hálózati interfész IP-címe nincs kitöltve',
+ 'nw_ValidateIppaddrNotRight' => 'A hálózati interfész IP-címe helytelenül van megadva',
+ 'nw_GatewayAddress' => 'Átjáró címe',
+ 'nw_IPAddress' => 'IP-cím',
+ 'nw_NetworkMask' => 'Alhálózati maszk (CIDR)',
+ 'nw_VlanID' => 'VLAN azonosító',
+ 'nw_NATInfo1' => 'Ha hálózata úgy van beállítva, hogy támogassa az 1:1 NAT-ot (általában ez az alapértelmezett felhőben), akkor nem kell további beállításokat megadnia az útválasztón.',
+ 'nw_NATInfo2' => 'Ha nem használ 1:1 NAT-ot, irányítsa át a következő portokat a nyilvános IP-ről az alközpont belső IP-címére az útválasztó beállításaiban.',
+ 'nw_NATInfo3' => '%SIP_PORT% TCP/UDP és %TLS_PORT% TCP',
+ 'nw_NATInfo5' => 'Ha külső állomásnevet ad meg, akkor a rendszer a külső IP-cím helyett azt használja.',
+ 'nw_NATInfo6OR' => 'VAGY',
+ 'nw_PublicSIPPort' => 'SIP-portszám továbbítva a belső %SIP_PORT% alközpontba',
+ 'nw_PublicTLSPort' => 'A SIP TLS portszám továbbításra került a belső %TLS_PORT% alközpontba',
+ 'nw_UseDHCP' => 'Használja a DHCP-t a hálózati beállításokhoz',
+ 'nw_LookUpExternalIp' => 'Ismerje meg a külső IP-címet',
+ 'nw_DeleteCurrentInterface' => 'Távolítsa el ezt a felületet',
+ 'nw_NetworkAddressTranslations' => 'Hálózati topológia',
+ 'nw_UpdateExternalIPAutomaticallyOnReboot' => 'Frissítse a külső IP-címet minden újraindításkor',
+ 'gs_MainTab' => 'Alapvető',
+ 'gs_FeaturesTab' => 'Hívásátvitel',
+ 'gs_SIPTab' => 'KORTY',
+ 'gs_AMITab' => 'AMI&AJAM',
+ 'gs_SSHTab' => 'SSH',
+ 'gs_WebTab' => 'Webes felület',
+ 'gs_PBXFeatureDigitTimeout' => 'A számjegyek közötti maximális időtúllépés mellékszám megadásakor (ezredmásodpercben)',
+ 'gs_PBXFeaturePickupExten' => 'Kombináció a bejövő hívások lehallgatására',
+ 'gs_PBXSplitAudioThread' => 'A felvételek mentése sztereó módban',
+ 'gs_PBXAllowGuestCalls' => 'Engedélyezze a bejövő hívásokat bármely szerverről',
+ 'gs_SIPPort' => 'SIP port telefonok regisztrálásához ezen az állomáson',
+ 'gs_TLS_PORT' => 'SIP TLS port (titkosított hívások)',
+ 'gs_KeepAliveHeader' => 'A regisztráció időtartamának beállításai',
+ 'gs_SIPDefaultExpiry' => 'Normál idő másodpercben a Keep-Alive küldéséhez',
+ 'gs_SIPExpiryRange' => 'Minimális és maximális idő másodpercben',
+ 'gs_SIPPortSettings' => 'Portbeállítások a SIP jelzéshez és az RTP tartományhoz',
+ 'gs_RTPPortRange' => 'RTP port tartomány',
+ 'gs_AMIEnabled' => 'Használja az AMI interfészt',
+ 'gs_AMIPort' => 'AMI port',
+ 'gs_AJAMEnabled' => 'Használja az AJAM interfészt',
+ 'gs_AJAMPort' => 'AJAM kikötője',
+ 'gs_AJAMPortTLS' => 'Titkosított AJAM port',
+ 'gs_SSHPort' => 'SSH port',
+ 'adv_SSHPPasswordCorrupt' => 'A webes felületen beállított SSH jelszó nem egyezik a rendszerben aktuálisval. javítás',
+ 'gs_SSHLogin' => 'Bejelentkezés az SSH konzolhoz',
+ 'gs_SSHPassword' => 'SSH jelszó',
+ 'gs_SSHAuthorizedKeys' => 'SSH hitelesített kulcsok',
+ 'gs_PasswordSimple' => 'A beállított jelszó túl egyszerű.',
+ 'gs_SetPassword' => 'Állítson be új jelszót',
+ 'gs_SetPasswordError' => 'Jelszó - %password% nem használható, az egyszerű jelszavak szótárában megtalálható.',
+ 'gs_SetPasswordInfo' => 'A megadott jelszó nem használható az egyszerű jelszószótárban.',
+ 'gs_PasswordNoNumbers' => 'A jelszónak számokat kell tartalmaznia',
+ 'gs_PasswordNoLowSimvol' => 'A jelszónak kisbetűket kell tartalmaznia',
+ 'gs_PasswordNoUpperSimvol' => 'A jelszónak nagybetűket kell tartalmaznia',
+ 'gs_WebPort' => 'HTTP port',
+ 'gs_WebHTTPSPort' => 'HTTPs port',
+ 'gs_WEBHTTPSPrivateKey' => 'HTTPs privát kulcs',
+ 'gs_ValidateEmptySSHPassword' => 'Az SSH jelszó nem lehet üres',
+ 'gs_ValidateWeakSSHPassword' => 'Az SSH-jelszónak 4 karakternél hosszabbnak kell lennie',
+ 'gs_ValidateSSHPasswordsFieldDifferent' => 'Az SSH jelszó hibásan lett megadva. Írja be újra a jelszavát.',
+ 'gs_ValidateWEBPortOutOfRange' => 'A HTTP port mező helytelen. Válasszon egy értéket a {ruleValue} közül.',
+ 'gs_ValidateWEBHTTPSPortOutOfRange' => 'A HTTPS-port mező helytelen. Válasszon egy értéket a {ruleValue} közül.',
+ 'gs_ValidateWEBHTTPSPortNotEqualToWEBPort' => 'A HTTP- és a HTTPS-portoknak különbözniük kell',
+ 'gs_ValidateWEBPortNotEqualToAjamPort' => 'A HTTP- és az AJAM-portoknak különbözniük kell',
+ 'gs_ValidateWEBPortNotEqualToAjamTLSPort' => 'A HTTP- és az AJAM-portoknak különbözniük kell',
+ 'gs_ValidateWEBHTTPSPortNotEqualToAjamPort' => 'A HTTPS és az AJAM portoknak különbözniük kell',
+ 'gs_ValidateWEBHTTPSPortNotEqualToAjamTLSPort' => 'A HTTPS és az AJAM portoknak különbözniük kell',
+ 'gs_SendAnonymousMetrics' => 'Összeomlási információk küldése a fejlesztőknek',
+ 'gs_WebAdminLanguage' => 'Webes felület nyelve',
+ 'gs_CodecsTab' => 'Audio/Videó kodekek',
+ 'gs_AudioCodecs' => 'Audiokodekek',
+ 'gs_VideoCodecs' => 'Videokodekek',
+ 'gs_RestoreAllSettingsMessage' => 'Az összes beállítás, híváselőzmények, hívásrögzítési fájlok és telepített bővítmények törlődnek.',
+ 'gs_EnterDeleteAllPhrasePreText' => 'A rendszer tisztításához írja be a következő kifejezést a beviteli mezőbe:',
+ 'gs_PBXRecordAnnouncementOut' => 'Válassza ki a hívásrögzítési figyelmeztetést a kimenő hívásokhoz',
+ 'ts_CurrentSettings' => 'Jelenlegi beállítások',
+ 'ts_SystemTime' => 'rendszeridő',
+ 'ts_TimeZone' => 'Időzóna',
+ 'ts_ModifySettings' => 'Új beállítások',
+ 'ts_ManualAdjustDateTime' => 'Állítsa be kézzel az időt',
+ 'ts_CurrentSystemTime' => 'Aktuális idő',
+ 'ts_NTPServer' => 'NTP szerverek',
+ 'ts_ValidateDateTime' => 'Helytelen dátum',
+ 'ms_SMTPSettings' => 'Üzenetküldési beállítások',
+ 'ms_NotificationTemplatesMissed' => 'Sablon – nem fogadott hívások',
+ 'ms_NotificationTemplatesVoicemail' => 'Sablon – hangposta',
+ 'ms_SMTPHost' => 'SMTP gazdagép',
+ 'ms_SMTPPort' => 'SMTP port',
+ 'ms_SMTPUsername' => 'SMTP bejelentkezés',
+ 'ms_SentTestEmailAfterSaveTo' => 'Küldjön teszt e-mailt erre a címre',
+ 'ms_MissedCallSubject' => 'Nem fogadott hívás – e-mail tárgya',
+ 'ms_MissedCallBody' => 'Nem fogadott hívás - a levél szövege',
+ 'ms_MissedCallFooter' => 'Nem fogadott hívás - pince',
+ 'ms_VoicemailSubject' => 'Hangposta - tárgysor',
+ 'ms_VoicemailBody' => 'Hangposta - a levél szövege',
+ 'ms_VoicemailFooter' => 'Hangposta - pince',
+ 'ms_MailSysadminEmail' => 'Rendszergazda e-mail',
+ 'ms_SystemEmailForMissed' => 'E-mail az elmulasztott értesítésekről',
+ 'ms_TestEmailSubject' => 'Levélküldés tesztelése',
+ 'ms_TestEmailSentSuccessfully' => 'Levél elküldve',
+ 'ms_TestEmailBody' => 'Ha megkapta ezt a levelet, az azt jelenti, hogy a levelezési beállításai helyesek.',
+ 'ms_MissedCalls' => 'Nem fogadott hívások',
+ 'ms_Voicemail' => 'Hangposta',
+ 'ms_VoicemailCommonEmail' => 'Egyetlen e-mail hangpostaüzenetek küldéséhez',
+ 'iv_ValidateDigitsIsNotCorrect' => 'A kód mező nincs megfelelően kitöltve',
+ 'iv_ValidateExtensionIsNotCorrect' => 'Az előfizetői szám nincs kiválasztva',
+ 'iv_ValidateExtensionIsEmpty' => 'Az IVR menü száma nincs megadva',
+ 'iv_ValidateAudioFileIsEmpty' => 'Nincs hangfájl kiválasztva hangos üdvözléshez',
+ 'iv_ValidateNameIsEmpty' => 'Az IVR menü neve nincs megadva',
+ 'iv_ValidateNoIVRExtensions' => 'Az IVR menü további tárcsázási műveletei nincsenek megadva',
+ 'iv_ValidateTimeoutExtensionIsEmpty' => 'Időtúllépési továbbítási szám nincs megadva',
+ 'iv_ValidateExtensionIsDouble' => 'A megadott IVR menüszám foglalt',
+ 'iv_ValidateRepeatNumberOutOfRange' => 'A menü ismétlések száma nem megfelelő',
+ 'iv_ValidateTimeoutOutOfRange' => 'A mellékszámra való várakozás időtúllépése helytelenül van megadva',
+ 'iv_Name' => 'Menü neve',
+ 'iv_Description' => 'Egy komment',
+ 'iv_Extensions' => 'IVR menü száma',
+ 'iv_PlaySound' => 'Hangos üdvözlet',
+ 'iv_Actions' => 'További toborzási intézkedések',
+ 'iv_DeleteRow' => 'Töröl',
+ 'iv_AddNewRow' => 'Hozzáadás',
+ 'iv_TimeoutExtension' => 'Alapértelmezett szám',
+ 'iv_TimeoutToRedirect' => 'Időtúllépés a mellékállomás számának megadására váráshoz, amely után a hangos üdvözlés megismétlődik',
+ 'iv_AllowEnterAnyInternalExtension' => 'Bármely belső szám további tárcsázásának engedélyezése',
+ 'iv_Extension' => 'IVR menü száma',
+ 'iv_Note' => 'Megjegyzések',
+ 'iv_AddNewIvrMenu' => 'Hozzon létre egy új IVR menüt',
+ 'iv_ThisNumberIsNotFree' => 'Ez a szám foglalt',
+ 'iv_NumberOfRepeat' => 'Az alapértelmezett számra váltás előtti újrapróbálkozások száma',
+ 'iv_ImpossibleToDeleteIVRMenu' => 'Az IVR menüt nem lehet törölni, aktív hivatkozások vannak rá',
+ 'da_Main' => 'Alkalmazás beállítások',
+ 'da_Applicationlogic' => 'Program kód',
+ 'da_Hint' => 'Célzás',
+ 'da_Description' => 'Egy komment',
+ 'da_Name' => 'Név',
+ 'da_Extensions' => 'Pályázati hívószám',
+ 'da_ThisNumberIsNotFree' => 'Ez a szám foglalt',
+ 'da_ColumnName' => 'Név',
+ 'da_ColumnNote' => 'Leírás',
+ 'da_ValidateNameIsEmpty' => 'A pályázat neve nincs kitöltve',
+ 'da_ValidateExtensionIsEmpty' => 'A jelentkezési szám nincs kitöltve',
+ 'da_ValidateExtensionDouble' => 'Az alkalmazáshoz megadott mellékszám foglalt',
+ 'da_AddNewDialplanApp' => 'Új hozzáadása',
+ 'da_TypePhp' => 'PHP-AGI szkript',
+ 'da_TypePlaintext' => 'Csillag tárcsázási terv',
+ 'da_ValidateExtensionNumber' => 'A mellékszám csak számokból állhat',
+ 'da_ImpossibleToDeleteDialplanApplication' => 'A Dialplans alkalmazást nem lehet törölni, linkjei vannak',
+ 'cr_AddNewConferenceRoom' => 'Konferencia hozzáadása',
+ 'cr_ColumnExtension' => 'Szám',
+ 'cr_ColumnName' => 'Név',
+ 'cr_Name' => 'Konferenciaterem neve',
+ 'cr_pinCode' => 'Konferencia PIN kódja',
+ 'cr_Extensions' => 'Szám',
+ 'cr_ThisNumberIsNotFree' => 'Ez a szám foglalt',
+ 'cr_ValidateExtensionDouble' => 'A konferenciához megadott mellékszám foglalt',
+ 'cr_ValidateExtensionEmpty' => 'A belső konferencia száma nincs megadva',
+ 'cr_ValidateNameEmpty' => 'A konferencia neve nincs megadva',
+ 'cr_ValidateExtensionNumber' => 'A mellékszám csak számokból állhat',
+ 'cr_ValidateExtensionLen' => 'A mellékszámnak két vagy több számjegyből kell állnia',
+ 'cr_ValidatePinNumber' => 'A PIN-kód csak számokból állhat',
+ 'cr_ImpossibleToDeleteConferenceRoom' => 'Ez a konferenciaterem nem törölhető',
+ 'cdr_ColumnDate' => 'Hívás dátuma',
+ 'cdr_ColumnFrom' => 'WHO',
+ 'cdr_ColumnTo' => 'Kinek',
+ 'cdr_ColumnDuration' => 'Időtartam',
+ 'cdr_ColumnRecordings' => 'Hívásfelvételek',
+ 'cdr_And' => 'És',
+ 'cf_ColumnPath' => 'A fájl elérési útja',
+ 'cf_ColumnMode' => 'Mód',
+ 'cf_ColumnNote' => 'A jegyzet',
+ 'cf_FileActionsNone' => 'Ne változz',
+ 'cf_FileActionsAppend' => 'Csatolás a fájl végéhez',
+ 'cf_FileActionsOverride' => 'Cserélje ki teljesen',
+ 'cf_FileActionsScript' => 'Folyamat scripttel',
+ 'cf_Main' => 'Megjegyzés a változásokhoz',
+ 'cf_Content' => 'Programkód vagy konfiguráció',
+ 'cf_Path' => 'A fájl elérési útja',
+ 'cf_Description' => 'Írja meg kommentben, hogy miért történt a változtatás',
+ 'cf_Mode' => 'Mód',
+ 'cf_OriginalFileHeader' => 'A rendszer által generált eredeti fájltartalom',
+ 'cf_UserEditHeader' => 'Szerkesztő a változtatásokhoz',
+ 'cf_ResultFileHeader' => 'A fájl tartalma változtatásokkal',
+ 'mo_BeforeDeleteFirst' => 'Vannak linkek az objektumhoz - %represent%',
+ 'ConstraintViolation' => 'A logikai integritás megsértése',
+ 'repAsteriskManagerUsers' => 'AMI bejegyzés – %represent%',
+ 'repCallQueues' => 'Hívási sor – %represent%',
+ 'repCallQueueMembers' => 'Hívási sor tagja – %represent%',
+ 'repConferenceRooms' => 'Konferencia – %represent%',
+ 'repCustomFiles' => 'Rendszerfájl – %represent%',
+ 'repDialplanApplications' => 'Dialplan alkalmazás – %represent%',
+ 'repExtensionForwardingRights' => 'Munkavállalói útválasztási beállítások – %represent%',
+ 'repExtensions' => 'Mellékállomás száma - %represent%',
+ 'repExternalPhones' => 'Külső szám - %represent%',
+ 'repIvrMenuActions' => 'Az IVR menü résztvevője – %represent%',
+ 'repLink' => 'link',
+ 'sf_ValidationFileNameIsEmpty' => 'A fájlnév nincs megadva',
+ 'sf_Filename' => 'Felvételi fájl neve',
+ 'sf_UploadNewSoundFile' => 'Új fájl feltöltése',
+ 'sf_RecordNewSoundFile' => 'Felvétel mikrofon segítségével',
+ 'sf_UploadSoundFileButton' => 'Letöltés',
+ 'sf_FileNotFound' => 'Hiba – a fájl nem játszható le',
+ 'sf_SelectAudioFile' => 'Válassza ki a hangfájlt',
+ 'sf_ValidationFileNotSelected' => 'Először töltse le a hangfájlt',
+ 'sf_CustomSounds' => 'Audio fájlok',
+ 'sf_MusicOnHold' => 'Zene tartásban',
+ 'lic_ValidateContactEmail' => 'A kötelező mező nincs kitöltve - a kapcsolattartó e-mail címe',
+ 'lic_ValidateContactName' => 'A kötelező mező nincs kitöltve - kapcsolattartó',
+ 'lic_ValidateCouponEmpty' => 'A kötelező mező nincs kitöltve - kupon',
+ 'lic_GetKeyForm' => 'Bejegyzés',
+ 'lic_ActivateCoupon' => 'Kupon aktiválás',
+ 'lic_LicenseKey' => 'Licenckulcs',
+ 'lic_CompanyName' => 'A szervezet neve',
+ 'lic_Email' => 'A kapcsolattartó e-mail címe',
+ 'lic_Contact' => 'A kapcsolattartó személy',
+ 'lic_Phone' => 'Kapcsolattartási telefonszám',
+ 'lic_Inn' => 'Egyedi cégazonosító (TIN, IIN, UNP stb.)',
+ 'lic_Coupon' => 'Licencmegújító kupon',
+ 'lic_ActivateCouponButton' => 'Kupon aktiválása',
+ 'lic_RegisterTheSystemButton' => 'Regisztráció',
+ 'lic_SaveLicenseKeyButton' => 'Kulcs mentése',
+ 'lic_GetTrialErrorCheckInternet' => 'A regisztráció sikertelen, ellenőrizze az internet elérhetőségét a MikoPBX-en',
+ 'lic_SuccessfulCouponActivation' => 'A kupon sikeresen aktiválva',
+ 'lic_SuccessfulActivation' => 'Sikeres rendszerregisztráció',
+ 'lic_WrongLicenseKeyOrEmpty' => 'A licenckulcsot helytelenül adta meg',
+ 'lic_FailedCheckLicense' => 'A licencszerver nem adott választ, ellenőrizze az internetbeállításokat',
+ 'lic_FailedCheckLicenseNotPbxResponse' => 'A MikoPBX nem válaszolt a licencinformációk iránti kérésre. A szolgáltatás nem elérhető.',
+ 'lic_UnknownLicenseMessage' => 'Nincs válasz az engedélyezési rendszertől',
+ 'lic_LicenseKeyMessage' => 'A licenckulcs az összes MIKO-termékhez tartozó licenc tárolására szolgál.
+Ha már van kulcsa, egyszerűen beírhatja ebbe a mezőbe.
+Ha volt kulcsa, de elfelejtette, keresse a beérkező leveleket a lic@miko.ru címen
+A regisztrációs űrlap kitöltésével automatikusan új kulcsot kaphat.
',
+ 'lic_CouponMessage' => 'A kupon az előfizetések, próbaverziók megújítására és a bővítőmodulok licenceinek aktiválására szolgál.
+A kupon egyszer aktiválható, ezután válik beválthatóvá.',
+ 'lic_CurrentLicenseInfo' => 'Részletes információk a licenckulcsban található termékekről',
+ 'lic_Expired' => 'A termék lejárt, kérjük, lépjen kapcsolatba a következővel: lic@mikopbx.com',
+ 'lic_ExpiredAfter' => 'A licenc az %expired% után jár le',
+ 'lic_Product' => 'Termék',
+ 'lic_FeatureInfo' => 'Összes %count% licenc a %name% számára, ebből foglalt %captured%',
+ 'lic_LicenseKeyProducts' => 'Aktivált termékek',
+ 'lic_LicenseKeyOwner' => 'Engedély birtokosa',
+ 'lic_ResetLicenseSettings' => 'Kulcskötés alaphelyzetbe állítása',
+ 'lic_LicenseKeyValid' => 'A program regisztrálva van',
+ 'lic_FailedToGetTrialKey2051' => '(2051) Ezt a példányt nem lehetett regisztrálni, mert már használta a regisztrációs számot egy másik e-mail címmel ezen a gépen.
+ Használja a korábban a lic@miko.ru címről küldött kulcsot',
+ 'lic_FailedToGetTrialKey2022' => '(2022) Nem sikerült regisztrálni ezt a példányt. A megadott e-mail címen már létrejött egy másik cég regisztrációs száma.
+ Használja a korábban a lic@miko.ru címről küldött kulcsot, vagy adja meg a helyes cégnevet.',
+ 'lic_FailedActivateCoupon2057' => '(2057) Ez a kupon le van tiltva',
+ 'lic_FailedActivateCoupon2040' => '(2040) Ez a kupon nem létezik, kérjük ellenőrizze a bejegyzés helyességét',
+ 'lic_FailedActivateCoupon2041' => '(2041) Ezt a kupont már korábban aktiválták',
+ 'lic_FailedActivateCoupon2037' => '(2037) Hiba a regisztrációs szám megadásakor',
+ 'lic_FailedCheckLicense2026' => '(2026) Hiba a licencszám megadásakor',
+ 'lic_FailedToCaptureFeature2008' => '(2008) Nincs szükség licencre, vagy másik MikoPBX-hez van kötve',
+ 'lic_InvalidLicenseKey2009' => '(2009) Licenckulcs hiba',
+ 'lic_FeatureExpired2011' => '(2011) A modul licence lejárt, kérjük, lépjen kapcsolatba a következővel: sale@mikopbx.com',
+ 'lic_IntroductionTabHeader' => 'A piacterek engedélyezéséről',
+ 'lic_ManagementTabHeader' => 'Regisztráció és licenckezelés',
+ 'lic_FirstQuestionHeader' => 'Szükséges-e regisztrálni?',
+ 'lic_FirstQuestionAnswer' => 'A MikoPBX alapvető funkciói teljesen ingyenesek, és nem korlátozzák a licencet. Az engedély hiánya semmilyen módon nem befolyásolja a hívásokat.
A Piactéren bármikor regisztrálhat, illetve törölheti a regisztrációt.',
+ 'lic_MarketplaceHeader' => 'A piactér további lehetőségeket kínál',
+ 'ext_ModuleInstallDescription' => 'A modul telepítésekor a rendszer ellenőrzi a licencet. A fizetős modulokhoz lehetőség szerint próbaverziót biztosítunk. Az ingyenes modulokat feltételek nélkül telepítik. Ha a modult korábban törölték a beállítások mentése közben, akkor azok visszaállnak. A modul telepítése közben jobb, ha nem hajt végre más műveleteket a rendszeren.',
+ 'ext_UpdateAllModulesTitle' => 'Az összes modul frissítése',
+ 'ext_UpdateAllModulesDescription' => 'A rendszer az összes telepített modult a legújabb verzióra frissíti, megtartva a jelenlegi beállításokat. Javasoljuk, hogy a frissítési folyamat során ne végezzen más műveletet a rendszeren.',
+ 'ext_UpdateModuleTitle' => 'Modul frissítés',
+ 'ext_ModuleUpdateDescription' => 'A kiválasztott modul frissül a lerakat legfrissebb verziójára, és minden beállítás mentésre kerül. Fizetős modulok esetén először a licencet ellenőrizzük. A frissítés során ajánlatos tartózkodni a rendszeren végzett egyéb műveletek végrehajtásától.',
+ 'ext_DowngradeModuleTitle' => 'Modul verzió visszagörgetése',
+ 'ext_ModuleDowngradeDescription' => 'A modul visszaáll az előző verzióra. A beállítások mentésre kerülnek, de a fizetős modulok esetében először a licenc ellenőrzése történik meg. Kérjük, vegye figyelembe, hogy a visszaállítás megváltoztathatja az adatstruktúrát, és előfordulhat, hogy a modult újra kell konfigurálni. A visszaállítás során ne hajtson végre más műveleteket a rendszeren.',
+ 'ext_InstallUpdateAction' => 'Végrehajtás',
+ 'ext_SystemVersionRequired' => 'A MikoPBX minimálisan kompatibilis verziója',
+ 'DimmerWaitForPBXIsOnline' => 'Megszakadt a kapcsolat az alközponti maggal…',
+ 'DimmerWaitForPBXOnlineDescription' => 'Normális, hogy az állomás újraindul.
Amint a kapcsolat helyreáll, az oldal automatikusan frissül!',
+ 'loc_NoResult' => 'Nincs találat',
+ 'mo_CallQueueShort4Dropdown' => 'Sor',
+ 'mo_ConferenceRoomsShort4Dropdown' => 'Konferencia',
+ 'mo_SystemExten_did2user' => 'Közvetlenül az alkalmazotthoz (a DID egyeztetése)',
+ 'mo_SystemExten_voicemail' => 'Hangposta',
+ 'GoToWikiDocumentation' => 'Nyissa meg az online dokumentációt',
+ 'mo_ModuleSettingsError' => 'Hibák a modul beállításaiban - %modulename%',
+ 'adv_MessagesHeader' => 'jegyzet',
+ 'adv_MessagesHeaderError' => 'Súlyos hiba',
+ 'adv_YouUseDefaultWebPassword' => 'Az alapértelmezett jelszót használja az adminisztrációs felületre való bejelentkezéshez - szerkesztés',
+ 'adv_YouUseDefaultSSHPassword' => 'Az alapértelmezett jelszót használja az SSH eléréséhez – szerkesztés',
+ 'adv_WebPasswordWeak' => 'Egyszerű rendszergazdai jelszó a webes felületen módosítás',
+ 'adv_SshPasswordWeak' => 'Egyszerű SSH-fiók jelszava módosítás',
+ 'adv_SipPasswordWeak' => 'Egyszerű SIP jelszó: %record%',
+ 'adv_AmiPasswordWeak' => 'Egyszerű jelszó az AMI-felhasználók számára %record%',
+ 'adv_PopupHeader' => 'A következő problémákat találtuk:',
+ 'pass_CheckWebAdminPasswordSimple' => 'A WEB jelszó túl egyszerű.',
+ 'pass_CheckWebAdminPasswordDontMatch' => 'A WEB-hez megadott jelszavak nem egyeznek',
+ 'pass_CheckWebAdminPasswordEmpty' => 'A mező üres: a WEB jelszava',
+ 'pass_CheckWebPassErrorChange' => 'Nem sikerült megváltoztatni a jelszót',
+ 'pass_CheckSSHPasswordDontMatch' => 'A megadott SSH jelszavak nem egyeznek',
+ 'adv_FirewallDisabled' => 'A tűzfal le van tiltva a rendszerben - szerkesztés',
+ 'adv_StorageDiskUnMounted' => 'A beállítások és adatok tárolására szolgáló lemez nincs csatlakoztatva!',
+ 'adv_NetworksNotConfigured' => 'Az engedélyezett alhálózatok paraméterei nincsenek konfigurálva - módosítás',
+ 'adv_AvailableNewVersionPBX' => 'Elérhető az alközpont új verziója – %ver%',
+ 'adv_StorageDiskRunningOutOfFreeSpace' => 'A tárolólemezen kifogy a szabad hely (%free% Mb)',
+ 'adv_ThisCopyHasLicensingTroubles' => 'PBX licencprobléma: %error% - az javítása',
+ 'adv_ProblemWithInternetConnection' => 'Nincs internet kapcsolat. Problémák adódhatnak a fizetős modulok működésében.',
+ 'cal_Yesterday' => 'Tegnap',
+ 'cal_LastWeek' => 'Az elmúlt 7 nap',
+ 'cal_Last30Days' => 'Az elmúlt 30 nap',
+ 'sntry_ErrorGeneric' => 'Ismeretlen hiba a küldés során. Próbáld újra!',
+ 'sntry_ErrorFormEntry' => 'A mezők nincsenek kitöltve, kérjük javítsa ki és próbálja meg újra elküldeni!',
+ 'sntry_SuccessMessage' => 'Köszönöm a segítségedet!',
+ 'lang_HelpWithTranslateIt' => 'Segítség a MikoPBX fordításában',
+ 'topMenu_Support' => 'Támogatás',
+ 'topMenu_SearchPlaceholder' => 'Írja be a keresett kifejezést',
+ 'topMenu_SidebarButton' => 'Menü',
+ 'MIKO_PBX' => 'MIKO alközpont',
+ 'PBX is running in Live or Recovery mode' => 'A rendszer helyreállítási módba indult (Live CD)',
+ 'LAN IP address assigned via DHCP' => 'DHCP szerveren keresztül hozzárendelt LAN IP',
+ 'LAN IP address' => 'A LAN IP manuális beállítása',
+ 'VLAN IP address assigned via' => 'VLAN IP: keresztül működik',
+ 'The integrity of the system is broken' => 'A rendszer integritása sérül',
+ 'adv_SystemBrokenComment' => 'A rendszerfájlok módosultak. Végezzen rendszer-visszaállítást/frissítést.',
+ 'PBX console setup' => 'MikoPBX konzol',
+ 'Install or recover' => 'Hajtsa végre a telepítést/visszaállítást',
+ 'Install on Hard Drive' => 'Hajtsa végre a telepítést',
+ 'Set up LAN IP address' => 'Konfigurálja a LAN IP-címét',
+ 'Reboot system' => 'Rendszer újraindítása',
+ 'Ping host' => 'Ping címek',
+ 'Firewall' => 'Tűzfal engedélyezése/letiltása',
+ 'Connect storage' => 'Csatlakoztasson egy lemezt az adattároláshoz',
+ 'Reset admin password' => 'Állítsa vissza a webes felület jelszavát',
+ 'Enter a number' => 'Adja meg a csapat számát',
+ 'Press ENTER to continue.' => 'Nyomja meg az ENTER-t a folytatáshoz…',
+ 'version' => 'változat',
+ 'this_is' => 'Ez ',
+ 'Do you want to use DHCP to configure your LAN interface?' => 'Használjak DHCP szervert a LAN interfész konfigurálásához?',
+ 'The LAN interface will now be configured via DHCP...' => "A LAN interfész DHCP használatával lesz konfigurálva…",
+ 'The LAN interface will now be configured ...' => "A LAN interfész beállítása…",
+ 'Enter the new LAN IP address: ' => 'Írja be az új LAN IP-címet:',
+ 'Subnet masks are to be entered as bit counts (as in CIDR notation).' => 'Alhálózati maszk CIDR formátumban (1-32)',
+ 'Enter the new LAN subnet bit count: ' => "Adja meg a maszk értékét:",
+ 'Enter the LAN gateway IP address: ' => "Adja meg az átjáró címét (LAN-átjáró IP-címe):",
+ 'Enter the LAN DNS IP address: ' => 'Adja meg a DNS-kiszolgáló címét:',
+ 'The system will reboot. This may take a minute.' => 'A rendszer újraindul. Ez eltart néhány percig.',
+ 'Do you want to proceed? (y/n): ' => 'Folytatja a folyamatot? (i/n):',
+ 'The system is rebooting now...' => 'Újraindítás…',
+ 'Enter a host name or IP address: ' => 'Adja meg a szerver címét:',
+ 'enable' => 'bekapcsol',
+ 'running' => 'beleértve',
+ 'stopped' => 'Tiltva',
+ 'Firewall is now' => 'Tűzfal most',
+ 'Firewall disabled' => 'Tűzfal letiltva',
+ 'Do you want disable firewall now? (y/n): ' => 'Letiltja? (i/n):',
+ 'Do you want enable firewall now? (y/n): ' => 'Bekapcsol? (i/n):',
+ 'Storage disk is already mounted...' => 'A tárolólemez már fel van szerelve',
+ 'Storage disk was mounted successfully...' => 'A tárolólemezt sikeresen csatlakoztatta',
+ 'Valid disks not found...' => 'Nem található egyező meghajtó',
+ 'Valid disks are:' => 'A megfelelő lemezek listája:',
+ 'Enter the device name:' => 'Írja be az eszköz nevét:',
+ 'Do you want reset password? (y/n): ' => 'Biztosan vissza szeretné állítani webes jelszavát a gyári beállításokra? (i/n):',
+ 'Password successfully reset. New login: admin. New password: admin.' => "Sikeres jelszó-visszaállítás. Felhasználónév: admin Jelszó: admin",
+ 'Install or recovery' => "Telepítés/helyreállítás",
+ 'All settings will be lost!' => 'Vissza a gyári beállításokhoz!',
+ 'All settings will be kept!' => 'Az aktuális beállítások mentésre kerülnek!',
+ 'Cancel' => 'Megszünteti',
+ 'Install' => 'Telepítés',
+ 'Reinstall to' => 'Frissítés verzióra',
+ 'Firmware version on this system:' => 'A rendszer jelenlegi firmware verziója:',
+ 'WARNING' => 'FIGYELEM',
+ 'The PBX will reboot after installation.' => 'A telepítés után a rendszer újraindul',
+ 'The PBX is about to be installed onto the' => 'A MikoPBX telepítve lesz a lemezre:',
+ 'everything on this device will be erased!' => 'az eszközön lévő összes adat törlődik!',
+ 'this cannot be undone!' => 'A művelet visszafordíthatatlan!',
+ 'Change language' => 'Nyelv módosítása / Az interfész nyelvének módosítása',
+ 'Select the drive to install the system.' => 'Válassza ki a lemezt a rendszer telepítéséhez',
+ 'Selected disk:' => 'Kiválasztott meghajtó:',
+ '(default value = ' => '(alapértelmezett = ',
+ 'Select the drive to store the data.' => 'Válasszon lemezt az adatok tárolására',
+ 'Partitioning and formatting storage disk' => 'Hozzon létre egy partíciót, és formázza meg a lemezt, hogy adatokat tároljon az eszközön',
+ 'Update storage partition 4 on disk' => 'A negyedik partíció frissítése az adatok lemezen való tárolására',
+ 'Installing PBX...' => 'MikoPBX telepítése…',
+ ' - Unmounting partitions...' => 'Felszerelt lemezpartíciók eltávolítása…',
+ ' - Unpacking img...' => 'A rendszerpartíció frissítése…',
+ 'Copying configuration...' => 'Kezdeti konfigurációs beállítások kitöltése…',
+ 'Save storage disk settings' => 'Lemezbeállítások mentése tároláshoz',
+ 'Formatting storage partition 4 on disk' => 'A negyedik partíció formázása adatok tárolására a lemezen',
+ 'Warning! Selected disk will be formatted!' => 'Figyelem! A kiválasztott lemez formázásra kerül, és minden adat megsemmisül!',
+ 'user' => 'felhasználó',
+ 'Reboot' => 'Indítsa újra a MikoPBX-et',
+ 'Power off' => 'Kikapcsol',
+ 'Choose action' => 'Válasszon egy műveletet',
+ 'Пропущенный вызов' => 'Nem fogadott hívása van',
+ 'Console' => 'Konzol (Shell)',
+ 'Failed to mount the disc...' => 'Nem sikerült a lemez csatlakoztatása',
+ 'All processes will be completed. Continue? (y/n):' => 'Minden folyamat befejeződik. Folytatni? (i/n):',
+ 'Configuring using DHCP' => 'Konfiguráció DHCP szerver segítségével',
+ 'Manual setting' => 'Kézi beállítás',
+ 'Storage' => 'Adattár',
+ 'Resize storage' => 'Növelje meg az adattároláshoz szükséges lemez méretét a teljes fel nem osztott terület felhasználásával',
+ 'Check storage' => 'Ellenőrizze a lemezt, hogy vannak-e hibák',
+ 'Storage unmounted' => 'A tárolólemez nincs csatlakoztatva',
+ 'sd_Filename' => 'Fájl',
+ 'sd_filter' => 'Szűrő',
+ 'sd_offset' => 'Offset',
+ 'sd_lines' => 'Határ',
+ 'sd_ShowLog' => 'Naplók megtekintése',
+ 'sd_CapturePcap' => 'Hálózati csomagok rögzítése',
+ 'sd_DownloadPcapFileError' => 'Hiba a naplóarchívum létrehozásakor',
+ 'sd_SystemInformation' => 'Rendszer információ',
+ 'sd_CollectingInfo' => 'Szolgáltatási információk gyűjtése',
+ 'sd_CollectingLogsInfo' => 'A naplófájlok listájának lekérése',
+ 'sd_PackingLogFiles' => 'Az összegyűjtött adatok csomagolása',
+ 'sd_ToolTipDownload' => 'Naplófájl letöltése',
+ 'sd_ToolTipRefresh' => 'Szerezze be a naplófájl legújabb verzióját',
+ 'sd_ToolTipAutoUpdate' => 'A képernyőn megjelenő tartalom automatikus frissítése',
+ 'msg_ErrorHeader' => 'Hiba',
+ 'msg_WarningHeader' => 'Figyelem',
+ 'msg_infoHeader' => 'Információ',
+ 'adv_SSHPasswordWasChangedSubject' => "Figyelem! Az SSH jelszó megváltozott!",
+ 'adv_SSHPasswordWasChangedBody' => "A MikoPBX eléréséhez szükséges SSH jelszó megváltozott!",
+ 'adv_SSHPasswordWasCompromisedSubject' => 'Figyelem! Az SSH jelszó a MikoPBX felületre való bejelentkezés nélkül megváltozott!',
+ 'adv_SSHPasswordMismatchStringsHash' => 'Az SSH jelszó a MikoPBX webes felületén kívül módosult',
+ 'adv_SSHPasswordMismatchFilesHash' => 'A MikoPBX SSH jelszó eltér a konfigurációs fájlban beállítotttól. Lehetséges, hogy manuálisan módosították a MikoPBX konzolról.',
+ 'adv_ThereIsSomeTroublesWithMikoPBX' => 'Figyelem! Problémákat észleltünk a MikoPBX-ben!',
+ 'lic_MarketplaceText' => 'A Marketplace-en történő regisztrációval további modulokhoz és bővítményekhez férhet hozzá.
Vannak ingyenes modulok, amelyeket eltávolítottunk az alapfunkciók közül a kezdeti beállítás egyszerűsítése érdekében, valamint fizetős modulok tőlünk és más fejlesztőktől.
Ha Ön Ha Ön fejlesztő, akkor vegye fel velünk a kapcsolatot, ha útmutatást szeretne kapni saját modulja fejlesztésével és a piactérhez való hozzáadásával kapcsolatban.',
+ 'fw_iaxDescription' => 'IAX - telefon regisztráció és hangforgalom',
+];
diff --git a/src/Common/Messages/it.php b/src/Common/Messages/it.php
index 2b432f2b5..2c2a1c666 100644
--- a/src/Common/Messages/it.php
+++ b/src/Common/Messages/it.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo6OR' => 'O',
'nw_PublicSIPPort' => 'Numero di porta SIP inoltrato al PBX interno %SIP_PORT%.',
'nw_PublicTLSPort' => 'Numero di porta SIP TLS inoltrato al PBX interno %TLS_PORT%.',
+ 'gs_ErrorSaveSettings' => 'Errore durante il salvataggio delle impostazioni',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Il numero di interno specificato è già in uso',
+ 'fw_iaxDescription' => 'IAX - registrazione telefonica e traffico vocale',
];
diff --git a/src/Common/Messages/ja.php b/src/Common/Messages/ja.php
index b86b10654..c26a15dc1 100644
--- a/src/Common/Messages/ja.php
+++ b/src/Common/Messages/ja.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo2' => '1:1 NAT が使用されていない場合は、ルーター設定で次のポートをパブリック IP から PBX の内部 IP アドレスにリダイレクトします。',
'nw_NATInfo3' => '%SIP_PORT% TCP/UDP および %TLS_PORT% TCP',
'nw_PublicTLSPort' => '内部 %TLS_PORT% PBX に転送される SIP TLS ポート番号',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => '指定された内線番号はすでに使用されています',
+ 'gs_ErrorSaveSettings' => '設定の保存中にエラーが発生しました',
+ 'fw_iaxDescription' => 'IAX - 電話の登録と音声トラフィック',
];
diff --git a/src/Common/Messages/ka.php b/src/Common/Messages/ka.php
index acade8f33..5d82d2f72 100644
--- a/src/Common/Messages/ka.php
+++ b/src/Common/Messages/ka.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo1' => 'თუ თქვენი ქსელი კონფიგურირებულია 1:1 NAT-ის მხარდასაჭერად (ჩვეულებრივ, ნაგულისხმევია ღრუბლებში), თქვენ არ გჭირდებათ რაიმე დამატებითი პარამეტრების გაკეთება თქვენს როუტერზე.',
'nw_NATInfo5' => 'თუ მითითებულია გარე ჰოსტის სახელი, ის გამოყენებული იქნება უპირატესად გარე IP მისამართის ნაცვლად.',
'nw_PublicSIPPort' => 'SIP პორტის ნომერი გადაგზავნილია შიდა %SIP_PORT% PBX-ში',
+ 'gs_ErrorSaveSettings' => 'შეცდომა პარამეტრების შენახვისას',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'მითითებული გაფართოების ნომერი უკვე გამოიყენება',
+ 'fw_iaxDescription' => 'IAX - ტელეფონის რეგისტრაცია და ხმოვანი ტრაფიკი',
];
diff --git a/src/Common/Messages/nl.php b/src/Common/Messages/nl.php
index 4c0561107..8ab11f1fc 100644
--- a/src/Common/Messages/nl.php
+++ b/src/Common/Messages/nl.php
@@ -1279,4 +1279,7 @@
'nw_NATInfo6OR' => 'OF',
'nw_PublicSIPPort' => 'SIP-poortnummer doorgestuurd naar interne %SIP_PORT% PBX',
'nw_PublicTLSPort' => 'SIP TLS-poortnummer doorgestuurd naar interne %TLS_PORT% PBX',
+ 'gs_ErrorSaveSettings' => 'Fout bij opslaan van instellingen',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Het opgegeven toestelnummer is al in gebruik',
+ 'fw_iaxDescription' => 'IAX - telefoonregistratie en spraakverkeer',
];
diff --git a/src/Common/Messages/pl.php b/src/Common/Messages/pl.php
index fbf24a53a..b45a7a029 100644
--- a/src/Common/Messages/pl.php
+++ b/src/Common/Messages/pl.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo5' => 'Jeśli określono zewnętrzną nazwę hosta, będzie ona używana zamiast zewnętrznego adresu IP.',
'nw_NATInfo6OR' => 'LUB',
'nw_PublicTLSPort' => 'Numer portu SIP TLS przekazywany do wewnętrznej centrali %TLS_PORT% PBX',
+ 'gs_ErrorSaveSettings' => 'Błąd podczas zapisywania ustawień',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Podany numer wewnętrzny jest już zajęty',
+ 'fw_iaxDescription' => 'IAX - rejestracja telefonu i ruch głosowy',
];
diff --git a/src/Common/Messages/pt.php b/src/Common/Messages/pt.php
index ecfcebd86..0a4bfedd8 100644
--- a/src/Common/Messages/pt.php
+++ b/src/Common/Messages/pt.php
@@ -830,7 +830,7 @@
'ex_Number' => 'Número do ramal',
'ex_Language' => 'Interface e linguagem de alerta',
'ex_ThisEmailAlreadyRegisteredForOtherUser' => 'O endereço digitado já está registrado para',
- 'ex_EmailAddress' => 'Endereço de email',
+ 'ex_EmailAddress' => 'Endereço de e-mail',
'ex_Username' => 'Nome completo do usuário',
'ex_RoutingSettings' => 'Configurações de roteamento',
'ex_GeneralSettings' => 'Parâmetros-chave',
@@ -876,13 +876,13 @@
'November' => 'Novembro',
'October' => 'Outubro',
'September' => 'Setembro',
- 'August' => 'Agosto',
+ 'August' => 'agosto',
'July' => 'Julho',
'June' => 'Junho',
'May' => 'Maio',
'April' => 'Abril',
'March' => 'Março',
- 'February' => 'Fevereiro',
+ 'February' => 'fevereiro',
'gs_WebAdminLanguage' => 'Linguagem da interface da Web',
'lang_HelpWithTranslateIt' => 'Ajuda com a tradução do MikoPBX',
'topMenu_Support' => 'Suporte',
@@ -1109,7 +1109,7 @@
'mo_SystemExten_hangup' => 'Terminar chamada',
'mo_SystemExten_busy' => 'Reproduzir sinal de ocupado',
'mo_SystemExten_did2user' => 'Direto ao funcionário (correspondência por DID)',
- 'pr_FromUser_v2' => 'do utilizador',
+ 'pr_FromUser_v2' => 'Usuário',
'pr_FromDomain_v2' => 'domínio',
'mo_SystemExten_voicemail' => 'Correio de voz',
'f2b_Jail_asterisk_v2' => 'Erros de autorização SIP',
@@ -1280,4 +1280,7 @@
'nw_NATInfo6OR' => 'OU',
'nw_PublicSIPPort' => 'Número da porta SIP encaminhado para PBX interno %SIP_PORT%',
'nw_PublicTLSPort' => 'Número da porta SIP TLS encaminhado para PBX interno %TLS_PORT%',
+ 'gs_ErrorSaveSettings' => 'Erro ao salvar as configurações',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'O número de ramal especificado já está em uso',
+ 'fw_iaxDescription' => 'IAX - registro telefônico e tráfego de voz',
];
diff --git a/src/Common/Messages/pt_BR.php b/src/Common/Messages/pt_BR.php
index e943aa656..750b112cf 100644
--- a/src/Common/Messages/pt_BR.php
+++ b/src/Common/Messages/pt_BR.php
@@ -384,9 +384,9 @@
'ex_Online' => 'Conectado',
'ex_UpdateStatus' => 'Atualização de status',
'ex_ValidateNumberIsDouble' => 'O número do ramal já está em uso',
- 'ex_ValidateMobileNumberIsDouble' => 'O número do celular já está sendo usado por outro funcionário',
+ 'ex_ValidateMobileNumberIsDouble' => 'O número do celular já está sendo usado por outro ramal',
'ex_ValidateForwardingToBeDifferent' => 'Você não pode configurar o encaminhamento de chamadas para seu próprio número',
- 'ex_ValidateNumberIsEmpty' => 'O número do ramal do funcionário não foi preenchido',
+ 'ex_ValidateNumberIsEmpty' => 'O número do ramal não foi preenchido',
'ex_ValidateRingingBeforeForwardOutOfRange' => 'O tempo de transferência está especificado incorretamente nas configurações de roteamento. Escolha um valor entre {ruleValue}.',
'ex_ValidateForwardingToBeFilled' => 'O número de encaminhamento de tempo limite não foi preenchido nas configurações de roteamento',
'ex_Status' => 'Status',
@@ -394,10 +394,10 @@
'ex_Mobile' => 'Móvel',
'ex_Extension' => 'Número do ramal',
'ex_Name' => 'Nome',
- 'ex_AddNewExtension' => 'Adicionar funcionário',
+ 'ex_AddNewExtension' => 'Adicionar ramal',
'ex_ValidateExtensionNumber' => 'O número do ramal deve consistir apenas em números',
'ex_ValidateSecretEmpty' => 'A senha SIP não pode estar vazia',
- 'ex_ValidateUsernameEmpty' => 'Insira o nome do funcionário',
+ 'ex_ValidateUsernameEmpty' => 'Insira o nome do ramal',
'ex_ValidateEmailEmpty' => 'Provavelmente o endereço de e-mail foi inserido incorretamente',
'ex_ValidateMobileIsNotCorrect' => 'Verifique se a inserção do número do celular está correta',
'ex_IfMainExtensionIsUnavailableRedirectCallTo' => 'Se o número principal não estiver disponível, transferimos a chamada para',
@@ -408,7 +408,7 @@
'ex_NatMode' => 'Modo NAT',
'ex_NetworkFilter' => 'Filtro de rede',
'ex_DTMFMode' => 'Modo DTMF',
- 'ex_BusyLevelInfo' => 'Ao atingir o número especificado de conversas, o telefone do funcionário será considerado ocupado.',
+ 'ex_BusyLevelInfo' => 'Ao atingir o número especificado de conversas, o telefone do ramal será considerado ocupado.',
'ex_BusyLevel' => 'Número máximo de chamadas paralelas',
'ex_SipSettings' => 'Configurações SIP',
'ex_MobileDialstring' => 'Substituindo uma string de discagem',
@@ -477,7 +477,7 @@
'cq_SecRingToEachMembers' => 'Tempo de tentativas de ligar para as operadores',
'cq_QueueMemberSettings' => 'Configurações de fila para operadores',
'cq_AddQueueMembers' => 'Nenhum operador selecionado',
- 'cq_SelectAgentForAddToQueue' => 'Selecione um funcionário para adicionar à fila atual',
+ 'cq_SelectAgentForAddToQueue' => 'Selecione um ramal para adicionar à fila atual',
'cq_QueueMembers' => 'Operadores de fila',
'cd_Description' => 'Um comentário',
'cq_QueueStrategy' => 'Estratégia de chamada para operadores',
@@ -1132,7 +1132,7 @@
'gs_Store3YearsOfRecords' => '3 anos',
'gs_PBXRecordSavePeriodLabel' => 'O período de armazenamento dos registros de conversas',
'gs_StoreAllPossibleRecords' => '∞',
- 'ex_UserPhotography' => 'foto do funcionário',
+ 'ex_UserPhotography' => 'foto do ramal',
'topMenu_SidebarButton' => 'Cardápio',
'ext_InstalledModules' => 'Módulos instalados',
'ext_Marketplace' => 'Mercado',
@@ -1279,4 +1279,7 @@
'nw_NATInfo5' => 'Se um nome de host externo for especificado, ele será usado preferencialmente ao endereço IP externo.',
'nw_NATInfo6OR' => 'OU',
'nw_PublicSIPPort' => 'Número da porta SIP encaminhado para PBX interno %SIP_PORT%',
+ 'gs_ErrorSaveSettings' => 'Erro ao salvar as configurações',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'O número de ramal especificado já está em uso',
+ 'fw_iaxDescription' => 'IAX - registro telefônico e tráfego de voz',
];
diff --git a/src/Common/Messages/ro.php b/src/Common/Messages/ro.php
index cf18aa1c2..4cdad68eb 100644
--- a/src/Common/Messages/ro.php
+++ b/src/Common/Messages/ro.php
@@ -1262,4 +1262,7 @@
'nw_NATInfo6OR' => 'SAU',
'nw_PublicSIPPort' => 'Numărul portului SIP redirecționat către PBX intern %SIP_PORT%.',
'nw_PublicTLSPort' => 'Numărul portului SIP TLS redirecționat către centrala internă %TLS_PORT%.',
+ 'gs_ErrorSaveSettings' => 'Eroare la salvarea setărilor',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Numărul de extensie specificat este deja în uz',
+ 'fw_iaxDescription' => 'IAX - înregistrare telefonică și trafic vocal',
];
diff --git a/src/Common/Messages/ru.php b/src/Common/Messages/ru.php
index f2960dd24..90b5424a1 100644
--- a/src/Common/Messages/ru.php
+++ b/src/Common/Messages/ru.php
@@ -246,6 +246,8 @@
'gs_PBXRecordSavePeriodLabel' => 'Период хранения записей разговоров',
'gs_StoreAllPossibleRecords' => '∞',
'gs_DisableAllModules' => 'Отключить маркетплейс',
+ 'gs_ErrorSaveSettings' => 'Ошибка сохранения настроек',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Указанный внутренний номер уже используется',
'pr_AddSIPProvider' => 'Подключить SIP',
'pr_AddIAXProvider' => 'Подключить IAX',
'pr_QualifyInstructionsIAX' => 'При включение этой опции Asterisk будет отправлять SIP Options пакеты. Это необходимо для поддержки NAT туннелирования на вашем маршрутизаторе.',
@@ -541,6 +543,7 @@
'fw_Permit' => 'Подсеть',
'fw_Rules' => 'Доступные сервисы',
'fw_sipDescription' => 'SIP & RTP - регистрация телефонов и голосовой трафик',
+ 'fw_iaxDescription' => 'IAX - регистрация телефонов и голосовой трафик',
'fw_webDescription' => 'WEB - доступ к административному интерфейсу',
'fw_amiDescription' => 'AMI - доступ к asterisk manager api через telnet',
'fw_ctiDescription' => 'CTI - подключение панели телефонии',
diff --git a/src/Common/Messages/sv.php b/src/Common/Messages/sv.php
index 9b643d04c..0fdca01ee 100644
--- a/src/Common/Messages/sv.php
+++ b/src/Common/Messages/sv.php
@@ -1246,4 +1246,7 @@
'nw_NATInfo6OR' => 'ELLER',
'nw_PublicSIPPort' => 'SIP-portnummer vidarebefordrat till intern %SIP_PORT% PBX',
'nw_PublicTLSPort' => 'SIP TLS-portnummer vidarebefordrat till intern %TLS_PORT% PBX',
+ 'gs_ErrorSaveSettings' => 'Det gick inte att spara inställningar',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Det angivna anknytningsnumret används redan',
+ 'fw_iaxDescription' => 'IAX - telefonregistrering och rösttrafik',
];
diff --git a/src/Common/Messages/th.php b/src/Common/Messages/th.php
index 04f44102e..d1a070e8d 100644
--- a/src/Common/Messages/th.php
+++ b/src/Common/Messages/th.php
@@ -106,13 +106,13 @@
'BreadcrumbIncomingRoutes' => 'เส้นทางขาเข้า',
'SubHeaderIncomingRoutes' => 'กฎและเทมเพลตสำหรับการกระจายสายเรียกเข้า',
'BreadcrumbIncomingRoutesmodify' => 'การตั้งกฎเกณฑ์',
- 'BreadcrumbExtensions' => 'พนักงาน',
+ 'BreadcrumbExtensions' => 'เบอร์ภายใน',
'SubHeaderExtensions' => 'การตั้งค่าหมายเลขโทรศัพท์หลักและกฎการส่งต่อส่วนบุคคล',
'BreadcrumbExtensionsmodify' => 'การเปลี่ยนการตั้งค่า',
'BreadcrumbCallQueues' => 'คิวโทร',
'SubHeaderCallQueues' => 'สายจะถูกพักสายแล้วกระจายไปยังผู้เข้าร่วมตามกลยุทธ์',
'BreadcrumbCallQueuesmodify' => 'การตั้งค่าคิว',
- 'BreadcrumbOutOffWorkTime' => 'เวลาไม่ทำงาน',
+ 'BreadcrumbOutOffWorkTime' => 'นอกเวลาทำการ',
'SubHeaderOutOffWorkTime' => 'กฎการดำเนินงานของสถานีนอกเวลาทำการ วันหยุด และวันหยุดสุดสัปดาห์',
'BreadcrumbOutOffWorkTimemodify' => 'การตั้งกฎเกณฑ์',
'BreadcrumbFirewall' => 'การตั้งค่าไฟร์วอลล์',
@@ -154,14 +154,14 @@
'BreadcrumbPbxExtensionModules' => 'การจัดการโมดูลและส่วนขยายสำหรับ MikoPBX',
'SubHeaderPbxExtensionModules' => 'อัปโหลดโมดูลของคุณเองหรือดาวน์โหลดจากตลาดของเรา',
'mm_Setup' => 'โทรศัพท์',
- 'mm_Extensions' => 'พนักงาน',
+ 'mm_Extensions' => 'เบอร์ภายใน',
'mm_CallQueues' => 'คิวโทร',
'mm_DialplanApplications' => 'แอปพลิเคชัน Dialplan',
'mm_Routing' => 'การกำหนดเส้นทาง',
'mm_Providers' => 'ผู้ให้บริการโทรศัพท์',
'mm_IncomingRoutes' => 'เส้นทางที่เข้ามา',
'mm_OutboundRoutes' => 'เส้นทางขาออก',
- 'mm_OutOffWorkTime' => 'เวลาไม่ทำงาน',
+ 'mm_OutOffWorkTime' => 'นอกเวลาทำการ',
'mm_System' => 'ระบบ',
'mm_NetworkSettings' => 'เครือข่ายและไฟร์วอลล์',
'mm_GeneralSettings' => 'การตั้งค่าทั่วไป',
@@ -229,7 +229,7 @@
'pr_WithoutRegistration' => 'การลงทะเบียนถูกปิดใช้งาน',
'pr_TableColumnProviderLogin' => 'เข้าสู่ระบบ',
'pr_TableColumnProviderHostName' => 'เจ้าภาพ',
- 'pr_TableColumnProviderType' => 'พิมพ์',
+ 'pr_TableColumnProviderType' => 'รูปแบบ',
'pr_TableColumnProviderName' => 'ผู้ให้บริการ',
'pr_TableColumnProviderStatus' => 'สถานะ',
'pr_ValidateRTPOutOfRange' => 'ช่วงของพอร์ต RTP ไม่ถูกต้อง ค่าต้องอยู่ระหว่าง {ruleValue}',
@@ -247,7 +247,7 @@
'gs_PBXRecordSavePeriodLabel' => 'ระยะเวลาการจัดเก็บสำหรับการบันทึกการโทร',
'gs_StoreAllPossibleRecords' => '∞',
'gs_DisableAllModules' => 'ปิดการใช้งานตลาด',
- 'pr_AddSIPProvider' => 'เชื่อมต่อเอสไอพี',
+ 'pr_AddSIPProvider' => 'เชื่อมต่อ SIP',
'pr_AddIAXProvider' => 'เชื่อมต่อ IAX',
'pr_QualifyInstructionsIAX' => 'เมื่อเปิดใช้งานตัวเลือกนี้ เครื่องหมายดอกจันจะส่งแพ็กเก็ตตัวเลือก SIP นี่เป็นสิ่งจำเป็นเพื่อรองรับ NAT tunneling บนเราเตอร์ของคุณ',
'pr_CustomFieldsDescriptions' => 'ในกรณีส่วนใหญ่ ช่องแทนที่ควรเว้นว่างไว้
@@ -334,18 +334,18 @@
'cd_Extensions' => 'หมายเลขโทรศัพท์สำหรับคิวนี้',
'cq_QueueStrategy' => 'กลยุทธ์การโทรสำหรับผู้ประกอบการ',
'cq_QueueMembers' => 'ตัวดำเนินการคิว',
- 'cq_SelectAgentForAddToQueue' => 'เลือกพนักงานที่จะเพิ่มลงในคิวปัจจุบัน',
+ 'cq_SelectAgentForAddToQueue' => 'เลือกเจ้าหน้าที่ ที่จะเพิ่มลงในคิวปัจจุบัน',
'cq_AddQueueMembers' => 'ไม่ได้เลือกโอเปอเรเตอร์',
'cq_QueueMemberSettings' => 'การตั้งค่าคิวสำหรับผู้ประกอบการ',
'cq_SecRingToEachMembers' => 'เวลาพยายามโทรสำหรับผู้ปฏิบัติงาน',
'cq_WrapupTime' => 'เวลาพักของผู้ให้บริการหลังจากรับสายก่อนเริ่มรับสายใหม่',
'cq_ReciveCallWhileOnCall' => 'รับสายใหม่ระหว่างการโทร',
'cq_QueueCallerSettings' => 'การตั้งค่าคิวผู้โทร',
- 'cq_CallerHearOnQueued' => 'สิ่งที่สมาชิกได้ยินขณะรอ',
+ 'cq_CallerHearOnQueued' => 'สิ่งที่ผู้โทรได้ยินขณะรอ',
'cq_ringing' => 'เสียงเรียกเข้า',
'cq_AnnoncePosition' => 'แจ้งตำแหน่งปัจจุบันในคิว',
'cq_AnnonceHoldTime' => 'แจ้งเกี่ยวกับเวลารอโดยประมาณ',
- 'cq_PereodicAnonceSoundFile' => 'วลีส่งเสริมการขายหรือการแจ้งเตือนเพิ่มเติม',
+ 'cq_PereodicAnonceSoundFile' => 'ข้อความเสียง ส่งเสริมการขาย หรือการแจ้งเตือนเพิ่มเติม',
'cq_PereodicAnonceMohSoundFile' => 'เพลงพื้นหลัง (MOH)',
'gs_SSHDisablePasswordLogins' => 'ปิดการใช้งานการตรวจสอบรหัสผ่าน',
'cq_PereodicAnonceFrequency' => 'เวลาเป็นวินาทีเพื่อทำซ้ำการแจ้งเตือนทั้งหมดเป็นระยะ',
@@ -354,7 +354,7 @@
'cq_ScenaryTwo' => 'สถานการณ์ #2',
'cq_ScenaryThree' => 'สถานการณ์ #3',
'cq_ScenaryFour' => 'สถานการณ์ #4',
- 'cq_IfQueueNotAnsweredFor' => 'หากสมาชิกรอคิวนานเกิน ',
+ 'cq_IfQueueNotAnsweredFor' => 'หากสายโทรเข้ารอคิวนานเกิน ',
'cq_SecondsCallWillBeRoutedTo' => ' วินาที โอนสายไปที่ ',
'cq_RedirectToExtensionIfEmtyQueue' => 'หากไม่มีโอเปอเรเตอร์อยู่ในคิว ให้โอนสายไปที่ ',
'cq_IfQueueNotAnsweredNumberCalls' => 'หากไม่มีโอเปอเรเตอร์รับสายภายใน ',
@@ -406,12 +406,12 @@
'ex_UserPhotography' => 'รูปถ่ายพนักงาน',
'ex_MobileSettings' => 'การตั้งค่าเพิ่มเติมสำหรับมือถือ',
'ex_MobileDialstring' => 'การแทนที่สตริงการเรียกเลขหมาย',
- 'ex_SipSettings' => 'การตั้งค่าจิบ',
+ 'ex_SipSettings' => 'การตั้งค่าSIP',
'ex_BusyLevel' => 'จำนวนการสนทนาคู่ขนานสูงสุด',
'ex_BusyLevelInfo' => 'เมื่อถึงจำนวนการโทรที่กำหนด โทรศัพท์ของพนักงานจะถือว่าไม่ว่าง',
'ex_DTMFMode' => 'โหมด DTMF',
'ex_NetworkFilter' => 'ตัวกรองเครือข่าย',
- 'ex_NatMode' => 'โหมดแนท',
+ 'ex_NatMode' => 'โหมด NAT',
'gs_CallRecordTab' => 'การบันทึกการสนทนา',
'ex_ManualAdditionalAttributes' => 'ตัวเลือกพิเศษ',
'ex_RingMainExtension' => 'ในระหว่าง',
@@ -427,7 +427,7 @@
'ex_PasswordNoLowSimvol' => 'รหัสผ่านจะต้องมีตัวอักษร',
'ex_PasswordNoNumbers' => 'รหัสผ่านจะต้องมีตัวเลข',
'ex_ValidateExtensionNumber' => 'หมายเลขต่อต้องประกอบด้วยตัวเลขเท่านั้น',
- 'ex_AddNewExtension' => 'เพิ่มพนักงาน',
+ 'ex_AddNewExtension' => 'เพิ่มเบอร์ภายใน',
'ex_Name' => 'พนักงาน',
'ex_Transport' => 'โปรโตคอลการขนส่ง',
'ex_Extension' => 'หมายเลขต่อขยาย',
@@ -465,7 +465,7 @@
'ex_dropdownCategory_MENUITEMS' => 'รายการเมนู',
'ex_dropdownCategory_SYSTEM' => 'หมายเลขบริการ',
'ex_dropdownCategory_PARKING' => 'ช่องจอดรถ',
- 'ex_ImpossibleToDeleteExtension' => 'ไม่สามารถลบพนักงานได้เพราะว่า มีลิงค์ต่อไปนี้',
+ 'ex_ImpossibleToDeleteExtension' => 'ไม่สามารถลบเบอร์ภายในได้เพราะว่า มีลิงค์ต่อไปนี้',
'ex_ImpossibleToGetSecret' => 'ไม่สามารถรับรหัสผ่านผู้ใช้',
'am_TableColumnName' => 'ชื่อ',
'am_TableColumnRead' => 'สิทธิ์การอ่าน',
@@ -588,9 +588,9 @@
'nw_NetworkAddressTranslations' => 'โทโพโลยีเครือข่าย',
'gs_MainTab' => 'ขั้นพื้นฐาน',
'gs_FeaturesTab' => 'การโอนสาย',
- 'gs_SIPTab' => 'จิบ',
+ 'gs_SIPTab' => 'SIP',
'gs_AMITab' => 'อามิ&อาจัม',
- 'gs_SSHTab' => 'สสส',
+ 'gs_SSHTab' => 'SSH',
'gs_WebTab' => 'เว็บอินเตอร์เฟส',
'gs_PBXName' => 'ชื่อระบบ PBX',
'gs_PBXDescription' => 'คำอธิบายเพิ่มเติม',
@@ -605,7 +605,7 @@
'gs_PBXFeatureAttendedTransfer' => 'การผสมผสานการแปลเชิงปรึกษา',
'gs_PBXFeatureBlindTransfer' => 'การรวมกันเพื่อการโอนแบบไม่มีเงื่อนไข',
'gs_PBXFeatureDigitTimeout' => 'การหมดเวลาระหว่างหลักสูงสุดเมื่อป้อนหมายเลขส่วนขยาย (เป็นมิลลิวินาที)',
- 'gs_PBXFeaturePickupExten' => 'ชุดค่าผสมสำหรับดักสายเรียกเข้า',
+ 'gs_PBXFeaturePickupExten' => 'Code ดึงสายโทรเข้า จากเครื่องอื่น',
'gs_PBXSplitAudioThread' => 'บันทึกการบันทึกในโหมดสเตอริโอ',
'gs_PBXAllowGuestCalls' => 'อนุญาตสายเรียกเข้าจากเซิร์ฟเวอร์ใด ๆ',
'gs_SIPPort' => 'พอร์ต SIP สำหรับลงทะเบียนโทรศัพท์ที่สถานีนี้',
@@ -802,7 +802,7 @@
'repConferenceRooms' => 'การประชุม - %represent%',
'repCustomFiles' => 'ไฟล์ระบบ - %represent%',
'repDialplanApplications' => 'แอปพลิเคชัน Dialplan - %represent%',
- 'repExtensionForwardingRights' => 'การตั้งค่าการกำหนดเส้นทางพนักงาน - %represent%',
+ 'repExtensionForwardingRights' => 'การตั้งค่าการกำหนดเส้นทางเบอร์ภายใน- %represent%',
'repExtensions' => 'หมายเลขต่อ - %represent%',
'repExternalPhones' => 'หมายเลขภายนอก - %represent%',
'repFail2BanRules' => 'กฎ Fail2Ban - %represent%',
@@ -1028,7 +1028,7 @@
'mo_ModuleShort4Dropdown' => 'โมดูล',
'mo_SystemExten_hangup' => 'วางสาย',
'mo_SystemExten_busy' => 'เล่นโทนไม่ว่าง',
- 'mo_SystemExten_did2user' => 'ส่งตรงถึงพนักงาน (จับคู่โดย DID)',
+ 'mo_SystemExten_did2user' => 'ส่งตรงถึงเบอร์ภายใน(จับคู่โดย DID)',
'mo_SystemExten_voicemail' => 'ข้อความเสียง',
'GoToWikiDocumentation' => 'ไปที่เอกสารออนไลน์',
'mo_ModuleSettingsError' => 'ข้อผิดพลาดในการตั้งค่าโมดูล - %modulename%',
@@ -1202,8 +1202,8 @@
'tf_calUrl' => 'URL ปฏิทิน',
'tf_calUser' => 'ชื่อผู้ใช้',
'tf_calSecret' => 'รหัสผ่าน',
- 'tf_calType' => 'พิมพ์',
- 'tf_CAL_TYPE_NONE' => 'สามัญ',
+ 'tf_calType' => 'รูปแบบ',
+ 'tf_CAL_TYPE_NONE' => 'ปกติ',
'tf_CAL_TYPE_CALDAV' => 'คาลดีเอวี',
'tf_CAL_TYPE_ICAL' => 'ไอแคล',
'ext_UpdateModuleTitle' => 'อัพเดตโมดูล',
@@ -1244,4 +1244,7 @@
'nw_PublicTLSPort' => 'หมายเลขพอร์ต SIP TLS ส่งต่อไปยัง PBX ภายใน %TLS_PORT%',
'nw_NATInfo1' => 'หากเครือข่ายของคุณได้รับการกำหนดค่าให้รองรับ NAT 1:1 (โดยปกติจะเป็นค่าเริ่มต้นในระบบคลาวด์) คุณไม่จำเป็นต้องทำการตั้งค่าเพิ่มเติมใดๆ บนเราเตอร์ของคุณ',
'nw_NATInfo2' => 'หากไม่ได้ใช้ NAT 1:1 ให้เปลี่ยนเส้นทางพอร์ตต่อไปนี้จาก IP สาธารณะไปยังที่อยู่ IP ภายในของ PBX ในการตั้งค่าเราเตอร์ของคุณ',
+ 'gs_ErrorSaveSettings' => 'เกิดข้อผิดพลาดในการบันทึกการตั้งค่า',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'หมายเลขต่อขยายที่ระบุมีการใช้งานแล้ว',
+ 'fw_iaxDescription' => 'IAX - การลงทะเบียนโทรศัพท์และการรับส่งข้อมูลด้วยเสียง',
];
diff --git a/src/Common/Messages/tr.php b/src/Common/Messages/tr.php
index 266403485..444548ce6 100644
--- a/src/Common/Messages/tr.php
+++ b/src/Common/Messages/tr.php
@@ -1246,4 +1246,7 @@
'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO% UDP',
'nw_NATInfo5' => 'Harici bir ana bilgisayar adı belirtilirse, harici IP adresi yerine bu ad kullanılacaktır.',
'nw_PublicSIPPort' => 'Dahili %SIP_PORT% PBX\'e iletilen SIP bağlantı noktası numarası',
+ 'gs_ErrorSaveSettings' => 'Ayarlar kaydedilirken hata oluştu',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Belirtilen dahili numara zaten kullanımda',
+ 'fw_iaxDescription' => 'IAX - telefon kaydı ve ses trafiği',
];
diff --git a/src/Common/Messages/uk.php b/src/Common/Messages/uk.php
index c3bae740a..c20e25432 100644
--- a/src/Common/Messages/uk.php
+++ b/src/Common/Messages/uk.php
@@ -1280,4 +1280,7 @@
'nw_NATInfo5' => 'Якщо вказано зовнішнє ім\'я хоста, воно буде використовуватись у пріоритеті замість зовнішньої IP-адреси.',
'nw_PublicSIPPort' => 'Номер порту SIP перенаправленого на внутрішній %SIP_PORT% PBX',
'nw_PublicTLSPort' => 'Номер порту SIP TLS перенаправленого на внутрішній %TLS_PORT% PBX',
+ 'gs_ErrorSaveSettings' => 'Помилка збереження налаштувань',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Вказаний внутрішній номер вже використовується',
+ 'fw_iaxDescription' => 'IAX - реєстрація телефонів та голосовий трафік',
];
diff --git a/src/Common/Messages/vi.php b/src/Common/Messages/vi.php
index 4eeded666..55f43da31 100644
--- a/src/Common/Messages/vi.php
+++ b/src/Common/Messages/vi.php
@@ -1246,4 +1246,7 @@
'nw_NATInfo3' => '%SIP_PORT% TCP/UDP và %TLS_PORT% TCP',
'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO% UDP',
'nw_NATInfo6OR' => 'HOẶC',
+ 'gs_ErrorSaveSettings' => 'Lỗi lưu cài đặt',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => 'Số máy nhánh được chỉ định đã được sử dụng',
+ 'fw_iaxDescription' => 'IAX - đăng ký điện thoại và lưu lượng thoại',
];
diff --git a/src/Common/Messages/zh_Hans.php b/src/Common/Messages/zh_Hans.php
index 4e706b227..55268c19b 100644
--- a/src/Common/Messages/zh_Hans.php
+++ b/src/Common/Messages/zh_Hans.php
@@ -1246,4 +1246,7 @@
'nw_NATInfo4' => '%RTP_PORT_FROM%-%RTP_PORT_TO% UDP',
'nw_NATInfo5' => '如果指定了外部主机名,则将优先使用外部主机名而不是外部 IP 地址。',
'nw_PublicTLSPort' => '转发到内部 %TLS_PORT% PBX 的 SIP TLS 端口号',
+ 'gs_ErrorSaveSettings' => '保存设置时出错',
+ 'mo_ThisNumberNotUniqueForExtensionsModels' => '指定的分机号码已被使用',
+ 'fw_iaxDescription' => 'IAX-电话注册和语音流量',
];
diff --git a/src/Common/Models/Extensions.php b/src/Common/Models/Extensions.php
index a5fb826c1..8ed11f48e 100644
--- a/src/Common/Models/Extensions.php
+++ b/src/Common/Models/Extensions.php
@@ -137,6 +137,42 @@ public static function getNextFreeApplicationNumber(): string
return $freeExtension;
}
+ /**
+ * Returns Caller ID by phone number.
+ * @param string $number
+ * @return string
+ */
+ public static function getCidByPhoneNumber(string $number):string
+ {
+ if(empty($number)){
+ return $number;
+ }
+ $number = preg_replace('/\D+/', '', $number);
+ $extensionLength = PbxSettings::getValueByKey(PbxSettingsConstants::PBX_INTERNAL_EXTENSION_LENGTH);
+ if(strlen($number) > $extensionLength){
+ $query = 'number LIKE :phone:';
+ $phone = '%'.substr($number, -9);
+ }else{
+ $query = 'number = :phone:';
+ $phone = $number;
+ }
+ $filter = [
+ $query,
+ 'columns' => 'callerid',
+ 'bind' => [
+ 'phone' => $phone
+ ]
+ ];
+ $data = self::findFirst($filter);
+ if($data){
+ $cid = $data->callerid;
+ }else{
+ $cid = $number;
+ }
+
+ return $cid;
+ }
+
/**
* Get the next available internal extension number.
*
diff --git a/src/Common/Models/FirewallRules.php b/src/Common/Models/FirewallRules.php
index 3f1489a6b..b24574c5d 100644
--- a/src/Common/Models/FirewallRules.php
+++ b/src/Common/Models/FirewallRules.php
@@ -146,6 +146,19 @@ public static function getDefaultRules(): array
'action' => 'allow',
'shortName' => 'SIP & RTP',
],
+ 'IAX' => [
+ 'rules' => [
+ [
+ 'portfrom' => $protectedPortSet[PbxSettingsConstants::IAX_PORT],
+ 'portto' => $protectedPortSet[PbxSettingsConstants::IAX_PORT],
+ 'protocol' => 'udp',
+ 'portFromKey' => PbxSettingsConstants::IAX_PORT,
+ 'portToKey' => PbxSettingsConstants::IAX_PORT,
+ ]
+ ],
+ 'action' => 'allow',
+ 'shortName' => 'IAX',
+ ],
'WEB' => [
'rules' => [
[
@@ -255,6 +268,7 @@ public static function getProtectedPortSet(): array
PbxSettingsConstants::WEB_PORT,
PbxSettingsConstants::WEB_HTTPS_PORT,
PbxSettingsConstants::SSH_PORT,
+ PbxSettingsConstants::IAX_PORT,
];
$result = [];
foreach ($portSet as $portName) {
diff --git a/src/Common/Providers/CDRDatabaseProvider.php b/src/Common/Providers/CDRDatabaseProvider.php
index 15a1b0a4e..2c13cf61c 100644
--- a/src/Common/Providers/CDRDatabaseProvider.php
+++ b/src/Common/Providers/CDRDatabaseProvider.php
@@ -77,7 +77,7 @@ public static function getCdr(array $filter = []): array
$client = new BeanstalkClient(WorkerCdr::SELECT_CDR_TUBE);
$filename = '';
try {
- list($result, $message) = $client->sendRequest(json_encode($filter), 2);
+ list($result, $message) = $client->sendRequest(json_encode($filter), 15);
if ($result!==false){
$filename = json_decode($message, true, 512, JSON_THROW_ON_ERROR);
}
diff --git a/src/Core/Asterisk/AsteriskManager.php b/src/Core/Asterisk/AsteriskManager.php
index e257d34d8..efac60a40 100644
--- a/src/Core/Asterisk/AsteriskManager.php
+++ b/src/Core/Asterisk/AsteriskManager.php
@@ -19,6 +19,7 @@
namespace MikoPBX\Core\Asterisk;
+use MikoPBX\Core\System\Processes;
use MikoPBX\Core\System\SystemMessages;
use MikoPBX\Core\System\Util;
use Throwable;
@@ -612,30 +613,42 @@ public function connect($server = null, $username = null, $secret = null, $event
}
// connect the socket
- $errno = $errstr = null;
+ $errno = $errStr = null;
$timeout = 2;
- $this->socket = @fsockopen($this->server, $this->port, $errno, $errstr, $timeout);
- if ($this->socket == false) {
- SystemMessages::sysLogMsg('asmanager', "Unable to connect to manager {$this->server}:{$this->port} ($errno): $errstr", LOG_ERR);
+ $netStatPath = Util::which('netstat');
+ $busyBoxPath = Util::which('busybox');
+
+ $chkCommand = "$netStatPath -ntap | $busyBoxPath grep '0.0.0.0:$this->port ' | $busyBoxPath grep LISTEN | $busyBoxPath grep asterisk";
+ if(Processes::mwExec($chkCommand) === 1){
+ SystemMessages::sysLogMsg('AMI', "Exceptions, Unable to connect to $server: the asterisk process is not running", LOG_ERR);
+ return false;
+ }
+ try {
+ $this->socket = fsockopen($this->server, $this->port, $errno, $errStr, $timeout);
+ }catch (Throwable $e){
+ SystemMessages::sysLogMsg('AMI', "Exceptions, Unable to connect to manager $server ($errno): $errStr", LOG_ERR);
+ return false;
+ }
+ if ($this->socket === false) {
+ SystemMessages::sysLogMsg('AMI', "Unable to connect to manager $server ($errno): $errStr", LOG_ERR);
return false;
}
- // PT1C;
stream_set_timeout($this->socket, 1, 0);
// read the header
$str = $this->getStringDataFromSocket();
if ($str === '') {
// a problem.
- Util::sysLogMsg('asmanager', "Asterisk Manager header not received.", LOG_ERR);
+ SystemMessages::sysLogMsg('AMI', "Asterisk Manager header not received.", LOG_ERR);
return false;
}
// login
$res = $this->sendRequest('login', ['Username' => $username, 'Secret' => $secret, 'Events' => $events]);
- if ($res['Response'] != 'Success') {
+ if ($res['Response'] !== 'Success') {
$this->_loggedIn = false;
- Util::sysLogMsg('asmanager', "Failed to login.", LOG_ERR);
+ SystemMessages::sysLogMsg('AMI', "Failed to login.", LOG_ERR);
$this->disconnect();
return false;
}
diff --git a/src/Core/Asterisk/Configs/ConferenceConf.php b/src/Core/Asterisk/Configs/ConferenceConf.php
index 285803136..cb768c0cf 100644
--- a/src/Core/Asterisk/Configs/ConferenceConf.php
+++ b/src/Core/Asterisk/Configs/ConferenceConf.php
@@ -20,6 +20,7 @@
namespace MikoPBX\Core\Asterisk\Configs;
use MikoPBX\Common\Models\ConferenceRooms;
+use MikoPBX\Core\System\Util;
/**
* Generates the configuration content for confbridge.conf.
@@ -39,9 +40,8 @@ class ConferenceConf extends AsteriskConfigClass
protected function generateConfigProtected(): void
{
$conf = "";
-
// Write the configuration content to the file
- file_put_contents($this->config->path('asterisk.astetcdir') . '/confbridge.conf', $conf);
+ Util::fileWriteContent($this->config->path('asterisk.astetcdir') . '/confbridge.conf', $conf);
}
/**
diff --git a/src/Core/Asterisk/Configs/ExtensionsOutWorkTimeConf.php b/src/Core/Asterisk/Configs/ExtensionsOutWorkTimeConf.php
index ad242a601..ebd7910a1 100644
--- a/src/Core/Asterisk/Configs/ExtensionsOutWorkTimeConf.php
+++ b/src/Core/Asterisk/Configs/ExtensionsOutWorkTimeConf.php
@@ -28,6 +28,7 @@
use MikoPBX\Common\Models\SoundFiles;
use MikoPBX\Core\System\Processes;
use MikoPBX\Core\System\Util;
+use DateTime;
/**
* Class ExtensionsOutWorkTimeConf
@@ -89,6 +90,22 @@ public function extensionGenContexts(): string
return $this->conf;
}
+
+ /**
+ *
+ * @return string Set global vars.
+ */
+ public function extensionGlobals(): string
+ {
+ $configs = '';
+ $dbData = Sip::find("type = 'friend' AND ( disabled <> '1')");
+ foreach ($dbData as $sipPeer) {
+ $context_id = SIPConf::getContextId($sipPeer->host, $sipPeer->port);
+ $configs .= "CONTEXT_ID_$sipPeer->uniqid=$context_id".PHP_EOL;
+ }
+ return $configs;
+ }
+
/**
* Generates the customized incoming context for a specific route before dialing system.
*
@@ -101,6 +118,7 @@ public function generateIncomingRoutBeforeDialSystem(string $rout_number): strin
// Check the schedule for incoming external calls.
return 'same => n,NoOp(contextID: ${contextID})' . PHP_EOL . "\t" .
'same => n,ExecIf($["${CONTEXT}" == "public-direct-dial"]?Set(contextID=none-incoming))' . PHP_EOL . "\t" .
+ 'same => n,ExecIf($["${contextID}x" == "x"]?Set(contextID=${CONTEXT_ID_${providerID}}))' . PHP_EOL . "\t" .
'same => n,ExecIf($["${contextID}x" == "x"]?Set(contextID=${CONTEXT}))' . PHP_EOL . "\t" .
'same => n,GosubIf($["${IGNORE_TIME}" != "1"]?' . self::OUT_WORK_TIME_CONTEXT . ',${EXTEN},1)' . PHP_EOL . "\t";
}
@@ -135,13 +153,8 @@ private function generateOutWorkTimes(): void
foreach ($data as $ruleData) {
$contextId = 'check-out-work-time-'.$ruleData['id'];
$this->conf .= 'same => n,Gosub('.$contextId.',${EXTEN},1)'.PHP_EOL."\t";
- [, $years] = $this->getOutWorkIntervals($ruleData['date_from'], $ruleData['date_to']);
$additionalContexts.= '['.$contextId.']'.PHP_EOL;
$additionalContexts.= 'exten => _[0-9*#+a-zA-Z]!,1,NoOp()'.PHP_EOL."\t";
- if(!empty($years)){
- $additionalContexts.= 'same => n,Set(TMP_YEARS='.implode('-',$years).'-)'.PHP_EOL."\t";
- $additionalContexts.= 'same => n,ExecIf($["STRREPLACE(TMP_YEARS,currentYear)" == "${TMP_YEARS}"]?return)'.PHP_EOL."\t";
- }
// Restrictions for the route are not allowed for this rule.
if ($ruleData['allowRestriction'] === '1') {
$additionalContexts.= 'same => n,ExecIf($["${DIALPLAN_EXISTS('.$contextId.'-${contextID},${EXTEN},1)}" == "0"]?return)'.PHP_EOL."\t";
@@ -202,7 +215,7 @@ private function getRoutesData(): array
}elseif ($provByType->registration_type === Sip::REG_TYPE_INBOUND){
$context_id = "{$provider->uniqid}-incoming";
} else {
- $context_id = SIPConf::getContextId($provByType->host . $provByType->port);
+ $context_id = SIPConf::getContextId($provByType->host , $provByType->port);
}
} else {
$context_id = 'none-incoming';
@@ -215,75 +228,75 @@ private function getRoutesData(): array
}
/**
- * Get the out-of-work intervals based on the provided date range.
+ * Generate the out-of-work rule based on the provided data.
*
- * @param int $date_from The starting date.
- * @param int $date_to The ending date.
+ * @param array $srcOutData The data for the out-of-work rule.
+ * @param string &$conf_out_set_var The output string for the SET variables.
+ * @param string &$conf The output string for the configuration.
*
- * @return array An array of intervals.
+ * @return void
*/
- private function getOutWorkIntervals($date_from, $date_to): array
+ private function generateOutWorkRule(array $srcOutData, string &$conf_out_set_var, string &$conf): void
{
- $years = [];
- $year_from = 1 * date('Y', (int)$date_from);
- $year_to = 1 * date('Y', (int)$date_to);
-
- $intervals = [];
- $Year = $year_from;
- if ($year_to === $year_from) {
- if(!empty($date_from)){
- $years[] = $Year;
+ $intervals = $this->splitIntoMonthlyIntervals($srcOutData['date_from'], $srcOutData['date_to']);
+ if(empty($intervals)){
+ $timesArray = $this->getTimesInterval($srcOutData);
+ $weekdays = $this->getWeekDayInterval($srcOutData);
+ [$mDays, $months] = $this->initDaysMonthsInterval($srcOutData);
+ $appdata = $this->initRuleAppData($srcOutData, $conf_out_set_var);
+ foreach ($timesArray as $times) {
+ $conf .= "same => n,GotoIfTime($times,$weekdays,$mDays,$months?{$appdata})\n\t";
}
- $intervals[] = [
- 'date_from' => $date_from,
- 'date_to' => $date_to
- ];
- return [$intervals, $years];
- }
- while ($Year <= $year_to) {
+ }else{
+ foreach ($intervals as $interval){
+ [$srcOutData['date_from'],$srcOutData['date_to']] = $interval;
- $years[] = $Year;
- if ($Year === $year_from) {
- $intervals[] = [
- 'date_from' => $date_from,
- 'date_to' => (string)strtotime('31-12-' . $Year)
- ];
- } elseif ($Year === $year_to) {
- $intervals[] = [
- 'date_from' => (string)strtotime('01-01-' . $Year),
- 'date_to' => $date_to
- ];
- } else {
- $intervals[] = [
- 'date_from' => (string)strtotime('01-01-' . $Year),
- 'date_to' => (string)strtotime('31-12-' . $Year)
- ];
+ $timesArray = $this->getTimesInterval($srcOutData);
+ $weekdays = $this->getWeekDayInterval($srcOutData);
+
+ [$mDays, $months] = $this->initDaysMonthsInterval($srcOutData);
+ $appdata = $this->initRuleAppData($srcOutData, $conf_out_set_var);
+
+ $year = 1 * date('Y', $srcOutData['date_from']);
+ foreach ($timesArray as $times) {
+ $timeAppData = "GotoIfTime($times,$weekdays,$mDays,$months?{$appdata})";
+ $conf .= 'same => n,ExecIf($["${currentYear}" == "'.$year.'"]?'.$timeAppData.')'."\n\t";
+ }
}
- $Year++;
}
- return [$intervals, $years];
}
/**
- * Generate the out-of-work rule based on the provided data.
- *
- * @param array $out_data The data for the out-of-work rule.
- * @param string &$conf_out_set_var The output string for the SET variables.
- * @param string &$conf The output string for the configuration.
- *
- * @return void
+ * Get intervals from timestamp
+ * @param $date_from
+ * @param $date_to
+ * @return array
*/
- private function generateOutWorkRule(array $out_data, string &$conf_out_set_var, string &$conf): void
+ private function splitIntoMonthlyIntervals($date_from, $date_to):array
{
- $timesArray = $this->getTimesInterval($out_data);
- $weekdays = $this->getWeekDayInterval($out_data);
-
- [$mDays, $months] = $this->initDaysMonthsInterval($out_data);
- $appdata = $this->initRuleAppData($out_data, $conf_out_set_var);
-
- foreach ($timesArray as $times) {
- $conf .= "same => n,GotoIfTime($times,$weekdays,$mDays,$months?{$appdata})\n\t";
+ if(empty($date_from) || empty($date_to)){
+ return [];
+ }
+ $intervals = [];
+ $start = new DateTime();
+ $start->setTimestamp($date_from);
+ $end = new DateTime();
+ $end->setTimestamp($date_to);
+ while ($start < $end) {
+ $interval_start = clone $start;
+ $interval_end = clone $start;
+ $interval_end->modify('last day of this month 23:59:59');
+ if ($interval_end > $end) {
+ $interval_end = $end;
+ }
+ $intervals[] = [
+ $interval_start->getTimestamp(),
+ $interval_end->getTimestamp()
+ ];
+ $start->modify('first day of next month 00:00:00');
}
+
+ return $intervals;
}
/**
diff --git a/src/Core/Asterisk/Configs/IAXConf.php b/src/Core/Asterisk/Configs/IAXConf.php
index c475d2d95..52a1b3bb9 100644
--- a/src/Core/Asterisk/Configs/IAXConf.php
+++ b/src/Core/Asterisk/Configs/IAXConf.php
@@ -36,9 +36,7 @@ class IAXConf extends AsteriskConfigClass
{
// The module hook applying priority
public int $priority = 600;
-
public const TYPE_IAX2 = 'IAX2';
-
protected string $description = 'iax.conf';
/**
@@ -64,9 +62,8 @@ public function extensionGenContexts(): string
*/
protected function generateConfigProtected(): void
{
- $conf = '';
- $conf .= $this->generateGeneral();
- $conf .= $this->generateProviders();
+ $conf = $this->generateGeneral();
+ $conf.= $this->generateProviders();
// Write the configuration content to the file
Util::fileWriteContent($this->config->path('asterisk.astetcdir') . '/iax.conf', $conf);
@@ -80,17 +77,15 @@ protected function generateConfigProtected(): void
*/
private function generateGeneral(): string
{
- $iax_port = (trim($this->generalSettings[PbxSettingsConstants::IAX_PORT]) !== '') ? $this->generalSettings[PbxSettingsConstants::IAX_PORT] : '4569';
- $conf = '[general]' . "\n";
- // $conf .= "context=public-direct-dial \n";
- $conf .= "bindport={$iax_port}\n";
- $conf .= "bindaddr=0.0.0.0\n";
- $conf .= "delayreject=yes\n";
- $conf .= "iaxthreadcount=100\n";
- $conf .= "iaxmaxthreadcount=200\n";
- $conf .= "jitterbuffer=no\n";
- $conf .= "forcejitterbuffer=no\n\n";
-
+ $iax_port = $this->generalSettings[PbxSettingsConstants::IAX_PORT];
+ $conf = '[general]'.PHP_EOL;
+ $conf .= "bindport=$iax_port".PHP_EOL;
+ $conf .= "bindaddr=0.0.0.0".PHP_EOL;
+ $conf .= "delayreject=yes".PHP_EOL;
+ $conf .= "iaxthreadcount=100".PHP_EOL;
+ $conf .= "iaxmaxthreadcount=200".PHP_EOL;
+ $conf .= "jitterbuffer=no".PHP_EOL;
+ $conf .= "forcejitterbuffer=no".PHP_EOL.PHP_EOL;
return $conf;
}
@@ -107,37 +102,42 @@ private function generateProviders(): string
$lang = str_replace('_', '-', strtolower($this->generalSettings[PbxSettingsConstants::PBX_LANGUAGE]));
$providers = $this->getProviders();
foreach ($providers as $provider) {
- $prov_config .= "[{$provider['uniqid']}];\n";
- $prov_config .= "type=friend\n";
- $prov_config .= "auth=md5\n";
- $prov_config .= "context={$provider['uniqid']}-incoming \n";
- $prov_config .= "language={$lang}\n";
- $prov_config .= "qualify=2000\n";
- $prov_config .= "transfer=mediaonly\n";
- $prov_config .= "disallow=all\n";
- $prov_config .= ";username={$provider['username']}\n";
- $prov_config .= "host=dynamic\n";
- $prov_config .= "trunk=yes\n";
-
- $prov_config .= "secret={$provider['secret']}\n";
+ $manual_attributes = Util::parseIniSettings(base64_decode($provider['manualattributes']));
+ $options = [
+ 'type' => 'friend',
+ 'auth' => 'plaintext',
+ 'context' => "{$provider['uniqid']}-incoming",
+ 'language' => $lang,
+ 'qualify' => 2000,
+ 'transfer' => 'mediaonly',
+ 'disallow' => 'all',
+ 'username' => $provider['username'],
+ 'trunk' => 'yes',
+ 'secret' => $provider['secret'],
+ 'host' => 'dynamic'
+ ];
+ $prov_config .= "[{$provider['uniqid']}];".PHP_EOL;
foreach ($provider['codecs'] as $codec) {
- $prov_config .= "allow={$codec}\n";
+ $prov_config .= "allow=$codec".PHP_EOL;
}
$prov_config .= "setvar=contextID={$provider['uniqid']}-incoming".PHP_EOL;
- $prov_config .= "\n";
+ $prov_config .= Util::overrideConfigurationArray($options, $manual_attributes, ' ');
+ $prov_config .= PHP_EOL;
// Formulate the registration string
- if ($provider['noregister'] == 0) {
+ if ($provider['noregister'] === '0') {
// Registration is only required if the current host has a dynamic IP
- $user = $provider['username'];
- $secret = (trim($provider['secret']) == '') ? '' : ":{$provider['secret']}";
- $host = $provider['host'];
- $port = '';
- $reg_strings .= "register => {$user}{$secret}@{$host}{$port} \n";
+ $user = $options['username'];
+ $secret = (trim($options['secret']) === '') ? '' : ":{$options['secret']}";
+ [$host, $port] = explode( ':',$provider['host']);
+ if(!empty($port)){
+ $port = ":$port";
+ }
+ $reg_strings .= "register => $user$secret@$host$port ".PHP_EOL;
}
}
- return $reg_strings . "\n" . $prov_config;
+ return $reg_strings .PHP_EOL . $prov_config;
}
/**
@@ -151,26 +151,19 @@ private function getProviders(): array
// Получим настройки всех аккаунтов.
$arrIaxProviders = Iax::find("disabled IS NULL OR disabled = '0'");
foreach ($arrIaxProviders as $peer) {
- /** @var \MikoPBX\Common\Models\Iax $peer */
+ /** @var Iax $peer */
$arr_data = $peer->toArray();
-
- // $network_filter = NetworkFilters::findFirst($peer->networkfilterid);
- // $arr_data['permit'] = ($network_filter==null)?'':$network_filter->permit;
- // $arr_data['deny'] = ($network_filter==null)?'':$network_filter->deny;
-
$arr_data['codecs'] = [];
$filter = [
'conditions' => 'disabled="0"',
'order' => 'type, priority',
];
- $codecs = Codecs::find($filter);
+ $codecs = Codecs::find($filter);
foreach ($codecs as $ob_codec) {
$arr_data['codecs'][] = $ob_codec->name;
}
$data_providers[] = $arr_data;
}
-
return $data_providers;
}
-
}
diff --git a/src/Core/Asterisk/Configs/IndicationConf.php b/src/Core/Asterisk/Configs/IndicationConf.php
index b07ea4ee1..a3a111c32 100644
--- a/src/Core/Asterisk/Configs/IndicationConf.php
+++ b/src/Core/Asterisk/Configs/IndicationConf.php
@@ -20,6 +20,8 @@
namespace MikoPBX\Core\Asterisk\Configs;
+use MikoPBX\Common\Models\PbxSettings;
+use MikoPBX\Common\Models\PbxSettingsConstants;
use MikoPBX\Core\System\Util;
use function MikoPBX\Common\Config\appPath;
@@ -32,8 +34,21 @@
*/
class IndicationConf extends AsteriskConfigClass
{
- // The module hook applying priority
- public int $priority = 1000;
+ public const LANG_ZONE_MAP = [
+ 'ru-ru' => 'ru',
+ 'en-en' => 'us',
+ 'en-gb' => 'uk',
+ 'de-de' => 'de',
+ 'da-dk' => 'dk',
+ 'es-es' => 'es',
+ 'gr-gr' => 'gr',
+ 'fr-ca' => 'fr',
+ 'it-it' => 'it',
+ 'ja-jp' => 'jp',
+ 'nl-nl' => 'nl',
+ 'pl-pl' => 'pl',
+ 'pt-br' => 'pt',
+ ];
protected string $description = 'indications.conf';
@@ -44,13 +59,12 @@ class IndicationConf extends AsteriskConfigClass
*/
protected function generateConfigProtected(): void
{
- $country = 'ru'; // TODO: Add to the interface if it's an important option
+ $lang = PbxSettings::getValueByKey(PbxSettingsConstants::PBX_LANGUAGE);
+ $country = self::LANG_ZONE_MAP[$lang] ?? 'ru';
$filePath = appPath('src/Core/Asterisk/Configs/Samples/indications.conf.sample');
$data = file_get_contents($filePath);
$conf = str_replace('{country}', $country, $data);
-
// Write the configuration content to the file
Util::fileWriteContent($this->config->path('asterisk.astetcdir') . '/indications.conf', $conf);
}
-
}
\ No newline at end of file
diff --git a/src/Core/Asterisk/Configs/QueueConf.php b/src/Core/Asterisk/Configs/QueueConf.php
index ef28f1235..d051e8f9c 100644
--- a/src/Core/Asterisk/Configs/QueueConf.php
+++ b/src/Core/Asterisk/Configs/QueueConf.php
@@ -136,6 +136,7 @@ public function extensionGenInternal(): string
}
$ringLength = trim($queue['timeout_to_redirect_to_extension']);
$queue_ext_conf .= "same => n,Queue({$queue['uniqid']},kT$options,,,$ringLength,,,queue_agent_answer) \n\t";
+ $queue_ext_conf .= 'same => n,Set(__QUEUE_SRC_CHAN=${EMPTY})' . "\n\t";
// Notify about the end of the queue.
$queue_ext_conf .= 'same => n,Gosub(queue_end,${EXTEN},1)' . "\n\t";
$timeoutExtension = trim($queue['timeout_extension']);
diff --git a/src/Core/Asterisk/Configs/SIPConf.php b/src/Core/Asterisk/Configs/SIPConf.php
index 4419d383a..3d681edfb 100644
--- a/src/Core/Asterisk/Configs/SIPConf.php
+++ b/src/Core/Asterisk/Configs/SIPConf.php
@@ -130,11 +130,15 @@ public function needAsteriskRestart(): bool
if ($di === null) {
return false;
}
- $mikoPBXConfig = new MikoPBXConfig();
[$topology, $extIpAddress, $externalHostName, $subnets] = $this->getTopologyData();
- $generalSettings = $mikoPBXConfig->getGeneralSettings();
- $now_hash = md5($topology . $externalHostName . $extIpAddress . $generalSettings[PbxSettingsConstants::SIP_PORT]. $generalSettings[PbxSettingsConstants::TLS_PORT] . implode('',$subnets));
+ $externalSipPort = $this->generalSettings[PbxSettingsConstants::EXTERNAL_SIP_PORT];
+ $externalTlsPort = $this->generalSettings[PbxSettingsConstants::EXTERNAL_TLS_PORT];
+ $sipPort = $this->generalSettings[PbxSettingsConstants::SIP_PORT];
+ $tlsPort = $this->generalSettings[PbxSettingsConstants::TLS_PORT];
+
+ $now_hash = md5($topology . $externalHostName . $extIpAddress . $sipPort.$externalSipPort. $tlsPort .$externalTlsPort. implode('',$subnets));
+
$old_hash = '';
$varEtcDir = $di->getShared('config')->path('core.varEtcDir');
if (file_exists($varEtcDir . self::TOPOLOGY_HASH_FILE)) {
@@ -388,7 +392,7 @@ private function getProviders(): array
$arr_data['transport'] = trim($arr_data['transport']);
// Retrieve used codecs.
$arr_data['codecs'] = $this->getCodecs();
- $context_id = self::getContextId($sip_peer->host.$sip_peer->port);
+ $context_id = self::getContextId($sip_peer->host, $sip_peer->port);
if ( ! isset($this->contexts_data[$context_id])) {
$this->contexts_data[$context_id] = [];
}
@@ -1084,7 +1088,7 @@ private function generateProviderEndpoint(array $provider, array $manual_attribu
// Add configuration section header
$conf .= "[{$provider['uniqid']}]".PHP_EOL;
- $conf .= 'set_var=contextID='.$context.PHP_EOL;
+ $conf .= 'set_var=providerID='.$provider['uniqid'].PHP_EOL;
// Generate and add configuration options
$conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint');
@@ -1098,11 +1102,17 @@ private function generateProviderEndpoint(array $provider, array $manual_attribu
* This method generates the context ID for a given name by removing non-alphanumeric characters and appending "-incoming".
*
* @param string $name The name to generate the context ID from.
+ * @param string $port The port to generate the context ID from.
* @return string The generated context ID.
*/
- public static function getContextId(string $name = ''):string
+ public static function getContextId(string $name, string $port):string
{
- return preg_replace("/[^a-z\d]/iu", '', $name).'-incoming';
+ if (filter_var($name, FILTER_VALIDATE_IP)) {
+ $nameNew = $name;
+ }else{
+ $nameNew = gethostbyname($name);
+ }
+ return preg_replace("/[^a-z\d]/iu", '', $nameNew.$port).'-incoming';
}
/**
@@ -1117,21 +1127,7 @@ public static function getContextId(string $name = ''):string
*/
public static function getToneZone(array &$options, string $lang): void
{
- $settings = [
- 'ru-ru' => 'ru',
- 'en-gb' => 'uk',
- 'de-de' => 'de',
- 'da-dk' => 'dk',
- 'es-es' => 'es',
- 'gr-gr' => 'gr',
- 'fr-ca' => 'fr',
- 'it-it' => 'it',
- 'ja-jp' => 'jp',
- 'nl-nl' => 'nl',
- 'pl-pl' => 'pl',
- 'pt-br' => 'pt',
- ];
- $toneZone = $settings[$lang] ?? '';
+ $toneZone = IndicationConf::LANG_ZONE_MAP[$lang] ?? 'ru';
if ( ! empty($toneZone)) {
$options['inband_progress'] = 'yes';
$options['tone_zone'] = $toneZone;
diff --git a/src/Core/Asterisk/Configs/Samples/indications.conf.sample b/src/Core/Asterisk/Configs/Samples/indications.conf.sample
index c5c63615f..85d73b008 100644
--- a/src/Core/Asterisk/Configs/Samples/indications.conf.sample
+++ b/src/Core/Asterisk/Configs/Samples/indications.conf.sample
@@ -1,62 +1,6 @@
-;
-; indications.conf
-;
-; Configuration file for location specific tone indications
-;
-
-;
-; NOTE:
-; When adding countries to this file, please keep them in alphabetical
-; order according to the 2-character country codes!
-;
-; The [general] category is for certain global variables.
-; All other categories are interpreted as location specific indications
-;
-
[general]
country={country}
-
-; [example]
-; description = string
-; The full name of your country, in English.
-; ringcadence = num[,num]*
-; List of durations the physical bell rings.
-; dial = tonelist
-; Set of tones to be played when one picks up the hook.
-; busy = tonelist
-; Set of tones played when the receiving end is busy.
-; congestion = tonelist
-; Set of tones played when there is some congestion (on the network?)
-; callwaiting = tonelist
-; Set of tones played when there is a call waiting in the background.
-; dialrecall = tonelist
-; Not well defined; many phone systems play a recall dial tone after hook
-; flash.
-; record = tonelist
-; Set of tones played when call recording is in progress.
-; info = tonelist
-; Set of tones played with special information messages (e.g., "number is
-; out of service")
-; name = tonelist
-; Every other variable will be available as a shortcut for the "PlayList" command
-; but will not be used automatically by Asterisk.
-;
-;
-; The tonelist itself is defined by a comma-separated sequence of elements.
-; Each element consist of a frequency (f) with an optional duration (in ms)
-; attached to it (f/duration). The frequency component may be a mixture of two
-; frequencies (f1+f2) or a frequency modulated by another frequency (f1*f2).
-; The implicit modulation depth is fixed at 90%, though.
-; If the list element starts with a !, that element is NOT repeated,
-; therefore, only if all elements start with !, the tonelist is time-limited,
-; all others will repeat indefinitely.
-;
-; concisely:
-; element = [!]freq[+|*freq2][/duration]
-; tonelist = element[,element]*
-;
-
[at]
description = Austria
ringcadence = 1000,5000
diff --git a/src/Core/Asterisk/Configs/lua/extensions.lua b/src/Core/Asterisk/Configs/lua/extensions.lua
index 4cd6a08b9..ca4233344 100644
--- a/src/Core/Asterisk/Configs/lua/extensions.lua
+++ b/src/Core/Asterisk/Configs/lua/extensions.lua
@@ -330,6 +330,11 @@ function event_dial(without_event)
channel = orign_chan;
end
+ if(channel == '')then
+ channel = get_variable('MASTER_CHANNEL(CHANNEL)');
+ app["NoOp"]('The channel could not be determined. Use Master: ('..channel..')');
+ end
+
local from_account = get_variable("FROM_PEER")
if ( from_account=='' and string.lower(agi_channel):find("local/") == nil )then
from_account = getAccountName(agi_channel);
diff --git a/src/Core/System/Configs/CronConf.php b/src/Core/System/Configs/CronConf.php
index d2740b26b..18afd4690 100644
--- a/src/Core/System/Configs/CronConf.php
+++ b/src/Core/System/Configs/CronConf.php
@@ -29,8 +29,6 @@
use MikoPBX\Modules\Config\SystemConfigInterface;
use Phalcon\Di\Injectable;
-use function MikoPBX\Common\Config\appPath;
-
/**
* Class CronConf
*
@@ -63,14 +61,13 @@ public function reStart(): int
$this->generateConfig($booting);
if (Util::isSystemctl()) {
$systemctl = Util::which('systemctl');
- Processes::mwExec("{$systemctl} restart ".self::PROC_NAME);
+ Processes::mwExec("$systemctl restart ".self::PROC_NAME);
} else {
// T2SDE or Docker
- $crond = Util::which(self::PROC_NAME);
+ $cronPath = Util::which(self::PROC_NAME);
Processes::killByName(self::PROC_NAME);
- Processes::mwExec("$crond -L /dev/null -l 8");
+ Processes::mwExec("$cronPath -S -l 0");
}
-
return 0;
}
@@ -86,7 +83,7 @@ private function generateConfig(bool $boot = true): void
$workerSafeScriptsPath = Util::getFilePathByClassName(WorkerSafeScriptsCore::class);
$phpPath = Util::which('php');
- $WorkerSafeScripts = "$phpPath -f {$workerSafeScriptsPath} start > /dev/null 2> /dev/null";
+ $WorkerSafeScripts = "$phpPath -f $workerSafeScriptsPath start > /dev/null 2> /dev/null";
$restart_night = $this->mikoPBXConfig->getGeneralSettings(PbxSettingsConstants::RESTART_EVERY_NIGHT);
$asterisk = Util::which('asterisk');
@@ -130,4 +127,19 @@ private function generateConfig(bool $boot = true): void
// Write the generated config to the cron file
Util::fileWriteContent($cron_filename, $conf);
}
+
+ /**
+ * Generate additional syslog rules.
+ * @return void
+ */
+ public static function generateSyslogConf():void
+ {
+ Util::mwMkdir('/etc/rsyslog.d');
+ $log_fileRedis = SyslogConf::getSyslogFile(self::PROC_NAME);
+ $pathScriptRedis = SyslogConf::createRotateScript(self::PROC_NAME);
+ $confSyslogD = '$outchannel log_'.self::PROC_NAME.','.$log_fileRedis.',10485760,'.$pathScriptRedis.PHP_EOL.
+ 'if $programname == "'.self::PROC_NAME.'" then :omfile:$log_'.self::PROC_NAME.PHP_EOL.
+ 'if $programname == "'.self::PROC_NAME.'" then stop'.PHP_EOL;
+ file_put_contents('/etc/rsyslog.d/'.self::PROC_NAME.'.conf', $confSyslogD);
+ }
}
\ No newline at end of file
diff --git a/src/Core/System/Configs/Fail2BanConf.php b/src/Core/System/Configs/Fail2BanConf.php
index bab46fa3a..96d6be925 100644
--- a/src/Core/System/Configs/Fail2BanConf.php
+++ b/src/Core/System/Configs/Fail2BanConf.php
@@ -24,8 +24,8 @@
use MikoPBX\Common\Models\PbxSettings;
use MikoPBX\Common\Models\PbxSettingsConstants;
use MikoPBX\Common\Providers\PBXConfModulesProvider;
+use MikoPBX\Core\System\Directories;
use MikoPBX\Core\System\Processes;
-use MikoPBX\Core\System\System;
use MikoPBX\Core\System\Util;
use MikoPBX\Core\System\Verify;
use MikoPBX\Modules\Config\SystemConfigInterface;
@@ -138,14 +138,14 @@ public static function reloadFail2ban(): void
*/
private function generateConf():void
{
- $log_dir = System::getLogDir() . '/fail2ban';
+ $log_dir = Directories::getDir(Directories::CORE_LOGS_DIR) . '/fail2ban';
$lofFileName = "$log_dir/fail2ban.log";
Util::mwMkdir($log_dir);
$conf = '['.'Definition'.']'.PHP_EOL.
'allowipv6 = auto'.PHP_EOL.
'loglevel = INFO'.PHP_EOL.
- 'logtarget = FILE'.PHP_EOL.
- "syslogsocket = $lofFileName".PHP_EOL.
+ "logtarget = $lofFileName".PHP_EOL.
+ 'syslogsocket = auto'.PHP_EOL.
'socket = /var/run/fail2ban/fail2ban.sock'.PHP_EOL.
'pidfile = /var/run/fail2ban/fail2ban.pid'.PHP_EOL.
'dbfile = /var/lib/fail2ban/fail2ban.sqlite3'.PHP_EOL.
@@ -168,7 +168,7 @@ public static function logRotate(): void
return;
}
$max_size = 10;
- $log_dir = System::getLogDir() . '/fail2ban/';
+ $log_dir = Directories::getDir(Directories::CORE_LOGS_DIR) . '/fail2ban/';
$text_config = $log_dir."fail2ban.log {
nocreate
nocopytruncate
@@ -331,7 +331,7 @@ public function writeConfig(): void
"logpath = $syslog_file\n" .
"action = $action\n\n";
}
- $log_dir = System::getLogDir() . '/asterisk/';
+ $log_dir = Directories::getDir(Directories::CORE_LOGS_DIR) . '/asterisk/';
$jails = [
'asterisk_security_log' => ['security_log', '', $asteriskPorts],
'asterisk_error' => ['error', '_ERROR', $asteriskPorts],
@@ -343,7 +343,7 @@ public function writeConfig(): void
$commonParams.
"filter = asterisk-main" . PHP_EOL.
'action = miko-iptables-multiport-all[name=ASTERISK'.$actionNamePrefix.', port="'.implode(',', $ports).'"]'. PHP_EOL.
- "logpath = {$log_dir}$logPrefix". PHP_EOL. PHP_EOL;
+ "logpath = $log_dir$logPrefix". PHP_EOL. PHP_EOL;
}
// Write the Fail2Ban configuration to the jail.local file
Util::fileWriteContent('/etc/fail2ban/jail.local', $config);
diff --git a/src/Core/System/Configs/RedisConf.php b/src/Core/System/Configs/RedisConf.php
index 2b64aeae9..dc061c04a 100644
--- a/src/Core/System/Configs/RedisConf.php
+++ b/src/Core/System/Configs/RedisConf.php
@@ -87,7 +87,14 @@ private function configure(): void
$conf .= "syslog-enabled yes" . PHP_EOL;
$conf .= "syslog-ident redis" . PHP_EOL;
file_put_contents(self::CONF_FILE, $conf);
+ }
+ /**
+ * Generate additional syslog rules.
+ * @return void
+ */
+ public static function generateSyslogConf():void
+ {
Util::mwMkdir('/etc/rsyslog.d');
$log_fileRedis = SyslogConf::getSyslogFile('redis');
$pathScriptRedis = SyslogConf::createRotateScript('redis');
diff --git a/src/Core/System/Configs/SSHConf.php b/src/Core/System/Configs/SSHConf.php
index 9ab671a28..ee22044ef 100644
--- a/src/Core/System/Configs/SSHConf.php
+++ b/src/Core/System/Configs/SSHConf.php
@@ -60,8 +60,8 @@ public function configure(): bool
file_put_contents($lofFile, '');
}
$this->generateDropbearKeys();
- $sshLogin = $this->getSSHLogin();
- $sshPort = escapeshellcmd(PbxSettings::getValueByKey(PbxSettingsConstants::SSH_PORT));
+ $sshLogin = $this->getCreateSshUser();
+ $sshPort = escapeshellcmd(PbxSettings::getValueByKey(PbxSettingsConstants::SSH_PORT));
// Update root password and restart SSH server
$this->updateShellPassword($sshLogin);
@@ -118,38 +118,42 @@ private function generateDropbearKeys(): void
*
* @return string SSH login username.
*/
- private function getSSHLogin(): string
+ private function getCreateSshUser(): string
{
$sshLogin = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_LOGIN);
$homeDir = $this->getUserHomeDir($sshLogin);
- $passwdPath = '/etc/passwd';
- $newEntry = "$sshLogin:x:0:0:MikoPBX Admin:$homeDir:/bin/bash\n";
-
- if ($sshLogin !== 'root') {
- // Read the current contents of the passwd file
- $passwdContent = file_get_contents($passwdPath);
- $lines = explode("\n", $passwdContent);
- $updated = false;
-
- // Check each line and update the entry if it exists
- foreach ($lines as &$line) {
- if (strpos($line, "$sshLogin:") === 0) {
- $line = $newEntry;
- $updated = true;
- break;
- }
- }
- unset($line); // break the reference with the last element
-
- // If the entry was updated, rewrite the file
- if ($updated) {
- file_put_contents($passwdPath, implode("\n", $lines));
- } else {
- // Append the new entry if it wasn't found
- file_put_contents($passwdPath, $newEntry, FILE_APPEND);
+ // System users, you can't touch them
+ $mainUsers = ['root', 'www'];
+ $bbPath = Util::which('busybox');
+ // We clean all non-system users
+ exec("$bbPath cut -f 1 -d ':' < /etc/passwd", $systemUsers);
+ foreach ($systemUsers as $user){
+ if($sshLogin === $user || in_array($user, $mainUsers, true)){
+ continue;
}
+ // Deleting the user
+ shell_exec("$bbPath deluser $user");
+ // Deleting the group
+ shell_exec("$bbPath delgroup $user");
}
+ if ($sshLogin !== 'root') {
+ // Adding a group '$sshLogin'
+ shell_exec("$bbPath addgroup $sshLogin");
+ // Adding user '$sshLogin'
+ shell_exec("$bbPath adduser -h $homeDir -g 'MikoPBX SSH Admin' -s /bin/bash -G root -D '$sshLogin'");
+ // Adding a user to the group '$sshLogin'
+ shell_exec("$bbPath addgroup -S '$sshLogin' $sshLogin");
+ // Adding a user to the group 'root'
+ shell_exec("$bbPath addgroup -S '$sshLogin' root");
+ $cat = Util::which('cat');
+ $cut = Util::which('cut');
+ $sed = Util::which('sed');
+ $chown = Util::which('chown');
+ $currentGroupId = trim(shell_exec("$cat /etc/passwd | grep '^$sshLogin:' | $cut -f 3 -d ':'"));
+ shell_exec("$sed -i 's/$sshLogin:x:$currentGroupId:/$sshLogin:x:0:/g' /etc/passwd");
+ shell_exec("$chown -R $sshLogin:$sshLogin $homeDir");
+ }
return $sshLogin;
}
@@ -174,17 +178,21 @@ private function getUserHomeDir(string $sshLogin = 'root'): string
*/
private function updateShellPassword(string $sshLogin = 'root'): void
{
- $password = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_PASSWORD);
- $hashString = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_PASSWORD_HASH_STRING);
- $disablePassLogin = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_DISABLE_SSH_PASSWORD);
+ $password = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_PASSWORD);
+ $hashString = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_PASSWORD_HASH_STRING);
+ $disablePassLogin = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_DISABLE_SSH_PASSWORD);
- $echo = Util::which('echo');
+ $echo = Util::which('echo');
$chpasswd = Util::which('chpasswd');
- $passwd = Util::which('passwd');
- Processes::mwExec("{$passwd} -l www");
+ $passwd = Util::which('passwd');
+ Processes::mwExec("$passwd -l www");
if ($disablePassLogin === '1') {
Processes::mwExec("$passwd -l $sshLogin");
+ Processes::mwExec("$passwd -l root");
+ } elseif($sshLogin === 'root') {
+ Processes::mwExec("$echo '$sshLogin:$password' | $chpasswd");
} else {
+ Processes::mwExec("$passwd -l root");
Processes::mwExec("$echo '$sshLogin:$password' | $chpasswd");
}
@@ -209,7 +217,7 @@ private function generateAuthorizedKeys(string $sshLogin = 'root'): void
Util::mwMkdir($sshDir);
$authorizedKeys = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_AUTHORIZED_KEYS);
- file_put_contents("{$sshDir}/authorized_keys", $authorizedKeys);
+ file_put_contents("$sshDir/authorized_keys", $authorizedKeys);
}
/**
diff --git a/src/Core/System/Configs/SyslogConf.php b/src/Core/System/Configs/SyslogConf.php
index fcf103b3d..d050e33c1 100644
--- a/src/Core/System/Configs/SyslogConf.php
+++ b/src/Core/System/Configs/SyslogConf.php
@@ -56,6 +56,10 @@ public function reStart(): void
}
Processes::killByName('syslogd');
}
+
+ RedisConf::generateSyslogConf();
+ CronConf::generateSyslogConf();
+
Processes::safeStartDaemon(self::PROC_NAME, '-n');
}
diff --git a/src/Core/System/Network.php b/src/Core/System/Network.php
index f7a832f57..87b877198 100644
--- a/src/Core/System/Network.php
+++ b/src/Core/System/Network.php
@@ -783,19 +783,17 @@ public function lanConfigure(): int
// Obtain IP and wait for the process to finish
$workerPath = '/etc/rc/udhcpc_configure';
- $options = '-t 6 -T 5 -q -n';
+ $options = '-t 2 -T 2 -q -n';
$arr_commands[] = "$udhcpc $options -i $if_name -x hostname:$hostname -s $workerPath";
// Start a new udhcpc process in the background
$options = '-t 6 -T 5 -S -b -n';
$arr_commands[] = "$nohup $udhcpc $options -p {$pid_file} -i $if_name -x hostname:$hostname -s $workerPath 2>&1 &";
/*
udhcpc - utility for configuring the interface
- - configures /etc/resolv.conf
+ - configures /etc/resolv.conf
Further route configuration will be performed in udhcpcConfigureRenewBound();
- and udhcpcConfigureDeconfig(). These methods will be called by the script WorkerUdhcpcConfigure.php.
- // man udhcp
+ and udhcpcConfigureDeconfig(). These methods will be called by the PHP script udhcpc_configure.
// http://pwet.fr/man/linux/administration_systeme/udhcpc/
-
*/
} else {
// Static IP configuration
diff --git a/src/Core/System/Notifications.php b/src/Core/System/Notifications.php
index 4f819fd95..6a13112cc 100644
--- a/src/Core/System/Notifications.php
+++ b/src/Core/System/Notifications.php
@@ -86,6 +86,9 @@ public static function sendAdminNotification(string $subject, array $messages, b
{
// Prevent sending the same message twice.
$di = Di::getDefault();
+ if(!$di){
+ return;
+ }
$managedCache = $di->getShared(ManagedCacheProvider::SERVICE_NAME);
$cacheKey = 'sendAdminNotification:' . md5($subject . implode('', $messages));
$cacheTime = 3600 * 24; // 1 day
@@ -96,7 +99,7 @@ public static function sendAdminNotification(string $subject, array $messages, b
}
// Check if the notification system is available (e.g., PHP Mailer is configured and working).
- if (!Notifications::checkConnection(Notifications::TYPE_PHP_MAILER)) {
+ if (!self::checkConnection(self::TYPE_PHP_MAILER)) {
return;
}
@@ -106,7 +109,8 @@ public static function sendAdminNotification(string $subject, array $messages, b
foreach ($messages as $message) {
$text .= '
' . Util::translate($message, false);
}
- $text = $text . '
' . SystemMessages::getInfoMessage("The MikoPBX connection information");
+ $text .= '
' . SystemMessages::getInfoMessage("The MikoPBX connection information");
+ $text = str_replace(PHP_EOL, '
', $text);
// Get the admin email address from PbxSettings.
$adminMail = PbxSettings::getValueByKey(PbxSettingsConstants::SYSTEM_NOTIFICATIONS_EMAIL);
diff --git a/src/Core/System/PBX.php b/src/Core/System/PBX.php
index 263e8a30e..7934c96ae 100644
--- a/src/Core/System/PBX.php
+++ b/src/Core/System/PBX.php
@@ -30,10 +30,12 @@
AsteriskConf,
AsteriskConfigClass,
AsteriskConfigInterface,
+ ConferenceConf,
ExtensionsConf,
FeaturesConf,
HttpConf,
IAXConf,
+ IndicationConf,
ManagerConf,
ModulesConf,
MusicOnHoldConf,
@@ -162,6 +164,9 @@ public static function coreReload(): void
$asteriskConf = new AsteriskConf();
$asteriskConf->generateConfig();
+ $indicationConf = new IndicationConf();
+ $indicationConf->generateConfig();
+
$arr_out = [];
$asteriskPath = Util::which('asterisk');
Processes::mwExec("{$asteriskPath} -rx 'core reload'", $arr_out);
@@ -174,6 +179,10 @@ public static function coreRestart(): void
{
$asteriskConf = new AsteriskConf();
$asteriskConf->generateConfig();
+
+ $indicationConf = new IndicationConf();
+ $indicationConf->generateConfig();
+
$asteriskPath = Util::which('asterisk');
Processes::mwExec("{$asteriskPath} -rx 'core restart now'");
}
@@ -206,6 +215,17 @@ public static function musicOnHoldReload(): void
Processes::mwExec("{$asteriskPath} -rx 'moh reload'");
}
+ /**
+ * Reloads the Asterisk music on hold module.
+ */
+ public static function confBridgeReload(): void
+ {
+ $o = new ConferenceConf();
+ $o->generateConfig();
+ $asteriskPath = Util::which('asterisk');
+ Processes::mwExec("$asteriskPath -rx 'module reload app_confbridge'");
+ }
+
/**
* Reloads the Asterisk voicemail module.
diff --git a/src/Core/System/PBXInstaller.php b/src/Core/System/PBXInstaller.php
index e0c189617..a2a083b4b 100644
--- a/src/Core/System/PBXInstaller.php
+++ b/src/Core/System/PBXInstaller.php
@@ -208,9 +208,6 @@ private function proceedInstallation()
$this->unpackImage();
$this->mountStorage();
$this->copyConfiguration();
- $umount = Util::which('umount');
- Processes::mwExec("$umount /mnttmp");
- echo "done\n";
// Reboot
file_put_contents('/tmp/ejectcd', '');
@@ -266,18 +263,25 @@ private function mountStorage()
/**
* Copy the configuration to the target disk.
*/
- private function copyConfiguration()
+ private function copyConfiguration():void
{
// Back up the table with disk information.
- echo Util::translate("Copying configuration...");
+ echo Util::translate("Copying configuration...").PHP_EOL;
Util::mwMkdir('/mnttmp');
- $confPartitionName = Storage::getDevPartName("/dev/{$this->target_disk}", '3');
-
+ echo "Target disk: $this->target_disk ...".PHP_EOL;
+ $confPartitionName = Storage::getDevPartName($this->target_disk, '3', true);
+ if(empty($confPartitionName)){
+ echo "Target partition not found: $this->target_disk (part 3) ...".PHP_EOL;
+ return;
+ }
// Mount the disk with settings.
- $mount = Util::which('mount');
- Processes::mwExec("{$mount} -w -o noatime {$confPartitionName} /mnttmp");
-
+ $mount = Util::which('mount');
+ $umount = Util::which('umount');
+ $resUMount = Processes::mwExec("$umount $confPartitionName");
+ echo "Umount $confPartitionName: $resUMount ...".PHP_EOL;
+ $resMount = Processes::mwExec("$mount -w -o noatime $confPartitionName /mnttmp");
+ echo "Mount $confPartitionName to /mnttmp: $resMount ...".PHP_EOL;
$filename = $this->config->path('database.dbfile');
$result_db_file = '/mnttmp/conf/mikopbx.db';
@@ -285,28 +289,33 @@ private function copyConfiguration()
$cp = Util::which('cp');
$sqlite3 = Util::which('sqlite3');
$dmpDbFile = tempnam('/tmp', 'storage');
-
// Save dump of settings.
$tables = ['m_Storage', 'm_LanInterfaces'];
file_put_contents($dmpDbFile, '');
foreach ($tables as $table) {
- shell_exec("sqlite3 /cf/conf/mikopbx.db '.schema $table' >> $dmpDbFile");
- shell_exec("sqlite3 /cf/conf/mikopbx.db '.dump $table' >> $dmpDbFile");
+ echo "DUMP $table from /cf/conf/mikopbx.db ...".PHP_EOL;
+ $res = shell_exec("sqlite3 /cf/conf/mikopbx.db '.schema $table' >> $dmpDbFile");
+ $res .= shell_exec("sqlite3 /cf/conf/mikopbx.db '.dump $table' >> $dmpDbFile");
+ echo "$res ...".PHP_EOL;
}
// If another language is selected - use another settings file.
$lang = PbxSettings::getValueByKey(PbxSettingsConstants::SSH_LANGUAGE);
- $filename_lang = "/offload/conf/mikopbx-{$lang}.db";
+ $filename_lang = "/offload/conf/mikopbx-$lang.db";
if ($lang !== 'en' && file_exists($filename_lang)) {
$filename = $filename_lang;
}
-
// Replace the settings file.
- Processes::mwExec("{$cp} {$filename} {$result_db_file}");
- system("{$sqlite3} {$result_db_file} 'DROP TABLE IF EXISTS m_Storage'");
- system("{$sqlite3} {$result_db_file} 'DROP TABLE IF EXISTS m_LanInterfaces'");
-
+ $resCopy = Processes::mwExec("$cp $filename $result_db_file");
+ echo "Copy $filename to $result_db_file: $resCopy ...".PHP_EOL;
+ foreach ($tables as $table) {
+ echo "DROP $table IF EXISTS in $result_db_file ...".PHP_EOL;
+ $res = shell_exec("$sqlite3 $result_db_file 'DROP TABLE IF EXISTS $table'");
+ echo "$res ...".PHP_EOL;
+ }
// Restore settings from backup file.
- system("{$sqlite3} {$result_db_file} < {$dmpDbFile}");
+ $resSaveSettings = Processes::mwExec("$sqlite3 $result_db_file < $dmpDbFile");
+ echo "Save settings to $result_db_file. Result: $resSaveSettings ...".PHP_EOL;
unlink($dmpDbFile);
+ Processes::mwExec("$umount /mnttmp");
}
}
\ No newline at end of file
diff --git a/src/Core/System/RootFS/etc/group b/src/Core/System/RootFS/etc/group
index cc2963de0..2010fe792 100644
--- a/src/Core/System/RootFS/etc/group
+++ b/src/Core/System/RootFS/etc/group
@@ -11,3 +11,4 @@ dialout:x:1008:
kmem:x:1009:
uucp:x:1010:
www:x:1011:
+kvm:x:61:
diff --git a/src/Core/System/RootFS/etc/profile b/src/Core/System/RootFS/etc/profile
index f5ee686bb..020d81e34 100644
--- a/src/Core/System/RootFS/etc/profile
+++ b/src/Core/System/RootFS/etc/profile
@@ -58,7 +58,7 @@ fi
# Set aliases
alias ls='ls --color=auto';
-alias myip="curl http://ipecho.net/plain; echo";
+alias myip="/usr/bin/curl https://checkip.amazonaws.com";
alias remount-offload="_remountOffload";
alias check-file-connection="_checkFileConnection";
alias ps='ps -A -f';
diff --git a/src/Core/System/RootFS/sbin/check-out-ip b/src/Core/System/RootFS/sbin/check-out-ip
index fb27e8e07..08f607da0 100644
--- a/src/Core/System/RootFS/sbin/check-out-ip
+++ b/src/Core/System/RootFS/sbin/check-out-ip
@@ -24,7 +24,7 @@ if [ "$needCheckOutAddress" != '1' ]; then
exit 0;
fi;
-outIp="$(/usr/bin/curl https://ipecho.net/plain 2> /dev/null)";
+outIp="$(/usr/bin/curl https://checkip.amazonaws.com 2> /dev/null)";
result="$?";
if [ "$result" != '0' ]; then
echo 'Error getting an IP address';
diff --git a/src/Core/System/RootFS/sbin/voicemail-sender b/src/Core/System/RootFS/sbin/voicemail-sender
index 59ef113f6..929ee496f 100644
--- a/src/Core/System/RootFS/sbin/voicemail-sender
+++ b/src/Core/System/RootFS/sbin/voicemail-sender
@@ -1,6 +1,7 @@
#!/usr/bin/php
saveAttachments('/tmp/'));
$recordingFile = VoiceMailConf::getCopyFilename($file, $linkedId, $d->getTimestamp(), true);
$recordingFile = Util::trimExtensionForFile($recordingFile) . '.wav';
+
+ /** Convert tmp file to mp3 */
+ $converter = Util::which('wav2mp3.sh');
+ $baseNameTmp= Util::trimExtensionForFile($file);
+ $mp3File = "$baseNameTmp.mp3";
+ Processes::mwExec("$converter $baseNameTmp");
+ if(file_exists($mp3File)){
+ $recordingFile = $mp3File;
+ }
unlink($file);
+ /** create mail message */
$addresses = mailparse_rfc822_parse_addresses($parser->getHeader('to'));
$rawHeaderTo = $addresses[0]['address']??'';
if(!empty($rawHeaderTo)){
$toMails[] = $rawHeaderTo;
}
-
$settings = PbxSettings::getAllPbxSettings();
$subject = str_replace([PHP_EOL, "\t"], '', $settings['MailTplVoicemailSubject']);
$body = str_replace([PHP_EOL, "\t"], ['
', ''], $settings['MailTplVoicemailBody']);
@@ -66,12 +77,19 @@ try {
unset($data);
}
}
-
+ $cidName = $params['VM_CALLER_NAME']??'';
+ if(empty($cidName)){
+ $params['VM_CALLER_NAME'] = Extensions::getCidByPhoneNumber($params['VM_CALLER_NUM']);
+ }
$message = "$body $footer";
replaceParams($subject, $params);
replaceParams($message, $params);
$notify = new Notifications();
$result = $notify->sendMail(implode(',', array_unique($toMails)), $subject, $message, $recordingFile);
+
+ if(file_exists($mp3File)){
+ unlink($mp3File);
+ }
}catch (Throwable $e){
$recordingFile = '';
SystemMessages::sysLogMsg('Voicemail-Sender', $e->getMessage());
@@ -89,4 +107,4 @@ $result_send = $client->publish(json_encode($data, JSON_THROW_ON_ERROR));
$manager = Util::getAstManager();
unset($data['action']);
-$manager->UserEvent('voicemail_end', $data);
+$manager->UserEvent('voicemail_end', $data);
\ No newline at end of file
diff --git a/src/Core/System/Storage.php b/src/Core/System/Storage.php
index 56512ea29..8ec32621b 100644
--- a/src/Core/System/Storage.php
+++ b/src/Core/System/Storage.php
@@ -111,7 +111,7 @@ public static function isStorageDiskMounted(string $filter = '', string &$mount_
}
if ('' === $filter) {
$varEtcDir = Directories::getDir(Directories::CORE_VAR_ETC_DIR);
- $filename = "{$varEtcDir}/storage_device";
+ $filename = "$varEtcDir/storage_device";
// If the storage_device file exists, read its contents as the filter, otherwise use 'usbdisk1' as the filter
if (file_exists($filename)) {
@@ -123,11 +123,12 @@ public static function isStorageDiskMounted(string $filter = '', string &$mount_
$grep = Util::which('grep');
$mount = Util::which('mount');
$awk = Util::which('awk');
+ $head = Util::which('head');
$filter = escapeshellarg($filter);
// Execute the command to filter the mount points based on the filter
- $out = shell_exec("$mount | $grep $filter | {$awk} '{print $3}'");
+ $out = shell_exec("$mount | $grep $filter | $awk '{print $3}' | $head -n 1");
$mount_dir = trim($out);
return ($mount_dir !== '');
}
@@ -172,157 +173,16 @@ public function copyMohFilesToStorage(): void
}
}
- /**
- * Mount an SFTP disk.
- *
- * @param string $host The SFTP server host.
- * @param string $port The SFTP server port.
- * @param string $user The SFTP server username.
- * @param string $pass The SFTP server password.
- * @param string $remote_dir The remote directory on the SFTP server.
- * @param string $local_dir The local directory to mount the SFTP disk.
- * @return bool Returns true if the SFTP disk is successfully mounted, false otherwise.
- */
- public static function mountSftpDisk(string $host, string $port, string $user, string $pass, string $remote_dir, string $local_dir): bool
- {
-
- // Create the local directory if it doesn't exist
- Util::mwMkdir($local_dir);
-
- $out = [];
- $timeoutPath = Util::which('timeout');
- $sshfsPath = Util::which('sshfs');
-
- // Build the command to mount the SFTP disk
- $command = "{$timeoutPath} 3 {$sshfsPath} -p {$port} -o nonempty -o password_stdin -o 'StrictHostKeyChecking=no' " . "{$user}@{$host}:{$remote_dir} {$local_dir} << EOF\n" . "{$pass}\n" . "EOF\n";
-
- // Execute the command to mount the SFTP disk
- Processes::mwExec($command, $out);
- $response = trim(implode('', $out));
-
- if ('Terminated' === $response) {
- // The remote server did not respond or an incorrect password was provided.
- unset($response);
- }
-
- return self::isStorageDiskMounted("$local_dir ");
- }
-
- /**
- * Mount an FTP disk.
- *
- * @param string $host The FTP server host.
- * @param string $port The FTP server port.
- * @param string $user The FTP server username.
- * @param string $pass The FTP server password.
- * @param string $remote_dir The remote directory on the FTP server.
- * @param string $local_dir The local directory to mount the FTP disk.
- * @return bool Returns true if the FTP disk is successfully mounted, false otherwise.
- */
- public static function mountFtp(string $host, string $port, string $user, string $pass, string $remote_dir, string $local_dir): bool
- {
-
- // Create the local directory if it doesn't exist
- Util::mwMkdir($local_dir);
- $out = [];
-
- // Build the authentication line for the FTP connection
- $auth_line = '';
- if (!empty($user)) {
- $auth_line .= 'user="' . $user;
- if (!empty($pass)) {
- $auth_line .= ":{$pass}";
- }
- $auth_line .= '",';
- }
-
- // Build the connect line for the FTP connection
- $connect_line = 'ftp://' . $host;
- if (!empty($port)) {
- $connect_line .= ":{$port}";
- }
- if (!empty($remote_dir)) {
- $connect_line .= "$remote_dir";
- }
-
- $timeoutPath = Util::which('timeout');
- $curlftpfsPath = Util::which('curlftpfs');
-
- // Build the command to mount the FTP disk
- $command = "{$timeoutPath} 3 {$curlftpfsPath} -o allow_other -o {$auth_line}fsname={$host} {$connect_line} {$local_dir}";
-
- // Execute the command to mount the FTP disk
- Processes::mwExec($command, $out);
- $response = trim(implode('', $out));
- if ('Terminated' === $response) {
- // The remote server did not respond or an incorrect password was provided.
- unset($response);
- }
-
- return self::isStorageDiskMounted("$local_dir ");
- }
-
- /**
- * Mount a WebDAV disk.
- *
- * @param string $host The WebDAV server host.
- * @param string $user The WebDAV server username.
- * @param string $pass The WebDAV server password.
- * @param string $dstDir The destination directory on the WebDAV server.
- * @param string $local_dir The local directory to mount the WebDAV disk.
- * @return bool Returns true if the WebDAV disk is successfully mounted, false otherwise.
- */
- public static function mountWebDav(string $host, string $user, string $pass, string $dstDir, string $local_dir): bool
- {
- $host = trim($host);
- $dstDir = trim($dstDir);
-
- // Remove trailing slash from host if present
- if (substr($host, -1) === '/') {
- $host = substr($host, 0, -1);
- }
-
- // Remove leading slash from destination directory if present
- if ($dstDir[0] === '/') {
- $dstDir = substr($dstDir, 1);
- }
-
- // Create the local directory if it doesn't exist
- Util::mwMkdir($local_dir);
- $out = [];
- $conf = 'dav_user www' . PHP_EOL .
- 'dav_group www' . PHP_EOL;
-
-
- // Write WebDAV credentials to secrets file
- file_put_contents('/etc/davfs2/secrets', "{$host}{$dstDir} $user $pass");
- file_put_contents('/etc/davfs2/davfs2.conf', $conf);
- $timeoutPath = Util::which('timeout');
- $mount = Util::which('mount.davfs');
-
- // Build the command to mount the WebDAV disk
- $command = "$timeoutPath 3 yes | $mount {$host}{$dstDir} {$local_dir}";
-
- // Execute the command to mount the WebDAV disk
- Processes::mwExec($command, $out);
- $response = trim(implode('', $out));
- if ('Terminated' === $response) {
- // The remote server did not respond or an incorrect password was provided.
- unset($response);
- }
- return self::isStorageDiskMounted("$local_dir ");
- }
-
/**
* Create a file system on a disk.
*
* @param string $dev The device path of the disk.
* @return bool Returns true if the file system creation process is initiated, false otherwise.
*/
- public static function mkfs_disk(string $dev)
+ public static function mkfs_disk(string $dev):bool
{
if (!file_exists($dev)) {
- $dev = "/dev/{$dev}";
+ $dev = "/dev/$dev";
}
if (!file_exists($dev)) {
return false;
@@ -332,7 +192,7 @@ public static function mkfs_disk(string $dev)
// If the disk is not mounted or successfully unmounted, proceed with the file system creation
if (empty($dir) || self::umountDisk($dir)) {
- $st = new Storage();
+ $st = new self();
// Initiate the file system creation process
$st->formatEntireDisk($dev, true);
sleep(1);
@@ -358,13 +218,13 @@ public static function umountDisk(string $dir): bool
// If the disk is mounted, terminate processes using the disk and unmount it
if (self::isStorageDiskMounted($dir)) {
Processes::mwExec("/sbin/shell_functions.sh 'killprocesses' '$dir' -TERM 0");
- Processes::mwExec("{$umount} {$dir}");
+ Processes::mwExec("$umount $dir");
}
$result = !self::isStorageDiskMounted($dir);
// If the disk is successfully unmounted and the directory exists, remove the directory
if ($result && file_exists($dir)) {
- Processes::mwExec("{$rm} -rf '{$dir}'");
+ Processes::mwExec("$rm -rf '$dir'");
}
return $result;
@@ -383,21 +243,15 @@ public function formatEntireDisk(string $device, bool $bg = false): bool
// First, remove existing partitions and then create a new msdos partition table and ext4 partition
// This command deletes all existing partitions and creates a new primary partition using the full disk
- $command = "{$parted} --script --align optimal '{$device}' 'mklabel msdos'";
+ $command = "$parted --script --align optimal '$device' 'mklabel msdos'";
Processes::mwExec($command); // Apply the command to clear the partition table
// Now create a new partition that spans the entire disk
- $createPartCommand = "{$parted} --script --align optimal '{$device}' 'mkpart primary ext4 0% 100%'";
+ $createPartCommand = "$parted --script --align optimal '$device' 'mkpart primary ext4 0% 100%'";
$retVal = Processes::mwExec($createPartCommand);
// Log the result of the create partition command
- SystemMessages::sysLogMsg(__CLASS__, "{$createPartCommand} returned {$retVal}", LOG_INFO);
-
- sleep(2); // Wait for the system to recognize changes to the partition table
-
- // Touch the disk to update disk tables
- $partprobe = Util::which('partprobe');
- Processes::mwExec("{$partprobe} '{$device}'");
+ SystemMessages::sysLogMsg(__CLASS__, "$createPartCommand returned $retVal", LOG_INFO);
// Get the newly created partition name, assuming it's always the first partition after a fresh format
$partition = self::getDevPartName($device, '1');
@@ -415,11 +269,11 @@ public function formatEntireDisk(string $device, bool $bg = false): bool
public function formatPartition(string $partition, bool $bg = false): bool
{
$mkfs = Util::which("mkfs.ext4");
- $cmd = "{$mkfs} {$partition}";
+ $cmd = "$mkfs $partition";
if ($bg === false) {
// Execute the mkfs command and check the return value
- $retVal = Processes::mwExec("{$cmd} 2>&1");
- SystemMessages::sysLogMsg(__CLASS__, "{$cmd} returned {$retVal}");
+ $retVal = Processes::mwExec("$cmd 2>&1");
+ SystemMessages::sysLogMsg(__CLASS__, "$cmd returned $retVal");
$result = ($retVal === 0);
} else {
usleep(200000);
@@ -440,14 +294,14 @@ public function formatPartition(string $partition, bool $bg = false): bool
public static function statusMkfs(string $dev): string
{
if (!file_exists($dev)) {
- $dev = "/dev/{$dev}";
+ $dev = "/dev/$dev";
}
$out = [];
$psPath = Util::which('ps');
$grepPath = Util::which('grep');
// Execute the command to check the status of mkfs process
- Processes::mwExec("{$psPath} -A -f | {$grepPath} {$dev} | {$grepPath} mkfs | {$grepPath} -v grep", $out);
+ Processes::mwExec("$psPath -A -f | $grepPath $dev | $grepPath mkfs | $grepPath -v grep", $out);
$mount_dir = trim(implode('', $out));
return empty($mount_dir) ? 'ended' : 'inprogress';
@@ -525,7 +379,7 @@ public static function selectAndConfigureStorageDisk(bool $automatic=false, bool
// Check if the disk selection should be automatic
if ($automatic) {
$target_disk_storage = $selected_disk['id'];
- SystemMessages::echoToTeletype(PHP_EOL.' |- '."Automatically selected storage disk is $target_disk_storage");
+ SystemMessages::echoToTeletype(PHP_EOL.' - '."Automatically selected storage disk is $target_disk_storage");
} else {
echo PHP_EOL." " . Util::translate('Select the drive to store the data.');
echo PHP_EOL." " . Util::translate('Selected disk:') . "\033[33;1m [{$selected_disk['id']}] \033[0m ".PHP_EOL.PHP_EOL;
@@ -566,13 +420,13 @@ public static function selectAndConfigureStorageDisk(bool $automatic=false, bool
$storage->formatEntireDisk($dev_disk);
} elseif($part === '4' && $forceFormatStorage) {
echo PHP_EOL . Util::translate('Formatting storage partition 4 on disk').': '.$dev_disk.'...'.PHP_EOL;
- passthru("exec /dev/console 2>/dev/console; /sbin/initial_storage_part_four create {$dev_disk}");
+ passthru("exec /dev/console 2>/dev/console; /sbin/initial_storage_part_four create $dev_disk");
} elseif($part === '4') {
echo PHP_EOL . Util::translate('Update storage partition 4 on disk').': '.$dev_disk.'...'.PHP_EOL;
- passthru("exec /dev/console 2>/dev/console; /sbin/initial_storage_part_four update {$dev_disk}");
+ passthru("exec /dev/console 2>/dev/console; /sbin/initial_storage_part_four update $dev_disk");
}
$partitionName = self::getDevPartName($target_disk_storage, $part);
- $uuid = $storage->getUuid($partitionName);
+ $uuid = self::getUuid($partitionName);
// Create an array of disk data
$data = [
'device' => $dev_disk,
@@ -580,7 +434,7 @@ public static function selectAndConfigureStorageDisk(bool $automatic=false, bool
'filesystemtype' => 'ext4',
'name' => 'Storage №1'
];
-
+ echo PHP_EOL ."Disk part: $dev_disk, uid: $uuid".PHP_EOL;
// Save the disk settings
$storage->saveDiskSettings($data);
if (file_exists('/offload/livecd')) {
@@ -645,21 +499,38 @@ public static function selectAndConfigureStorageDisk(bool $automatic=false, bool
*
* @param string $dev The device name
* @param string $part The partition number
+ * @param bool $verbose print verbose messages
* @return string The partition name
*/
- public static function getDevPartName(string $dev, string $part): string
+ public static function getDevPartName(string $dev, string $part, bool $verbose = false): string
{
$lsBlkPath = Util::which('lsblk');
- $cutPath = Util::which('cut');
- $grepPath = Util::which('grep');
- $sortPath = Util::which('sort');
-
- $command = "{$lsBlkPath} -r | {$grepPath} ' part' | {$sortPath} -u | {$cutPath} -d ' ' -f 1 | {$grepPath} \"" . basename(
- $dev
- ) . "\" | {$grepPath} \"{$part}\$\"";
- Processes::mwExec($command, $out);
- $devName = trim(implode('', $out));
- return '/dev/'.trim($devName);
+ $cutPath = Util::which('cut');
+ $grepPath = Util::which('grep');
+ $sortPath = Util::which('sort');
+
+ $basenameDisk = basename($dev);
+ $pathToDisk = trim(shell_exec("$lsBlkPath -n -p -a -r -o NAME,TYPE | $grepPath disk | $grepPath '$basenameDisk' | $cutPath -d ' ' -f 1"));
+ if($verbose) {
+ echo "Get dev full path...".PHP_EOL;
+ echo "Source dev: $dev, result full path: $pathToDisk".PHP_EOL;
+ }
+ // Touch the disk to update disk tables
+ $partProbePath = Util::which('partprobe');
+ shell_exec($partProbePath." '$pathToDisk'");
+
+ // Touch the disk to update disk tables
+ $command = "$lsBlkPath -r -p | $grepPath ' part' | $sortPath -u | $cutPath -d ' ' -f 1 | $grepPath '" . $pathToDisk . "' | $grepPath \"$part\$\"";
+ $devName = trim(shell_exec($command));
+ if(empty($devName) && $verbose ){
+ $verboseMsg = trim(shell_exec("$lsBlkPath -r -p"));
+ echo "--- filtered command ---".PHP_EOL;
+ echo $command.PHP_EOL;
+ echo "--- result 'lsblk -r -p' ---".PHP_EOL;
+ echo $verboseMsg.PHP_EOL;
+ echo "--- --- ---".PHP_EOL;
+ }
+ return $devName;
}
/**
@@ -680,8 +551,8 @@ public static function isStorageDisk(string $device): bool
Util::mwMkdir($tmp_dir);
$out = [];
+ $uid_part = 'UUID=' . self::getUuid($device);
$storage = new self();
- $uid_part = 'UUID=' . $storage->getUuid($device) . '';
$format = $storage->getFsType($device);
// If the file system type is not available, return false
if ($format === '') {
@@ -691,8 +562,8 @@ public static function isStorageDisk(string $device): bool
$umount = Util::which('umount');
$rm = Util::which('rm');
- Processes::mwExec("{$mount} -t {$format} {$uid_part} {$tmp_dir}", $out);
- if (is_dir("{$tmp_dir}/mikopbx") && trim(implode('', $out)) === '') {
+ Processes::mwExec("$mount -t $format $uid_part $tmp_dir", $out);
+ if (is_dir("$tmp_dir/mikopbx") && trim(implode('', $out)) === '') {
// $out - empty string, no errors
// mikopbx directory exists
$result = true;
@@ -700,12 +571,12 @@ public static function isStorageDisk(string $device): bool
// Check if the storage disk is mounted, and unmount if necessary
if (self::isStorageDiskMounted($device)) {
- Processes::mwExec("{$umount} {$device}");
+ Processes::mwExec("$umount $device");
}
// Check if the storage disk is unmounted, and remove the temporary directory
if (!self::isStorageDiskMounted($device)) {
- Processes::mwExec("{$rm} -rf '{$tmp_dir}'");
+ Processes::mwExec("$rm -rf '$tmp_dir'");
}
return $result;
@@ -729,7 +600,9 @@ public function saveDiskSettings(array $data, string $id = '1'): void
foreach ($data as $key => $value) {
$storage_settings->writeAttribute($key, $value);
}
- $storage_settings->save();
+ if(!$storage_settings->save()){
+ echo PHP_EOL ."Fail save new storage ID in database...".PHP_EOL;
+ }
}
/**
@@ -760,8 +633,8 @@ public function getDiskSettings(string $id = ''): array
*/
public function configure(): void
{
- $varEtcDir = $this->config->path('core.varEtcDir');
- $storage_dev_file = "{$varEtcDir}/storage_device";
+ $varEtcDir = $this->config->path(Directories::CORE_VAR_ETC_DIR);
+ $storage_dev_file = "$varEtcDir/storage_device";
if (!Util::isT2SdeLinux()) {
// Configure for non-T2Sde Linux
file_put_contents($storage_dev_file, "/storage/usbdisk1");
@@ -807,11 +680,11 @@ public function configure(): void
// Check if the file system type matches the expected type
if ($formatFs !== $disk['filesystemtype'] && !($formatFs === 'ext4' && $disk['filesystemtype'] === 'ext2')) {
- SystemMessages::sysLogMsg(__METHOD__, "The file system type has changed {$disk['filesystemtype']} -> {$formatFs}. The disk will not be connected.");
+ SystemMessages::sysLogMsg(__METHOD__, "The file system type has changed {$disk['filesystemtype']} -> $formatFs. The disk will not be connected.");
continue;
}
- $str_uid = 'UUID=' . $this->getUuid($dev);
- $conf .= "{$str_uid} /storage/usbdisk{$disk['id']} {$formatFs} async,rw 0 0\n";
+ $str_uid = 'UUID=' . self::getUuid($dev);
+ $conf .= "$str_uid /storage/usbdisk{$disk['id']} $formatFs async,rw 0 0\n";
$mount_point = "/storage/usbdisk{$disk['id']}";
Util::mwMkdir($mount_point);
SystemMessages::sysLogMsg(__METHOD__, "Create mount point: $conf");
@@ -847,7 +720,7 @@ private function updateConfigWithNewMountPoint(string $mount_point): void
try {
$data = json_decode($jsonString, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
- throw new Error("{$staticSettingsFileOrig} has broken format");
+ throw new Error("$staticSettingsFileOrig has broken format");
}
foreach ($data as $rootKey => $rootEntry) {
foreach ($rootEntry as $nestedKey => $entry) {
@@ -893,7 +766,7 @@ private function createWorkDirs(): void
{
$path = '';
$mountPath = Util::which('mount');
- Processes::mwExec("{$mountPath} -o remount,rw /offload 2> /dev/null");
+ Processes::mwExec("$mountPath -o remount,rw /offload 2> /dev/null");
$isLiveCd = file_exists('/offload/livecd');
@@ -936,7 +809,7 @@ private function createWorkDirs(): void
$this->clearCacheFiles();
$this->clearTmpFiles();
$this->applyFolderRights();
- Processes::mwExec("{$mountPath} -o remount,ro /offload 2> /dev/null");
+ Processes::mwExec("$mountPath -o remount,ro /offload 2> /dev/null");
}
/**
@@ -947,25 +820,25 @@ private function createWorkDirs(): void
public function clearCacheFiles(): void
{
$cacheDirs = [];
- $cacheDirs[] = $this->config->path('www.uploadDir');
- $cacheDirs[] = $this->config->path('www.downloadCacheDir');
- $cacheDirs[] = $this->config->path('adminApplication.assetsCacheDir') . '/js';
- $cacheDirs[] = $this->config->path('adminApplication.assetsCacheDir') . '/css';
- $cacheDirs[] = $this->config->path('adminApplication.assetsCacheDir') . '/img';
- $cacheDirs[] = $this->config->path('adminApplication.viewCacheDir');
- $cacheDirs[] = $this->config->path('adminApplication.voltCacheDir');
+ $cacheDirs[] = $this->config->path(Directories::WWW_UPLOAD_DIR);
+ $cacheDirs[] = $this->config->path(Directories::WWW_DOWNLOAD_CACHE_DIR);
+ $cacheDirs[] = $this->config->path(Directories::APP_ASSETS_CACHE_DIR) . '/js';
+ $cacheDirs[] = $this->config->path(Directories::APP_ASSETS_CACHE_DIR) . '/css';
+ $cacheDirs[] = $this->config->path(Directories::APP_ASSETS_CACHE_DIR) . '/img';
+ $cacheDirs[] = $this->config->path(Directories::APP_VIEW_CACHE_DIR);
+ $cacheDirs[] = $this->config->path(Directories::APP_VOLT_CACHE_DIR);
$rmPath = Util::which('rm');
// Clear cache files for each directory
foreach ($cacheDirs as $cacheDir) {
if (!empty($cacheDir)) {
- Processes::mwExec("{$rmPath} -rf {$cacheDir}/*");
+ Processes::mwExec("$rmPath -rf $cacheDir/*");
}
}
// Delete boot cache folders if storage disk is mounted
if (is_dir('/mountpoint') && self::isStorageDiskMounted()) {
- Processes::mwExec("{$rmPath} -rf /mountpoint");
+ Processes::mwExec("$rmPath -rf /mountpoint");
}
}
@@ -978,8 +851,9 @@ private function clearTmpFiles(): void
$timeout = Util::which('timeout');
$find = Util::which('find');
$mv = Util::which('mv');
+ $rm = Util::which('rm');
$nice = Util::which('nice');
- $tmpDir = $this->config->path('core.tempDir');
+ $tmpDir = $this->config->path(Directories::CORE_TEMP_DIR);
if (!file_exists($tmpDir)) {
return;
}
@@ -995,7 +869,7 @@ private function clearTmpFiles(): void
shell_exec("$mv '$resDirForRm/swapfile' '$tmpDir/swapfile'");
}
// Let's start deleting temporary files
- Processes::mwExecBg("$nice -n 19 $mv -rf $resDirForRm");
+ Processes::mwExecBg("$nice -n 19 $rm -rf $resDirForRm");
}
Util::mwMkdir($tmpDir, true);
}
@@ -1022,7 +896,7 @@ private function getStorageDev(array $disk, string $cf_disk): string
}
}
// Determine the disk by its name.
- if ($disk['device'] !== "/dev/{$cf_disk}") {
+ if ($disk['device'] !== "/dev/$cf_disk") {
// If it's a regular disk, use partition 1.
$part = "1";
} else {
@@ -1058,7 +932,7 @@ private function hddExists(string $disk): bool
// Loop for up to 10 seconds or until a non-empty UUID is found.
while (true) {
// Retrieve the UUID for the disk.
- $uid = $this->getUuid($disk);
+ $uid = self::getUuid($disk);
SystemMessages::sysLogMsg(__METHOD__, "Disk with name $disk has GUID: $uid", LOG_DEBUG);
// If the UUID is not empty, the disk exists.
@@ -1087,7 +961,7 @@ private function hddExists(string $disk): bool
*/
public function saveFstab(string $conf = ''): void
{
- $varEtcDir = $this->config->path('core.varEtcDir');
+ $varEtcDir = $this->config->path(Directories::CORE_VAR_ETC_DIR);
// Create the mount point directory for additional disks
Util::mwMkdir('/storage');
@@ -1109,9 +983,9 @@ public function saveFstab(string $conf = ''): void
$part2 = self::getDevPartName($cf_disk, '2');
$part3 = self::getDevPartName($cf_disk, '3');
- $uid_part2 = 'UUID=' . $this->getUuid("$part2");
+ $uid_part2 = 'UUID=' . self::getUuid($part2);
$format_p2 = $this->getFsType($part2);
- $uid_part3 = 'UUID=' . $this->getUuid("$part3");
+ $uid_part3 = 'UUID=' . self::getUuid($part3);
$format_p3 = $this->getFsType($part3);
$fstab .= "$uid_part2 /offload $format_p2 ro 0 0\n";
@@ -1187,7 +1061,7 @@ private function getLsBlkDiskInfo(): array
// Execute lsblk command to get disk information in JSON format
Processes::mwExec(
- "{$lsBlkPath} -J -b -o VENDOR,MODEL,SERIAL,LABEL,TYPE,FSTYPE,MOUNTPOINT,SUBSYSTEMS,NAME,UUID",
+ "$lsBlkPath -J -b -o VENDOR,MODEL,SERIAL,LABEL,TYPE,FSTYPE,MOUNTPOINT,SUBSYSTEMS,NAME,UUID",
$out
);
try {
@@ -1208,7 +1082,7 @@ public function createWorkDirsAfterDBUpgrade(): void
{
// Remount /offload directory as read-write
$mountPath = Util::which('mount');
- Processes::mwExec("{$mountPath} -o remount,rw /offload 2> /dev/null");
+ Processes::mwExec("$mountPath -o remount,rw /offload 2> /dev/null");
// Create symlinks for module caches
$this->createModulesCacheSymlinks();
@@ -1217,7 +1091,7 @@ public function createWorkDirsAfterDBUpgrade(): void
$this->applyFolderRights();
// Remount /offload directory as read-only
- Processes::mwExec("{$mountPath} -o remount,ro /offload 2> /dev/null");
+ Processes::mwExec("$mountPath -o remount,ro /offload 2> /dev/null");
}
/**
@@ -1249,15 +1123,15 @@ public function createAssetsSymlinks(): void
{
// Create symlink for JS cache directory
$jsCacheDir = appPath('sites/admin-cabinet/assets/js/cache');
- Util::createUpdateSymlink($this->config->path('adminApplication.assetsCacheDir') . '/js', $jsCacheDir);
+ Util::createUpdateSymlink($this->config->path(Directories::APP_ASSETS_CACHE_DIR) . '/js', $jsCacheDir);
// Create symlink for CSS cache directory
$cssCacheDir = appPath('sites/admin-cabinet/assets/css/cache');
- Util::createUpdateSymlink($this->config->path('adminApplication.assetsCacheDir') . '/css', $cssCacheDir);
+ Util::createUpdateSymlink($this->config->path(Directories::APP_ASSETS_CACHE_DIR) . '/css', $cssCacheDir);
// Create symlink for image cache directory
$imgCacheDir = appPath('sites/admin-cabinet/assets/img/cache');
- Util::createUpdateSymlink($this->config->path('adminApplication.assetsCacheDir') . '/img', $imgCacheDir);
+ Util::createUpdateSymlink($this->config->path(Directories::APP_ASSETS_CACHE_DIR) . '/img', $imgCacheDir);
}
@@ -1269,7 +1143,7 @@ public function createAssetsSymlinks(): void
public function createViewSymlinks(): void
{
$viewCacheDir = appPath('src/AdminCabinet/Views/Modules');
- Util::createUpdateSymlink($this->config->path('adminApplication.viewCacheDir'), $viewCacheDir);
+ Util::createUpdateSymlink($this->config->path(Directories::APP_VIEW_CACHE_DIR), $viewCacheDir);
}
/**
@@ -1280,16 +1154,16 @@ public function createViewSymlinks(): void
*/
public function createAGIBINSymlinks(bool $isLiveCd): void
{
- $agiBinDir = $this->config->path('asterisk.astagidir');
+ $agiBinDir = $this->config->path(Directories::AST_AGI_BIN_DIR);
if ($isLiveCd && strpos($agiBinDir, '/offload/') !== 0) {
Util::mwMkdir($agiBinDir);
}
$roAgiBinFolder = appPath('src/Core/Asterisk/agi-bin');
- $files = glob("{$roAgiBinFolder}/*.{php}", GLOB_BRACE);
+ $files = glob("$roAgiBinFolder/*.{php}", GLOB_BRACE);
foreach ($files as $file) {
$fileInfo = pathinfo($file);
- $newFilename = "{$agiBinDir}/{$fileInfo['filename']}.{$fileInfo['extension']}";
+ $newFilename = "$agiBinDir/{$fileInfo['filename']}.{$fileInfo['extension']}";
Util::createUpdateSymlink($file, $newFilename);
}
}
@@ -1320,8 +1194,8 @@ private function applyFolderRights(): void
}
// Add additional directories with WWW rights
- $www_dirs[] = $this->config->path('core.tempDir');
- $www_dirs[] = $this->config->path('core.logsDir');
+ $www_dirs[] = $this->config->path(Directories::CORE_TEMP_DIR);
+ $www_dirs[] = $this->config->path(Directories::CORE_LOGS_DIR);
// Create empty log files with WWW rights
$logFiles = [
@@ -1349,7 +1223,7 @@ private function applyFolderRights(): void
Util::addExecutableRights(implode(' ', $exec_dirs));
$mountPath = Util::which('mount');
- Processes::mwExec("{$mountPath} -o remount,ro /offload 2> /dev/null");
+ Processes::mwExec("$mountPath -o remount,ro /offload 2> /dev/null");
}
/**
@@ -1357,18 +1231,18 @@ private function applyFolderRights(): void
*/
public function mountSwap(): void
{
- $tempDir = $this->config->path('core.tempDir');
- $swapFile = "{$tempDir}/swapfile";
+ $tempDir = $this->config->path(Directories::CORE_TEMP_DIR);
+ $swapFile = "$tempDir/swapfile";
$swapOffCmd = Util::which('swapoff');
- Processes::mwExec("{$swapOffCmd} {$swapFile}");
+ Processes::mwExec("$swapOffCmd $swapFile");
$this->makeSwapFile($swapFile);
if (!file_exists($swapFile)) {
return;
}
$swapOnCmd = Util::which('swapon');
- $result = Processes::mwExec("{$swapOnCmd} {$swapFile}");
+ $result = Processes::mwExec("$swapOnCmd $swapFile");
SystemMessages::sysLogMsg('Swap', 'connect swap result: ' . $result, LOG_INFO);
}
@@ -1382,7 +1256,7 @@ private function makeSwapFile(string $swapFile): void
$swapLabel = Util::which('swaplabel');
// Check if swap file already exists
- if (Processes::mwExec("{$swapLabel} {$swapFile}") === 0) {
+ if (Processes::mwExec("$swapLabel $swapFile") === 0) {
return;
}
if (file_exists($swapFile)) {
@@ -1405,12 +1279,12 @@ private function makeSwapFile(string $swapFile): void
SystemMessages::sysLogMsg('Swap', 'make swap ' . $swapFile, LOG_INFO);
// Create swap file using dd command
- Processes::mwExec("{$ddCmd} if=/dev/zero of={$swapFile} bs={$bs} count={$countBlock}");
+ Processes::mwExec("$ddCmd if=/dev/zero of=$swapFile bs=$bs count=$countBlock");
$mkSwapCmd = Util::which('mkswap');
// Set up swap space on the file
- Processes::mwExec("{$mkSwapCmd} {$swapFile}");
+ Processes::mwExec("$mkSwapCmd $swapFile");
}
/**
@@ -1456,7 +1330,7 @@ public function getAllHdd(bool $mounted_only = false): array
// Execute the command to get disk information for /storage directory
Processes::mwExec(
- "{$dfPath} -k /storage | {$awkPath} '{ print \$1 \"|\" $3 \"|\" \$4} ' | {$grepPath} -v 'Available'",
+ "$dfPath -k /storage | $awkPath '{ print \$1 \"|\" $3 \"|\" \$4} ' | $grepPath -v 'Available'",
$out
);
$disk_data = explode('|', implode(" ", $out));
@@ -1481,10 +1355,10 @@ public function getAllHdd(bool $mounted_only = false): array
// Get CD-ROM and HDD devices
$cd_disks = $this->cdromGetDevices();
- $disks = $this->diskGetDevices();
+ $disks = $this->diskGetDevices();
$cf_disk = '';
- $varEtcDir = $this->config->path('core.varEtcDir');
+ $varEtcDir = $this->config->path(Directories::CORE_VAR_ETC_DIR);
if (file_exists($varEtcDir . '/cfdevice')) {
$cf_disk = trim(file_get_contents($varEtcDir . '/cfdevice'));
@@ -1518,7 +1392,7 @@ public function getAllHdd(bool $mounted_only = false): array
if ($mb_size > 100) {
$temp_size = sprintf("%.0f MB", $mb_size);
$temp_vendor = $this->getVendorDisk($diskInfo);
- $free_space = $this->getFreeSpace($disk);
+ $free_space = self::getFreeSpace($disk);
$arr_disk_info = $this->determineFormatFs($diskInfo);
@@ -1616,9 +1490,10 @@ public static function diskIsMounted(string $disk, string $filter = '/dev/')
$out = [];
$grepPath = Util::which('grep');
$mountPath = Util::which('mount');
+ $headPath = Util::which('head');
// Execute mount command and grep the output for the disk name
- Processes::mwExec("{$mountPath} | {$grepPath} '{$filter}{$disk}'", $out);
+ Processes::mwExec("$mountPath | $grepPath '$filter${disk}' | $headPath -n 1", $out);
if (count($out) > 0) {
$res_out = end($out);
} else {
@@ -1649,7 +1524,7 @@ private function getVendorDisk(array $diskInfo): string
}
// If no vendor-related data is found, use the disk name
- if (count($temp_vendor) === 0) {
+ if (empty($temp_vendor)) {
$temp_vendor[] = $diskInfo['name'] ?? 'ERROR: NoName';
}
return implode(', ', $temp_vendor);
@@ -1668,9 +1543,10 @@ public static function getFreeSpace(string $hdd)
$grep = Util::which('grep');
$awk = Util::which('awk');
$df = Util::which('df');
+ $head = Util::which('head');
// Execute df command to get the free space for the HDD
- Processes::mwExec("$df -m | $grep $hdd | $awk '{print $4}'", $out);
+ Processes::mwExec("$df -m | $grep $hdd | $grep -v custom_modules | $head -n 1 | $awk '{print $4}'", $out);
$result = 0;
// Sum up the free space values
@@ -1700,19 +1576,19 @@ public function determineFormatFs(array $deviceInfo): array
// Iterate through each device partition
foreach ($devices as $dev) {
- if (empty($dev) || (count($devices) > 1 && $device === $dev) || is_dir("/sys/block/{$dev}")) {
+ if (empty($dev) || (count($devices) > 1 && $device === $dev) || is_dir("/sys/block/$dev")) {
continue;
}
$mb_size = 0;
$path_size_info = '';
- $tmp_path = "/sys/block/{$device}/{$dev}/size";
+ $tmp_path = "/sys/block/$device/$dev/size";
if (file_exists($tmp_path)) {
$path_size_info = $tmp_path;
}
// If the size path is not found, try an alternate path
if (empty($path_size_info)) {
- $tmp_path = "/sys/block/" . substr($dev, 0, 3) . "/{$dev}/size";
+ $tmp_path = "/sys/block/" . substr($dev, 0, 3) . "/$dev/size";
if (file_exists($tmp_path)) {
$path_size_info = $tmp_path;
}
@@ -1733,16 +1609,16 @@ public function determineFormatFs(array $deviceInfo): array
$mount_dir = '';
// Check if the device is currently mounted
- if (self::isStorageDiskMounted("/dev/{$dev} ", $mount_dir)) {
+ if (self::isStorageDiskMounted("/dev/$dev ", $mount_dir)) {
$grepPath = Util::which('grep');
$awkPath = Util::which('awk');
$mountPath = Util::which('mount');
// Get the file system type and free space of the mounted device
- Processes::mwExec("{$mountPath} | {$grepPath} '/dev/{$dev}' | {$awkPath} '{print $5}'", $out);
+ Processes::mwExec("$mountPath | $grepPath '/dev/$dev' | $awkPath '{print $5}'", $out);
$fs = trim(implode("", $out));
$fs = ($fs === 'fuseblk') ? 'ntfs' : $fs;
- $free_space = $this->getFreeSpace("/dev/{$dev} ");
+ $free_space = self::getFreeSpace("/dev/$dev ");
$used_space = $mb_size - $free_space;
} else {
$format = $this->getFsType($device);
@@ -1765,7 +1641,7 @@ public function determineFormatFs(array $deviceInfo): array
'size' => round($mb_size, 2),
"used_space" => round($used_space, 2),
"free_space" => round($mb_size - $used_space, 2),
- "uuid" => $this->getUuid("/dev/{$dev} "),
+ "uuid" => self::getUuid("/dev/$dev "),
"fs" => $fs,
];
@@ -1790,7 +1666,7 @@ private function getDiskParted(string $diskName): array
$lsBlkPath = Util::which('lsblk');
// Execute lsblk command to get disk partition information in JSON format
- Processes::mwExec("{$lsBlkPath} -J -b -o NAME,TYPE {$diskName}", $out);
+ Processes::mwExec("$lsBlkPath -J -b -o NAME,TYPE $diskName", $out);
try {
$data = json_decode(implode(PHP_EOL, $out), true, 512, JSON_THROW_ON_ERROR);
@@ -1831,7 +1707,7 @@ public function getFsType(string $device): string
// Execute the command to retrieve the file system type of the device
Processes::mwExec(
- "$blkid -ofull /dev/{$device} | $sed -r 's/[[:alnum:]]+=/\\n&/g' | $grep \"^TYPE=\" | $awk -F \"\\\"\" '{print $2}'",
+ "$blkid -ofull /dev/$device | $sed -r 's/[[:alnum:]]+=/\\n&/g' | $grep \"^TYPE=\" | $awk -F \"\\\"\" '{print $2}'",
$out
);
$format = implode('', $out);
@@ -1855,7 +1731,7 @@ public function getFsType(string $device): string
public static function mountDisk(string $dev, string $format, string $dir): bool
{
// Check if the disk is already mounted
- if (self::isStorageDiskMounted("/dev/{$dev} ")) {
+ if (self::isStorageDiskMounted("/dev/$dev ")) {
return true;
}
@@ -1875,17 +1751,16 @@ public static function mountDisk(string $dev, string $format, string $dir): bool
if ('ntfs' === $format) {
// Mount NTFS disk using 'mount.ntfs-3g' command
$mountNtfs3gPath = Util::which('mount.ntfs-3g');
- Processes::mwExec("{$mountNtfs3gPath} /dev/{$dev} {$dir}", $out);
+ Processes::mwExec("$mountNtfs3gPath /dev/$dev $dir", $out);
} else {
// Mount disk using specified file system format and UUID
- $storage = new self();
- $uid_part = 'UUID=' . $storage->getUuid("/dev/{$dev}") . '';
+ $uid_part = 'UUID=' . self::getUuid("/dev/$dev");
$mountPath = Util::which('mount');
- Processes::mwExec("{$mountPath} -t {$format} {$uid_part} {$dir}", $out);
+ Processes::mwExec("$mountPath -t $format $uid_part $dir", $out);
}
// Check if the disk is now mounted
- return self::isStorageDiskMounted("/dev/{$dev} ");
+ return self::isStorageDiskMounted("/dev/$dev ");
}
/**
@@ -1906,7 +1781,7 @@ public static function getUuid(string $device): string
// Build the command to retrieve the UUID of the device
$cmd = "$lsblk -r -o NAME,UUID | $grep " . basename($device) . " | $cut -d ' ' -f 2";
$res = Processes::mwExec($cmd, $output);
- if ($res === 0 && count($output) > 0) {
+ if ($res === 0 && !empty($output)) {
$result = $output[0];
} else {
$result = '';
@@ -1931,9 +1806,9 @@ public function getRecoverDiskName(): string
}
foreach ($diskInfo['children'] as $child) {
$mountpoint = $child['mountpoint'] ?? '';
- $diskPath = "/dev/{$disk}";
+ $diskPath = "/dev/$disk";
if ($mountpoint === '/conf.recover' && file_exists($diskPath)) {
- return "/dev/{$disk}";
+ return "/dev/$disk";
}
}
}
@@ -1963,7 +1838,7 @@ public static function connectStorageInCloud(): string
}
// In some Clouds the virtual machine starts immediately before the storage disk was attached
- if (!Storage::selectAndConfigureStorageDisk(true)){
+ if (!self::selectAndConfigureStorageDisk(true)){
return SystemMessages::RESULT_FAILED;
}
diff --git a/src/Core/System/SystemConfiguration.php b/src/Core/System/SystemConfiguration.php
index d83117ade..10f38b287 100644
--- a/src/Core/System/SystemConfiguration.php
+++ b/src/Core/System/SystemConfiguration.php
@@ -54,37 +54,38 @@ public function tryRestoreConf():void
$backupDir = str_replace(['/storage/usbdisk1','/mountpoint'], ['',''], $confBackupDir);
$confFile = $this->configDBPath;
foreach ($storages as $dev => $fs){
- SystemMessages::echoToTeletype(" - mount $dev ..."."\n", true);
+ SystemMessages::echoToTeletype(PHP_EOL." - mount $dev ...".PHP_EOL, true);
Util::mwMkdir($tmpMountDir."/$dev");
$res = Storage::mountDisk($dev, $fs, $tmpMountDir."/$dev");
if(!$res){
- SystemMessages::echoToTeletype(" - fail mount $dev ..."."\n", true);
+ SystemMessages::echoToTeletype(" - fail mount $dev ...".PHP_EOL, true);
}
}
$tail = Util::which('tail');
$sort = Util::which('sort');
$find = Util::which('find');
- $mount = Util::which('umount');
- $rm = Util::which('rm');
$cut = Util::which('cut');
- $gzip = Util::which('gzip');
- $sqlite3 = Util::which('sqlite3');
$lastBackUp = trim(shell_exec("$find $tmpMountDir/dev/*$backupDir -type f -printf '%T@ %p\\n' | $sort -n | $tail -1 | $cut -f2- -d' '"));
- if(empty($lastBackUp)){
- return;
- }
- SystemMessages::echoToTeletype(" - Restore $lastBackUp ..."."\n", true);
- shell_exec("$rm -rf {$confFile}*");
- shell_exec("$gzip -c -d $lastBackUp | sqlite3 $confFile");
- Processes::mwExec("$sqlite3 $confFile 'select * from m_Storage'", $out, $ret);
- if($ret !== 0){
- SystemMessages::echoToTeletype(" - restore $lastBackUp failed..."."\n", true);
- copy(self::DEFAULT_CONFIG_DB, $confFile);
- }elseif(!$this->isDefaultConf()){
- System::reboot();
+ if(!empty($lastBackUp)){
+ $rm = Util::which('rm');
+ $gzip = Util::which('gzip');
+ $sqlite3= Util::which('sqlite3');
+
+ SystemMessages::echoToTeletype(" - Restore $lastBackUp ...".PHP_EOL, true);
+ shell_exec("$rm -rf {$confFile}*");
+ shell_exec("$gzip -c -d $lastBackUp | sqlite3 $confFile");
+ Processes::mwExec("$sqlite3 $confFile 'select * from m_Storage'", $out, $ret);
+ if($ret !== 0){
+ SystemMessages::echoToTeletype(" - restore $lastBackUp failed...".PHP_EOL, true);
+ copy(self::DEFAULT_CONFIG_DB, $confFile);
+ }elseif(!$this->isDefaultConf()){
+ System::reboot();
+ }
}
+ $mount = Util::which('umount');
foreach ($storages as $dev => $fs){
+ SystemMessages::echoToTeletype(" - umount $dev ...".PHP_EOL, true);
shell_exec("$mount $dev");
}
}
diff --git a/src/Core/System/Upgrade/Releases/UpdateConfigsUpToVer2024v2v10.php b/src/Core/System/Upgrade/Releases/UpdateConfigsUpToVer2024v2v10.php
new file mode 100644
index 000000000..8af0480f3
--- /dev/null
+++ b/src/Core/System/Upgrade/Releases/UpdateConfigsUpToVer2024v2v10.php
@@ -0,0 +1,73 @@
+.
+ */
+
+namespace MikoPBX\Core\System\Upgrade\Releases;
+
+use MikoPBX\Common\Models\FirewallRules;
+use MikoPBX\Common\Models\NetworkFilters;
+use MikoPBX\Common\Models\PbxSettings;
+use MikoPBX\Common\Models\PbxSettingsConstants;
+use MikoPBX\Core\System\Upgrade\UpgradeSystemConfigInterface;
+use Phalcon\Di\Injectable;
+
+class UpdateConfigsUpToVer2024v2v10 extends Injectable implements UpgradeSystemConfigInterface
+{
+ public const PBX_VERSION = '2024.2.10';
+
+ /**
+ * Class constructor.
+ */
+ public function __construct()
+ {
+ }
+
+ /**
+ * https://github.com/mikopbx/Core/issues/782
+ */
+ public function processUpdate(): void
+ {
+ $colName = PbxSettingsConstants::IAX_PORT;
+ $iax_port = PbxSettings::getValueByKey(PbxSettingsConstants::IAX_PORT);
+ $nets = NetworkFilters::find(['columns' => 'id']);
+ foreach ($nets as $net){
+ $filter = [
+ "portFromKey='$colName' AND networkfilterid='$net->id'",
+ 'columns' => 'id'
+ ];
+ $rule = FirewallRules::findFirst($filter);
+ if($rule){
+ continue;
+ }
+ $rule = new FirewallRules();
+ foreach ($rule->toArray() as $key => $value){
+ $rule->$key = $value;
+ }
+ $rule->networkfilterid = $net->id;
+ $rule->action = 'block';
+ $rule->portfrom = $iax_port;
+ $rule->portto = $iax_port;
+ $rule->protocol = 'udp';
+ $rule->portFromKey = $colName;
+ $rule->portToKey = $colName;
+ $rule->category = 'IAX';
+ $rule->save();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Core/System/Util.php b/src/Core/System/Util.php
index cd534c1db..7e29d93b1 100644
--- a/src/Core/System/Util.php
+++ b/src/Core/System/Util.php
@@ -53,7 +53,7 @@ class Util
*
* @return string The resulting configuration string.
*/
- public static function overrideConfigurationArray($options, $manual_attributes, $section): string
+ public static function overrideConfigurationArray(&$options, $manual_attributes, $section): string
{
$result_config = '';
if ($manual_attributes !== null && isset($manual_attributes[$section])) {
@@ -70,9 +70,9 @@ public static function overrideConfigurationArray($options, $manual_attributes,
}
if (is_array($value)) {
array_unshift($value, ' ');
- $result_config .= trim(implode("\n{$key} = ", $value)) . "\n";
+ $result_config .= trim(implode("\n$key = ", $value)) . "\n";
} else {
- $result_config .= "{$key} = {$value}\n";
+ $result_config .= "$key = $value\n";
}
}
@@ -744,30 +744,33 @@ public static function parseIniSettings(string $manual_attributes): array
foreach ($sections as $section) {
$data_rows = explode("\n", trim($section));
$section_name = trim($data_rows[0] ?? '');
- if (!empty($section_name)) {
+ if(empty($section_name) || strpos($section_name, '[') === false){
+ // Noname section
+ $section_name = ' ';
+ }else{
unset($data_rows[0]);
- $manual_data[$section_name] = [];
- foreach ($data_rows as $row) {
- $value = '';
+ }
+ $manual_data[$section_name] = [];
+ foreach ($data_rows as $row) {
+ $value = '';
- // Skip rows without an equal sign
- if (strpos($row, '=') === false) {
- continue;
- }
- $key = '';
- $arr_value = explode('=', $row);
- if (count($arr_value) > 1) {
- $key = trim($arr_value[0]);
- unset($arr_value[0]);
- $value = trim(implode('=', $arr_value));
- }
+ // Skip rows without an equal sign
+ if (strpos($row, '=') === false) {
+ continue;
+ }
+ $key = '';
+ $arr_value = explode('=', $row);
+ if (count($arr_value) > 1) {
+ $key = trim($arr_value[0]);
+ unset($arr_value[0]);
+ $value = trim(implode('=', $arr_value));
+ }
- // Skip rows with empty key or value not equal to '0'
- if (($value !== '0' && empty($value)) || empty($key)) {
- continue;
- }
- $manual_data[$section_name][$key] = $value;
+ // Skip rows with empty key or value not equal to '0'
+ if (($value !== '0' && empty($value)) || empty($key)) {
+ continue;
}
+ $manual_data[$section_name][$key] = $value;
}
}
diff --git a/src/Core/Workers/Libs/WorkerCallEvents/ActionDialAnswer.php b/src/Core/Workers/Libs/WorkerCallEvents/ActionDialAnswer.php
index 218743ce6..cd345d65e 100644
--- a/src/Core/Workers/Libs/WorkerCallEvents/ActionDialAnswer.php
+++ b/src/Core/Workers/Libs/WorkerCallEvents/ActionDialAnswer.php
@@ -118,16 +118,15 @@ private static function fillPickUpCdr($worker, $data): void
$new_data = $m_row_data->toArray();
// Update certain fields in the new data.
- $new_data['start'] = $data['answer'];
- $new_data['answer'] = $data['answer'];
- $new_data['endtime'] = '';
+ $new_data['start'] = $data['answer'];
+ $new_data['answer'] = $data['answer'];
+ $new_data['endtime'] = '';
$new_data['dst_chan'] = $data['agi_channel'];
- $new_data['dst_num'] = $data['dst_num'];
+ $new_data['dst_num'] = $data['dst_num'];
$new_data['UNIQUEID'] = $data['id'];
// Check if call recording is enabled for this source and destination numbers.
if ($worker->enableMonitor($new_data['src_num'] ?? '', $new_data['dst_num'] ?? '')) {
-
// If it is, start recording the call.
$new_data['recordingfile'] = $worker->MixMonitor($new_data['dst_chan'], 'pickup_' . $new_data['UNIQUEID'], '', '', 'fillPickUpCdr');
}
diff --git a/src/Core/Workers/Libs/WorkerModelsEvents/Actions/ReloadConferenceAction.php b/src/Core/Workers/Libs/WorkerModelsEvents/Actions/ReloadConferenceAction.php
new file mode 100644
index 000000000..c71a43576
--- /dev/null
+++ b/src/Core/Workers/Libs/WorkerModelsEvents/Actions/ReloadConferenceAction.php
@@ -0,0 +1,19 @@
+ '/etc/asterisk/confbridge.conf',
+ 'actions' => [
+ ReloadConferenceAction::class
+ ],
+ ];
+
$tables[] = [
'filePath' => '/etc/asterisk/modules.conf',
'actions' => [
diff --git a/src/Core/Workers/WorkerModelsEvents.php b/src/Core/Workers/WorkerModelsEvents.php
index 94c4d3f00..bbb74a1fe 100644
--- a/src/Core/Workers/WorkerModelsEvents.php
+++ b/src/Core/Workers/WorkerModelsEvents.php
@@ -30,6 +30,7 @@
use MikoPBX\Core\System\{BeanstalkClient, SystemMessages};
use MikoPBX\Core\Workers\Libs\WorkerModelsEvents\Actions\ReloadCloudDescriptionAction;
use MikoPBX\Core\Workers\Libs\WorkerModelsEvents\Actions\ReloadCloudParametersAction;
+use MikoPBX\Core\Workers\Libs\WorkerModelsEvents\Actions\ReloadConferenceAction;
use MikoPBX\Core\Workers\Libs\WorkerModelsEvents\Actions\ReloadCrondAction;
use MikoPBX\Core\Workers\Libs\WorkerModelsEvents\Actions\ReloadDialplanAction;
use MikoPBX\Core\Workers\Libs\WorkerModelsEvents\Actions\ReloadFail2BanConfAction;
@@ -200,6 +201,7 @@ private function getReloadActionsWithPriority(): array
ReloadDialplanAction::class,
ReloadParkingAction::class,
ReloadQueuesAction::class,
+ ReloadConferenceAction::class,
ReloadManagerAction::class,
ReloadVoicemailAction::class,
ReloadMOHAction::class,
diff --git a/src/Core/Workers/WorkerNotifyByEmail.php b/src/Core/Workers/WorkerNotifyByEmail.php
index 7505a81da..68eca17f5 100644
--- a/src/Core/Workers/WorkerNotifyByEmail.php
+++ b/src/Core/Workers/WorkerNotifyByEmail.php
@@ -20,7 +20,9 @@
namespace MikoPBX\Core\Workers;
require_once 'Globals.php';
+use AWS\CRT\Internal\Extension;
use MikoPBX\Core\System\{BeanstalkClient, MikoPBXConfig, Notifications, SystemMessages, Util};
+use MikoPBX\Common\Models\Extensions;
use MikoPBX\Common\Models\PbxSettingsConstants;
/**
@@ -60,8 +62,9 @@ public function start(array $argv): void
*/
public function workerNotifyByEmail($message): void
{
+ $phonesCid = [];
$notifier = new Notifications();
- $config = new MikoPBXConfig();
+ $config = new MikoPBXConfig();
$settings = $config->getGeneralSettings();
/** @var BeanstalkClient $message */
@@ -80,11 +83,16 @@ public function workerNotifyByEmail($message): void
$tmpArray = [];
foreach ($data as $call) {
$keyHash = $call['email'] . $call['start'] . $call['from_number'] . $call['to_number'];
-
// Skip duplicate emails
if (in_array($keyHash, $tmpArray, true)) {
continue;
}
+ if(isset($phonesCid[$call['to_number']])){
+ $call['to_name'] = $phonesCid[$call['to_number']];
+ }else{
+ $call['to_name'] = Extensions::getCidByPhoneNumber($call['to_number']);
+ $phonesCid[$call['to_number']] = $call['to_name'];
+ }
$tmpArray[] = $keyHash;
if (!isset($emails[$call['email']])) {
$emails[$call['email']] = [
@@ -98,7 +106,6 @@ public function workerNotifyByEmail($message): void
$emails[$call['email']]['body'] .= "$email
";
}
}
-
foreach ($emails as $to => $email) {
$subject = $email['subject'];
$body = "{$email['body']}
{$email['footer']}";
@@ -122,6 +129,7 @@ private function replaceParams(string $src, array $params): string
"NOTIFICATION_MISSEDCAUSE",
"NOTIFICATION_CALLERID",
"NOTIFICATION_TO",
+ "NOTIFICATION_NAME_TO",
"NOTIFICATION_DURATION",
"NOTIFICATION_DATE"
],
@@ -130,6 +138,7 @@ private function replaceParams(string $src, array $params): string
'NOANSWER',
$params['from_number'],
$params['to_number'],
+ $params['to_name'],
$params['duration'],
explode('.', $params['start'])[0]
],
diff --git a/src/PBXCoreREST/Lib/CdrDB/GetActiveChannelsAction.php b/src/PBXCoreREST/Lib/CdrDB/GetActiveChannelsAction.php
index 7878681c5..dea8ec183 100644
--- a/src/PBXCoreREST/Lib/CdrDB/GetActiveChannelsAction.php
+++ b/src/PBXCoreREST/Lib/CdrDB/GetActiveChannelsAction.php
@@ -19,17 +19,18 @@
namespace MikoPBX\PBXCoreREST\Lib\CdrDB;
-use MikoPBX\Core\System\BeanstalkClient;
+use MikoPBX\Common\Providers\CDRDatabaseProvider;
use MikoPBX\Core\System\Util;
-use MikoPBX\Core\Workers\WorkerCdr;
use MikoPBX\PBXCoreREST\Lib\PBXApiResult;
+use Phalcon\Exception;
+use Phalcon\Di\Injectable;
/**
* Get active channels. These are the unfinished calls (endtime IS NULL).
*
* @package MikoPBX\PBXCoreREST\Lib\CdrDB
*/
-class GetActiveChannelsAction extends \Phalcon\Di\Injectable
+class GetActiveChannelsAction extends Injectable
{
/**
* Get active channels. These are the unfinished calls (endtime IS NULL).
@@ -40,52 +41,41 @@ public static function main(): PBXApiResult
{
$res = new PBXApiResult();
$res->processor = __METHOD__;
+ $res->success = true;
try {
- $res->success = true;
+ $activeChannels = Util::getAstManager('off')->GetChannels();
+ }catch (Exception $e){
+ $res->success = false;
+ $res->messages[] = $e->getMessage();
+ return $res;
+ }
- $filter = [
- 'endtime=""',
- 'order' => 'id',
- 'columns' => 'start,answer,src_chan,dst_chan,src_num,dst_num,did,linkedid',
- 'miko_tmp_db' => true,
- 'miko_result_in_file' => true,
- ];
- $client = new BeanstalkClient(WorkerCdr::SELECT_CDR_TUBE);
- list($result, $message) = $client->sendRequest(json_encode($filter), 2);
- if ($result === false) {
- $res->data = [];
- } else {
- $am = Util::getAstManager('off');
- $active_chans = $am->GetChannels(true);
- $result_data = [];
+ $filter = [
+ 'endtime=""',
+ 'order' => 'id',
+ 'columns' => 'start,answer,src_chan,dst_chan,src_num,dst_num,did,linkedid',
+ 'miko_tmp_db' => true,
+ ];
+ $cdrData = CDRDatabaseProvider::getCdr($filter);
- $result = json_decode($message);
- if (file_exists($result)) {
- $data = json_decode(file_get_contents($result), true);
- unlink($result);
- foreach ($data as $row) {
- if (!isset($active_chans[$row['linkedid']])) {
- // The call no longer exists.
- continue;
- }
- if (empty($row['dst_chan']) && empty($row['src_chan'])) {
- // This is an erroneous situation. Ignore such a call.
- continue;
- }
- $channels = $active_chans[$row['linkedid']];
- if ((empty($row['src_chan']) || in_array($row['src_chan'], $channels))
- && (empty($row['dst_chan']) || in_array($row['dst_chan'], $channels))) {
- $result_data[] = $row;
- }
- }
- }
- $res->data = $result_data;
+ $result_data = [];
+ foreach ($cdrData as $row) {
+ if (!isset($activeChannels[$row['linkedid']])) {
+ // The call no longer exists.
+ continue;
+ }
+ if (empty($row['dst_chan']) && empty($row['src_chan'])) {
+ // This is an erroneous situation. Ignore such a call.
+ continue;
+ }
+ $channels = $activeChannels[$row['linkedid']];
+ if ((empty($row['src_chan']) || in_array($row['src_chan'], $channels, true))
+ && (empty($row['dst_chan']) || in_array($row['dst_chan'], $channels, true))) {
+ $result_data[] = $row;
}
- } catch (\Throwable $e) {
- $res->success = false;
- $res->messages[] = $e->getMessage();
}
+ $res->data = $result_data;
return $res;
}
}
\ No newline at end of file
diff --git a/src/PBXCoreREST/Lib/System/ConvertAudioFileAction.php b/src/PBXCoreREST/Lib/System/ConvertAudioFileAction.php
index 826325408..1606fc490 100644
--- a/src/PBXCoreREST/Lib/System/ConvertAudioFileAction.php
+++ b/src/PBXCoreREST/Lib/System/ConvertAudioFileAction.php
@@ -22,11 +22,12 @@
use MikoPBX\Core\System\Processes;
use MikoPBX\Core\System\Util;
use MikoPBX\PBXCoreREST\Lib\PBXApiResult;
+use Phalcon\Di\Injectable;
/**
*
* @package MikoPBX\PBXCoreREST\Lib\System
*/
-class ConvertAudioFileAction extends \Phalcon\Di\Injectable
+class ConvertAudioFileAction extends Injectable
{
/**
* Convert the audio file to various codecs using Asterisk.
@@ -38,18 +39,18 @@ public static function main(string $filename): PBXApiResult
{
$res = new PBXApiResult();
$res->processor = __METHOD__;
- if ( ! file_exists($filename)) {
+ $res->success = true;
+ if (!file_exists($filename)) {
$res->success = false;
- $res->messages[] = "File '{$filename}' not found.";
-
- return $res;
+ $res->messages[] = "File '$filename' not found.";
}
$out = [];
$tmp_filename = '/tmp/' . time() . "_" . basename($filename);
- if (false === copy($filename, $tmp_filename)) {
+ if ($res->success && false === copy($filename, $tmp_filename)) {
$res->success = false;
- $res->messages[] = "Unable to create temporary file '{$tmp_filename}'.";
-
+ $res->messages[] = "Unable to create temporary file '$tmp_filename'.";
+ }
+ if(!$res->success){
return $res;
}
@@ -60,27 +61,25 @@ public static function main(string $filename): PBXApiResult
// Convert file to wav format
$tmp_filename = escapeshellcmd($tmp_filename);
- $n_filename = escapeshellcmd($n_filename);
$soxPath = Util::which('sox');
- Processes::mwExec("{$soxPath} -v 0.99 -G '{$tmp_filename}' -c 1 -r 8000 -b 16 '{$n_filename}'", $out);
+ $soxIPath = Util::which('soxi');
+ $busyBoxPath = Util::which('busybox');
+ // Pre-conversion to wav step 1.
+ if(Processes::mwExec("$soxIPath $tmp_filename | $busyBoxPath grep MPEG") === 0){
+ Processes::mwExec("$soxPath $tmp_filename $tmp_filename.wav", $out);
+ unlink($tmp_filename);
+ $tmp_filename = "$tmp_filename.wav";
+ }
+ $n_filename = escapeshellcmd($n_filename);
+ // Pre-conversion to wav step 2.
+ Processes::mwExec("$soxPath -v 0.99 -G '$tmp_filename' -c 1 -r 8000 -b 16 '$n_filename'", $out);
$result_str = implode('', $out);
// Convert wav file to mp3 format
$lamePath = Util::which('lame');
- Processes::mwExec("{$lamePath} -b 32 --silent '{$n_filename}' '{$n_filename_mp3}'", $out);
+ Processes::mwExec("$lamePath -b 16 --silent '$n_filename' '$n_filename_mp3'", $out);
$result_mp3 = implode('', $out);
- // Convert the file to various codecs using Asterisk
- $codecs = ['alaw', 'ulaw', 'gsm', 'g722', 'wav'];
- $rmPath = Util::which('rm');
- $asteriskPath = Util::which('asterisk');
- foreach ($codecs as $codec){
- $result = shell_exec("$asteriskPath -rx 'file convert $tmp_filename $trimmedFileName.$codec'");
- if(strpos($result, 'Converted') !== 0){
- shell_exec("$rmPath -rf /root/test.{$codec}");
- }
- }
-
// Remove temporary file
unlink($tmp_filename);
if ($result_str !== '' && $result_mp3 !== '') {
@@ -91,9 +90,8 @@ public static function main(string $filename): PBXApiResult
return $res;
}
- if (file_exists($filename)
- && $filename !== $n_filename
- && $filename !== $n_filename_mp3) {
+ if ($filename !== $n_filename
+ && $filename !== $n_filename_mp3 && file_exists($filename)) {
// Remove the original file if it's different from the converted files
unlink($filename);
}