rubyfox-server 2.17.3.1 → 2.19.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubyfox/server/data/config/admin/descriptors/config_room.txt +10 -1
  3. data/lib/rubyfox/server/data/config/admin/descriptors/config_server.txt +90 -20
  4. data/lib/rubyfox/server/data/config/admin/descriptors/config_zone.txt +9 -0
  5. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_room.txt +11 -0
  6. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_user.txt +3 -3
  7. data/lib/rubyfox/server/data/config/core.xml +4 -4
  8. data/lib/rubyfox/server/data/config/default.words.txt +11 -0
  9. data/lib/rubyfox/server/data/config/log4j.properties +1 -2
  10. data/lib/rubyfox/server/data/config/server.xml +1 -1
  11. data/lib/rubyfox/server/data/data/GeoLite2-Country.mmdb +0 -0
  12. data/lib/rubyfox/server/data/data/bannedusers/users.bin +0 -0
  13. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/bootstrap.jar +0 -0
  14. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina-tasks.xml +39 -39
  15. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina.sh +0 -0
  16. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/ciphers.sh +0 -0
  17. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/commons-daemon-native.tar.gz +0 -0
  18. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/commons-daemon.jar +0 -0
  19. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/configtest.sh +0 -0
  20. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/daemon.sh +0 -0
  21. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/digest.sh +0 -0
  22. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/makebase.sh +0 -0
  23. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/setclasspath.sh +0 -0
  24. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/shutdown.sh +0 -0
  25. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/startup.sh +0 -0
  26. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tomcat-juli.jar +0 -0
  27. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tomcat-native.tar.gz +0 -0
  28. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tool-wrapper.sh +0 -0
  29. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/version.sh +0 -0
  30. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/Catalina/localhost/rewrite.config +1 -1
  31. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.policy +263 -264
  32. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.properties +209 -207
  33. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/context.xml +31 -31
  34. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xml +23 -23
  35. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xsd +52 -52
  36. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/keystore.jks +0 -0
  37. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/server.xml +177 -161
  38. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xml +18 -7
  39. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xsd +59 -59
  40. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/web.xml +4740 -4737
  41. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/annotations-api.jar +0 -0
  42. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ant.jar +0 -0
  43. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ha.jar +0 -0
  44. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ssi.jar +0 -0
  45. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-storeconfig.jar +0 -0
  46. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-tribes.jar +0 -0
  47. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina.jar +0 -0
  48. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/el-api.jar +0 -0
  49. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper-el.jar +0 -0
  50. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper.jar +0 -0
  51. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jaspic-api.jar +0 -0
  52. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jsp-api.jar +0 -0
  53. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/servlet-api.jar +0 -0
  54. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/sfs2x-ws-helper.jar +0 -0
  55. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-api.jar +0 -0
  56. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-coyote.jar +0 -0
  57. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-dbcp.jar +0 -0
  58. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-cs.jar +0 -0
  59. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-de.jar +0 -0
  60. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-es.jar +0 -0
  61. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-fr.jar +0 -0
  62. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ja.jar +0 -0
  63. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ko.jar +0 -0
  64. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-pt-BR.jar +0 -0
  65. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ru.jar +0 -0
  66. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-zh-CN.jar +0 -0
  67. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jdbc.jar +0 -0
  68. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jni.jar +0 -0
  69. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util-scan.jar +0 -0
  70. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util.jar +0 -0
  71. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-websocket.jar +0 -0
  72. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/websocket-api.jar +0 -0
  73. data/lib/rubyfox/server/data/lib/javax.activation-1.2.0.jar +0 -0
  74. data/lib/rubyfox/server/data/lib/javax.mail.jar +0 -0
  75. data/lib/rubyfox/server/data/lib/js/JSApi.js +2 -1
  76. data/lib/rubyfox/server/data/lib/js/LibApi.js +181 -48
  77. data/lib/rubyfox/server/data/lib/sfs2x-admin.jar +0 -0
  78. data/lib/rubyfox/server/data/lib/sfs2x-cluster.jar +0 -0
  79. data/lib/rubyfox/server/data/lib/sfs2x-core.jar +0 -0
  80. data/lib/rubyfox/server/data/lib/sfs2x.jar +0 -0
  81. data/lib/rubyfox/server/data/sfs2x-service +26 -30
  82. data/lib/rubyfox/server/data/www/BlueBox.war +0 -0
  83. data/lib/rubyfox/server/data/www/HelloServlet/WEB-INF/web.xml +1 -3
  84. data/lib/rubyfox/server/data/www/ROOT/_css_/default.css +14 -6
  85. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/style.css +44 -2
  86. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/application.bundle.js +98 -61
  87. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/endors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-6~mod-7~mod-8~mod-9.bundle.js +17357 -0
  88. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-0.bundle.js +4 -4
  89. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-1.bundle.js +3 -3
  90. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-10.bundle.js +101 -66
  91. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-11.bundle.js +544 -8
  92. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12.bundle.js +915 -1480
  93. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-15~module-16~module-4.bundle.js +2665 -0
  94. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13.bundle.js +606 -3093
  95. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13~module-16~module-17~module-4.bundle.js +2665 -0
  96. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-14.bundle.js +764 -0
  97. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-15.bundle.js +71 -0
  98. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-16.bundle.js +1787 -0
  99. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-17.bundle.js +3383 -0
  100. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-4.bundle.js +121 -1009
  101. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-5.bundle.js +1214 -1744
  102. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-6.bundle.js +398 -666
  103. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-7.bundle.js +717 -192
  104. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-8.bundle.js +2117 -665
  105. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-9.bundle.js +613 -690
  106. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~mod-0~mod-1~mod-10~mod-11~mod-16~mod-5~mod-6~mod-7~mod-8.bundle.js +17357 -0
  107. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-5~mod-6~mod-7~mod-8~mod-9.bundle.js +17357 -0
  108. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/{vendors~module-0~module-1~module-13~module-4~module-5~module-7~module-8.bundle.js → vendors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-5~mod-7~mod-8~mod-9.bundle.js} +2 -2
  109. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-12.bundle.js +807 -0
  110. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-13.bundle.js +807 -0
  111. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-configurator.html +32 -0
  112. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-monitor.html +185 -0
  113. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-updater.html +47 -0
  114. data/lib/rubyfox/server/data/www/ROOT/admin/modules/extension-deployer.html +84 -0
  115. data/lib/rubyfox/server/data/www/ROOT/admin/modules/zone-monitor.html +15 -8
  116. data/lib/rubyfox/server/data/www/ROOT/index.html +13 -23
  117. data/lib/rubyfox/server/data/www/host-manager/META-INF/context.xml +2 -2
  118. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/jsp/404.jsp +2 -2
  119. data/lib/rubyfox/server/data/www/host-manager/{manager.xml → WEB-INF/manager.xml} +5 -1
  120. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/web.xml +17 -0
  121. data/lib/rubyfox/server/data/www/host-manager/css/manager.css +141 -0
  122. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.svg +967 -0
  123. data/lib/rubyfox/server/data/www/manager/META-INF/context.xml +2 -0
  124. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCerts.jsp +1 -1
  125. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCiphers.jsp +1 -1
  126. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorTrustedCerts.jsp +1 -1
  127. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionDetail.jsp +3 -3
  128. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionsList.jsp +1 -1
  129. data/lib/rubyfox/server/data/www/manager/WEB-INF/web.xml +17 -0
  130. data/lib/rubyfox/server/data/www/manager/css/manager.css +141 -0
  131. data/lib/rubyfox/server/data/www/manager/images/tomcat.svg +967 -0
  132. data/lib/rubyfox/server/data/www/manager/xform.xsl +74 -59
  133. data/lib/rubyfox/server/version.rb +1 -1
  134. metadata +30 -31
  135. data/lib/rubyfox/server/data/config/admin/icons/Analytics.png +0 -0
  136. data/lib/rubyfox/server/data/config/admin/icons/BanManager.png +0 -0
  137. data/lib/rubyfox/server/data/config/admin/icons/BlueBoxMonitor.png +0 -0
  138. data/lib/rubyfox/server/data/config/admin/icons/Console.png +0 -0
  139. data/lib/rubyfox/server/data/config/admin/icons/Dashboard.png +0 -0
  140. data/lib/rubyfox/server/data/config/admin/icons/ExtensionManager.png +0 -0
  141. data/lib/rubyfox/server/data/config/admin/icons/LicenseManager.png +0 -0
  142. data/lib/rubyfox/server/data/config/admin/icons/LogViewer.png +0 -0
  143. data/lib/rubyfox/server/data/config/admin/icons/ServerConfigurator.png +0 -0
  144. data/lib/rubyfox/server/data/config/admin/icons/ServletManager.png +0 -0
  145. data/lib/rubyfox/server/data/config/admin/icons/ZoneConfigurator.png +0 -0
  146. data/lib/rubyfox/server/data/config/admin/icons/ZoneMonitor.png +0 -0
  147. data/lib/rubyfox/server/data/lib/BlueBox.war +0 -0
  148. data/lib/rubyfox/server/data/lib/apache-tomcat/LICENSE +0 -1061
  149. data/lib/rubyfox/server/data/lib/apache-tomcat/NOTICE +0 -68
  150. data/lib/rubyfox/server/data/lib/apache-tomcat/README.md +0 -81
  151. data/lib/rubyfox/server/data/lib/apache-tomcat/RELEASE-NOTES +0 -174
  152. data/lib/rubyfox/server/data/lib/imap.jar +0 -0
  153. data/lib/rubyfox/server/data/lib/mailapi.jar +0 -0
  154. data/lib/rubyfox/server/data/lib/pop3.jar +0 -0
  155. data/lib/rubyfox/server/data/lib/smtp.jar +0 -0
  156. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-13~module-9.bundle.js +0 -2634
  157. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-9.bundle.js +0 -807
  158. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.gif +0 -0
  159. data/lib/rubyfox/server/data/www/manager/images/tomcat.gif +0 -0
  160. /data/lib/rubyfox/server/data/data/buddylists/{BasicExamples/.keep → .keep} +0 -0
@@ -0,0 +1,2665 @@
1
+ /*! (c) gotoAndPlay | All rights reserved */
2
+ (window["webpackJsonpapplication"] = window["webpackJsonpapplication"] || []).push([["module-12~module-15~module-16~module-4"],{
3
+
4
+ /***/ "./src/components/uibuilder/config-check-box.js":
5
+ /*!******************************************************!*\
6
+ !*** ./src/components/uibuilder/config-check-box.js ***!
7
+ \******************************************************/
8
+ /*! exports provided: ConfigCheckBox */
9
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
10
+
11
+ "use strict";
12
+ __webpack_require__.r(__webpack_exports__);
13
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigCheckBox", function() { return ConfigCheckBox; });
14
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
15
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
16
+
17
+
18
+
19
+ class ConfigCheckBox extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
20
+ {
21
+ constructor(configParam, editEnabled, inDialog)
22
+ {
23
+ super(configParam, editEnabled, inDialog);
24
+ }
25
+
26
+ /**
27
+ * Create widget to render the ConfigParameter value.
28
+ * If parameter is not editable, a simple label is used.
29
+ * @override
30
+ */
31
+ _generateInnerWidget()
32
+ {
33
+ if (this._data.editable)
34
+ {
35
+ // Set widget configuration
36
+ let config = {
37
+ type: 'checkbox',
38
+ class: '',
39
+ id: this._data.name,
40
+ name: this._data.name,
41
+ 'data-role': 'switch',
42
+ };
43
+
44
+ // Set widget attributes (see parent class)
45
+ this._setWidgetAttributes(config);
46
+
47
+ // Set additional widget attributes based on validation rules (see parent class)
48
+ this._setWidgetValidationAttributes(config);
49
+
50
+ // Create widget's html
51
+ this._widgetHtml = $('<input>', config);
52
+ }
53
+ else
54
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
55
+
56
+ // Return component
57
+ return this._widgetHtml;
58
+ }
59
+
60
+ /**
61
+ * Initialize widget.
62
+ * @override
63
+ */
64
+ _initialize()
65
+ {
66
+ if (this._data.editable)
67
+ {
68
+ // Initialize kendo widget
69
+ kendo.init(this._widgetHtml);
70
+
71
+ // Save ref. to widget
72
+ this._innerWidget = this._widgetHtml.data('kendoSwitch');
73
+
74
+ // Enable value commit binding
75
+ this._innerWidget.bind('change', $.proxy(this._onValueInput, this));
76
+ }
77
+
78
+ // Proceed with initialization
79
+ super._initialize();
80
+ }
81
+
82
+ /**
83
+ * Set widget's value.
84
+ * If parameter is not editable, the label text is set.
85
+ * @override
86
+ */
87
+ _setWidgetValue()
88
+ {
89
+ if (this._data.editable)
90
+ this._innerWidget.value(this._data.value);
91
+ else
92
+ this._widgetHtml.value = this._data.value;
93
+
94
+ // Trigger event
95
+ this._triggerEvent();
96
+ }
97
+
98
+ /**
99
+ * Set widget's disabled state.
100
+ * @override
101
+ */
102
+ _setWidgetEditEnabled()
103
+ {
104
+ if (this._data.editable)
105
+ this._innerWidget.enable(this._editEnabled);
106
+ }
107
+
108
+ /**
109
+ * Update Configuration Parameter value.
110
+ * @override
111
+ */
112
+ _onValueInput(e)
113
+ {
114
+ // Update Configuration Parameter to new value
115
+ this._data.value = this._innerWidget.value();
116
+
117
+ // Trigger event
118
+ this._triggerEvent();
119
+ }
120
+ }
121
+
122
+ // DEFINE COMPONENT
123
+ if (!window.customElements.get('config-check-box'))
124
+ window.customElements.define('config-check-box', ConfigCheckBox);
125
+
126
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
127
+
128
+ /***/ }),
129
+
130
+ /***/ "./src/components/uibuilder/config-drop-down-list.js":
131
+ /*!***********************************************************!*\
132
+ !*** ./src/components/uibuilder/config-drop-down-list.js ***!
133
+ \***********************************************************/
134
+ /*! exports provided: ConfigDropDownList */
135
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
136
+
137
+ "use strict";
138
+ __webpack_require__.r(__webpack_exports__);
139
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigDropDownList", function() { return ConfigDropDownList; });
140
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
141
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
142
+
143
+
144
+
145
+ class ConfigDropDownList extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
146
+ {
147
+ constructor(configParam, editEnabled, inDialog)
148
+ {
149
+ super(configParam, editEnabled, inDialog);
150
+ }
151
+
152
+ /**
153
+ * Create widget to render the ConfigParameter value.
154
+ * If parameter is not editable, a simple label is used.
155
+ * @override
156
+ */
157
+ _generateInnerWidget()
158
+ {
159
+ if (this._data.editable)
160
+ {
161
+ // Set widget configuration
162
+ let config = {
163
+ class: 'form-control',
164
+ id: this._data.name,
165
+ name: this._data.name,
166
+ 'data-role': 'dropdownlist',
167
+ };
168
+
169
+ // Set widget attributes (see parent class)
170
+ this._setWidgetAttributes(config);
171
+
172
+ // Set additional widget attributes based on validation rules (see parent class)
173
+ this._setWidgetValidationAttributes(config);
174
+
175
+ // Create widget's html
176
+ this._widgetHtml = $('<input>', config);
177
+ }
178
+ else
179
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
180
+
181
+ // Return component
182
+ return this._widgetHtml;
183
+ }
184
+
185
+ /**
186
+ * Initialize widget.
187
+ * @override
188
+ */
189
+ _initialize()
190
+ {
191
+ if (this._data.editable)
192
+ {
193
+ // Initialize kendo widget
194
+ kendo.init(this._widgetHtml);
195
+
196
+ // Save ref. to widget
197
+ this._innerWidget = this._widgetHtml.data('kendoDropDownList');
198
+
199
+ // Set list items
200
+ this._innerWidget.setDataSource(this._getDataSource(this._data.dataProvider))
201
+
202
+ // Enable value commit binding
203
+ this._widgetHtml.bind('change', $.proxy(this._onValueInput, this));
204
+ }
205
+
206
+ // Proceed with initialization
207
+ super._initialize();
208
+ }
209
+
210
+ /**
211
+ * Set widget's value.
212
+ * If parameter is not editable, the label text is set.
213
+ * @override
214
+ */
215
+ _setWidgetValue()
216
+ {
217
+ if (this._data.editable)
218
+ this._innerWidget.value(this._data.value);
219
+ else
220
+ this._widgetHtml.value = this._data.value;
221
+
222
+ // Trigger event
223
+ this._triggerEvent();
224
+ }
225
+
226
+ /**
227
+ * Set widget's disabled state.
228
+ * @override
229
+ */
230
+ _setWidgetEditEnabled()
231
+ {
232
+ if (this._data.editable)
233
+ this._innerWidget.wrapper.attr('disabled', !this._editEnabled);
234
+ }
235
+
236
+ /**
237
+ * Update Configuration Parameter value.
238
+ * @override
239
+ */
240
+ _onValueInput(e)
241
+ {
242
+ // Update Configuration Parameter to new value
243
+ this._data.value = this._innerWidget.value();
244
+
245
+ // Trigger event
246
+ this._triggerEvent();
247
+ }
248
+
249
+ _getDataSource(dpString)
250
+ {
251
+ if (dpString)
252
+ return dpString.split(',');
253
+
254
+ // In case the dataprovider is empty, add at least the current value
255
+ else
256
+ return [this._data.value];
257
+ }
258
+ }
259
+
260
+ // DEFINE COMPONENT
261
+ if (!window.customElements.get('config-drop-down-list'))
262
+ window.customElements.define('config-drop-down-list', ConfigDropDownList);
263
+
264
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
265
+
266
+ /***/ }),
267
+
268
+ /***/ "./src/components/uibuilder/config-dual-list.js":
269
+ /*!******************************************************!*\
270
+ !*** ./src/components/uibuilder/config-dual-list.js ***!
271
+ \******************************************************/
272
+ /*! exports provided: ConfigDualList */
273
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
274
+
275
+ "use strict";
276
+ __webpack_require__.r(__webpack_exports__);
277
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigDualList", function() { return ConfigDualList; });
278
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
279
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
280
+
281
+
282
+
283
+ class ConfigDualList extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
284
+ {
285
+ constructor(configParam, editEnabled, inDialog)
286
+ {
287
+ super(configParam, editEnabled, inDialog);
288
+ }
289
+
290
+ /**
291
+ * Create widget to render the ConfigParameter.
292
+ * @override
293
+ */
294
+ _generateInnerWidget()
295
+ {
296
+ this._widgetHtml = $('<div>');
297
+
298
+ const availableId = this._getId(this._data.name, 'available');
299
+ const selectedId = this._getId(this._data.name, 'selected');
300
+
301
+ // Create header for labels
302
+ let header = $('<div>', {class: 'form-label-container dual-list-labels'});
303
+
304
+ header.append($('<label>', {
305
+ class: 'font-italic form-label dual-list-left-col' + (!this._data.editable ? ' no-interact' : ''),
306
+ for: availableId,
307
+ }).text('Available'));
308
+
309
+ header.append($('<label>', {
310
+ class: 'font-italic font-weight-bold form-label dual-list-right-col' + (!this._data.editable ? ' no-interact' : ''),
311
+ for: selectedId,
312
+ }).text('Selected'));
313
+
314
+ this._widgetHtml.append(header);
315
+
316
+ // Add available items list
317
+ this._availableListHtml = $('<select>', {
318
+ id: availableId,
319
+ class: 'dual-list-left-col' + (!this._data.editable ? ' no-interact' : ''),
320
+ });
321
+ this._widgetHtml.append(this._availableListHtml);
322
+
323
+ // Add selected items list
324
+ this._selectedListHtml = $('<select>', {
325
+ id: selectedId,
326
+ class: 'dual-list-right-col' + (!this._data.editable ? ' no-interact' : ''),
327
+ });
328
+ this._widgetHtml.append(this._selectedListHtml);
329
+
330
+ // Return component
331
+ return this._widgetHtml;
332
+ }
333
+
334
+ // IDs containing a "." cause issues to connected lists
335
+ _getId(name, suffix)
336
+ {
337
+ return name.replace('.', '_') + '-' + suffix;
338
+ }
339
+
340
+ /**
341
+ * Initialize widget.
342
+ * @override
343
+ */
344
+ _initialize()
345
+ {
346
+ // Initialize "avalable" listbox
347
+ this._availableList = this._availableListHtml.kendoListBox({
348
+ connectWith: this._getId(this._data.name, 'selected'),
349
+ toolbar: {
350
+ tools: this._data.editable ? ['transferTo', 'transferFrom', 'transferAllTo', 'transferAllFrom'] : []
351
+ },
352
+ template: "<div>#:value#</div>",
353
+ selectable: 'multiple',
354
+ }).data('kendoListBox');
355
+
356
+ // Initialize "selected" listbox
357
+ this._selectedList = this._selectedListHtml.kendoListBox({
358
+ template: "<div>#:value#</div>",
359
+ selectable: 'multiple',
360
+ // The following listeners can't be used because events are fired before the datasource is actually updated
361
+ // We have to use a change event listener on the datasource (see below), even if not optimal
362
+ //add: $.proxy(this._onValueInput, this),
363
+ //remove: $.proxy(this._onValueInput, this),
364
+ }).data('kendoListBox');
365
+
366
+ // Proceed with initialization
367
+ super._initialize();
368
+ }
369
+
370
+ /**
371
+ * Set widget's datasource.
372
+ * @override
373
+ */
374
+ _setWidgetValue()
375
+ {
376
+ let availableArr = this._data.dataProvider != '' ? this._data.dataProvider.split(',') : [];
377
+ let selectedArr = this._data.value != '' ? this._data.value.split(',') : [];
378
+
379
+ // Remove selected values from available values
380
+ if (selectedArr.length > 0)
381
+ {
382
+ let temp = [];
383
+
384
+ for (let val of availableArr)
385
+ {
386
+ if (selectedArr.indexOf(val) == -1)
387
+ temp.push(val);
388
+ }
389
+
390
+ availableArr = temp;
391
+ }
392
+
393
+ // Convert lists of strings to lists of objects
394
+ let availableValues = [];
395
+ for (let val of availableArr)
396
+ availableValues.push({value: val});
397
+
398
+ let selectedValues = [];
399
+ for (let val of selectedArr)
400
+ selectedValues.push({value: val});
401
+
402
+ // Clear selection
403
+ this._availableList.clearSelection();
404
+ this._selectedList.clearSelection();
405
+
406
+ // Set datasources
407
+ this._availableList.setDataSource(new kendo.data.DataSource({
408
+ data: availableValues
409
+ }));
410
+
411
+ this._selectedList.setDataSource(new kendo.data.DataSource({
412
+ data: selectedValues,
413
+ // We listen to the change event instead of the add/remove events on the listbox, because those are fired before the datasource is updated
414
+ // This is not optimal because the event is fired for each item added to or removed from the datasource
415
+ change: $.proxy(this._onValueInput, this)
416
+ }));
417
+
418
+ // Disable editing
419
+ if (!this._data.editable)
420
+ {
421
+ this._availableList.enable('.k-item', false);
422
+ this._selectedList.enable('.k-item', false);
423
+ }
424
+
425
+ // Trigger event
426
+ this._triggerEvent();
427
+ }
428
+
429
+ /**
430
+ * Set widget's disabled state.
431
+ * @override
432
+ */
433
+ _setWidgetEditEnabled()
434
+ {
435
+ if (this._data.editable)
436
+ {
437
+ // Clear selection
438
+ this._availableList.clearSelection();
439
+ this._selectedList.clearSelection();
440
+
441
+ // Enable/disable lists
442
+ this._availableList.wrapper.attr('disabled', !this._editEnabled);
443
+ this._selectedList.wrapper.attr('disabled', !this._editEnabled);
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Update Configuration Parameter value.
449
+ * @override
450
+ */
451
+ _onValueInput(e)
452
+ {
453
+ let listData = this._selectedList.dataSource.data();
454
+
455
+ // Update Configuration Parameter to new value
456
+ this._data.value = listData.map(e => e.value).join(',');
457
+
458
+ // Trigger event
459
+ this._triggerEvent();
460
+ }
461
+ }
462
+
463
+ // DEFINE COMPONENT
464
+ if (!window.customElements.get('config-dual-list'))
465
+ window.customElements.define('config-dual-list', ConfigDualList);
466
+
467
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
468
+
469
+ /***/ }),
470
+
471
+ /***/ "./src/components/uibuilder/config-form-item.js":
472
+ /*!******************************************************!*\
473
+ !*** ./src/components/uibuilder/config-form-item.js ***!
474
+ \******************************************************/
475
+ /*! exports provided: ConfigFormItem */
476
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
477
+
478
+ "use strict";
479
+ __webpack_require__.r(__webpack_exports__);
480
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigFormItem", function() { return ConfigFormItem; });
481
+ class ConfigFormItem extends HTMLElement
482
+ {
483
+ constructor(configParam, editEnabled, inDialog)
484
+ {
485
+ super();
486
+
487
+ this.id = 'form-item-' + configParam.name;
488
+ this._editEnabled = editEnabled;
489
+ this._data = configParam;
490
+
491
+ // Create form item view
492
+ this._buildView(inDialog);
493
+
494
+ // Initialize form item
495
+ this._initialize();
496
+ }
497
+
498
+ connectedCallback()
499
+ {
500
+ // Trigger event
501
+ // NOTE: when a ConfigFormItem is instantiated, the _triggerEvent method is called as soon as its value is set.
502
+ // When this happens, due to the fact that the object is not yet in the DOM, the event is not catched by the listener
503
+ // (which is attached to the outer container). So forcing the event to trigger again as soon as the ConfigFormItem
504
+ // is appended to the DOM is needed.
505
+ this._triggerEvent();
506
+ }
507
+
508
+ set data(configParam)
509
+ {
510
+ this._data = configParam;
511
+ this._setWidgetValue();
512
+ }
513
+
514
+ get data()
515
+ {
516
+ return this._data;
517
+ }
518
+
519
+ set editEnabled(enable)
520
+ {
521
+ if (enable != this._editEnabled)
522
+ {
523
+ this._editEnabled = enable;
524
+ this._setWidgetEditEnabled();
525
+ }
526
+ }
527
+
528
+ get editEnabled()
529
+ {
530
+ return this._editEnabled;
531
+ }
532
+
533
+ _buildView(isInsideDialog)
534
+ {
535
+ if (!isInsideDialog)
536
+ {
537
+ // Set additional classes for inner widget
538
+ let classNames = '';
539
+
540
+ switch (this._data.type)
541
+ {
542
+ case 'DualList':
543
+ classNames = 'col-sm-7 col-lg-8';
544
+ break;
545
+ case 'DataGrid':
546
+ classNames = 'col-sm'; // Use 'col-sm-7 col-lg-8' for DataGrid too?
547
+ break;
548
+ case 'TextInput':
549
+ classNames = 'col-sm col-lg-5 col-xl-4';
550
+ break;
551
+ default:
552
+ classNames = 'col-sm-auto';
553
+
554
+ }
555
+
556
+ // Generate boilerplate html, surrounding the actual widget (label, numeric stepper, etc)
557
+ this.innerHTML = `
558
+ <div class="form-group position-relative row">
559
+ <div class="col-sm-5 col-lg-4 col-form-label form-label-container">
560
+ <label for="${this._data.name}" class="form-label ${(this._data.clientOnly ? 'client-only' : '')}">${this._data.label} <i class="fas fa-question-circle text-muted help" title="${this._data.tooltip}"></i>${(this._data.immediate ? '<i class="fas fa-bolt text-muted ml-1 help" title="This setting is applied <b>immediately</b> on submit, without requiring a server restart"></i>' : '')}</label>
561
+ </div>
562
+ <div class="inner-widget align-self-center ${classNames}">
563
+ <span class="k-invalid-msg" data-for="${this._data.name}"></span>
564
+ </div>
565
+ </div>
566
+ `;
567
+ }
568
+ else
569
+ {
570
+ this.innerHTML = `
571
+ <div class="form-group position-relative">
572
+ <div class="col-form-label form-label-container">
573
+ <label for="${this._data.name}" class="form-label ${(this._data.clientOnly ? 'client-only' : '')}">${this._data.label} <i class="fas fa-question-circle text-muted help" title="${this._data.tooltip}"></i></label>
574
+ </div>
575
+ <div class="inner-widget">
576
+ <span class="k-invalid-msg" data-for="${this._data.name}"></span>
577
+ </div>
578
+ </div>
579
+ `;
580
+ }
581
+
582
+ // Create inner widget (must be overridden)
583
+ let widget = this._generateInnerWidget();
584
+
585
+ // Append inner widget
586
+ $(this).find('.inner-widget').prepend(widget);
587
+ }
588
+
589
+ /**
590
+ * TO BE OVERRIDDEN
591
+ */
592
+ _generateInnerWidget()
593
+ {
594
+ // Show an error, should be overridden
595
+ console.error(`Unable to create ${this._data.type} form item for configuration parameter ${this.id}`);
596
+ }
597
+
598
+ /**
599
+ * Set attributes on the widget configuration object.
600
+ */
601
+ _setWidgetAttributes(config)
602
+ {
603
+ const attribs = this._data.attributes;
604
+
605
+ if (attribs)
606
+ {
607
+ for (let attr in attribs)
608
+ {
609
+ config[attr] = attribs[attr];
610
+
611
+ if (attr == 'pattern')
612
+ config['data-pattern-msg'] = 'Contains invalid characters';
613
+ }
614
+ }
615
+ }
616
+
617
+ /**
618
+ * Set additional attributes on the widget configuration object to properly validate input.
619
+ */
620
+ _setWidgetValidationAttributes(config)
621
+ {
622
+ const val = this._data.validator;
623
+
624
+ if (val != null && val != '')
625
+ {
626
+ if (val == 'ip')
627
+ {
628
+ config['pattern'] = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
629
+ config['data-pattern-msg'] = 'Invalid IP address';
630
+ config['required'] = true;
631
+ config['data-required-msg'] = 'Required';
632
+ }
633
+
634
+ else if (val == 'ipRange')
635
+ {
636
+ config['pattern'] = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/[3][0-2]|\/[1-2]?[0-9])?$';
637
+ config['data-pattern-msg'] = 'Invalid IP address or range';
638
+ config['required'] = true;
639
+ config['data-required-msg'] = 'Required';
640
+ }
641
+
642
+ else if (val == 'notNull')
643
+ {
644
+ config['required'] = true;
645
+ config['data-required-msg'] = 'Required';
646
+ }
647
+
648
+ else if (val == 'pwd')
649
+ {
650
+ config['pattern'] = '^.{6,}$';
651
+ config['data-pattern-msg'] = 'Minimum length: 6 characters';
652
+ }
653
+
654
+ else if (val == 'posNum')
655
+ {
656
+ config['pattern'] = '^[0-9]\d*$';
657
+ config['data-pattern-msg'] = 'Non-negative number required';
658
+ }
659
+
660
+ else if (val == 'aoi')
661
+ {
662
+ // Nothing to do
663
+ // See Kendo validation initialization in config-interface-builder.js
664
+ }
665
+
666
+ else if (val == 'url')
667
+ {
668
+ config['type'] = 'url';
669
+ config['data-url-msg'] = 'Invalid URL';
670
+ }
671
+ }
672
+ }
673
+
674
+ /**
675
+ * Initialize form item.
676
+ *
677
+ * NOTE: must be overridden if inner widget requires special initialization (for example Kendo widgets)
678
+ */
679
+ _initialize()
680
+ {
681
+ // Set value
682
+ this._setWidgetValue();
683
+
684
+ // Set edit enabled
685
+ this._setWidgetEditEnabled();
686
+ }
687
+
688
+ /**
689
+ * TO BE OVERRIDDEN
690
+ */
691
+ _setWidgetValue()
692
+ {
693
+ // Nothing to do, must be overridden
694
+ }
695
+
696
+ /**
697
+ * TO BE OVERRIDDEN
698
+ */
699
+ _setWidgetEditEnabled()
700
+ {
701
+ // Nothing to do, must be overridden
702
+ }
703
+
704
+ /**
705
+ * TO BE OVERRIDDEN
706
+ */
707
+ _onValueInput(e)
708
+ {
709
+ // Nothing to do, must be overridden
710
+ }
711
+
712
+ _triggerEvent()
713
+ {
714
+ if (this._data.trigger)
715
+ {
716
+ let event = new CustomEvent('value-set', {detail: null, bubbles: true, cancelable: true});
717
+ this.dispatchEvent(event);
718
+ }
719
+ }
720
+ }
721
+
722
+ // DEFINE COMPONENT
723
+ if (!window.customElements.get('config-form-item'))
724
+ window.customElements.define('config-form-item', ConfigFormItem);
725
+
726
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
727
+
728
+ /***/ }),
729
+
730
+ /***/ "./src/components/uibuilder/config-grid.js":
731
+ /*!*************************************************!*\
732
+ !*** ./src/components/uibuilder/config-grid.js ***!
733
+ \*************************************************/
734
+ /*! exports provided: ConfigGrid */
735
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
736
+
737
+ "use strict";
738
+ __webpack_require__.r(__webpack_exports__);
739
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigGrid", function() { return ConfigGrid; });
740
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
741
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
742
+ /* harmony import */ var _widgets_list_item_editor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./widgets/list-item-editor */ "./src/components/uibuilder/widgets/list-item-editor.js");
743
+
744
+
745
+
746
+
747
+ class ConfigGrid extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
748
+ {
749
+ constructor(configParam, editEnabled, inDialog)
750
+ {
751
+ super(configParam, editEnabled, inDialog);
752
+ }
753
+
754
+ /**
755
+ * Create widget to render the ConfigParameter.
756
+ * @override
757
+ */
758
+ _generateInnerWidget()
759
+ {
760
+ // Create main widget's html
761
+ this._widgetHtml = $('<div>', {class: ''});
762
+
763
+ // Set grid widget configuration
764
+ let gridConfig = {
765
+ id: this._data.name,
766
+ name: this._data.name,
767
+ class: 'limited-height' + (!this._data.editable ? ' no-interact' : '')
768
+ };
769
+
770
+ // Append grid to main html; grid will be converted to Kendo widget during initialization
771
+ this._widgetHtml.append($('<div>', gridConfig));
772
+
773
+ if (this._data.editable)
774
+ {
775
+ // BUTTONS
776
+
777
+ // Create buttons container
778
+ let buttons = $('<div>', {class: 'mt-2 text-right'});
779
+
780
+ // Append buttons to container
781
+ this._addButton = $('<button>', {type: 'button', class: 'k-button k-secondary', title: 'Add'}).append($('<i class="fas fa-plus"></i>'));
782
+ this._editButton = $('<button>', {type: 'button', class: 'k-button k-secondary ml-2', title: 'Edit', disabled: true}).append($('<i class="fas fa-pen"></i>'));
783
+ this._removeButton = $('<button>', {type: 'button', class: 'k-button k-secondary ml-2', title: 'Remove', disabled: true}).append($('<i class="fas fa-times"></i>'));
784
+
785
+ buttons.append(this._addButton);
786
+ buttons.append(this._editButton);
787
+ buttons.append(this._removeButton);
788
+
789
+ // Append buttons container to main html
790
+ this._widgetHtml.append(buttons);
791
+
792
+ // Create edit dialog
793
+ // NOTE: data-dismiss="modal" on the close/cancel buttons was removed to work around an issue with nested modals;
794
+ // the custom "data-cancel" attribute is used to add a custom listener to the buttons
795
+ this._editDialog = $(`
796
+ <div class="modal" tabindex="-1" role="dialog" aria-labelledby="modalTitle" aria-hidden="true" data-keyboard="false" data-backdrop="static">
797
+ <div class="modal-dialog modal-dialog-centered" role="document">
798
+ <div class="modal-content">
799
+ <div class="modal-header">
800
+ <h5 class="modal-title text-primary" id="modalTitle">${this._data.label}</h5>
801
+ <button type="button" class="close" aria-label="Close" data-cancel="modal">
802
+ <span aria-hidden="true">&times;</span>
803
+ </button>
804
+ </div>
805
+ <div class="modal-body in-flow-invalid-msg">
806
+
807
+ </div>
808
+ <div class="modal-footer flex-column">
809
+ <div class="d-flex w-100">
810
+ <div class="flex-grow-1 text-left">
811
+ <button type="button" class="k-button k-primary">...</button>
812
+ </div>
813
+ <div class="flex-grow-1 text-right">
814
+ <button type="button" class="k-button k-secondary" data-cancel="modal">Cancel</button>
815
+ </div>
816
+ </div>
817
+ </div>
818
+ </div>
819
+ </div>
820
+ </div>
821
+ `);
822
+
823
+ // Add listener to dialog hide event
824
+ this._editDialog.on('hidden.bs.modal', $.proxy(this._onEditPanelHidden, this));
825
+
826
+ // Add listener to main button click event
827
+ $('button.k-primary', this._editDialog).on('click', $.proxy(this._onSubmitBtClick, this));
828
+
829
+ // Add listener to close/cancel buttons click event
830
+ $('button[data-cancel="modal"]', this._editDialog).on('click', $.proxy(this._onCancelBtClick, this));
831
+
832
+ // Append edit dialog to main html
833
+ this._widgetHtml.append(this._editDialog);
834
+ }
835
+
836
+ // Return component
837
+ return this._widgetHtml;
838
+ }
839
+
840
+ /**
841
+ * Initialize widget.
842
+ * @override
843
+ */
844
+ _initialize()
845
+ {
846
+ let columns = [];
847
+ for (let subConfigParam of this._data.defaultListItem)
848
+ {
849
+ let col = {
850
+ field: subConfigParam.name,
851
+ title: subConfigParam.label,
852
+ width: 120
853
+ }
854
+
855
+ // Display V or X for booleans
856
+ if (typeof subConfigParam.value === 'boolean')
857
+ col.template = `#= ${subConfigParam.name} ? '<i class="fas fa-check"></i>' : '<i class="fas fa-times"></i>' #`;
858
+
859
+ // Hide passwords
860
+ if (subConfigParam.type == 'TextInput' && subConfigParam.attributes != null && subConfigParam.attributes.type == 'password')
861
+ col.template = `#= '•'.repeat(data.${subConfigParam.name}.length) #`;
862
+
863
+ columns.push(col);
864
+ }
865
+
866
+ // Initialize grid
867
+ let gridHtml = this._widgetHtml.find(`#${$.escapeSelector(this._data.name)}`);
868
+
869
+ gridHtml.kendoGrid({
870
+ resizable: true,
871
+ selectable: this._data.editable ? 'row' : false,
872
+ change: $.proxy(this._onGridSelectionChange, this),
873
+ columns: columns,
874
+ noRecords: {
875
+ template: 'No items.'
876
+ }
877
+ });
878
+
879
+ // Save ref. to widget
880
+ this._gridWidget = gridHtml.data('kendoGrid');
881
+
882
+ // Show tootip if grid's cell content exceeds cell width (ellipsis is displayed by Kendo Grid)
883
+ gridHtml.kendoTooltip({
884
+ filter: 'td',
885
+ show: function(e) {
886
+ // Never show tooltip...
887
+ this.content.parent().css('visibility', 'hidden');
888
+
889
+ // ...unless content is returned (see below) due to cell width being exceeded
890
+ if (this.content.text() != '')
891
+ this.content.parent().css('visibility', 'visible');
892
+ },
893
+ hide: function() {
894
+ this.content.parent().css('visibility', 'hidden');
895
+ },
896
+ content: function(e) {
897
+ let element = e.target[0];
898
+ if (element.offsetWidth < element.scrollWidth)
899
+ return e.target.text();
900
+ else
901
+ return '';
902
+ }
903
+ });
904
+
905
+ /*
906
+ // Initialize button tooltips
907
+ this._widgetHtml.kendoTooltip({
908
+ filter: 'button',
909
+ content: function(e) {
910
+ return `<div class="help-tooltip">${e.target.data('title')}</div>`;
911
+ }
912
+ });
913
+ */
914
+
915
+ // Add button listeners
916
+ if (this._data.editable)
917
+ {
918
+ this._addButton.click($.proxy(this._onAddClick, this));
919
+ this._editButton.click($.proxy(this._onEditClick, this));
920
+ this._removeButton.click($.proxy(this._onRemoveClick, this));
921
+ }
922
+
923
+ // Proceed with initialization
924
+ super._initialize();
925
+ }
926
+
927
+ /**
928
+ * Set widget's datasource.
929
+ * @override
930
+ */
931
+ _setWidgetValue()
932
+ {
933
+ let dataSource = new kendo.data.DataSource({
934
+ data: this._data.listValues
935
+ });
936
+
937
+ // Read current horizontal scroll value
938
+ const scrollLeft = $('.k-grid-content', this._gridWidget.wrapper).scrollLeft();
939
+
940
+ // Clear grid selection if any
941
+ this._gridWidget.clearSelection();
942
+
943
+ // Set updated grid's datasource
944
+ this._gridWidget.setDataSource(dataSource);
945
+
946
+ // Set horizontal scroll
947
+ $('.k-grid-content', this._gridWidget.wrapper).scrollLeft(scrollLeft);
948
+ }
949
+
950
+ /**
951
+ * Set widget's disabled state.
952
+ * @override
953
+ */
954
+ _setWidgetEditEnabled()
955
+ {
956
+ if (this._data.editable)
957
+ {
958
+ // Deselect item
959
+ this._gridWidget.clearSelection();
960
+
961
+ // Enable/disable grid
962
+ this._gridWidget.wrapper.attr('disabled', !this._editEnabled);
963
+
964
+ // Enable "Add" button
965
+ if (this._editEnabled)
966
+ this._addButton.attr('disabled', false);
967
+
968
+ // Disable all buttons
969
+ else
970
+ {
971
+ this._addButton.attr('disabled', true);
972
+ this._editButton.attr('disabled', true);
973
+ this._removeButton.attr('disabled', true);
974
+ }
975
+ }
976
+ }
977
+
978
+ _onGridSelectionChange(e)
979
+ {
980
+ let selectedRows = this._gridWidget.select();
981
+ let selectedDataItems = [];
982
+
983
+ for (let i = 0; i < selectedRows.length; i++)
984
+ {
985
+ let dataItem = this._gridWidget.dataItem(selectedRows[i]);
986
+ selectedDataItems.push(dataItem);
987
+ }
988
+
989
+ // Enable/disable edit button
990
+ if (this._editButton)
991
+ this._editButton.prop('disabled', selectedDataItems.length == 0);
992
+
993
+ // Enable/disable remove button
994
+ if (this._removeButton)
995
+ {
996
+ // Always disable button if no list item is selected
997
+ this._removeButton.prop('disabled', selectedDataItems.length == 0);
998
+
999
+ // Also disable button if denyEmpty == true and just one item remains in the list
1000
+ if (this._data.denyEmpty)
1001
+ this._removeButton.prop('disabled', this._data.listItems.length <= 1);
1002
+ }
1003
+ }
1004
+
1005
+ _onRemoveClick()
1006
+ {
1007
+ let selectedIndex = this._gridWidget.select().index();
1008
+
1009
+ // Remove item from list
1010
+ this._data.removeListItem(selectedIndex);
1011
+
1012
+ // Regenerate datagrid's datasource
1013
+ this._setWidgetValue();
1014
+ }
1015
+
1016
+ _onAddClick()
1017
+ {
1018
+ // Clone default item and add to list
1019
+ let newListItem = [];
1020
+ for (let subCP of this._data.defaultListItem)
1021
+ newListItem.push(subCP.clone(true));
1022
+
1023
+ // Create edit popup
1024
+ this._openEditPanel(newListItem);
1025
+ }
1026
+
1027
+ _onEditClick()
1028
+ {
1029
+ let selectedIndex = this._gridWidget.select().index();
1030
+
1031
+ // Clone selected item and add to list
1032
+ let clonedListItem = [];
1033
+ for (let subCP of this._data.listItems[selectedIndex])
1034
+ clonedListItem.push(subCP.clone(true));
1035
+
1036
+ // Create edit popup
1037
+ this._openEditPanel(clonedListItem, selectedIndex);
1038
+ }
1039
+
1040
+ _openEditPanel(subConfigParamsArray, editIndex = -1)
1041
+ {
1042
+ // Check if this configuration item is inside a modal window;
1043
+ // if yes, the edit panel (which is a modal as well) must be configured to remove the dark background
1044
+ if ($(this).parents('.modal').length > 0)
1045
+ $('.modal', $(this)).attr('data-backdrop', false);
1046
+
1047
+ // Create dialog content
1048
+ this._itemEditor = new _widgets_list_item_editor__WEBPACK_IMPORTED_MODULE_2__["ListItemEditor"]();
1049
+ this._itemEditor.data = subConfigParamsArray;
1050
+ this._itemEditor.index = editIndex;
1051
+
1052
+ let itemEditor = $(this._itemEditor);
1053
+
1054
+ // Append content to dialog
1055
+ $('.modal-body', this._editDialog).append(itemEditor);
1056
+
1057
+ // Set dialog main button text
1058
+ $('button.k-primary', this._editDialog).html(editIndex > -1 ? '<i class="fas fa-pen mr-1"></i>Update' : '<i class="fas fa-plus mr-1"></i>Add');
1059
+
1060
+ // Display dialog
1061
+ this._editDialog.modal('show');
1062
+ }
1063
+
1064
+ _onSubmitBtClick()
1065
+ {
1066
+ if (this._itemEditor.validate())
1067
+ {
1068
+ let data = this._itemEditor.data;
1069
+ let index = this._itemEditor.index;
1070
+
1071
+ // Hide modal
1072
+ this._editDialog.modal('hide');
1073
+
1074
+ // Complete editing
1075
+ this._onEditComplete(data, index);
1076
+ }
1077
+ }
1078
+
1079
+ _onCancelBtClick()
1080
+ {
1081
+ // Hide modal
1082
+ this._editDialog.modal('hide');
1083
+ }
1084
+
1085
+ _onEditPanelHidden(e)
1086
+ {
1087
+ // Remove content from dialog
1088
+ this._itemEditor.remove();
1089
+
1090
+ // Set dialog main button text
1091
+ $('button.k-primary', this._editDialog).html('...');
1092
+
1093
+ this._itemEditor = null;
1094
+ }
1095
+
1096
+ _onEditComplete(listItem, editIndex)
1097
+ {
1098
+ // An existing list item was updated
1099
+ if (editIndex > -1)
1100
+ this._data.updateListItem(listItem, editIndex);
1101
+
1102
+ // A new list item was added; add it to the configuration parameter
1103
+ else
1104
+ this._data.addListItem(listItem);
1105
+
1106
+ // Regenerate datagrid's datasource
1107
+ this._setWidgetValue();
1108
+ }
1109
+ }
1110
+
1111
+ // DEFINE COMPONENT
1112
+ if (!window.customElements.get('config-grid'))
1113
+ window.customElements.define('config-grid', ConfigGrid);
1114
+
1115
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1116
+
1117
+ /***/ }),
1118
+
1119
+ /***/ "./src/components/uibuilder/config-label.js":
1120
+ /*!**************************************************!*\
1121
+ !*** ./src/components/uibuilder/config-label.js ***!
1122
+ \**************************************************/
1123
+ /*! exports provided: ConfigLabel */
1124
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1125
+
1126
+ "use strict";
1127
+ __webpack_require__.r(__webpack_exports__);
1128
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigLabel", function() { return ConfigLabel; });
1129
+ class ConfigLabel extends HTMLElement
1130
+ {
1131
+ constructor()
1132
+ {
1133
+ super();
1134
+
1135
+ this.setAttribute('class','config-label');
1136
+ }
1137
+
1138
+ set value(val)
1139
+ {
1140
+ if (typeof val === 'boolean')
1141
+ this.innerHTML = (val ? 'true' : 'false');
1142
+ else if (typeof val === 'number')
1143
+ this.innerHTML = (val ? val : 0);
1144
+ else
1145
+ this.innerHTML = (val != '' ? val : '&mdash;');
1146
+ }
1147
+
1148
+ get value()
1149
+ {
1150
+ return this.textContent;
1151
+ }
1152
+ }
1153
+
1154
+ // DEFINE COMPONENT
1155
+ if (!window.customElements.get('config-label'))
1156
+ window.customElements.define('config-label', ConfigLabel);
1157
+
1158
+
1159
+ /***/ }),
1160
+
1161
+ /***/ "./src/components/uibuilder/config-numeric-stepper.js":
1162
+ /*!************************************************************!*\
1163
+ !*** ./src/components/uibuilder/config-numeric-stepper.js ***!
1164
+ \************************************************************/
1165
+ /*! exports provided: ConfigNumericStepper */
1166
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1167
+
1168
+ "use strict";
1169
+ __webpack_require__.r(__webpack_exports__);
1170
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigNumericStepper", function() { return ConfigNumericStepper; });
1171
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1172
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1173
+
1174
+
1175
+
1176
+ class ConfigNumericStepper extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1177
+ {
1178
+ constructor(configParam, editEnabled, inDialog)
1179
+ {
1180
+ super(configParam, editEnabled, inDialog);
1181
+ }
1182
+
1183
+ /**
1184
+ * Create widget to render the ConfigParameter value.
1185
+ * If parameter is not editable, a simple label is used.
1186
+ * @override
1187
+ */
1188
+ _generateInnerWidget()
1189
+ {
1190
+ if (this._data.editable)
1191
+ {
1192
+ // Set widget configuration
1193
+ let config = {
1194
+ type: 'number',
1195
+ class: 'form-control',
1196
+ id: this._data.name,
1197
+ name: this._data.name,
1198
+ 'data-role': 'numerictextbox',
1199
+ 'data-required-msg': 'Required',
1200
+ 'data-format': '#',
1201
+ required: 'required',
1202
+ };
1203
+
1204
+ // Set widget attributes (see parent class)
1205
+ this._setWidgetAttributes(config);
1206
+
1207
+ // Set additional widget attributes based on validation rules (see parent class)
1208
+ this._setWidgetValidationAttributes(config);
1209
+
1210
+ // Create widget's html
1211
+ this._widgetHtml = $('<input>', config);
1212
+ }
1213
+ else
1214
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1215
+
1216
+ // Return component
1217
+ return this._widgetHtml;
1218
+ }
1219
+
1220
+ /**
1221
+ * Initialize widget.
1222
+ * @override
1223
+ */
1224
+ _initialize()
1225
+ {
1226
+ if (this._data.editable)
1227
+ {
1228
+ // Initialize kendo widget
1229
+ kendo.init(this._widgetHtml);
1230
+
1231
+ // Save ref. to widget
1232
+ this._innerWidget = this._widgetHtml.data('kendoNumericTextBox');
1233
+
1234
+ // Enable value commit binding
1235
+ this._innerWidget.bind('change', $.proxy(this._onValueInput, this));
1236
+ }
1237
+
1238
+ // Proceed with initialization
1239
+ super._initialize();
1240
+ }
1241
+
1242
+ /**
1243
+ * Set widget's value.
1244
+ * If parameter is not editable, the label text is set.
1245
+ * @override
1246
+ */
1247
+ _setWidgetValue()
1248
+ {
1249
+ if (this._data.editable)
1250
+ this._innerWidget.value(this._data.value);
1251
+ else
1252
+ this._widgetHtml.value = this._data.value;
1253
+
1254
+ // Trigger event
1255
+ this._triggerEvent();
1256
+ }
1257
+
1258
+ /**
1259
+ * Set widget's disabled state.
1260
+ * @override
1261
+ */
1262
+ _setWidgetEditEnabled()
1263
+ {
1264
+ if (this._data.editable)
1265
+ this._innerWidget.enable(this._editEnabled);
1266
+ }
1267
+
1268
+ /**
1269
+ * Update Configuration Parameter value.
1270
+ * @override
1271
+ */
1272
+ _onValueInput(e)
1273
+ {
1274
+ // Update Configuration Parameter to new value
1275
+ this._data.value = Number(this._innerWidget.value());
1276
+
1277
+ // Trigger event
1278
+ this._triggerEvent();
1279
+ }
1280
+ }
1281
+
1282
+ // DEFINE COMPONENT
1283
+ if (!window.customElements.get('config-numeric-stepper'))
1284
+ window.customElements.define('config-numeric-stepper', ConfigNumericStepper);
1285
+
1286
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1287
+
1288
+ /***/ }),
1289
+
1290
+ /***/ "./src/components/uibuilder/config-text-input.js":
1291
+ /*!*******************************************************!*\
1292
+ !*** ./src/components/uibuilder/config-text-input.js ***!
1293
+ \*******************************************************/
1294
+ /*! exports provided: ConfigTextInput */
1295
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1296
+
1297
+ "use strict";
1298
+ __webpack_require__.r(__webpack_exports__);
1299
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigTextInput", function() { return ConfigTextInput; });
1300
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1301
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1302
+
1303
+
1304
+
1305
+ class ConfigTextInput extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1306
+ {
1307
+ constructor(configParam, editEnabled, inDialog)
1308
+ {
1309
+ super(configParam, editEnabled, inDialog);
1310
+ }
1311
+
1312
+ /**
1313
+ * Create widget to render the ConfigParameter value.
1314
+ * If parameter is not editable, a simple label is used.
1315
+ * @override
1316
+ */
1317
+ _generateInnerWidget()
1318
+ {
1319
+ if (this._data.editable)
1320
+ {
1321
+ // Set widget configuration
1322
+ let config = {
1323
+ type: 'text',
1324
+ class: 'form-control k-textbox',
1325
+ id: this._data.name,
1326
+ name: this._data.name,
1327
+ autocomplete: 'off',
1328
+ };
1329
+
1330
+ // Set widget attributes
1331
+ this._setWidgetAttributes(config);
1332
+
1333
+ // Set additional widget attributes based on validation rules
1334
+ this._setWidgetValidationAttributes(config);
1335
+
1336
+ // Create widget's html
1337
+ this._widgetHtml = $('<input>', config);
1338
+
1339
+ // Enable value commit binding
1340
+ this._widgetHtml.on('change', $.proxy(this._onValueInput, this));
1341
+ }
1342
+ else
1343
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1344
+
1345
+ // Return component
1346
+ return this._widgetHtml;
1347
+ }
1348
+
1349
+ /**
1350
+ * Set widget's value.
1351
+ * If parameter is not editable, the label text is set.
1352
+ * @override
1353
+ */
1354
+ _setWidgetValue()
1355
+ {
1356
+ if (this._data.editable)
1357
+ this._widgetHtml.val(this._data.value);
1358
+ else
1359
+ this._widgetHtml.value = this._data.value;
1360
+
1361
+ // Trigger event
1362
+ this._triggerEvent();
1363
+ }
1364
+
1365
+ /**
1366
+ * Set widget's disabled state.
1367
+ * @override
1368
+ */
1369
+ _setWidgetEditEnabled()
1370
+ {
1371
+ if (this._data.editable)
1372
+ this._widgetHtml.attr('disabled', !this._editEnabled);
1373
+ }
1374
+
1375
+ /**
1376
+ * Update Configuration Parameter value.
1377
+ * @override
1378
+ */
1379
+ _onValueInput(e)
1380
+ {
1381
+ // Update Configuration Parameter to new value
1382
+ this._data.value = this._widgetHtml.val();
1383
+
1384
+ // Trigger event
1385
+ this._triggerEvent();
1386
+ }
1387
+ }
1388
+
1389
+ // DEFINE COMPONENT
1390
+ if (!window.customElements.get('config-text-input'))
1391
+ window.customElements.define('config-text-input', ConfigTextInput);
1392
+
1393
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1394
+
1395
+ /***/ }),
1396
+
1397
+ /***/ "./src/components/uibuilder/config-vector-3d.js":
1398
+ /*!******************************************************!*\
1399
+ !*** ./src/components/uibuilder/config-vector-3d.js ***!
1400
+ \******************************************************/
1401
+ /*! exports provided: ConfigVector3D */
1402
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1403
+
1404
+ "use strict";
1405
+ __webpack_require__.r(__webpack_exports__);
1406
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigVector3D", function() { return ConfigVector3D; });
1407
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1408
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1409
+ /* harmony import */ var _widgets_vector_3d_input__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./widgets/vector-3d-input */ "./src/components/uibuilder/widgets/vector-3d-input.js");
1410
+
1411
+
1412
+
1413
+
1414
+ class ConfigVector3D extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1415
+ {
1416
+ constructor(configParam, editEnabled, inDialog)
1417
+ {
1418
+ super(configParam, editEnabled, inDialog);
1419
+ }
1420
+
1421
+ /**
1422
+ * Create widget to render the ConfigParameter value.
1423
+ * If parameter is not editable, a simple label is used.
1424
+ * @override
1425
+ */
1426
+ _generateInnerWidget()
1427
+ {
1428
+ if (this._data.editable)
1429
+ {
1430
+ // Create widget's html
1431
+ this._widgetHtml = new _widgets_vector_3d_input__WEBPACK_IMPORTED_MODULE_2__["Vector3DInput"](this._data.name, this._data.validator == 'aoi');
1432
+
1433
+ // Set widget attributes
1434
+ this._setWidgetAttributes(this._widgetHtml);
1435
+
1436
+ // Enable value commit binding
1437
+ $(this._widgetHtml).on('change', $.proxy(this._onValueInput, this));
1438
+ }
1439
+ else
1440
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1441
+
1442
+ // Return component
1443
+ return this._widgetHtml;
1444
+ }
1445
+
1446
+ /**
1447
+ * Set widget's value.
1448
+ * If parameter is not editable, the label text is set.
1449
+ * @override
1450
+ */
1451
+ _setWidgetValue()
1452
+ {
1453
+ this._widgetHtml.value = this._data.value;
1454
+
1455
+ // Trigger event
1456
+ this._triggerEvent();
1457
+ }
1458
+
1459
+ /**
1460
+ * Set widget's disabled state.
1461
+ * @override
1462
+ */
1463
+ _setWidgetEditEnabled()
1464
+ {
1465
+ if (this._data.editable)
1466
+ {
1467
+ $(this._widgetHtml).attr('disabled', !this._editEnabled);
1468
+ }
1469
+ }
1470
+
1471
+ /**
1472
+ * Update Configuration Parameter value.
1473
+ * @override
1474
+ */
1475
+ _onValueInput(e)
1476
+ {
1477
+ // Update Configuration Parameter to new value
1478
+ this._data.value = this._widgetHtml.value;
1479
+
1480
+ // Trigger event
1481
+ this._triggerEvent();
1482
+ }
1483
+ }
1484
+
1485
+ // DEFINE COMPONENT
1486
+ if (!window.customElements.get('config-vector-3d'))
1487
+ window.customElements.define('config-vector-3d', ConfigVector3D);
1488
+
1489
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1490
+
1491
+ /***/ }),
1492
+
1493
+ /***/ "./src/components/uibuilder/widgets/list-item-editor.js":
1494
+ /*!**************************************************************!*\
1495
+ !*** ./src/components/uibuilder/widgets/list-item-editor.js ***!
1496
+ \**************************************************************/
1497
+ /*! exports provided: ListItemEditor */
1498
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1499
+
1500
+ "use strict";
1501
+ __webpack_require__.r(__webpack_exports__);
1502
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ListItemEditor", function() { return ListItemEditor; });
1503
+ /* harmony import */ var _utils_uibuilder_config_form_item_factory__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../utils/uibuilder/config-form-item-factory */ "./src/utils/uibuilder/config-form-item-factory.js");
1504
+
1505
+
1506
+ class ListItemEditor extends HTMLElement
1507
+ {
1508
+ constructor()
1509
+ {
1510
+ super();
1511
+ }
1512
+
1513
+ set data(subConfigParamsArray)
1514
+ {
1515
+ this._data = subConfigParamsArray;
1516
+
1517
+ this._buildView();
1518
+ }
1519
+
1520
+ get data()
1521
+ {
1522
+ return this._data;
1523
+ }
1524
+
1525
+ set index(index)
1526
+ {
1527
+ this._index = index;
1528
+ }
1529
+
1530
+ get index()
1531
+ {
1532
+ return this._index;
1533
+ }
1534
+
1535
+ _buildView()
1536
+ {
1537
+ // Generate container form
1538
+ this._form = $('<form>', {
1539
+ onsubmit: 'return false;'
1540
+ });
1541
+
1542
+ // Append form
1543
+ $(this).append(this._form);
1544
+
1545
+ // Generate form fields
1546
+ for (let configParam of this._data)
1547
+ {
1548
+ // Create form item
1549
+ let formItem = _utils_uibuilder_config_form_item_factory__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItemFactory"].create(configParam, true, true);
1550
+ formItem.data = configParam;
1551
+
1552
+ // Add form item to form
1553
+ this._form.append(formItem);
1554
+ }
1555
+
1556
+ // Initialize kendo validation on form
1557
+ this._validator = this._form.kendoValidator({
1558
+ validateOnBlur: true,
1559
+ rules: {
1560
+ // Add rule to validate AOI form items?
1561
+ // (see: https://demos.telerik.com/kendo-ui/validator/custom-validation)
1562
+ aoi: function (input) {
1563
+ if (input.is('[data-aoi-msg]') && input.val() != '')
1564
+ {
1565
+ if (input.val() == '0,0,0')
1566
+ return false;
1567
+ }
1568
+
1569
+ return true;
1570
+ }
1571
+ }
1572
+ }).data('kendoValidator');
1573
+ }
1574
+
1575
+ validate()
1576
+ {
1577
+ return this._validator.validate();
1578
+ }
1579
+ }
1580
+
1581
+ // DEFINE COMPONENT
1582
+ if (!window.customElements.get('list-item-editor'))
1583
+ window.customElements.define('list-item-editor', ListItemEditor);
1584
+
1585
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1586
+
1587
+ /***/ }),
1588
+
1589
+ /***/ "./src/components/uibuilder/widgets/vector-3d-input.js":
1590
+ /*!*************************************************************!*\
1591
+ !*** ./src/components/uibuilder/widgets/vector-3d-input.js ***!
1592
+ \*************************************************************/
1593
+ /*! exports provided: Vector3DInput */
1594
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1595
+
1596
+ "use strict";
1597
+ __webpack_require__.r(__webpack_exports__);
1598
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3DInput", function() { return Vector3DInput; });
1599
+ class Vector3DInput extends HTMLElement
1600
+ {
1601
+ constructor(id, isValidable)
1602
+ {
1603
+ super();
1604
+
1605
+ this.id = id;
1606
+ this.name = id;
1607
+
1608
+ this._isValidable = isValidable;
1609
+
1610
+ this._initialize();
1611
+ }
1612
+
1613
+ set enableClear(value)
1614
+ {
1615
+ if (value)
1616
+ this._clearButton.show();
1617
+ else
1618
+ this._clearButton.hide();
1619
+ }
1620
+
1621
+ set allowNegative(value)
1622
+ {
1623
+ if (value)
1624
+ {
1625
+ this._widgetX.setOptions( {min: null} );
1626
+ this._widgetY.setOptions( {min: null} );
1627
+ this._widgetZ.setOptions( {min: null} );
1628
+ }
1629
+ }
1630
+
1631
+ set value(val)
1632
+ {
1633
+ var coords = val.split(',');
1634
+
1635
+ if (coords.length >= 1)
1636
+ this._widgetX.value(coords[0]);
1637
+
1638
+ if (coords.length >= 2)
1639
+ this._widgetY.value(coords[1]);
1640
+
1641
+ if (coords.length >= 3)
1642
+ this._widgetZ.value(coords[2]);
1643
+
1644
+ if (this._isValidable)
1645
+ this._inputVal.val(this.value);
1646
+ }
1647
+
1648
+ get value()
1649
+ {
1650
+ if (this._widgetX.value() == null && this._widgetY.value() == null && this._widgetZ.value() == null)
1651
+ return '';
1652
+ else
1653
+ return this._widgetX.value() + ',' + this._widgetY.value() + ',' + this._widgetZ.value();
1654
+ }
1655
+
1656
+ _initialize()
1657
+ {
1658
+ // Generate container form
1659
+ this._container = $('<div>', {
1660
+ class: 'form-inline'
1661
+ });
1662
+
1663
+ // Append container
1664
+ $(this).append(this._container);
1665
+
1666
+ // Set inputs configuration
1667
+ let configHtml = {
1668
+ type: 'number',
1669
+ class: 'form-control short-4',
1670
+ };
1671
+
1672
+ // Set widget configuration
1673
+ let configWidget = {
1674
+ min: 0,
1675
+ spinners: false,
1676
+ format: '#.######',
1677
+ decimals: 6,
1678
+ round: false,
1679
+ spinners: false,
1680
+ restrictDecimals: false,
1681
+ change: $.proxy(this._onChange, this)
1682
+ };
1683
+
1684
+ // Create widgets
1685
+ this._inputX = $('<input>', configHtml);
1686
+ this._container.append(this._inputX);
1687
+ this._widgetX = this._inputX.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1688
+
1689
+ this._container.append('<span class="px-1">,</span>');
1690
+
1691
+ this._inputY = $('<input>', configHtml);
1692
+ this._container.append(this._inputY);
1693
+ this._widgetY = this._inputY.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1694
+
1695
+ this._container.append('<span class="px-1">,</span>');
1696
+
1697
+ this._inputZ = $('<input>', configHtml);
1698
+ this._container.append(this._inputZ);
1699
+ this._widgetZ = this._inputZ.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1700
+
1701
+ this._container.append('<span class="px-1"></span>'); // Additional spacer
1702
+
1703
+ // Create invisible field to apply overall validation
1704
+ if (this._isValidable)
1705
+ {
1706
+ this._inputVal = $('<input>', {name: `${this.name}-custom-validate`, 'data-aoi-msg': 'Values can\'t all be 0'});
1707
+ this._container.append(this._inputVal);
1708
+ this._container.append(`<span class="k-invalid-msg" data-for="${this.name}-custom-validate"></span>`)
1709
+ this._inputVal.hide();
1710
+ }
1711
+
1712
+ // Create and append Clear button
1713
+ this._clearButton = $('<button>', {type: 'button', class: 'k-button k-secondary my-1', title: 'Clear'}).append($('<i class="fas fa-times"></i>'));
1714
+ this._clearButton.on('click', $.proxy(this._onClearClick, this));
1715
+ this._container.append(this._clearButton);
1716
+
1717
+ // Hide button by default
1718
+ this._clearButton.hide();
1719
+ }
1720
+
1721
+ _onChange()
1722
+ {
1723
+ // Empty strings are not allowed
1724
+ if (this._widgetX.value() == null)
1725
+ this._widgetX.value(0);
1726
+
1727
+ if (this._widgetY.value() == null)
1728
+ this._widgetY.value(0);
1729
+
1730
+ if (this._widgetZ.value() == null)
1731
+ this._widgetZ.value(0);
1732
+
1733
+ this._dispatchCommit();
1734
+ }
1735
+
1736
+ _onClearClick()
1737
+ {
1738
+ this._widgetX.value('');
1739
+ this._widgetY.value('');
1740
+ this._widgetZ.value('');
1741
+
1742
+ this._dispatchCommit();
1743
+ }
1744
+
1745
+ _dispatchCommit()
1746
+ {
1747
+ if (this._isValidable)
1748
+ this._inputVal.val(this.value);
1749
+
1750
+ this.dispatchEvent(new Event('change'));
1751
+ }
1752
+ }
1753
+
1754
+ // DEFINE COMPONENT
1755
+ if (!window.customElements.get('vector-3d-input'))
1756
+ window.customElements.define('vector-3d-input', Vector3DInput);
1757
+
1758
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1759
+
1760
+ /***/ }),
1761
+
1762
+ /***/ "./src/utils/uibuilder/config-form-item-factory.js":
1763
+ /*!*********************************************************!*\
1764
+ !*** ./src/utils/uibuilder/config-form-item-factory.js ***!
1765
+ \*********************************************************/
1766
+ /*! exports provided: ConfigFormItemFactory */
1767
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1768
+
1769
+ "use strict";
1770
+ __webpack_require__.r(__webpack_exports__);
1771
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigFormItemFactory", function() { return ConfigFormItemFactory; });
1772
+ /* harmony import */ var _components_uibuilder_config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../components/uibuilder/config-form-item */ "./src/components/uibuilder/config-form-item.js");
1773
+ /* harmony import */ var _components_uibuilder_config_numeric_stepper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../components/uibuilder/config-numeric-stepper */ "./src/components/uibuilder/config-numeric-stepper.js");
1774
+ /* harmony import */ var _components_uibuilder_config_text_input__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../components/uibuilder/config-text-input */ "./src/components/uibuilder/config-text-input.js");
1775
+ /* harmony import */ var _components_uibuilder_config_check_box__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../components/uibuilder/config-check-box */ "./src/components/uibuilder/config-check-box.js");
1776
+ /* harmony import */ var _components_uibuilder_config_drop_down_list__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../components/uibuilder/config-drop-down-list */ "./src/components/uibuilder/config-drop-down-list.js");
1777
+ /* harmony import */ var _components_uibuilder_config_grid__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../components/uibuilder/config-grid */ "./src/components/uibuilder/config-grid.js");
1778
+ /* harmony import */ var _components_uibuilder_config_dual_list__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../components/uibuilder/config-dual-list */ "./src/components/uibuilder/config-dual-list.js");
1779
+ /* harmony import */ var _components_uibuilder_config_vector_3d__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../components/uibuilder/config-vector-3d */ "./src/components/uibuilder/config-vector-3d.js");
1780
+
1781
+
1782
+
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+ class ConfigFormItemFactory
1791
+ {
1792
+ static create(configParam, editEnabled, inDialog = false)
1793
+ {
1794
+ switch (configParam.type)
1795
+ {
1796
+ case 'TextInput':
1797
+ return new _components_uibuilder_config_text_input__WEBPACK_IMPORTED_MODULE_2__["ConfigTextInput"](configParam, editEnabled, inDialog);
1798
+ break;
1799
+
1800
+ case 'CheckBox':
1801
+ return new _components_uibuilder_config_check_box__WEBPACK_IMPORTED_MODULE_3__["ConfigCheckBox"](configParam, editEnabled, inDialog);
1802
+ break;
1803
+
1804
+ case 'NumericStepper':
1805
+ return new _components_uibuilder_config_numeric_stepper__WEBPACK_IMPORTED_MODULE_1__["ConfigNumericStepper"](configParam, editEnabled, inDialog);
1806
+ break;
1807
+
1808
+ case 'ComboBox':
1809
+ return new _components_uibuilder_config_drop_down_list__WEBPACK_IMPORTED_MODULE_4__["ConfigDropDownList"](configParam, editEnabled, inDialog);
1810
+ break;
1811
+
1812
+ case 'DataGrid':
1813
+ return new _components_uibuilder_config_grid__WEBPACK_IMPORTED_MODULE_5__["ConfigGrid"](configParam, editEnabled, inDialog);
1814
+ break;
1815
+
1816
+ case 'DualList':
1817
+ return new _components_uibuilder_config_dual_list__WEBPACK_IMPORTED_MODULE_6__["ConfigDualList"](configParam, editEnabled, inDialog);
1818
+ break;
1819
+
1820
+ case 'Vector3D':
1821
+ return new _components_uibuilder_config_vector_3d__WEBPACK_IMPORTED_MODULE_7__["ConfigVector3D"](configParam, editEnabled, inDialog);
1822
+ break;
1823
+
1824
+ default:
1825
+ return new _components_uibuilder_config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"](configParam, editEnabled, inDialog); // Will log an error for missing form item type
1826
+ }
1827
+ }
1828
+ }
1829
+
1830
+
1831
+ /***/ }),
1832
+
1833
+ /***/ "./src/utils/uibuilder/config-interface-builder.js":
1834
+ /*!*********************************************************!*\
1835
+ !*** ./src/utils/uibuilder/config-interface-builder.js ***!
1836
+ \*********************************************************/
1837
+ /*! exports provided: ConfigInterfaceBuilder */
1838
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1839
+
1840
+ "use strict";
1841
+ __webpack_require__.r(__webpack_exports__);
1842
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigInterfaceBuilder", function() { return ConfigInterfaceBuilder; });
1843
+ /* harmony import */ var _configuration_parameter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./configuration-parameter */ "./src/utils/uibuilder/configuration-parameter.js");
1844
+ /* harmony import */ var _config_form_item_factory__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-form-item-factory */ "./src/utils/uibuilder/config-form-item-factory.js");
1845
+
1846
+
1847
+
1848
+ class ConfigInterfaceBuilder
1849
+ {
1850
+ constructor()
1851
+ {
1852
+ // Set some constants
1853
+ this.TAB_PREFIX = 'tab-'
1854
+ this.TAB_PANE_PREFIX = 'tabpane-';
1855
+ this.SEPARATOR_BEFORE = 'before';
1856
+ this.SEPARATOR_AFTER = 'after';
1857
+ }
1858
+
1859
+ dump(modifiedOnly = false)
1860
+ {
1861
+ let dumpStr = '';
1862
+
1863
+ for (let cp of this._configParams)
1864
+ {
1865
+ if (modifiedOnly)
1866
+ {
1867
+ if (cp.isModified)
1868
+ dumpStr += cp.toString() + '\n';
1869
+ }
1870
+ else
1871
+ dumpStr += cp.toString() + '\n';
1872
+ }
1873
+
1874
+ console.log(dumpStr);
1875
+ }
1876
+
1877
+ buildInterface(data, mainContainerId, disableEdit = false, tabSuffix = '')
1878
+ {
1879
+ this._mainContainerId = mainContainerId;
1880
+ this._configParams = new Array();
1881
+ this._validator = null;
1882
+
1883
+ let hasNewFormItem = false;
1884
+
1885
+ //console.log(data.getDump())
1886
+
1887
+ for (let i = 0; i < data.size(); i++)
1888
+ {
1889
+ // PARSE DATA
1890
+
1891
+ let configParam = _configuration_parameter__WEBPACK_IMPORTED_MODULE_0__["ConfigurationParameter"].fromSfsObject(data.get(i));
1892
+ this._configParams.push(configParam);
1893
+
1894
+ // Get tab and tab pane id from group id
1895
+ const tabId = this.TAB_PREFIX + configParam.categoryId + (tabSuffix ? '_' + tabSuffix : '');
1896
+ const tabPaneId = this.TAB_PANE_PREFIX + configParam.categoryId + (tabSuffix ? '_' + tabSuffix : '');
1897
+
1898
+ // BUILD INTERFACE :: TABS
1899
+
1900
+ // Check if a tab specific for this group already exists inside the mainContainer: if not, create it
1901
+ // (a tab already exists if it was created in a previous loop)
1902
+ let tab = $(`#${mainContainerId} > #tabs #${tabId}`);
1903
+
1904
+ if (tab.length == 0)
1905
+ {
1906
+ // Create tab for tab pane
1907
+ tab = $('<li>', {class: 'nav-item'});
1908
+ tab.append($('<a>', {
1909
+ class: 'nav-link' + (i == 0 ? ' active' : ''),
1910
+ id: tabId,
1911
+ 'data-toggle': 'tab',
1912
+ href: '#' + tabPaneId,
1913
+ role: 'tab',
1914
+ 'aria-controls': tabPaneId,
1915
+ 'aria-selected': (i == 0 ? 'true' : 'false'),
1916
+ html: configParam.category,
1917
+ }));
1918
+
1919
+ // Add tab to container
1920
+ $(`#${mainContainerId} > #tabs`).append(tab);
1921
+ }
1922
+
1923
+ // BUILD INTERFACE :: TAB PANES
1924
+
1925
+ // Check if a tab pane specific for this group already exists inside the mainContainer: if not, create it
1926
+ // (a tab pane already exists if it was created in a previous loop or if it exists statically in the html - in case it is needed to add some static content)
1927
+ let tabPane = $(`#${mainContainerId} > #tabPanels > #${tabPaneId}`);
1928
+
1929
+ if (tabPane.length == 0)
1930
+ {
1931
+ // Create tab pane
1932
+ tabPane = $('<div>', {
1933
+ class: 'tab-pane' + (i == 0 ? ' show active' : ''),
1934
+ id: tabPaneId,
1935
+ role: 'tabpanel',
1936
+ 'aria-labelledby': tabId,
1937
+ 'data-dynamic': 'true',
1938
+ });
1939
+
1940
+ // Add tab pane to container
1941
+ $(`#${mainContainerId} > #tabPanels`).append(tabPane);
1942
+ }
1943
+
1944
+ // BUILD INTERFACE :: TAB PANES' FORM
1945
+
1946
+ // Check if a form already exists inside the tab pane: if not, create it
1947
+ let form = tabPane.find('form');
1948
+
1949
+ if (form.length == 0)
1950
+ {
1951
+ // Create form
1952
+ form = $('<form>', {
1953
+ class: '',
1954
+ autocomplete: 'off'
1955
+ });
1956
+
1957
+ // Create an inner fieldset; this might be useful to easily disable the whole form at once (actually we don't use it because Kendo widgets are not disabled automatically)
1958
+ form.append(
1959
+ $('<fieldset>', {
1960
+ class: ''
1961
+ })
1962
+ );
1963
+
1964
+ // Add form to tab pane
1965
+ tabPane.prepend(form);
1966
+
1967
+ // form.on("keypress", function(event) {
1968
+ // // If the user presses the "Enter" key on the keyboard
1969
+ // if (event.key === "Enter") {
1970
+ // // Cancel the default action, if needed
1971
+ // event.preventDefault();
1972
+ // console.log("ENTER")
1973
+ // }
1974
+ // });
1975
+ form.submit(function(evt) {
1976
+ console.log("SUBMIT")
1977
+ evt.preventDefault();
1978
+ });
1979
+ }
1980
+
1981
+ // Get fieldset, which is the actual form items container
1982
+ let fieldset = form.find('fieldset');
1983
+
1984
+ // BUILD INTERFACE :: TAB PANES' FORM ITEMS
1985
+
1986
+ // Check if form item already exists in fieldset; if yes, just update its data
1987
+ let formItem = fieldset.find(`#form-item-${$.escapeSelector(configParam.name)}`);
1988
+
1989
+ if (formItem.length == 0)
1990
+ {
1991
+ hasNewFormItem = true;
1992
+
1993
+ formItem = _config_form_item_factory__WEBPACK_IMPORTED_MODULE_1__["ConfigFormItemFactory"].create(configParam, !disableEdit);
1994
+
1995
+ // Add separator before
1996
+ if (configParam.separator != null && configParam.separator.pos == 'before')
1997
+ fieldset.append(this._buildSeparator(configParam.separator));
1998
+
1999
+ // Add form item to form
2000
+ fieldset.append(formItem);
2001
+
2002
+ // Add separator after
2003
+ if (configParam.separator != null && configParam.separator.pos == 'after')
2004
+ fieldset.append(this._buildSeparator(configParam.separator));
2005
+ }
2006
+ else
2007
+ formItem[0].data = configParam;
2008
+ }
2009
+
2010
+ // Add listener to show help tooltips
2011
+ let allTabPanes = $(`#${mainContainerId} > #tabPanels > div.tab-pane`);
2012
+ allTabPanes.kendoTooltip({
2013
+ filter: 'i[title].help',
2014
+ position: 'right',
2015
+ width: '250px',
2016
+ content: function(e) {
2017
+ return `<div class="help-tooltip">${e.target.data('title')}</div>`;
2018
+ }
2019
+ });
2020
+
2021
+ // Initialize kendo validation on forms' main container
2022
+ this._validator = $(`#${mainContainerId}`).kendoValidator({
2023
+ validateOnBlur: true,
2024
+ rules: {
2025
+ // Add rule to validate AOI form items
2026
+ // (see: https://demos.telerik.com/kendo-ui/validator/custom-validation)
2027
+ aoi: function (input) {
2028
+ if (input.is('[data-aoi-msg]') && input.val() != '')
2029
+ {
2030
+ if (input.val() == '0,0,0')
2031
+ return false;
2032
+ }
2033
+
2034
+ return true;
2035
+ }
2036
+ }
2037
+ }).data('kendoValidator');
2038
+ }
2039
+
2040
+ destroyInterface()
2041
+ {
2042
+ // Destroy all Kendo widgets in forms
2043
+ kendo.destroy($(`#${this._mainContainerId} > #tabPanels > div.tab-pane > form`));
2044
+
2045
+ // Remove all tabs
2046
+ $(`#${this._mainContainerId} > #tabs`).empty();
2047
+
2048
+ // Remove dynamic tab panes (tab panes created by Interface Builder)
2049
+ $(`#${this._mainContainerId} > #tabPanels > div.tab-pane[data-dynamic="true"]`).remove();
2050
+
2051
+ // Remove form inside static tab panes (predefined tab panes in html)
2052
+ $(`#${this._mainContainerId} > #tabPanels > div.tab-pane > form`).remove();
2053
+
2054
+ // Remove "active" class from static tab panes (otherwise this class messes with the tab navigator functioning)
2055
+ $(`#${this._mainContainerId} > #tabPanels > div.tab-pane`).removeClass('active');
2056
+ }
2057
+
2058
+ disableInterface(disable)
2059
+ {
2060
+ // Enable/disable all config form items
2061
+ $(`#${this._mainContainerId} *[id^='form-item-']`).prop('editEnabled', !disable);
2062
+ }
2063
+
2064
+ _buildSeparator(separator)
2065
+ {
2066
+ if (separator.text == null)
2067
+ return $(`<hr class="config-form-separator">`);
2068
+
2069
+ else
2070
+ return $(`<label class="config-form-separator-label mb-3">${separator.text}</label>`);
2071
+ }
2072
+
2073
+ getChangedData()
2074
+ {
2075
+ let changes = new SFS2X.SFSArray();
2076
+
2077
+ for (var cp of this._configParams)
2078
+ {
2079
+ if (cp.isModified)
2080
+ changes.addSFSObject(cp.toSfsObject());
2081
+ }
2082
+
2083
+ return changes;
2084
+ }
2085
+
2086
+ resetIsModified()
2087
+ {
2088
+ for (let cp of this._configParams)
2089
+ {
2090
+ if (cp.isModified)
2091
+ cp.resetIsModified();
2092
+ }
2093
+ }
2094
+
2095
+ checkIsValid()
2096
+ {
2097
+ return this._validator.validate();
2098
+ }
2099
+
2100
+ resetValidation()
2101
+ {
2102
+ this._validator.hideMessages();
2103
+
2104
+ // The method above doesn't remove the k-invalid classes and aria-invalid="true" attributes from inputs
2105
+ // Let's do it manually
2106
+ $(`#${this._mainContainerId} .k-invalid`).removeClass('k-invalid');
2107
+ $(`#${this._mainContainerId} [aria-invalid="true"]`).removeAttr('aria-invalid');
2108
+ }
2109
+
2110
+ getConfigFormItem(configParamName)
2111
+ {
2112
+ let formItem = $(`#${this._mainContainerId}`).find(`#form-item-${$.escapeSelector(configParamName)}`);
2113
+
2114
+ if (formItem.length > 0)
2115
+ return formItem[0];
2116
+ else
2117
+ return null;
2118
+ }
2119
+
2120
+ activateFirstTabPanel()
2121
+ {
2122
+ let configParam = this._configParams[0];
2123
+ const tabPaneId = this.TAB_PANE_PREFIX + configParam.categoryId;
2124
+ let tabPane = $(`#${this._mainContainerId} > #tabPanels > #${tabPaneId}`);
2125
+ tabPane.addClass('show active');
2126
+ }
2127
+ }
2128
+
2129
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
2130
+
2131
+ /***/ }),
2132
+
2133
+ /***/ "./src/utils/uibuilder/configuration-parameter.js":
2134
+ /*!********************************************************!*\
2135
+ !*** ./src/utils/uibuilder/configuration-parameter.js ***!
2136
+ \********************************************************/
2137
+ /*! exports provided: ConfigurationParameter */
2138
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
2139
+
2140
+ "use strict";
2141
+ __webpack_require__.r(__webpack_exports__);
2142
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigurationParameter", function() { return ConfigurationParameter; });
2143
+ class ConfigurationParameter
2144
+ {
2145
+ static fromSfsObject(element)
2146
+ {
2147
+ let cp = new ConfigurationParameter();
2148
+
2149
+ // Parse common data
2150
+ cp.name = element.getUtfString('name');
2151
+ cp.label = element.getUtfString('label');
2152
+ cp.category = element.getUtfString('category');
2153
+ cp.immediate = (element.containsKey('immediate') ? element.getBool('immediate') : false);
2154
+ cp.tooltip = element.getUtfString('tooltip');
2155
+ cp.type = element.getUtfString('type');
2156
+ cp.value = element.get('value');
2157
+ cp.validator = element.getUtfString('validator');
2158
+ cp.editable = (element.containsKey('edit') ? element.getBool('edit') : true);
2159
+ cp.trigger = (element.containsKey('trigger') ? element.getBool('trigger') : false);
2160
+ cp.triggerData = element.getSFSArray('triggerData');
2161
+ cp.clientOnly = (element.containsKey('clientOnly') ? element.getBool('clientOnly') : false);
2162
+ cp.dataProvider = element.getUtfString('dataProvider');
2163
+
2164
+ // Parse component specific attributes
2165
+ let tmpAttributes = element.getSFSObject('attributes');
2166
+ if (tmpAttributes != null)
2167
+ {
2168
+ let attributes = {};
2169
+
2170
+ let keys = tmpAttributes.getKeysArray();
2171
+ for (let key of keys)
2172
+ attributes[key] = tmpAttributes.get(key);
2173
+
2174
+ cp.attributes = attributes;
2175
+ }
2176
+
2177
+ // Parse separator settings
2178
+ let tmpSeparator = element.getSFSObject('separator');
2179
+ if (tmpSeparator != null)
2180
+ {
2181
+ let separator = {};
2182
+
2183
+ let keys1 = tmpSeparator.getKeysArray();
2184
+ for (let key1 of keys1)
2185
+ separator[key1] = tmpSeparator.get(key1);
2186
+
2187
+ cp.separator = separator;
2188
+ }
2189
+
2190
+ // Parse default list item
2191
+ let tmpDefaultListItem = element.getSFSArray('defaultListItem');
2192
+ if (tmpDefaultListItem != null && tmpDefaultListItem.size() > 0)
2193
+ {
2194
+ let defaultListItem = [];
2195
+
2196
+ for (let i = 0; i < tmpDefaultListItem.size(); i++)
2197
+ defaultListItem.push(ConfigurationParameter.fromSfsObject(tmpDefaultListItem.getSFSObject(i)));
2198
+
2199
+ cp.defaultListItem = defaultListItem;
2200
+
2201
+ // Parse list values
2202
+ let listValues = [];
2203
+
2204
+ let tmpListValues = element.getSFSArray('listValues');
2205
+ if (tmpListValues != null && tmpListValues.size() > 0)
2206
+ {
2207
+ for (let v = 0; v < tmpListValues.size(); v++)
2208
+ {
2209
+ let listValueObj = tmpListValues.getSFSObject(v);
2210
+ let obj = {};
2211
+
2212
+ let keys2 = listValueObj.getKeysArray();
2213
+ for (let key2 of keys2)
2214
+ obj[key2] = listValueObj.get(key2);
2215
+
2216
+ listValues.push(obj);
2217
+ }
2218
+ }
2219
+
2220
+ cp.listValues = listValues;
2221
+
2222
+ // If we have a list, on the server-side items could be represented by a class
2223
+ cp.clazz = element.getUtfString('clazz');
2224
+
2225
+ // Avoid list to be emptied
2226
+ cp.denyEmpty = (element.containsKey('denyEmpty') ? element.getBool('denyEmpty') : false);
2227
+ }
2228
+
2229
+ return cp;
2230
+ }
2231
+
2232
+ constructor()
2233
+ {
2234
+ /* CONSTANTS */
2235
+ this.DEFAULT_CATEGORY_NAME = 'General';
2236
+ this.DEFAULT_CATEGORY_ID = 'general';
2237
+
2238
+ /* PUBLIC VARS */
2239
+
2240
+ this.name = '';
2241
+ this.label = '';
2242
+ this.tooltip = '';
2243
+ this.type = null;
2244
+ this.trigger = false;
2245
+ this.triggerData = null;
2246
+ this.clientOnly = false;
2247
+ this.editable = true;
2248
+ this.attributes = null;
2249
+ this.dataProvider = null;
2250
+
2251
+ this.separator = null; // Parameter used to create a separator before or after the config parameter
2252
+ this.defaultListItem = null; // List of sub-ConfigurationParameters, each containing the default values
2253
+ this.clazz = null; // Name of the class representing the list item (not used in case of primiteve data types)
2254
+ this.denyEmpty = false; // Disallow to empty a list (DataGrid config parameter type only)
2255
+
2256
+ this.immediate = false; // Shows icon indicating that setting will be applied immediately on submit, without the need for a server restart
2257
+
2258
+ /* PRIVATE VARS */
2259
+
2260
+ this._category = this.DEFAULT_CATEGORY_NAME;
2261
+ this._categoryId = this.DEFAULT_CATEGORY_ID;
2262
+ this._value = null;
2263
+ this._initialValue = null; // Save the initial value of the configuration parameter, to check if the value was modified
2264
+ this._validator = null;
2265
+
2266
+ this._listItems = []; // Array of arrays of ConfigurationParameters
2267
+ this._listItemsChanged = false; // Flag to be set in case a list item is added or removed
2268
+ }
2269
+
2270
+ //---------------------------------------------
2271
+ // GETTERS / SETTERS
2272
+ //---------------------------------------------
2273
+
2274
+ set category(val)
2275
+ {
2276
+ if (val)
2277
+ {
2278
+ this._category = val;
2279
+ this._setIdFromCategoryName(this._category);
2280
+ }
2281
+ }
2282
+
2283
+ get category()
2284
+ {
2285
+ return this._category;
2286
+ }
2287
+
2288
+ set value(val)
2289
+ {
2290
+ if (this._value != val)
2291
+ {
2292
+ // If value is null, then we are setting this for the first time and
2293
+ // we want to save the initial value, to check later if it has been modified
2294
+ if (this._value == null)
2295
+ this._initialValue = val;
2296
+
2297
+ this._value = val;
2298
+ }
2299
+ }
2300
+
2301
+ get value()
2302
+ {
2303
+ return this._value;
2304
+ }
2305
+
2306
+ set validator(val)
2307
+ {
2308
+ if (val)
2309
+ this._validator = val;
2310
+ }
2311
+
2312
+ get validator()
2313
+ {
2314
+ return this._validator;
2315
+ }
2316
+
2317
+ /**
2318
+ * An array of objects; each object contains the name-value pairs used to
2319
+ * populate the list of sub-configuration parameters arrays, based on defaultListItem.
2320
+ */
2321
+ set listValues(arr)
2322
+ {
2323
+ this._setSubConfigurationParams(arr);
2324
+ }
2325
+
2326
+ get listValues()
2327
+ {
2328
+ return this._getSubConfigurationParamsValues();
2329
+ }
2330
+
2331
+ //---------------------------------------------
2332
+ // GETTERS ONLY
2333
+ //---------------------------------------------
2334
+
2335
+ get isModified()
2336
+ {
2337
+ let _isModified = false;
2338
+
2339
+ // If the parameter is used on the client only (for example in a custom trigger)
2340
+ // then we never have to consider it as modified, to prevent it being sent to the server
2341
+ if (!this.clientOnly)
2342
+ {
2343
+ if (this._value != this._initialValue || this._listItemsChanged)
2344
+ _isModified = true;
2345
+ else
2346
+ {
2347
+ // Check sub parameters
2348
+ outerLoop: for (let listItem of this._listItems)
2349
+ {
2350
+ for (let subCP of listItem)
2351
+ {
2352
+ if (subCP.isModified)
2353
+ {
2354
+ _isModified = true;
2355
+ break outerLoop;
2356
+ }
2357
+ }
2358
+ }
2359
+ }
2360
+ }
2361
+
2362
+ return _isModified;
2363
+ }
2364
+
2365
+ get categoryId()
2366
+ {
2367
+ return this._categoryId;
2368
+ }
2369
+
2370
+ get listItems()
2371
+ {
2372
+ return this._listItems;
2373
+ }
2374
+
2375
+ //---------------------------------------------
2376
+ // PUBLIC METHODS
2377
+ //---------------------------------------------
2378
+
2379
+ /**
2380
+ * Return a clone of this ConfigurationParameter.
2381
+ */
2382
+ clone(cloneValue = false)
2383
+ {
2384
+ let cp = new ConfigurationParameter();
2385
+ cp.name = this.name;
2386
+ cp.label = this.label;
2387
+ cp.category = this.category;
2388
+ cp.tooltip = this.tooltip;
2389
+ cp.type = this.type;
2390
+ cp.validator = this.validator;
2391
+ cp.trigger = this.trigger;
2392
+ cp.triggerData = (this.triggerData != null ? SFS2X.SFSArray.newFromBinaryData(this.triggerData.toBinary()) : null);
2393
+ cp.clientOnly = this.clientOnly;
2394
+ cp.dataProvider = this.dataProvider;
2395
+
2396
+ if (cloneValue)
2397
+ cp.value = this.value;
2398
+
2399
+ if (this.attributes != null)
2400
+ {
2401
+ cp.attributes = new Object();
2402
+ for (let s1 in this.attributes)
2403
+ cp.attributes[s1] = this.attributes[s1];
2404
+ }
2405
+
2406
+ if (this.separator != null)
2407
+ {
2408
+ cp.separator = new Object()
2409
+ for (let s2 in this.separator)
2410
+ cp.separator[s2] = this.separator[s2];
2411
+ }
2412
+
2413
+ if (this.defaultListItem != null)
2414
+ {
2415
+ let clonedDefaultListItems = [];
2416
+
2417
+ for (let subCP of this.defaultListItem)
2418
+ clonedDefaultListItems.push(subCP.clone(cloneValue));
2419
+
2420
+ cp.defaultListItem = clonedDefaultListItems;
2421
+ }
2422
+
2423
+ cp.listValues = this.listValues; // No need to clone this, as the listValues setter already does it
2424
+ cp.clazz = this.clazz;
2425
+ cp.denyEmpty = this.denyEmpty;
2426
+ cp.immediate = this.immediate;
2427
+
2428
+ return cp;
2429
+ }
2430
+
2431
+ /**
2432
+ * Reset initial value by copying the current value.
2433
+ */
2434
+ resetIsModified()
2435
+ {
2436
+ this._initialValue = this._value;
2437
+
2438
+ // Reset sub-parameters
2439
+ if (this._listItems != null)
2440
+ {
2441
+ for (let listItem of this._listItems)
2442
+ {
2443
+ for (let subCP of listItem)
2444
+ subCP.resetIsModified();
2445
+ }
2446
+ }
2447
+
2448
+ this._listItemsChanged = false;
2449
+ }
2450
+
2451
+ addListItem(newListItem)
2452
+ {
2453
+ this._listItems.push(newListItem);
2454
+ this._listItemsChanged = true;
2455
+ }
2456
+
2457
+ updateListItem(listItem, itemIndex)
2458
+ {
2459
+ this._listItems[itemIndex] = listItem;
2460
+ this._listItemsChanged = true;
2461
+ }
2462
+
2463
+ removeListItem(itemIndex)
2464
+ {
2465
+ this._listItems.splice(itemIndex, 1);
2466
+ this._listItemsChanged = true;
2467
+ }
2468
+
2469
+ toSfsObject()
2470
+ {
2471
+ let obj = new SFS2X.SFSObject();
2472
+
2473
+ // Set changed setting name
2474
+ obj.putUtfString('name', this.name);
2475
+
2476
+ // Set changed setting class, if any
2477
+ if (this.clazz != null)
2478
+ obj.putUtfString('clazz', this.clazz);
2479
+
2480
+ if (this.value != null)
2481
+ {
2482
+ // Set changed setting value
2483
+ if (typeof this.value === 'boolean')
2484
+ obj.putBool('value', this.value);
2485
+ else if (typeof this.value === 'number')
2486
+ obj.putInt('value', this.value);
2487
+ else
2488
+ obj.putText('value', this.value);
2489
+ }
2490
+ else
2491
+ {
2492
+ // Set changed setting list of values
2493
+
2494
+ let listItems = new SFS2X.SFSArray();
2495
+
2496
+ for (let a of this._listItems)
2497
+ {
2498
+ if (a.length == 1) // We have just one sub config param; no need to parse it complitely
2499
+ {
2500
+ // Simple list
2501
+ let tempObj = a[0].toSfsObject();
2502
+ let wa = tempObj.getWrappedItem('value');
2503
+ listItems.add(wa.value, wa.type);
2504
+ }
2505
+ else
2506
+ {
2507
+ // Complex list
2508
+
2509
+ let values = new SFS2X.SFSArray();
2510
+
2511
+ for (let subCp of a)
2512
+ values.addSFSObject(subCp.toSfsObject());
2513
+
2514
+ listItems.addSFSArray(values);
2515
+ }
2516
+ }
2517
+
2518
+ obj.putSFSArray('value', listItems);
2519
+ }
2520
+
2521
+ return obj;
2522
+ }
2523
+
2524
+ /**
2525
+ * Return a description of the ConfigurationParameter instance.
2526
+ */
2527
+ toString()
2528
+ {
2529
+ let s = ``;
2530
+ s += `Configuration parameter: ${this.name}\n`;
2531
+ s += `\ttype: ${this.type}\n`;
2532
+ s += `\tlabel: ${this.label}\n`;
2533
+ s += `\tcategory name: ${this.category}\n`;
2534
+ s += `\tcategory id: ${this.categoryId}\n`;
2535
+ s += `\timmediate: ${this.immediate}\n`;
2536
+ s += `\ttooltip: ${this.tooltip}\n`;
2537
+ s += `\tvalue: ${this.value}\n`;
2538
+ s += `\ttrigger: ${this.trigger}\n`;
2539
+ s += `\ttrigger data: ${this.triggerData}\n`;
2540
+ s += `\tclient only: ${this.clientOnly}\n`;
2541
+ s += `\tvalidator: ${this.validator}\n`;
2542
+ s += `\tis modified: ${this.isModified}\n`;
2543
+
2544
+ if (this.attributes != null)
2545
+ {
2546
+ s += `\tcomponent attributes:\n`;
2547
+
2548
+ for (let s1 in this.attributes)
2549
+ s += `\t\t${s1} --> ${this.attributes[s1]}\n`;
2550
+ }
2551
+
2552
+ if (this.dataProvider != null)
2553
+ s += `\tdata provider: ${this.dataProvider}\n`;
2554
+
2555
+ if (this.separator != null)
2556
+ {
2557
+ s += `\tseparator:\n`;
2558
+
2559
+ for (let s2 in this.separator)
2560
+ s += `\t\t${s2} --> ${this.separator[s2]}\n`;
2561
+ }
2562
+
2563
+ if (this._listItems != null && this._listItems.length > 0)
2564
+ {
2565
+ s += `\t# list items: ${this._listItems.length}\n`;
2566
+
2567
+ for (let i = 0; i < this._listItems.length; i++)
2568
+ {
2569
+ s += `\tlist item ${i} sub-parameters:\n`;
2570
+ for (let e = 0; e < this._listItems[i].length; e++)
2571
+ s += `\t\t${this._listItems[i][e].toCompactString()}\n`;
2572
+ }
2573
+
2574
+ s += `\tclass name: ${this.clazz}\n`;
2575
+ s += `\tdeny empty list: ${this.denyEmpty}\n`;
2576
+ }
2577
+
2578
+ return s;
2579
+ }
2580
+
2581
+ /**
2582
+ * Return a compact description of the ConfigurationParameter instance.
2583
+ */
2584
+ toCompactString()
2585
+ {
2586
+ return `Configuration parameter '${this.name}': ${this.value} ${this.isModified ? '[X]' : '[ ]'}`;
2587
+ }
2588
+
2589
+ //---------------------------------------------
2590
+ // PRIVATE METHODS
2591
+ //---------------------------------------------
2592
+
2593
+ /**
2594
+ * Retrieve the category id form the category name.
2595
+ * Spaces and invalid characters are removed; words are separated using capitals.
2596
+ */
2597
+ _setIdFromCategoryName(categoryName)
2598
+ {
2599
+ this._categoryId = categoryName;
2600
+
2601
+ // Strip invalid characters
2602
+ var pattern = /[^0-9a-zA-Z]/g;
2603
+ this._categoryId = this._categoryId.replace(pattern, ' ');
2604
+
2605
+ // Capitalize words
2606
+ var words = this._categoryId.split(' ');
2607
+ this._categoryId = '';
2608
+
2609
+ for (let i = 0; i < words.length; i++)
2610
+ {
2611
+ let word = words[i];
2612
+ if (word.length > 0)
2613
+ this._categoryId += (i > 0 ? word.substr(0,1).toUpperCase() : word.substr(0,1).toLowerCase()) + (word.length > 1 ? word.substr(1) : "");
2614
+ }
2615
+
2616
+ if (this._categoryId.length == 0)
2617
+ this._categoryId = this.DEFAULT_CATEGORY_ID;
2618
+ }
2619
+
2620
+ _setSubConfigurationParams(_listValues)
2621
+ {
2622
+ this._listItems = [];
2623
+
2624
+ for (let obj of _listValues)
2625
+ {
2626
+ let listItem = [];
2627
+
2628
+ for (let defaultCP of this.defaultListItem)
2629
+ {
2630
+ let subCP = defaultCP.clone(false);
2631
+ subCP.value = obj[subCP.name];
2632
+
2633
+ listItem.push(subCP);
2634
+ }
2635
+
2636
+ this._listItems.push(listItem);
2637
+ }
2638
+ }
2639
+
2640
+ _getSubConfigurationParamsValues()
2641
+ {
2642
+ let _listValues = [];
2643
+
2644
+ for (let listItem of this._listItems)
2645
+ {
2646
+ let obj = {};
2647
+
2648
+ for (let subCP of listItem)
2649
+ {
2650
+ if (subCP.value != null)
2651
+ obj[subCP.name] = subCP.value;
2652
+ }
2653
+
2654
+ _listValues.push(obj);
2655
+ }
2656
+
2657
+ return _listValues;
2658
+ }
2659
+ }
2660
+
2661
+
2662
+ /***/ })
2663
+
2664
+ }]);
2665
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtMTJ+bW9kdWxlLTE1fm1vZHVsZS0xNn5tb2R1bGUtNC5idW5kbGUuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctY2hlY2stYm94LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kcm9wLWRvd24tbGlzdC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctZHVhbC1saXN0LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1mb3JtLWl0ZW0uanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWdyaWQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWxhYmVsLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1udW1lcmljLXN0ZXBwZXIuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXRleHQtaW5wdXQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXZlY3Rvci0zZC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci93aWRnZXRzL2xpc3QtaXRlbS1lZGl0b3IuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvd2lkZ2V0cy92ZWN0b3ItM2QtaW5wdXQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvdXRpbHMvdWlidWlsZGVyL2NvbmZpZy1mb3JtLWl0ZW0tZmFjdG9yeS5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy91dGlscy91aWJ1aWxkZXIvY29uZmlnLWludGVyZmFjZS1idWlsZGVyLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL3V0aWxzL3VpYnVpbGRlci9jb25maWd1cmF0aW9uLXBhcmFtZXRlci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnQ2hlY2tCb3ggZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0dHlwZTogJ2NoZWNrYm94Jyxcblx0XHRcdFx0Y2xhc3M6ICcnLFxuXHRcdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRuYW1lOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdCdkYXRhLXJvbGUnOiAnc3dpdGNoJyxcblx0XHRcdH07XG5cblx0XHRcdC8vIFNldCB3aWRnZXQgYXR0cmlidXRlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuICAgX2luaXRpYWxpemUoKVxuICAge1xuXHQgICBpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0ICAge1xuXHRcdCAgIC8vIEluaXRpYWxpemUga2VuZG8gd2lkZ2V0XG5cdFx0ICAga2VuZG8uaW5pdCh0aGlzLl93aWRnZXRIdG1sKTtcblxuXHRcdCAgIC8vIFNhdmUgcmVmLiB0byB3aWRnZXRcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldCA9IHRoaXMuX3dpZGdldEh0bWwuZGF0YSgna2VuZG9Td2l0Y2gnKTtcblxuXHRcdCAgIC8vIEVuYWJsZSB2YWx1ZSBjb21taXQgYmluZGluZ1xuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0LmJpbmQoJ2NoYW5nZScsICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSk7XG5cdCAgIH1cblxuXHQgICAvLyBQcm9jZWVkIHdpdGggaW5pdGlhbGl6YXRpb25cblx0ICAgc3VwZXIuX2luaXRpYWxpemUoKTtcbiAgIH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCB0aGUgbGFiZWwgdGV4dCBpcyBzZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQudmFsdWUodGhpcy5fZGF0YS52YWx1ZSk7XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbC52YWx1ZSA9IHRoaXMuX2RhdGEudmFsdWU7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LmVuYWJsZSh0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9vblZhbHVlSW5wdXQoZSlcblx0e1xuXHRcdC8vIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB0byBuZXcgdmFsdWVcblx0XHR0aGlzLl9kYXRhLnZhbHVlID0gdGhpcy5faW5uZXJXaWRnZXQudmFsdWUoKTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1jaGVjay1ib3gnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLWNoZWNrLWJveCcsIENvbmZpZ0NoZWNrQm94KTtcbiIsImltcG9ydCB7Q29uZmlnRm9ybUl0ZW19IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbSc7XG5pbXBvcnQge0NvbmZpZ0xhYmVsfSBmcm9tICcuL2NvbmZpZy1sYWJlbCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdEcm9wRG93bkxpc3QgZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0Y2xhc3M6ICdmb3JtLWNvbnRyb2wnLFxuXHRcdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRuYW1lOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdCdkYXRhLXJvbGUnOiAnZHJvcGRvd25saXN0Jyxcblx0XHRcdH07XG5cblx0XHRcdC8vIFNldCB3aWRnZXQgYXR0cmlidXRlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfaW5pdGlhbGl6ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHdpZGdldFxuXHRcdFx0a2VuZG8uaW5pdCh0aGlzLl93aWRnZXRIdG1sKTtcblxuXHRcdFx0Ly8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQgPSB0aGlzLl93aWRnZXRIdG1sLmRhdGEoJ2tlbmRvRHJvcERvd25MaXN0Jyk7XG5cblx0XHRcdC8vIFNldCBsaXN0IGl0ZW1zXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC5zZXREYXRhU291cmNlKHRoaXMuX2dldERhdGFTb3VyY2UodGhpcy5fZGF0YS5kYXRhUHJvdmlkZXIpKVxuXG5cdFx0XHQvLyBFbmFibGUgdmFsdWUgY29tbWl0IGJpbmRpbmdcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYmluZCgnY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0XHR9XG5cblx0XHQvLyBQcm9jZWVkIHdpdGggaW5pdGlhbGl6YXRpb25cblx0XHRzdXBlci5faW5pdGlhbGl6ZSgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LnZhbHVlKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC53cmFwcGVyLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0X2dldERhdGFTb3VyY2UoZHBTdHJpbmcpXG5cdHtcblx0XHRpZiAoZHBTdHJpbmcpXG5cdFx0XHRyZXR1cm4gZHBTdHJpbmcuc3BsaXQoJywnKTtcblxuXHRcdC8vIEluIGNhc2UgdGhlIGRhdGFwcm92aWRlciBpcyBlbXB0eSwgYWRkIGF0IGxlYXN0IHRoZSBjdXJyZW50IHZhbHVlXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIFt0aGlzLl9kYXRhLnZhbHVlXTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kcm9wLWRvd24tbGlzdCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZHJvcC1kb3duLWxpc3QnLCBDb25maWdEcm9wRG93bkxpc3QpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0R1YWxMaXN0IGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlci5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGRpdj4nKTtcblxuXHRcdGNvbnN0IGF2YWlsYWJsZUlkID0gdGhpcy5fZ2V0SWQodGhpcy5fZGF0YS5uYW1lLCAnYXZhaWxhYmxlJyk7XG5cdFx0Y29uc3Qgc2VsZWN0ZWRJZCA9IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyk7XG5cblx0XHQvLyBDcmVhdGUgaGVhZGVyIGZvciBsYWJlbHNcblx0XHRsZXQgaGVhZGVyID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICdmb3JtLWxhYmVsLWNvbnRhaW5lciBkdWFsLWxpc3QtbGFiZWxzJ30pO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb250LWl0YWxpYyBmb3JtLWxhYmVsIGR1YWwtbGlzdC1sZWZ0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHRcdGZvcjogYXZhaWxhYmxlSWQsXG5cdFx0fSkudGV4dCgnQXZhaWxhYmxlJykpO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb250LWl0YWxpYyBmb250LXdlaWdodC1ib2xkIGZvcm0tbGFiZWwgZHVhbC1saXN0LXJpZ2h0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHRcdGZvcjogc2VsZWN0ZWRJZCxcblx0XHR9KS50ZXh0KCdTZWxlY3RlZCcpKTtcblxuXHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKGhlYWRlcik7XG5cblx0XHQvLyBBZGQgYXZhaWxhYmxlIGl0ZW1zIGxpc3Rcblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0SHRtbCA9ICQoJzxzZWxlY3Q+Jywge1xuXHRcdFx0aWQ6IGF2YWlsYWJsZUlkLFxuXHRcdFx0Y2xhc3M6ICdkdWFsLWxpc3QtbGVmdC1jb2wnICsgKCF0aGlzLl9kYXRhLmVkaXRhYmxlID8gJyBuby1pbnRlcmFjdCcgOiAnJyksXG5cdFx0fSk7XG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC5hcHBlbmQodGhpcy5fYXZhaWxhYmxlTGlzdEh0bWwpO1xuXG5cdFx0Ly8gQWRkIHNlbGVjdGVkIGl0ZW1zIGxpc3Rcblx0XHR0aGlzLl9zZWxlY3RlZExpc3RIdG1sID0gJCgnPHNlbGVjdD4nLCB7XG5cdFx0XHRpZDogc2VsZWN0ZWRJZCxcblx0XHRcdGNsYXNzOiAnZHVhbC1saXN0LXJpZ2h0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHR9KTtcblx0XHR0aGlzLl93aWRnZXRIdG1sLmFwcGVuZCh0aGlzLl9zZWxlY3RlZExpc3RIdG1sKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8vIElEcyBjb250YWluaW5nIGEgXCIuXCIgY2F1c2UgaXNzdWVzIHRvIGNvbm5lY3RlZCBsaXN0c1xuXHRfZ2V0SWQobmFtZSwgc3VmZml4KVxuXHR7XG5cdFx0cmV0dXJuIG5hbWUucmVwbGFjZSgnLicsICdfJykgKyAnLScgKyBzdWZmaXg7XG5cdH1cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSB3aWRnZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2luaXRpYWxpemUoKVxuXHR7XG5cdFx0Ly8gSW5pdGlhbGl6ZSBcImF2YWxhYmxlXCIgbGlzdGJveFxuXHRcdHRoaXMuX2F2YWlsYWJsZUxpc3QgPSB0aGlzLl9hdmFpbGFibGVMaXN0SHRtbC5rZW5kb0xpc3RCb3goe1xuICAgICAgICAgICAgY29ubmVjdFdpdGg6IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyksXG4gICAgICAgICAgICB0b29sYmFyOiB7XG4gICAgICAgICAgICAgICAgdG9vbHM6IHRoaXMuX2RhdGEuZWRpdGFibGUgPyBbJ3RyYW5zZmVyVG8nLCAndHJhbnNmZXJGcm9tJywgJ3RyYW5zZmVyQWxsVG8nLCAndHJhbnNmZXJBbGxGcm9tJ10gOiBbXVxuICAgICAgICAgICAgfSxcblx0XHRcdHRlbXBsYXRlOiBcIjxkaXY+Izp2YWx1ZSM8L2Rpdj5cIixcblx0XHRcdHNlbGVjdGFibGU6ICdtdWx0aXBsZScsXG4gICAgICAgIH0pLmRhdGEoJ2tlbmRvTGlzdEJveCcpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBcInNlbGVjdGVkXCIgbGlzdGJveFxuICAgICAgICB0aGlzLl9zZWxlY3RlZExpc3QgPSB0aGlzLl9zZWxlY3RlZExpc3RIdG1sLmtlbmRvTGlzdEJveCh7XG5cdFx0XHR0ZW1wbGF0ZTogXCI8ZGl2PiM6dmFsdWUjPC9kaXY+XCIsXG5cdFx0XHRzZWxlY3RhYmxlOiAnbXVsdGlwbGUnLFxuXHRcdFx0Ly8gVGhlIGZvbGxvd2luZyBsaXN0ZW5lcnMgY2FuJ3QgYmUgdXNlZCBiZWNhdXNlIGV2ZW50cyBhcmUgZmlyZWQgYmVmb3JlIHRoZSBkYXRhc291cmNlIGlzIGFjdHVhbGx5IHVwZGF0ZWRcblx0XHRcdC8vIFdlIGhhdmUgdG8gdXNlIGEgY2hhbmdlIGV2ZW50IGxpc3RlbmVyIG9uIHRoZSBkYXRhc291cmNlIChzZWUgYmVsb3cpLCBldmVuIGlmIG5vdCBvcHRpbWFsXG5cdFx0XHQvL2FkZDogJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpLFxuXHRcdFx0Ly9yZW1vdmU6ICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSxcblx0XHR9KS5kYXRhKCdrZW5kb0xpc3RCb3gnKTtcblxuXHRcdC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHRcdHN1cGVyLl9pbml0aWFsaXplKCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRhdGFzb3VyY2UuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGxldCBhdmFpbGFibGVBcnIgPSB0aGlzLl9kYXRhLmRhdGFQcm92aWRlciAhPSAnJyA/IHRoaXMuX2RhdGEuZGF0YVByb3ZpZGVyLnNwbGl0KCcsJykgOiBbXTtcblx0XHRsZXQgc2VsZWN0ZWRBcnIgPSB0aGlzLl9kYXRhLnZhbHVlICE9ICcnID8gdGhpcy5fZGF0YS52YWx1ZS5zcGxpdCgnLCcpIDogW107XG5cblx0XHQvLyBSZW1vdmUgc2VsZWN0ZWQgdmFsdWVzIGZyb20gYXZhaWxhYmxlIHZhbHVlc1xuXHRcdGlmIChzZWxlY3RlZEFyci5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdGxldCB0ZW1wID0gW107XG5cblx0XHRcdGZvciAobGV0IHZhbCBvZiBhdmFpbGFibGVBcnIpXG5cdFx0XHR7XG5cdFx0XHRcdGlmIChzZWxlY3RlZEFyci5pbmRleE9mKHZhbCkgPT0gLTEpXG5cdFx0XHRcdFx0dGVtcC5wdXNoKHZhbCk7XG5cdFx0XHR9XG5cblx0XHRcdGF2YWlsYWJsZUFyciA9IHRlbXA7XG5cdFx0fVxuXG5cdFx0Ly8gQ29udmVydCBsaXN0cyBvZiBzdHJpbmdzIHRvIGxpc3RzIG9mIG9iamVjdHNcblx0XHRsZXQgYXZhaWxhYmxlVmFsdWVzID0gW107XG5cdFx0Zm9yIChsZXQgdmFsIG9mIGF2YWlsYWJsZUFycilcblx0XHRcdGF2YWlsYWJsZVZhbHVlcy5wdXNoKHt2YWx1ZTogdmFsfSk7XG5cblx0XHRsZXQgc2VsZWN0ZWRWYWx1ZXMgPSBbXTtcblx0XHRmb3IgKGxldCB2YWwgb2Ygc2VsZWN0ZWRBcnIpXG5cdFx0XHRzZWxlY3RlZFZhbHVlcy5wdXNoKHt2YWx1ZTogdmFsfSk7XG5cblx0XHQvLyBDbGVhciBzZWxlY3Rpb25cblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cdFx0dGhpcy5fc2VsZWN0ZWRMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cblx0XHQvLyBTZXQgZGF0YXNvdXJjZXNcblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LnNldERhdGFTb3VyY2UobmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSh7XG5cdFx0XHRkYXRhOiBhdmFpbGFibGVWYWx1ZXNcblx0XHR9KSk7XG5cblx0XHR0aGlzLl9zZWxlY3RlZExpc3Quc2V0RGF0YVNvdXJjZShuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtcblx0XHRcdGRhdGE6IHNlbGVjdGVkVmFsdWVzLFxuXHRcdFx0Ly8gV2UgbGlzdGVuIHRvIHRoZSBjaGFuZ2UgZXZlbnQgaW5zdGVhZCBvZiB0aGUgYWRkL3JlbW92ZSBldmVudHMgb24gdGhlIGxpc3Rib3gsIGJlY2F1c2UgdGhvc2UgYXJlIGZpcmVkIGJlZm9yZSB0aGUgZGF0YXNvdXJjZSBpcyB1cGRhdGVkXG5cdFx0XHQvLyBUaGlzIGlzIG5vdCBvcHRpbWFsIGJlY2F1c2UgdGhlIGV2ZW50IGlzIGZpcmVkIGZvciBlYWNoIGl0ZW0gYWRkZWQgdG8gb3IgcmVtb3ZlZCBmcm9tIHRoZSBkYXRhc291cmNlXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKVxuXHRcdH0pKTtcblxuXHRcdC8vIERpc2FibGUgZWRpdGluZ1xuXHRcdGlmICghdGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmVuYWJsZSgnLmstaXRlbScsIGZhbHNlKTtcblx0XHRcdHRoaXMuX3NlbGVjdGVkTGlzdC5lbmFibGUoJy5rLWl0ZW0nLCBmYWxzZSk7XG5cdFx0fVxuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQ2xlYXIgc2VsZWN0aW9uXG5cdFx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZExpc3QuY2xlYXJTZWxlY3Rpb24oKTtcblxuXHRcdFx0Ly8gRW5hYmxlL2Rpc2FibGUgbGlzdHNcblx0XHRcdHRoaXMuX2F2YWlsYWJsZUxpc3Qud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZExpc3Qud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB2YWx1ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfb25WYWx1ZUlucHV0KGUpXG5cdHtcblx0XHRsZXQgbGlzdERhdGEgPSB0aGlzLl9zZWxlY3RlZExpc3QuZGF0YVNvdXJjZS5kYXRhKCk7XG5cblx0XHQvLyBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdG8gbmV3IHZhbHVlXG5cdFx0dGhpcy5fZGF0YS52YWx1ZSA9IGxpc3REYXRhLm1hcChlID0+IGUudmFsdWUpLmpvaW4oJywnKTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kdWFsLWxpc3QnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLWR1YWwtbGlzdCcsIENvbmZpZ0R1YWxMaXN0KTtcbiIsImV4cG9ydCBjbGFzcyBDb25maWdGb3JtSXRlbSBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cblx0XHR0aGlzLmlkID0gJ2Zvcm0taXRlbS0nICsgY29uZmlnUGFyYW0ubmFtZTtcblx0XHR0aGlzLl9lZGl0RW5hYmxlZCA9IGVkaXRFbmFibGVkO1xuXHRcdHRoaXMuX2RhdGEgPSBjb25maWdQYXJhbTtcblxuXHRcdC8vIENyZWF0ZSBmb3JtIGl0ZW0gdmlld1xuXHRcdHRoaXMuX2J1aWxkVmlldyhpbkRpYWxvZyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGZvcm0gaXRlbVxuXHRcdHRoaXMuX2luaXRpYWxpemUoKTtcblx0fVxuXG5cdGNvbm5lY3RlZENhbGxiYWNrKClcblx0e1xuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHQvLyBOT1RFOiB3aGVuIGEgQ29uZmlnRm9ybUl0ZW0gaXMgaW5zdGFudGlhdGVkLCB0aGUgX3RyaWdnZXJFdmVudCBtZXRob2QgaXMgY2FsbGVkIGFzIHNvb24gYXMgaXRzIHZhbHVlIGlzIHNldC5cblx0XHQvLyBXaGVuIHRoaXMgaGFwcGVucywgZHVlIHRvIHRoZSBmYWN0IHRoYXQgdGhlIG9iamVjdCBpcyBub3QgeWV0IGluIHRoZSBET00sIHRoZSBldmVudCBpcyBub3QgY2F0Y2hlZCBieSB0aGUgbGlzdGVuZXJcblx0XHQvLyAod2hpY2ggaXMgYXR0YWNoZWQgdG8gdGhlIG91dGVyIGNvbnRhaW5lcikuIFNvIGZvcmNpbmcgdGhlIGV2ZW50IHRvIHRyaWdnZXIgYWdhaW4gYXMgc29vbiBhcyB0aGUgQ29uZmlnRm9ybUl0ZW1cblx0XHQvLyBpcyBhcHBlbmRlZCB0byB0aGUgRE9NIGlzIG5lZWRlZC5cblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxuXG5cdHNldCBkYXRhKGNvbmZpZ1BhcmFtKVxuXHR7XG5cdFx0dGhpcy5fZGF0YSA9IGNvbmZpZ1BhcmFtO1xuXHRcdHRoaXMuX3NldFdpZGdldFZhbHVlKCk7XG5cdH1cblxuXHRnZXQgZGF0YSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fZGF0YTtcblx0fVxuXG5cdHNldCBlZGl0RW5hYmxlZChlbmFibGUpXG5cdHtcblx0XHRpZiAoZW5hYmxlICE9IHRoaXMuX2VkaXRFbmFibGVkKVxuXHRcdHtcblx0XHRcdHRoaXMuX2VkaXRFbmFibGVkID0gZW5hYmxlO1xuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKTtcblx0XHR9XG5cdH1cblxuXHRnZXQgZWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2VkaXRFbmFibGVkO1xuXHR9XG5cblx0X2J1aWxkVmlldyhpc0luc2lkZURpYWxvZylcblx0e1xuXHRcdGlmICghaXNJbnNpZGVEaWFsb2cpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgY2xhc3NlcyBmb3IgaW5uZXIgd2lkZ2V0XG5cdFx0XHRsZXQgY2xhc3NOYW1lcyA9ICcnO1xuXG5cdFx0XHRzd2l0Y2ggKHRoaXMuX2RhdGEudHlwZSlcblx0XHRcdHtcblx0XHRcdFx0Y2FzZSAnRHVhbExpc3QnOlxuXHRcdFx0XHRcdGNsYXNzTmFtZXMgPSAnY29sLXNtLTcgY29sLWxnLTgnO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICdEYXRhR3JpZCc6XG5cdFx0XHRcdFx0Y2xhc3NOYW1lcyA9ICdjb2wtc20nOyAvLyBVc2UgJ2NvbC1zbS03IGNvbC1sZy04JyBmb3IgRGF0YUdyaWQgdG9vP1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICdUZXh0SW5wdXQnOlxuXHRcdFx0XHRcdGNsYXNzTmFtZXMgPSAnY29sLXNtIGNvbC1sZy01IGNvbC14bC00Jztcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRjbGFzc05hbWVzID0gJ2NvbC1zbS1hdXRvJztcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZW5lcmF0ZSBib2lsZXJwbGF0ZSBodG1sLCBzdXJyb3VuZGluZyB0aGUgYWN0dWFsIHdpZGdldCAobGFiZWwsIG51bWVyaWMgc3RlcHBlciwgZXRjKVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSBgXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIHBvc2l0aW9uLXJlbGF0aXZlIHJvd1wiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNSBjb2wtbGctNCBjb2wtZm9ybS1sYWJlbCBmb3JtLWxhYmVsLWNvbnRhaW5lclwiPlxuXHRcdFx0XHRcdFx0PGxhYmVsIGZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiIGNsYXNzPVwiZm9ybS1sYWJlbCAkeyh0aGlzLl9kYXRhLmNsaWVudE9ubHkgPyAnY2xpZW50LW9ubHknIDogJycpfVwiPiR7dGhpcy5fZGF0YS5sYWJlbH0gPGkgY2xhc3M9XCJmYXMgZmEtcXVlc3Rpb24tY2lyY2xlIHRleHQtbXV0ZWQgaGVscFwiIHRpdGxlPVwiJHt0aGlzLl9kYXRhLnRvb2x0aXB9XCI+PC9pPiR7KHRoaXMuX2RhdGEuaW1tZWRpYXRlID8gJzxpIGNsYXNzPVwiZmFzIGZhLWJvbHQgdGV4dC1tdXRlZCBtbC0xIGhlbHBcIiB0aXRsZT1cIlRoaXMgc2V0dGluZyBpcyBhcHBsaWVkIDxiPmltbWVkaWF0ZWx5PC9iPiBvbiBzdWJtaXQsIHdpdGhvdXQgcmVxdWlyaW5nIGEgc2VydmVyIHJlc3RhcnRcIj48L2k+JyA6ICcnKX08L2xhYmVsPlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJpbm5lci13aWRnZXQgYWxpZ24tc2VsZi1jZW50ZXIgJHtjbGFzc05hbWVzfVwiPlxuXHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJrLWludmFsaWQtbXNnXCIgZGF0YS1mb3I9XCIke3RoaXMuX2RhdGEubmFtZX1cIj48L3NwYW4+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0YDtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdHRoaXMuaW5uZXJIVE1MID0gYFxuXHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZm9ybS1ncm91cCBwb3NpdGlvbi1yZWxhdGl2ZVwiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtZm9ybS1sYWJlbCBmb3JtLWxhYmVsLWNvbnRhaW5lclwiPlxuXHRcdFx0XHRcdFx0PGxhYmVsIGZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiIGNsYXNzPVwiZm9ybS1sYWJlbCAkeyh0aGlzLl9kYXRhLmNsaWVudE9ubHkgPyAnY2xpZW50LW9ubHknIDogJycpfVwiPiR7dGhpcy5fZGF0YS5sYWJlbH0gPGkgY2xhc3M9XCJmYXMgZmEtcXVlc3Rpb24tY2lyY2xlIHRleHQtbXV0ZWQgaGVscFwiIHRpdGxlPVwiJHt0aGlzLl9kYXRhLnRvb2x0aXB9XCI+PC9pPjwvbGFiZWw+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImlubmVyLXdpZGdldFwiPlxuXHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJrLWludmFsaWQtbXNnXCIgZGF0YS1mb3I9XCIke3RoaXMuX2RhdGEubmFtZX1cIj48L3NwYW4+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0YDtcblx0XHR9XG5cblx0XHQvLyBDcmVhdGUgaW5uZXIgd2lkZ2V0IChtdXN0IGJlIG92ZXJyaWRkZW4pXG5cdFx0bGV0IHdpZGdldCA9IHRoaXMuX2dlbmVyYXRlSW5uZXJXaWRnZXQoKTtcblxuXHRcdC8vIEFwcGVuZCBpbm5lciB3aWRnZXRcblx0XHQkKHRoaXMpLmZpbmQoJy5pbm5lci13aWRnZXQnKS5wcmVwZW5kKHdpZGdldCk7XG5cdH1cblxuXHQvKipcblx0ICogVE8gQkUgT1ZFUlJJRERFTlxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0Ly8gU2hvdyBhbiBlcnJvciwgc2hvdWxkIGJlIG92ZXJyaWRkZW5cblx0XHRjb25zb2xlLmVycm9yKGBVbmFibGUgdG8gY3JlYXRlICR7dGhpcy5fZGF0YS50eXBlfSBmb3JtIGl0ZW0gZm9yIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVyICR7dGhpcy5pZH1gKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgYXR0cmlidXRlcyBvbiB0aGUgd2lkZ2V0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuXHQgKi9cblx0X3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKVxuXHR7XG5cdFx0Y29uc3QgYXR0cmlicyA9IHRoaXMuX2RhdGEuYXR0cmlidXRlcztcblxuXHRcdGlmIChhdHRyaWJzKVxuXHRcdHtcblx0XHRcdGZvciAobGV0IGF0dHIgaW4gYXR0cmlicylcblx0XHRcdHtcblx0XHRcdFx0Y29uZmlnW2F0dHJdID0gYXR0cmlic1thdHRyXTtcblxuXHRcdFx0XHRpZiAoYXR0ciA9PSAncGF0dGVybicpXG5cdFx0XHRcdFx0Y29uZmlnWydkYXRhLXBhdHRlcm4tbXNnJ10gPSAnQ29udGFpbnMgaW52YWxpZCBjaGFyYWN0ZXJzJztcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU2V0IGFkZGl0aW9uYWwgYXR0cmlidXRlcyBvbiB0aGUgd2lkZ2V0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIHByb3Blcmx5IHZhbGlkYXRlIGlucHV0LlxuXHQgKi9cblx0X3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZylcblx0e1xuXHRcdGNvbnN0IHZhbCA9IHRoaXMuX2RhdGEudmFsaWRhdG9yO1xuXG5cdFx0aWYgKHZhbCAhPSBudWxsICYmIHZhbCAhPSAnJylcblx0XHR7XG5cdFx0XHRpZiAodmFsID09ICdpcCcpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbmZpZ1sncGF0dGVybiddID0gJ14oMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KVxcLigyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pXFwuKDI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPylcXC4oMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KSQnO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtcGF0dGVybi1tc2cnXSA9ICdJbnZhbGlkIElQIGFkZHJlc3MnO1xuXHRcdFx0XHRjb25maWdbJ3JlcXVpcmVkJ10gPSB0cnVlO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtcmVxdWlyZWQtbXNnJ10gPSAnUmVxdWlyZWQnO1xuXHRcdFx0fVxuXG5cdFx0XHRlbHNlIGlmICh2YWwgPT0gJ2lwUmFuZ2UnKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbJ3BhdHRlcm4nXSA9ICdeKDI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPylcXC4oMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KVxcLigyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pXFwuKDI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPykoXFwvWzNdWzAtMl18XFwvWzEtMl0/WzAtOV0pPyQnO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtcGF0dGVybi1tc2cnXSA9ICdJbnZhbGlkIElQIGFkZHJlc3Mgb3IgcmFuZ2UnO1xuXHRcdFx0XHRjb25maWdbJ3JlcXVpcmVkJ10gPSB0cnVlO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtcmVxdWlyZWQtbXNnJ10gPSAnUmVxdWlyZWQnO1xuXHRcdFx0fVxuXG5cdFx0XHRlbHNlIGlmICh2YWwgPT0gJ25vdE51bGwnKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbJ3JlcXVpcmVkJ10gPSB0cnVlO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtcmVxdWlyZWQtbXNnJ10gPSAnUmVxdWlyZWQnO1xuXHRcdFx0fVxuXG5cdFx0XHRlbHNlIGlmICh2YWwgPT0gJ3B3ZCcpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbmZpZ1sncGF0dGVybiddID0gJ14uezYsfSQnO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtcGF0dGVybi1tc2cnXSA9ICdNaW5pbXVtIGxlbmd0aDogNiBjaGFyYWN0ZXJzJztcblx0XHRcdH1cblxuXHRcdFx0ZWxzZSBpZiAodmFsID09ICdwb3NOdW0nKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbJ3BhdHRlcm4nXSA9ICdeWzAtOV1cXGQqJCc7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1wYXR0ZXJuLW1zZyddID0gJ05vbi1uZWdhdGl2ZSBudW1iZXIgcmVxdWlyZWQnO1xuXHRcdFx0fVxuXG5cdFx0XHRlbHNlIGlmICh2YWwgPT0gJ2FvaScpXG5cdFx0XHR7XG5cdFx0XHRcdC8vIE5vdGhpbmcgdG8gZG9cblx0XHRcdFx0Ly8gU2VlIEtlbmRvIHZhbGlkYXRpb24gaW5pdGlhbGl6YXRpb24gaW4gY29uZmlnLWludGVyZmFjZS1idWlsZGVyLmpzXG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAndXJsJylcblx0XHRcdHtcblx0XHRcdFx0Y29uZmlnWyd0eXBlJ10gPSAndXJsJztcblx0XHRcdFx0Y29uZmlnWydkYXRhLXVybC1tc2cnXSA9ICdJbnZhbGlkIFVSTCc7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgZm9ybSBpdGVtLlxuXHQgKlxuXHQgKiBOT1RFOiBtdXN0IGJlIG92ZXJyaWRkZW4gaWYgaW5uZXIgd2lkZ2V0IHJlcXVpcmVzIHNwZWNpYWwgaW5pdGlhbGl6YXRpb24gKGZvciBleGFtcGxlIEtlbmRvIHdpZGdldHMpXG5cdCAqL1xuXHRfaW5pdGlhbGl6ZSgpXG5cdHtcblx0XHQvLyBTZXQgdmFsdWVcbiBcdCAgIHRoaXMuX3NldFdpZGdldFZhbHVlKCk7XG5cbiBcdCAgIC8vIFNldCBlZGl0IGVuYWJsZWRcbiBcdCAgIHRoaXMuX3NldFdpZGdldEVkaXRFbmFibGVkKCk7XG5cdH1cblxuXHQvKipcblx0ICogVE8gQkUgT1ZFUlJJRERFTlxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdC8vIE5vdGhpbmcgdG8gZG8sIG11c3QgYmUgb3ZlcnJpZGRlblxuXHR9XG5cblx0LyoqXG5cdCAqIFRPIEJFIE9WRVJSSURERU5cblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHQvLyBOb3RoaW5nIHRvIGRvLCBtdXN0IGJlIG92ZXJyaWRkZW5cblx0fVxuXG5cdC8qKlxuXHQgKiBUTyBCRSBPVkVSUklEREVOXG5cdCAqL1xuXHRfb25WYWx1ZUlucHV0KGUpXG5cdHtcblx0XHQvLyBOb3RoaW5nIHRvIGRvLCBtdXN0IGJlIG92ZXJyaWRkZW5cblx0fVxuXG5cdF90cmlnZ2VyRXZlbnQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEudHJpZ2dlcilcblx0XHR7XG5cdFx0XHRsZXQgZXZlbnQgPSBuZXcgQ3VzdG9tRXZlbnQoJ3ZhbHVlLXNldCcsIHtkZXRhaWw6IG51bGwsIGJ1YmJsZXM6IHRydWUsIGNhbmNlbGFibGU6IHRydWV9KTtcblx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG5cdFx0fVxuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLWZvcm0taXRlbScpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZm9ybS1pdGVtJywgQ29uZmlnRm9ybUl0ZW0pO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcbmltcG9ydCB7TGlzdEl0ZW1FZGl0b3J9IGZyb20gJy4vd2lkZ2V0cy9saXN0LWl0ZW0tZWRpdG9yJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0dyaWQgZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdC8vIENyZWF0ZSBtYWluIHdpZGdldCdzIGh0bWxcblx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICcnfSk7XG5cblx0XHQvLyBTZXQgZ3JpZCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdGxldCBncmlkQ29uZmlnID0ge1xuXHRcdFx0aWQ6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdG5hbWU6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdGNsYXNzOiAnbGltaXRlZC1oZWlnaHQnICsgKCF0aGlzLl9kYXRhLmVkaXRhYmxlID8gJyBuby1pbnRlcmFjdCcgOiAnJylcblx0XHR9O1xuXG5cdFx0Ly8gQXBwZW5kIGdyaWQgdG8gbWFpbiBodG1sOyBncmlkIHdpbGwgYmUgY29udmVydGVkIHRvIEtlbmRvIHdpZGdldCBkdXJpbmcgaW5pdGlhbGl6YXRpb25cblx0XHR0aGlzLl93aWRnZXRIdG1sLmFwcGVuZCgkKCc8ZGl2PicsIGdyaWRDb25maWcpKTtcblxuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIEJVVFRPTlNcblxuXHRcdFx0Ly8gQ3JlYXRlIGJ1dHRvbnMgY29udGFpbmVyXG5cdFx0XHRsZXQgYnV0dG9ucyA9ICQoJzxkaXY+Jywge2NsYXNzOiAnbXQtMiB0ZXh0LXJpZ2h0J30pO1xuXG5cdFx0XHQvLyBBcHBlbmQgYnV0dG9ucyB0byBjb250YWluZXJcblx0XHRcdHRoaXMuX2FkZEJ1dHRvbiA9ICQoJzxidXR0b24+Jywge3R5cGU6ICdidXR0b24nLCBjbGFzczogJ2stYnV0dG9uIGstc2Vjb25kYXJ5JywgdGl0bGU6ICdBZGQnfSkuYXBwZW5kKCQoJzxpIGNsYXNzPVwiZmFzIGZhLXBsdXNcIj48L2k+JykpO1xuXHRcdFx0dGhpcy5fZWRpdEJ1dHRvbiA9ICQoJzxidXR0b24+Jywge3R5cGU6ICdidXR0b24nLCBjbGFzczogJ2stYnV0dG9uIGstc2Vjb25kYXJ5IG1sLTInLCB0aXRsZTogJ0VkaXQnLCBkaXNhYmxlZDogdHJ1ZX0pLmFwcGVuZCgkKCc8aSBjbGFzcz1cImZhcyBmYS1wZW5cIj48L2k+JykpO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQnV0dG9uID0gJCgnPGJ1dHRvbj4nLCB7dHlwZTogJ2J1dHRvbicsIGNsYXNzOiAnay1idXR0b24gay1zZWNvbmRhcnkgbWwtMicsIHRpdGxlOiAnUmVtb3ZlJywgZGlzYWJsZWQ6IHRydWV9KS5hcHBlbmQoJCgnPGkgY2xhc3M9XCJmYXMgZmEtdGltZXNcIj48L2k+JykpO1xuXG5cdFx0XHRidXR0b25zLmFwcGVuZCh0aGlzLl9hZGRCdXR0b24pO1xuXHRcdFx0YnV0dG9ucy5hcHBlbmQodGhpcy5fZWRpdEJ1dHRvbik7XG5cdFx0XHRidXR0b25zLmFwcGVuZCh0aGlzLl9yZW1vdmVCdXR0b24pO1xuXG5cdFx0XHQvLyBBcHBlbmQgYnV0dG9ucyBjb250YWluZXIgdG8gbWFpbiBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLmFwcGVuZChidXR0b25zKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIGVkaXQgZGlhbG9nXG5cdFx0XHQvLyBOT1RFOiBkYXRhLWRpc21pc3M9XCJtb2RhbFwiIG9uIHRoZSBjbG9zZS9jYW5jZWwgYnV0dG9ucyB3YXMgcmVtb3ZlZCB0byB3b3JrIGFyb3VuZCBhbiBpc3N1ZSB3aXRoIG5lc3RlZCBtb2RhbHM7XG5cdFx0XHQvLyB0aGUgY3VzdG9tIFwiZGF0YS1jYW5jZWxcIiBhdHRyaWJ1dGUgaXMgdXNlZCB0byBhZGQgYSBjdXN0b20gbGlzdGVuZXIgdG8gdGhlIGJ1dHRvbnNcblx0XHRcdHRoaXMuX2VkaXREaWFsb2cgPSAkKGBcblx0XHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsXCIgdGFiaW5kZXg9XCItMVwiIHJvbGU9XCJkaWFsb2dcIiBhcmlhLWxhYmVsbGVkYnk9XCJtb2RhbFRpdGxlXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgZGF0YS1rZXlib2FyZD1cImZhbHNlXCIgZGF0YS1iYWNrZHJvcD1cInN0YXRpY1wiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1kaWFsb2cgbW9kYWwtZGlhbG9nLWNlbnRlcmVkXCIgcm9sZT1cImRvY3VtZW50XCI+XG5cdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWwtY29udGVudFwiPlxuXHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWwtaGVhZGVyXCI+XG5cdFx0XHRcdFx0XHRcdFx0PGg1IGNsYXNzPVwibW9kYWwtdGl0bGUgdGV4dC1wcmltYXJ5XCIgaWQ9XCJtb2RhbFRpdGxlXCI+JHt0aGlzLl9kYXRhLmxhYmVsfTwvaDU+XG5cdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJjbG9zZVwiIGFyaWEtbGFiZWw9XCJDbG9zZVwiIGRhdGEtY2FuY2VsPVwibW9kYWxcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxzcGFuIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPiZ0aW1lczs8L3NwYW4+XG5cdFx0XHRcdFx0XHRcdFx0PC9idXR0b24+XG5cdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWwtYm9keSBpbi1mbG93LWludmFsaWQtbXNnXCI+XG5cblx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXIgZmxleC1jb2x1bW5cIj5cblx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZC1mbGV4IHctMTAwXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZmxleC1ncm93LTEgdGV4dC1sZWZ0XCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiay1idXR0b24gay1wcmltYXJ5XCI+Li4uPC9idXR0b24+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmbGV4LWdyb3ctMSB0ZXh0LXJpZ2h0XCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiay1idXR0b24gay1zZWNvbmRhcnlcIiBkYXRhLWNhbmNlbD1cIm1vZGFsXCI+Q2FuY2VsPC9idXR0b24+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHRgKTtcblxuXHRcdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIGRpYWxvZyBoaWRlIGV2ZW50XG5cdFx0XHR0aGlzLl9lZGl0RGlhbG9nLm9uKCdoaWRkZW4uYnMubW9kYWwnLCAkLnByb3h5KHRoaXMuX29uRWRpdFBhbmVsSGlkZGVuLCB0aGlzKSk7XG5cblx0XHRcdC8vIEFkZCBsaXN0ZW5lciB0byBtYWluIGJ1dHRvbiBjbGljayBldmVudFxuXHRcdFx0JCgnYnV0dG9uLmstcHJpbWFyeScsIHRoaXMuX2VkaXREaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25TdWJtaXRCdENsaWNrLCB0aGlzKSk7XG5cblx0XHRcdC8vIEFkZCBsaXN0ZW5lciB0byBjbG9zZS9jYW5jZWwgYnV0dG9ucyBjbGljayBldmVudFxuXHRcdFx0JCgnYnV0dG9uW2RhdGEtY2FuY2VsPVwibW9kYWxcIl0nLCB0aGlzLl9lZGl0RGlhbG9nKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uQ2FuY2VsQnRDbGljaywgdGhpcykpO1xuXG5cdFx0XHQvLyBBcHBlbmQgZWRpdCBkaWFsb2cgdG8gbWFpbiBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLmFwcGVuZCh0aGlzLl9lZGl0RGlhbG9nKTtcblx0XHR9XG5cblx0XHQvLyBSZXR1cm4gY29tcG9uZW50XG5cdFx0cmV0dXJuIHRoaXMuX3dpZGdldEh0bWw7XG5cdH1cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSB3aWRnZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2luaXRpYWxpemUoKVxuXHR7XG5cdFx0bGV0IGNvbHVtbnMgPSBbXTtcblx0XHRmb3IgKGxldCBzdWJDb25maWdQYXJhbSBvZiB0aGlzLl9kYXRhLmRlZmF1bHRMaXN0SXRlbSlcblx0XHR7XG5cdFx0XHRsZXQgY29sID0ge1xuXHRcdFx0XHRmaWVsZDogc3ViQ29uZmlnUGFyYW0ubmFtZSxcblx0XHRcdFx0dGl0bGU6IHN1YkNvbmZpZ1BhcmFtLmxhYmVsLFxuXHRcdFx0XHR3aWR0aDogMTIwXG5cdFx0XHR9XG5cblx0XHRcdC8vIERpc3BsYXkgViBvciBYIGZvciBib29sZWFuc1xuXHRcdFx0aWYgKHR5cGVvZiBzdWJDb25maWdQYXJhbS52YWx1ZSA9PT0gJ2Jvb2xlYW4nKVxuXHRcdFx0XHRjb2wudGVtcGxhdGUgPSBgIz0gJHtzdWJDb25maWdQYXJhbS5uYW1lfSA/ICc8aSBjbGFzcz1cImZhcyBmYS1jaGVja1wiPjwvaT4nIDogJzxpIGNsYXNzPVwiZmFzIGZhLXRpbWVzXCI+PC9pPicgI2A7XG5cblx0XHRcdC8vIEhpZGUgcGFzc3dvcmRzXG5cdFx0XHRpZiAoc3ViQ29uZmlnUGFyYW0udHlwZSA9PSAnVGV4dElucHV0JyAmJiBzdWJDb25maWdQYXJhbS5hdHRyaWJ1dGVzICE9IG51bGwgJiYgc3ViQ29uZmlnUGFyYW0uYXR0cmlidXRlcy50eXBlID09ICdwYXNzd29yZCcpXG5cdFx0XHRcdGNvbC50ZW1wbGF0ZSA9IGAjPSAn4oCiJy5yZXBlYXQoZGF0YS4ke3N1YkNvbmZpZ1BhcmFtLm5hbWV9Lmxlbmd0aCkgI2A7XG5cblx0XHRcdGNvbHVtbnMucHVzaChjb2wpO1xuXHRcdH1cblxuXHRcdC8vIEluaXRpYWxpemUgZ3JpZFxuXHRcdGxldCBncmlkSHRtbCA9IHRoaXMuX3dpZGdldEh0bWwuZmluZChgIyR7JC5lc2NhcGVTZWxlY3Rvcih0aGlzLl9kYXRhLm5hbWUpfWApO1xuXG5cdFx0Z3JpZEh0bWwua2VuZG9HcmlkKHtcblx0XHRcdHJlc2l6YWJsZTogdHJ1ZSxcblx0XHRcdHNlbGVjdGFibGU6IHRoaXMuX2RhdGEuZWRpdGFibGUgPyAncm93JyA6IGZhbHNlLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uR3JpZFNlbGVjdGlvbkNoYW5nZSwgdGhpcyksXG5cdFx0XHRjb2x1bW5zOiBjb2x1bW5zLFxuXHRcdFx0bm9SZWNvcmRzOiB7XG5cdFx0XHRcdHRlbXBsYXRlOiAnTm8gaXRlbXMuJ1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdHRoaXMuX2dyaWRXaWRnZXQgPSBncmlkSHRtbC5kYXRhKCdrZW5kb0dyaWQnKTtcblxuXHRcdC8vIFNob3cgdG9vdGlwIGlmIGdyaWQncyBjZWxsIGNvbnRlbnQgZXhjZWVkcyBjZWxsIHdpZHRoIChlbGxpcHNpcyBpcyBkaXNwbGF5ZWQgYnkgS2VuZG8gR3JpZClcblx0XHRncmlkSHRtbC5rZW5kb1Rvb2x0aXAoe1xuXHRcdFx0ZmlsdGVyOiAndGQnLFxuXHRcdFx0c2hvdzogZnVuY3Rpb24oZSkge1xuXHRcdFx0XHQvLyBOZXZlciBzaG93IHRvb2x0aXAuLi5cblx0XHRcdFx0dGhpcy5jb250ZW50LnBhcmVudCgpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcblxuXHRcdFx0XHQvLyAuLi51bmxlc3MgY29udGVudCBpcyByZXR1cm5lZCAoc2VlIGJlbG93KSBkdWUgdG8gY2VsbCB3aWR0aCBiZWluZyBleGNlZWRlZFxuXHRcdFx0XHRpZiAodGhpcy5jb250ZW50LnRleHQoKSAhPSAnJylcblx0XHRcdFx0XHR0aGlzLmNvbnRlbnQucGFyZW50KCkuY3NzKCd2aXNpYmlsaXR5JywgJ3Zpc2libGUnKTtcblx0XHRcdH0sXG5cdFx0XHRoaWRlOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5jb250ZW50LnBhcmVudCgpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcblx0XHRcdH0sXG5cdFx0XHRjb250ZW50OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdGxldCBlbGVtZW50ID0gZS50YXJnZXRbMF07XG5cdFx0XHRcdGlmIChlbGVtZW50Lm9mZnNldFdpZHRoIDwgZWxlbWVudC5zY3JvbGxXaWR0aClcblx0XHRcdFx0XHRyZXR1cm4gZS50YXJnZXQudGV4dCgpO1xuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0cmV0dXJuICcnO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Lypcblx0XHQvLyBJbml0aWFsaXplIGJ1dHRvbiB0b29sdGlwc1xuXHRcdHRoaXMuX3dpZGdldEh0bWwua2VuZG9Ub29sdGlwKHtcblx0XHRcdGZpbHRlcjogJ2J1dHRvbicsXG5cdFx0XHRjb250ZW50OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdHJldHVybiBgPGRpdiBjbGFzcz1cImhlbHAtdG9vbHRpcFwiPiR7ZS50YXJnZXQuZGF0YSgndGl0bGUnKX08L2Rpdj5gO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdCovXG5cblx0XHQvLyBBZGQgYnV0dG9uIGxpc3RlbmVyc1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdHRoaXMuX2FkZEJ1dHRvbi5jbGljaygkLnByb3h5KHRoaXMuX29uQWRkQ2xpY2ssIHRoaXMpKTtcblx0XHRcdHRoaXMuX2VkaXRCdXR0b24uY2xpY2soJC5wcm94eSh0aGlzLl9vbkVkaXRDbGljaywgdGhpcykpO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQnV0dG9uLmNsaWNrKCQucHJveHkodGhpcy5fb25SZW1vdmVDbGljaywgdGhpcykpO1xuXHRcdH1cblxuXHRcdC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHRcdHN1cGVyLl9pbml0aWFsaXplKCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRhdGFzb3VyY2UuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGxldCBkYXRhU291cmNlID0gbmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSh7XG5cdFx0XHRkYXRhOiB0aGlzLl9kYXRhLmxpc3RWYWx1ZXNcblx0XHR9KTtcblxuXHRcdC8vIFJlYWQgY3VycmVudCBob3Jpem9udGFsIHNjcm9sbCB2YWx1ZVxuXHRcdGNvbnN0IHNjcm9sbExlZnQgPSAkKCcuay1ncmlkLWNvbnRlbnQnLCB0aGlzLl9ncmlkV2lkZ2V0LndyYXBwZXIpLnNjcm9sbExlZnQoKTtcblxuXHRcdC8vIENsZWFyIGdyaWQgc2VsZWN0aW9uIGlmIGFueVxuXHRcdHRoaXMuX2dyaWRXaWRnZXQuY2xlYXJTZWxlY3Rpb24oKTtcblxuXHRcdC8vIFNldCB1cGRhdGVkIGdyaWQncyBkYXRhc291cmNlXG5cdFx0dGhpcy5fZ3JpZFdpZGdldC5zZXREYXRhU291cmNlKGRhdGFTb3VyY2UpO1xuXG5cdFx0Ly8gU2V0IGhvcml6b250YWwgc2Nyb2xsXG5cdFx0JCgnLmstZ3JpZC1jb250ZW50JywgdGhpcy5fZ3JpZFdpZGdldC53cmFwcGVyKS5zY3JvbGxMZWZ0KHNjcm9sbExlZnQpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gRGVzZWxlY3QgaXRlbVxuXHRcdFx0dGhpcy5fZ3JpZFdpZGdldC5jbGVhclNlbGVjdGlvbigpO1xuXG5cdFx0XHQvLyBFbmFibGUvZGlzYWJsZSBncmlkXG5cdFx0XHR0aGlzLl9ncmlkV2lkZ2V0LndyYXBwZXIuYXR0cignZGlzYWJsZWQnLCAhdGhpcy5fZWRpdEVuYWJsZWQpO1xuXG5cdFx0XHQvLyBFbmFibGUgXCJBZGRcIiBidXR0b25cblx0XHRcdGlmICh0aGlzLl9lZGl0RW5hYmxlZClcblx0XHRcdFx0dGhpcy5fYWRkQnV0dG9uLmF0dHIoJ2Rpc2FibGVkJywgZmFsc2UpO1xuXG5cdFx0XHQvLyBEaXNhYmxlIGFsbCBidXR0b25zXG5cdFx0XHRlbHNlXG5cdFx0XHR7XG5cdFx0XHRcdHRoaXMuX2FkZEJ1dHRvbi5hdHRyKCdkaXNhYmxlZCcsIHRydWUpO1xuXHRcdFx0XHR0aGlzLl9lZGl0QnV0dG9uLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUJ1dHRvbi5hdHRyKCdkaXNhYmxlZCcsIHRydWUpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdF9vbkdyaWRTZWxlY3Rpb25DaGFuZ2UoZSlcblx0e1xuXHRcdGxldCBzZWxlY3RlZFJvd3MgPSB0aGlzLl9ncmlkV2lkZ2V0LnNlbGVjdCgpO1xuXHRcdGxldCBzZWxlY3RlZERhdGFJdGVtcyA9IFtdO1xuXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBzZWxlY3RlZFJvd3MubGVuZ3RoOyBpKyspXG5cdFx0e1xuXHRcdFx0bGV0IGRhdGFJdGVtID0gdGhpcy5fZ3JpZFdpZGdldC5kYXRhSXRlbShzZWxlY3RlZFJvd3NbaV0pO1xuXHRcdFx0c2VsZWN0ZWREYXRhSXRlbXMucHVzaChkYXRhSXRlbSk7XG5cdFx0fVxuXG5cdFx0Ly8gRW5hYmxlL2Rpc2FibGUgZWRpdCBidXR0b25cblx0XHRpZiAodGhpcy5fZWRpdEJ1dHRvbilcblx0XHRcdHRoaXMuX2VkaXRCdXR0b24ucHJvcCgnZGlzYWJsZWQnLCBzZWxlY3RlZERhdGFJdGVtcy5sZW5ndGggPT0gMCk7XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSByZW1vdmUgYnV0dG9uXG5cdFx0aWYgKHRoaXMuX3JlbW92ZUJ1dHRvbilcblx0XHR7XG5cdFx0XHQvLyBBbHdheXMgZGlzYWJsZSBidXR0b24gaWYgbm8gbGlzdCBpdGVtIGlzIHNlbGVjdGVkXG5cdFx0XHR0aGlzLl9yZW1vdmVCdXR0b24ucHJvcCgnZGlzYWJsZWQnLCBzZWxlY3RlZERhdGFJdGVtcy5sZW5ndGggPT0gMCk7XG5cblx0XHRcdC8vIEFsc28gZGlzYWJsZSBidXR0b24gaWYgZGVueUVtcHR5ID09IHRydWUgYW5kIGp1c3Qgb25lIGl0ZW0gcmVtYWlucyBpbiB0aGUgbGlzdFxuXHRcdFx0aWYgKHRoaXMuX2RhdGEuZGVueUVtcHR5KVxuXHRcdFx0XHR0aGlzLl9yZW1vdmVCdXR0b24ucHJvcCgnZGlzYWJsZWQnLCB0aGlzLl9kYXRhLmxpc3RJdGVtcy5sZW5ndGggPD0gMSk7XG5cdFx0fVxuICAgIH1cblxuXHRfb25SZW1vdmVDbGljaygpXG5cdHtcblx0XHRsZXQgc2VsZWN0ZWRJbmRleCA9IHRoaXMuX2dyaWRXaWRnZXQuc2VsZWN0KCkuaW5kZXgoKTtcblxuXHRcdC8vIFJlbW92ZSBpdGVtIGZyb20gbGlzdFxuXHRcdHRoaXMuX2RhdGEucmVtb3ZlTGlzdEl0ZW0oc2VsZWN0ZWRJbmRleCk7XG5cblx0XHQvLyBSZWdlbmVyYXRlIGRhdGFncmlkJ3MgZGF0YXNvdXJjZVxuXHRcdHRoaXMuX3NldFdpZGdldFZhbHVlKCk7XG5cdH1cblxuXHRfb25BZGRDbGljaygpXG5cdHtcblx0XHQvLyBDbG9uZSBkZWZhdWx0IGl0ZW0gYW5kIGFkZCB0byBsaXN0XG5cdFx0bGV0IG5ld0xpc3RJdGVtID0gW107XG5cdFx0Zm9yIChsZXQgc3ViQ1Agb2YgdGhpcy5fZGF0YS5kZWZhdWx0TGlzdEl0ZW0pXG5cdFx0XHRuZXdMaXN0SXRlbS5wdXNoKHN1YkNQLmNsb25lKHRydWUpKTtcblxuXHRcdC8vIENyZWF0ZSBlZGl0IHBvcHVwXG5cdFx0dGhpcy5fb3BlbkVkaXRQYW5lbChuZXdMaXN0SXRlbSk7XG5cdH1cblxuXHRfb25FZGl0Q2xpY2soKVxuXHR7XG5cdFx0bGV0IHNlbGVjdGVkSW5kZXggPSB0aGlzLl9ncmlkV2lkZ2V0LnNlbGVjdCgpLmluZGV4KCk7XG5cblx0XHQvLyBDbG9uZSBzZWxlY3RlZCBpdGVtIGFuZCBhZGQgdG8gbGlzdFxuXHRcdGxldCBjbG9uZWRMaXN0SXRlbSA9IFtdO1xuXHRcdGZvciAobGV0IHN1YkNQIG9mIHRoaXMuX2RhdGEubGlzdEl0ZW1zW3NlbGVjdGVkSW5kZXhdKVxuXHRcdFx0Y2xvbmVkTGlzdEl0ZW0ucHVzaChzdWJDUC5jbG9uZSh0cnVlKSk7XG5cblx0XHQvLyBDcmVhdGUgZWRpdCBwb3B1cFxuXHRcdHRoaXMuX29wZW5FZGl0UGFuZWwoY2xvbmVkTGlzdEl0ZW0sIHNlbGVjdGVkSW5kZXgpO1xuXHR9XG5cblx0X29wZW5FZGl0UGFuZWwoc3ViQ29uZmlnUGFyYW1zQXJyYXksIGVkaXRJbmRleCA9IC0xKVxuXHR7XG5cdFx0Ly8gQ2hlY2sgaWYgdGhpcyBjb25maWd1cmF0aW9uIGl0ZW0gaXMgaW5zaWRlIGEgbW9kYWwgd2luZG93O1xuXHRcdC8vIGlmIHllcywgdGhlIGVkaXQgcGFuZWwgKHdoaWNoIGlzIGEgbW9kYWwgYXMgd2VsbCkgbXVzdCBiZSBjb25maWd1cmVkIHRvIHJlbW92ZSB0aGUgZGFyayBiYWNrZ3JvdW5kXG5cdFx0aWYgKCQodGhpcykucGFyZW50cygnLm1vZGFsJykubGVuZ3RoID4gMClcblx0XHRcdCQoJy5tb2RhbCcsICQodGhpcykpLmF0dHIoJ2RhdGEtYmFja2Ryb3AnLCBmYWxzZSk7XG5cblx0XHQvLyBDcmVhdGUgZGlhbG9nIGNvbnRlbnRcblx0XHR0aGlzLl9pdGVtRWRpdG9yID0gbmV3IExpc3RJdGVtRWRpdG9yKCk7XG5cdFx0dGhpcy5faXRlbUVkaXRvci5kYXRhID0gc3ViQ29uZmlnUGFyYW1zQXJyYXk7XG5cdFx0dGhpcy5faXRlbUVkaXRvci5pbmRleCA9IGVkaXRJbmRleDtcblxuXHRcdGxldCBpdGVtRWRpdG9yID0gJCh0aGlzLl9pdGVtRWRpdG9yKTtcblxuXHRcdC8vIEFwcGVuZCBjb250ZW50IHRvIGRpYWxvZ1xuXHRcdCQoJy5tb2RhbC1ib2R5JywgdGhpcy5fZWRpdERpYWxvZykuYXBwZW5kKGl0ZW1FZGl0b3IpO1xuXG5cdFx0Ly8gU2V0IGRpYWxvZyBtYWluIGJ1dHRvbiB0ZXh0XG5cdFx0JCgnYnV0dG9uLmstcHJpbWFyeScsIHRoaXMuX2VkaXREaWFsb2cpLmh0bWwoZWRpdEluZGV4ID4gLTEgPyAnPGkgY2xhc3M9XCJmYXMgZmEtcGVuIG1yLTFcIj48L2k+VXBkYXRlJyA6ICc8aSBjbGFzcz1cImZhcyBmYS1wbHVzIG1yLTFcIj48L2k+QWRkJyk7XG5cblx0XHQvLyBEaXNwbGF5IGRpYWxvZ1xuXHRcdHRoaXMuX2VkaXREaWFsb2cubW9kYWwoJ3Nob3cnKTtcblx0fVxuXG5cdF9vblN1Ym1pdEJ0Q2xpY2soKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2l0ZW1FZGl0b3IudmFsaWRhdGUoKSlcblx0XHR7XG5cdFx0XHRsZXQgZGF0YSA9IHRoaXMuX2l0ZW1FZGl0b3IuZGF0YTtcblx0XHRcdGxldCBpbmRleCA9IHRoaXMuX2l0ZW1FZGl0b3IuaW5kZXg7XG5cblx0XHRcdC8vIEhpZGUgbW9kYWxcblx0XHRcdHRoaXMuX2VkaXREaWFsb2cubW9kYWwoJ2hpZGUnKTtcblxuXHRcdFx0Ly8gQ29tcGxldGUgZWRpdGluZ1xuXHRcdFx0dGhpcy5fb25FZGl0Q29tcGxldGUoZGF0YSwgaW5kZXgpO1xuXHRcdH1cblx0fVxuXG5cdF9vbkNhbmNlbEJ0Q2xpY2soKVxuXHR7XG5cdFx0Ly8gSGlkZSBtb2RhbFxuXHRcdHRoaXMuX2VkaXREaWFsb2cubW9kYWwoJ2hpZGUnKTtcblx0fVxuXG5cdF9vbkVkaXRQYW5lbEhpZGRlbihlKVxuXHR7XG5cdFx0Ly8gUmVtb3ZlIGNvbnRlbnQgZnJvbSBkaWFsb2dcblx0XHR0aGlzLl9pdGVtRWRpdG9yLnJlbW92ZSgpO1xuXG5cdFx0Ly8gU2V0IGRpYWxvZyBtYWluIGJ1dHRvbiB0ZXh0XG5cdFx0JCgnYnV0dG9uLmstcHJpbWFyeScsIHRoaXMuX2VkaXREaWFsb2cpLmh0bWwoJy4uLicpO1xuXG5cdFx0dGhpcy5faXRlbUVkaXRvciA9IG51bGw7XG5cdH1cblxuXHRfb25FZGl0Q29tcGxldGUobGlzdEl0ZW0sIGVkaXRJbmRleClcblx0e1xuXHRcdC8vIEFuIGV4aXN0aW5nIGxpc3QgaXRlbSB3YXMgdXBkYXRlZFxuXHRcdGlmIChlZGl0SW5kZXggPiAtMSlcblx0XHRcdHRoaXMuX2RhdGEudXBkYXRlTGlzdEl0ZW0obGlzdEl0ZW0sIGVkaXRJbmRleCk7XG5cblx0XHQvLyBBIG5ldyBsaXN0IGl0ZW0gd2FzIGFkZGVkOyBhZGQgaXQgdG8gdGhlIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVyXG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fZGF0YS5hZGRMaXN0SXRlbShsaXN0SXRlbSk7XG5cblx0XHQvLyBSZWdlbmVyYXRlIGRhdGFncmlkJ3MgZGF0YXNvdXJjZVxuXHRcdHRoaXMuX3NldFdpZGdldFZhbHVlKCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctZ3JpZCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZ3JpZCcsIENvbmZpZ0dyaWQpO1xuIiwiZXhwb3J0IGNsYXNzIENvbmZpZ0xhYmVsIGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywnY29uZmlnLWxhYmVsJyk7XG5cdH1cblxuXHRzZXQgdmFsdWUodmFsKVxuXHR7XG5cdFx0aWYgKHR5cGVvZiB2YWwgPT09ICdib29sZWFuJylcblx0XHRcdHRoaXMuaW5uZXJIVE1MID0gKHZhbCA/ICd0cnVlJyA6ICdmYWxzZScpO1xuXHRcdGVsc2UgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSAodmFsID8gdmFsIDogMCk7XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSAodmFsICE9ICcnID8gdmFsIDogJyZtZGFzaDsnKTtcblx0fVxuXG5cdGdldCB2YWx1ZSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy50ZXh0Q29udGVudDtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1sYWJlbCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctbGFiZWwnLCBDb25maWdMYWJlbCk7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnTnVtZXJpY1N0ZXBwZXIgZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0dHlwZTogJ251bWJlcicsXG5cdFx0XHRcdGNsYXNzOiAnZm9ybS1jb250cm9sJyxcblx0XHRcdFx0aWQ6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0bmFtZTogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHQnZGF0YS1yb2xlJzogJ251bWVyaWN0ZXh0Ym94Jyxcblx0XHRcdFx0J2RhdGEtcmVxdWlyZWQtbXNnJzogJ1JlcXVpcmVkJyxcblx0XHRcdFx0J2RhdGEtZm9ybWF0JzogJyMnLFxuXHRcdFx0XHRyZXF1aXJlZDogJ3JlcXVpcmVkJyxcblx0XHRcdH07XG5cblx0XHRcdC8vIFNldCB3aWRnZXQgYXR0cmlidXRlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuICAgX2luaXRpYWxpemUoKVxuICAge1xuXHQgICBpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0ICAge1xuXHRcdCAgIC8vIEluaXRpYWxpemUga2VuZG8gd2lkZ2V0XG5cdFx0ICAga2VuZG8uaW5pdCh0aGlzLl93aWRnZXRIdG1sKTtcblxuXHRcdCAgIC8vIFNhdmUgcmVmLiB0byB3aWRnZXRcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldCA9IHRoaXMuX3dpZGdldEh0bWwuZGF0YSgna2VuZG9OdW1lcmljVGV4dEJveCcpO1xuXG5cdFx0ICAgLy8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0ICAgdGhpcy5faW5uZXJXaWRnZXQuYmluZCgnY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0ICAgfVxuXG5cdCAgIC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHQgICBzdXBlci5faW5pdGlhbGl6ZSgpO1xuICAgfVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIHRoZSBsYWJlbCB0ZXh0IGlzIHNldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC52YWx1ZSh0aGlzLl9kYXRhLnZhbHVlKTtcblx0XHRlbHNlXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLnZhbHVlID0gdGhpcy5fZGF0YS52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGlzYWJsZWQgc3RhdGUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQuZW5hYmxlKHRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSBOdW1iZXIodGhpcy5faW5uZXJXaWRnZXQudmFsdWUoKSk7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctbnVtZXJpYy1zdGVwcGVyJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2NvbmZpZy1udW1lcmljLXN0ZXBwZXInLCBDb25maWdOdW1lcmljU3RlcHBlcik7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnVGV4dElucHV0IGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlciB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgYSBzaW1wbGUgbGFiZWwgaXMgdXNlZC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBTZXQgd2lkZ2V0IGNvbmZpZ3VyYXRpb25cblx0XHRcdGxldCBjb25maWcgPSB7XG5cdFx0XHRcdHR5cGU6ICd0ZXh0Jyxcblx0XHRcdFx0Y2xhc3M6ICdmb3JtLWNvbnRyb2wgay10ZXh0Ym94Jyxcblx0XHRcdFx0aWQ6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0bmFtZTogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRhdXRvY29tcGxldGU6ICdvZmYnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzXG5cdFx0XHR0aGlzLl9zZXRXaWRnZXRBdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIFNldCBhZGRpdGlvbmFsIHdpZGdldCBhdHRyaWJ1dGVzIGJhc2VkIG9uIHZhbGlkYXRpb24gcnVsZXNcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cblx0XHRcdC8vIEVuYWJsZSB2YWx1ZSBjb21taXQgYmluZGluZ1xuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbC5vbignY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl93aWRnZXRIdG1sLnZhbCgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLXRleHQtaW5wdXQnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLXRleHQtaW5wdXQnLCBDb25maWdUZXh0SW5wdXQpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcbmltcG9ydCB7VmVjdG9yM0RJbnB1dH0gZnJvbSAnLi93aWRnZXRzL3ZlY3Rvci0zZC1pbnB1dCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdWZWN0b3IzRCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgVmVjdG9yM0RJbnB1dCh0aGlzLl9kYXRhLm5hbWUsIHRoaXMuX2RhdGEudmFsaWRhdG9yID09ICdhb2knKTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzXG5cdFx0XHR0aGlzLl9zZXRXaWRnZXRBdHRyaWJ1dGVzKHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0XHQvLyBFbmFibGUgdmFsdWUgY29tbWl0IGJpbmRpbmdcblx0XHRcdCQodGhpcy5fd2lkZ2V0SHRtbCkub24oJ2NoYW5nZScsICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIHRoZSBsYWJlbCB0ZXh0IGlzIHNldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC52YWx1ZSA9IHRoaXMuX2RhdGEudmFsdWU7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQkKHRoaXMuX3dpZGdldEh0bWwpLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9vblZhbHVlSW5wdXQoZSlcblx0e1xuXHRcdC8vIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB0byBuZXcgdmFsdWVcblx0XHR0aGlzLl9kYXRhLnZhbHVlID0gdGhpcy5fd2lkZ2V0SHRtbC52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy12ZWN0b3ItM2QnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLXZlY3Rvci0zZCcsIENvbmZpZ1ZlY3RvcjNEKTtcbiIsImltcG9ydCB7Q29uZmlnRm9ybUl0ZW1GYWN0b3J5fSBmcm9tICcuLi8uLi8uLi91dGlscy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbS1mYWN0b3J5JztcblxuZXhwb3J0IGNsYXNzIExpc3RJdGVtRWRpdG9yIGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXHR9XG5cblx0c2V0IGRhdGEoc3ViQ29uZmlnUGFyYW1zQXJyYXkpXG5cdHtcblx0XHR0aGlzLl9kYXRhID0gc3ViQ29uZmlnUGFyYW1zQXJyYXk7XG5cblx0XHR0aGlzLl9idWlsZFZpZXcoKTtcblx0fVxuXG5cdGdldCBkYXRhKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9kYXRhO1xuXHR9XG5cblx0c2V0IGluZGV4KGluZGV4KVxuXHR7XG5cdFx0dGhpcy5faW5kZXggPSBpbmRleDtcblx0fVxuXG5cdGdldCBpbmRleCgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5faW5kZXg7XG5cdH1cblxuXHRfYnVpbGRWaWV3KClcblx0e1xuXHRcdC8vIEdlbmVyYXRlIGNvbnRhaW5lciBmb3JtXG5cdFx0dGhpcy5fZm9ybSA9ICQoJzxmb3JtPicsIHtcblx0XHRcdG9uc3VibWl0OiAncmV0dXJuIGZhbHNlOydcblx0XHR9KTtcblxuXHRcdC8vIEFwcGVuZCBmb3JtXG5cdFx0JCh0aGlzKS5hcHBlbmQodGhpcy5fZm9ybSk7XG5cblx0XHQvLyBHZW5lcmF0ZSBmb3JtIGZpZWxkc1xuXHRcdGZvciAobGV0IGNvbmZpZ1BhcmFtIG9mIHRoaXMuX2RhdGEpXG5cdFx0e1xuXHRcdFx0Ly8gQ3JlYXRlIGZvcm0gaXRlbVxuXHRcdFx0bGV0IGZvcm1JdGVtID0gQ29uZmlnRm9ybUl0ZW1GYWN0b3J5LmNyZWF0ZShjb25maWdQYXJhbSwgdHJ1ZSwgdHJ1ZSk7XG5cdFx0XHRmb3JtSXRlbS5kYXRhID0gY29uZmlnUGFyYW07XG5cblx0XHRcdC8vIEFkZCBmb3JtIGl0ZW0gdG8gZm9ybVxuXHRcdFx0dGhpcy5fZm9ybS5hcHBlbmQoZm9ybUl0ZW0pO1xuXHRcdH1cblxuXHRcdC8vIEluaXRpYWxpemUga2VuZG8gdmFsaWRhdGlvbiBvbiBmb3JtXG5cdFx0dGhpcy5fdmFsaWRhdG9yID0gdGhpcy5fZm9ybS5rZW5kb1ZhbGlkYXRvcih7XG5cdFx0XHR2YWxpZGF0ZU9uQmx1cjogdHJ1ZSxcblx0XHRcdHJ1bGVzOiB7XG5cdFx0XHRcdC8vIEFkZCBydWxlIHRvIHZhbGlkYXRlIEFPSSBmb3JtIGl0ZW1zP1xuXHRcdFx0XHQvLyAoc2VlOiBodHRwczovL2RlbW9zLnRlbGVyaWsuY29tL2tlbmRvLXVpL3ZhbGlkYXRvci9jdXN0b20tdmFsaWRhdGlvbilcblx0XHRcdFx0YW9pOiBmdW5jdGlvbiAoaW5wdXQpIHtcblx0XHRcdFx0XHRpZiAoaW5wdXQuaXMoJ1tkYXRhLWFvaS1tc2ddJykgJiYgaW5wdXQudmFsKCkgIT0gJycpXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0aWYgKGlucHV0LnZhbCgpID09ICcwLDAsMCcpXG5cdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblx0XHRcdH1cblx0XHR9KS5kYXRhKCdrZW5kb1ZhbGlkYXRvcicpO1xuXHR9XG5cblx0dmFsaWRhdGUoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvci52YWxpZGF0ZSgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnbGlzdC1pdGVtLWVkaXRvcicpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdsaXN0LWl0ZW0tZWRpdG9yJywgTGlzdEl0ZW1FZGl0b3IpO1xuIiwiZXhwb3J0IGNsYXNzIFZlY3RvcjNESW5wdXQgZXh0ZW5kcyBIVE1MRWxlbWVudFxue1xuXHRjb25zdHJ1Y3RvcihpZCwgaXNWYWxpZGFibGUpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cblx0XHR0aGlzLmlkID0gaWQ7XG5cdFx0dGhpcy5uYW1lID0gaWQ7XG5cblx0XHR0aGlzLl9pc1ZhbGlkYWJsZSA9IGlzVmFsaWRhYmxlO1xuXG5cdFx0dGhpcy5faW5pdGlhbGl6ZSgpO1xuXHR9XG5cblx0c2V0IGVuYWJsZUNsZWFyKHZhbHVlKVxuXHR7XG5cdFx0aWYgKHZhbHVlKVxuXHRcdFx0dGhpcy5fY2xlYXJCdXR0b24uc2hvdygpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX2NsZWFyQnV0dG9uLmhpZGUoKTtcblx0fVxuXG5cdHNldCBhbGxvd05lZ2F0aXZlKHZhbHVlKVxuXHR7XG5cdFx0aWYgKHZhbHVlKVxuXHRcdHtcblx0XHRcdHRoaXMuX3dpZGdldFguc2V0T3B0aW9ucygge21pbjogbnVsbH0gKTtcblx0XHRcdHRoaXMuX3dpZGdldFkuc2V0T3B0aW9ucygge21pbjogbnVsbH0gKTtcblx0XHRcdHRoaXMuX3dpZGdldFouc2V0T3B0aW9ucygge21pbjogbnVsbH0gKTtcblx0XHR9XG5cdH1cblxuXHRzZXQgdmFsdWUodmFsKVxuXHR7XG5cdFx0dmFyIGNvb3JkcyA9IHZhbC5zcGxpdCgnLCcpO1xuXG5cdFx0aWYgKGNvb3Jkcy5sZW5ndGggPj0gMSlcblx0XHRcdHRoaXMuX3dpZGdldFgudmFsdWUoY29vcmRzWzBdKTtcblxuXHRcdGlmIChjb29yZHMubGVuZ3RoID49IDIpXG5cdFx0XHR0aGlzLl93aWRnZXRZLnZhbHVlKGNvb3Jkc1sxXSk7XG5cblx0XHRpZiAoY29vcmRzLmxlbmd0aCA+PSAzKVxuXHRcdFx0dGhpcy5fd2lkZ2V0Wi52YWx1ZShjb29yZHNbMl0pO1xuXG5cdFx0aWYgKHRoaXMuX2lzVmFsaWRhYmxlKVxuXHRcdFx0dGhpcy5faW5wdXRWYWwudmFsKHRoaXMudmFsdWUpO1xuXHR9XG5cblx0Z2V0IHZhbHVlKClcblx0e1xuXHRcdGlmICh0aGlzLl93aWRnZXRYLnZhbHVlKCkgPT0gbnVsbCAmJiB0aGlzLl93aWRnZXRZLnZhbHVlKCkgPT0gbnVsbCAmJiB0aGlzLl93aWRnZXRaLnZhbHVlKCkgPT0gbnVsbClcblx0XHRcdHJldHVybiAnJztcblx0XHRlbHNlXG5cdFx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0WC52YWx1ZSgpICsgJywnICsgdGhpcy5fd2lkZ2V0WS52YWx1ZSgpICsgJywnICsgdGhpcy5fd2lkZ2V0Wi52YWx1ZSgpO1xuXHR9XG5cblx0X2luaXRpYWxpemUoKVxuXHR7XG5cdFx0Ly8gR2VuZXJhdGUgY29udGFpbmVyIGZvcm1cblx0XHR0aGlzLl9jb250YWluZXIgPSAkKCc8ZGl2PicsIHtcblx0XHRcdGNsYXNzOiAnZm9ybS1pbmxpbmUnXG5cdFx0fSk7XG5cblx0XHQvLyBBcHBlbmQgY29udGFpbmVyXG5cdFx0JCh0aGlzKS5hcHBlbmQodGhpcy5fY29udGFpbmVyKTtcblxuXHRcdC8vIFNldCBpbnB1dHMgY29uZmlndXJhdGlvblxuXHRcdGxldCBjb25maWdIdG1sID0ge1xuXHRcdFx0dHlwZTogJ251bWJlcicsXG5cdFx0XHRjbGFzczogJ2Zvcm0tY29udHJvbCBzaG9ydC00Jyxcblx0XHR9O1xuXG5cdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0bGV0IGNvbmZpZ1dpZGdldCA9IHtcblx0XHRcdG1pbjogMCxcblx0XHRcdHNwaW5uZXJzOiBmYWxzZSxcblx0XHRcdGZvcm1hdDogJyMuIyMjIyMjJyxcblx0XHRcdGRlY2ltYWxzOiA2LFxuXHRcdFx0cm91bmQ6IGZhbHNlLFxuXHRcdFx0c3Bpbm5lcnM6IGZhbHNlLFxuXHRcdFx0cmVzdHJpY3REZWNpbWFsczogZmFsc2UsXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25DaGFuZ2UsIHRoaXMpXG5cdFx0fTtcblxuXHRcdC8vIENyZWF0ZSB3aWRnZXRzXG5cdFx0dGhpcy5faW5wdXRYID0gJCgnPGlucHV0PicsIGNvbmZpZ0h0bWwpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5faW5wdXRYKTtcblx0XHR0aGlzLl93aWRnZXRYID0gdGhpcy5faW5wdXRYLmtlbmRvTnVtZXJpY1RleHRCb3goY29uZmlnV2lkZ2V0KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKCc8c3BhbiBjbGFzcz1cInB4LTFcIj4sPC9zcGFuPicpO1xuXG5cdFx0dGhpcy5faW5wdXRZID0gJCgnPGlucHV0PicsIGNvbmZpZ0h0bWwpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5faW5wdXRZKTtcblx0XHR0aGlzLl93aWRnZXRZID0gdGhpcy5faW5wdXRZLmtlbmRvTnVtZXJpY1RleHRCb3goY29uZmlnV2lkZ2V0KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKCc8c3BhbiBjbGFzcz1cInB4LTFcIj4sPC9zcGFuPicpO1xuXG5cdFx0dGhpcy5faW5wdXRaID0gJCgnPGlucHV0PicsIGNvbmZpZ0h0bWwpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5faW5wdXRaKTtcblx0XHR0aGlzLl93aWRnZXRaID0gdGhpcy5faW5wdXRaLmtlbmRvTnVtZXJpY1RleHRCb3goY29uZmlnV2lkZ2V0KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKCc8c3BhbiBjbGFzcz1cInB4LTFcIj48L3NwYW4+Jyk7IC8vIEFkZGl0aW9uYWwgc3BhY2VyXG5cblx0XHQvLyBDcmVhdGUgaW52aXNpYmxlIGZpZWxkIHRvIGFwcGx5IG92ZXJhbGwgdmFsaWRhdGlvblxuXHRcdGlmICh0aGlzLl9pc1ZhbGlkYWJsZSlcblx0XHR7XG5cdFx0XHR0aGlzLl9pbnB1dFZhbCA9ICQoJzxpbnB1dD4nLCB7bmFtZTogYCR7dGhpcy5uYW1lfS1jdXN0b20tdmFsaWRhdGVgLCAnZGF0YS1hb2ktbXNnJzogJ1ZhbHVlcyBjYW5cXCd0IGFsbCBiZSAwJ30pO1xuXHRcdFx0dGhpcy5fY29udGFpbmVyLmFwcGVuZCh0aGlzLl9pbnB1dFZhbCk7XG5cdFx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKGA8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2dcIiBkYXRhLWZvcj1cIiR7dGhpcy5uYW1lfS1jdXN0b20tdmFsaWRhdGVcIj48L3NwYW4+YClcblx0XHRcdHRoaXMuX2lucHV0VmFsLmhpZGUoKTtcblx0XHR9XG5cblx0XHQvLyBDcmVhdGUgYW5kIGFwcGVuZCBDbGVhciBidXR0b25cblx0XHR0aGlzLl9jbGVhckJ1dHRvbiA9ICQoJzxidXR0b24+Jywge3R5cGU6ICdidXR0b24nLCBjbGFzczogJ2stYnV0dG9uIGstc2Vjb25kYXJ5IG15LTEnLCB0aXRsZTogJ0NsZWFyJ30pLmFwcGVuZCgkKCc8aSBjbGFzcz1cImZhcyBmYS10aW1lc1wiPjwvaT4nKSk7XG5cdFx0dGhpcy5fY2xlYXJCdXR0b24ub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbkNsZWFyQ2xpY2ssIHRoaXMpKTtcblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKHRoaXMuX2NsZWFyQnV0dG9uKTtcblxuXHRcdC8vIEhpZGUgYnV0dG9uIGJ5IGRlZmF1bHRcblx0XHR0aGlzLl9jbGVhckJ1dHRvbi5oaWRlKCk7XG5cdH1cblxuXHRfb25DaGFuZ2UoKVxuXHR7XG5cdFx0Ly8gRW1wdHkgc3RyaW5ncyBhcmUgbm90IGFsbG93ZWRcblx0XHRpZiAodGhpcy5fd2lkZ2V0WC52YWx1ZSgpID09IG51bGwpXG5cdFx0XHR0aGlzLl93aWRnZXRYLnZhbHVlKDApO1xuXG5cdFx0aWYgKHRoaXMuX3dpZGdldFkudmFsdWUoKSA9PSBudWxsKVxuXHRcdFx0dGhpcy5fd2lkZ2V0WS52YWx1ZSgwKTtcblxuXHRcdGlmICh0aGlzLl93aWRnZXRaLnZhbHVlKCkgPT0gbnVsbClcblx0XHRcdHRoaXMuX3dpZGdldFoudmFsdWUoMCk7XG5cblx0XHR0aGlzLl9kaXNwYXRjaENvbW1pdCgpO1xuXHR9XG5cblx0X29uQ2xlYXJDbGljaygpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRYLnZhbHVlKCcnKTtcblx0XHR0aGlzLl93aWRnZXRZLnZhbHVlKCcnKTtcblx0XHR0aGlzLl93aWRnZXRaLnZhbHVlKCcnKTtcblxuXHRcdHRoaXMuX2Rpc3BhdGNoQ29tbWl0KCk7XG5cdH1cblxuXHRfZGlzcGF0Y2hDb21taXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2lzVmFsaWRhYmxlKVxuXHRcdFx0dGhpcy5faW5wdXRWYWwudmFsKHRoaXMudmFsdWUpO1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnY2hhbmdlJykpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgndmVjdG9yLTNkLWlucHV0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ3ZlY3Rvci0zZC1pbnB1dCcsIFZlY3RvcjNESW5wdXQpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbSc7XG5cbmltcG9ydCB7Q29uZmlnTnVtZXJpY1N0ZXBwZXJ9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1udW1lcmljLXN0ZXBwZXInO1xuaW1wb3J0IHtDb25maWdUZXh0SW5wdXR9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy10ZXh0LWlucHV0JztcbmltcG9ydCB7Q29uZmlnQ2hlY2tCb3h9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1jaGVjay1ib3gnO1xuaW1wb3J0IHtDb25maWdEcm9wRG93bkxpc3R9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kcm9wLWRvd24tbGlzdCc7XG5pbXBvcnQge0NvbmZpZ0dyaWR9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1ncmlkJztcbmltcG9ydCB7Q29uZmlnRHVhbExpc3R9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kdWFsLWxpc3QnO1xuaW1wb3J0IHtDb25maWdWZWN0b3IzRH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXZlY3Rvci0zZCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdGb3JtSXRlbUZhY3Rvcnlcbntcblx0c3RhdGljIGNyZWF0ZShjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nID0gZmFsc2UpXG5cdHtcblx0XHRzd2l0Y2ggKGNvbmZpZ1BhcmFtLnR5cGUpXG5cdFx0e1xuXHRcdFx0Y2FzZSAnVGV4dElucHV0Jzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdUZXh0SW5wdXQoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdDaGVja0JveCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnQ2hlY2tCb3goY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdOdW1lcmljU3RlcHBlcic6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnTnVtZXJpY1N0ZXBwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdDb21ib0JveCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnRHJvcERvd25MaXN0KGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnRGF0YUdyaWQnOlxuXHRcdFx0XHRyZXR1cm4gbmV3IENvbmZpZ0dyaWQoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdEdWFsTGlzdCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnRHVhbExpc3QoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdWZWN0b3IzRCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnVmVjdG9yM0QoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRyZXR1cm4gbmV3IENvbmZpZ0Zvcm1JdGVtKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpOyAvLyBXaWxsIGxvZyBhbiBlcnJvciBmb3IgbWlzc2luZyBmb3JtIGl0ZW0gdHlwZVxuXHRcdH1cblx0fVxufVxuIiwiaW1wb3J0IHtDb25maWd1cmF0aW9uUGFyYW1ldGVyfSBmcm9tICcuL2NvbmZpZ3VyYXRpb24tcGFyYW1ldGVyJztcbmltcG9ydCB7Q29uZmlnRm9ybUl0ZW1GYWN0b3J5fSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0tZmFjdG9yeSc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdJbnRlcmZhY2VCdWlsZGVyXG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHRcdC8vIFNldCBzb21lIGNvbnN0YW50c1xuXHRcdHRoaXMuVEFCX1BSRUZJWCA9ICd0YWItJ1xuXHRcdHRoaXMuVEFCX1BBTkVfUFJFRklYID0gJ3RhYnBhbmUtJztcblx0XHR0aGlzLlNFUEFSQVRPUl9CRUZPUkUgPSAnYmVmb3JlJztcblx0XHR0aGlzLlNFUEFSQVRPUl9BRlRFUiA9ICdhZnRlcic7XG5cdH1cblxuXHRkdW1wKG1vZGlmaWVkT25seSA9IGZhbHNlKVxuXHR7XG5cdFx0bGV0IGR1bXBTdHIgPSAnJztcblxuXHRcdGZvciAobGV0IGNwIG9mIHRoaXMuX2NvbmZpZ1BhcmFtcylcblx0XHR7XG5cdFx0XHRpZiAobW9kaWZpZWRPbmx5KVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoY3AuaXNNb2RpZmllZClcblx0XHRcdFx0XHRkdW1wU3RyICs9IGNwLnRvU3RyaW5nKCkgKyAnXFxuJztcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdFx0ZHVtcFN0ciArPSBjcC50b1N0cmluZygpICsgJ1xcbic7XG5cdFx0fVxuXG5cdFx0Y29uc29sZS5sb2coZHVtcFN0cik7XG5cdH1cblxuXHRidWlsZEludGVyZmFjZShkYXRhLCBtYWluQ29udGFpbmVySWQsIGRpc2FibGVFZGl0ID0gZmFsc2UsIHRhYlN1ZmZpeCA9ICcnKVxuXHR7XG5cdFx0dGhpcy5fbWFpbkNvbnRhaW5lcklkID0gbWFpbkNvbnRhaW5lcklkO1xuXHRcdHRoaXMuX2NvbmZpZ1BhcmFtcyA9IG5ldyBBcnJheSgpO1xuXHRcdHRoaXMuX3ZhbGlkYXRvciA9IG51bGw7XG5cblx0XHRsZXQgaGFzTmV3Rm9ybUl0ZW0gPSBmYWxzZTtcblxuXHRcdC8vY29uc29sZS5sb2coZGF0YS5nZXREdW1wKCkpXG5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGRhdGEuc2l6ZSgpOyBpKyspXG5cdFx0e1xuXHRcdFx0Ly8gUEFSU0UgREFUQVxuXG5cdFx0XHRsZXQgY29uZmlnUGFyYW0gPSBDb25maWd1cmF0aW9uUGFyYW1ldGVyLmZyb21TZnNPYmplY3QoZGF0YS5nZXQoaSkpO1xuXHRcdFx0dGhpcy5fY29uZmlnUGFyYW1zLnB1c2goY29uZmlnUGFyYW0pO1xuXG5cdFx0XHQvLyBHZXQgdGFiIGFuZCB0YWIgcGFuZSBpZCBmcm9tIGdyb3VwIGlkXG5cdFx0XHRjb25zdCB0YWJJZCA9IHRoaXMuVEFCX1BSRUZJWCArIGNvbmZpZ1BhcmFtLmNhdGVnb3J5SWQgKyAodGFiU3VmZml4ID8gJ18nICsgdGFiU3VmZml4IDogJycpO1xuXHRcdFx0Y29uc3QgdGFiUGFuZUlkID0gdGhpcy5UQUJfUEFORV9QUkVGSVggKyBjb25maWdQYXJhbS5jYXRlZ29yeUlkICsgKHRhYlN1ZmZpeCA/ICdfJyArIHRhYlN1ZmZpeCA6ICcnKTtcblxuXHRcdFx0Ly8gQlVJTEQgSU5URVJGQUNFIDo6IFRBQlNcblxuXHRcdFx0Ly8gQ2hlY2sgaWYgYSB0YWIgc3BlY2lmaWMgZm9yIHRoaXMgZ3JvdXAgYWxyZWFkeSBleGlzdHMgaW5zaWRlIHRoZSBtYWluQ29udGFpbmVyOiBpZiBub3QsIGNyZWF0ZSBpdFxuXHRcdFx0Ly8gKGEgdGFiIGFscmVhZHkgZXhpc3RzIGlmIGl0IHdhcyBjcmVhdGVkIGluIGEgcHJldmlvdXMgbG9vcClcblx0XHRcdGxldCB0YWIgPSAkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYnMgIyR7dGFiSWR9YCk7XG5cblx0XHRcdGlmICh0YWIubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENyZWF0ZSB0YWIgZm9yIHRhYiBwYW5lXG5cdFx0XHRcdHRhYiA9ICQoJzxsaT4nLCB7Y2xhc3M6ICduYXYtaXRlbSd9KTtcblx0XHRcdFx0dGFiLmFwcGVuZCgkKCc8YT4nLCB7XG5cdFx0XHRcdFx0Y2xhc3M6ICduYXYtbGluaycgKyAoaSA9PSAwID8gJyBhY3RpdmUnIDogJycpLFxuXHRcdFx0XHRcdGlkOiB0YWJJZCxcblx0XHRcdFx0XHQnZGF0YS10b2dnbGUnOiAndGFiJyxcblx0XHRcdFx0XHRocmVmOiAnIycgKyB0YWJQYW5lSWQsXG5cdFx0XHRcdFx0cm9sZTogJ3RhYicsXG5cdFx0XHRcdFx0J2FyaWEtY29udHJvbHMnOiB0YWJQYW5lSWQsXG5cdFx0XHRcdFx0J2FyaWEtc2VsZWN0ZWQnOiAoaSA9PSAwID8gJ3RydWUnIDogJ2ZhbHNlJyksXG5cdFx0XHRcdFx0aHRtbDogY29uZmlnUGFyYW0uY2F0ZWdvcnksXG5cdFx0XHRcdH0pKTtcblxuXHRcdFx0XHQvLyBBZGQgdGFiIHRvIGNvbnRhaW5lclxuXHRcdFx0XHQkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYnNgKS5hcHBlbmQodGFiKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQlVJTEQgSU5URVJGQUNFIDo6IFRBQiBQQU5FU1xuXG5cdFx0XHQvLyBDaGVjayBpZiBhIHRhYiBwYW5lIHNwZWNpZmljIGZvciB0aGlzIGdyb3VwIGFscmVhZHkgZXhpc3RzIGluc2lkZSB0aGUgbWFpbkNvbnRhaW5lcjogaWYgbm90LCBjcmVhdGUgaXRcblx0XHRcdC8vIChhIHRhYiBwYW5lIGFscmVhZHkgZXhpc3RzIGlmIGl0IHdhcyBjcmVhdGVkIGluIGEgcHJldmlvdXMgbG9vcCBvciBpZiBpdCBleGlzdHMgc3RhdGljYWxseSBpbiB0aGUgaHRtbCAtIGluIGNhc2UgaXQgaXMgbmVlZGVkIHRvIGFkZCBzb21lIHN0YXRpYyBjb250ZW50KVxuXHRcdFx0bGV0IHRhYlBhbmUgPSAkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+ICMke3RhYlBhbmVJZH1gKTtcblxuXHRcdFx0aWYgKHRhYlBhbmUubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENyZWF0ZSB0YWIgcGFuZVxuXHRcdFx0XHR0YWJQYW5lID0gJCgnPGRpdj4nLCB7XG5cdFx0XHRcdFx0Y2xhc3M6ICd0YWItcGFuZScgKyAoaSA9PSAwID8gJyBzaG93IGFjdGl2ZScgOiAnJyksXG5cdFx0XHRcdFx0aWQ6IHRhYlBhbmVJZCxcblx0XHRcdFx0XHRyb2xlOiAndGFicGFuZWwnLFxuXHRcdFx0XHRcdCdhcmlhLWxhYmVsbGVkYnknOiB0YWJJZCxcblx0XHRcdFx0XHQnZGF0YS1keW5hbWljJzogJ3RydWUnLFxuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHQvLyBBZGQgdGFiIHBhbmUgdG8gY29udGFpbmVyXG5cdFx0XHRcdCQoYCMke21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzYCkuYXBwZW5kKHRhYlBhbmUpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBCVUlMRCBJTlRFUkZBQ0UgOjogVEFCIFBBTkVTJyBGT1JNXG5cblx0XHRcdC8vIENoZWNrIGlmIGEgZm9ybSBhbHJlYWR5IGV4aXN0cyBpbnNpZGUgdGhlIHRhYiBwYW5lOiBpZiBub3QsIGNyZWF0ZSBpdFxuXHRcdFx0bGV0IGZvcm0gPSB0YWJQYW5lLmZpbmQoJ2Zvcm0nKTtcblxuXHRcdFx0aWYgKGZvcm0ubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENyZWF0ZSBmb3JtXG5cdFx0XHRcdGZvcm0gPSAkKCc8Zm9ybT4nLCB7XG5cdFx0XHRcdFx0Y2xhc3M6ICcnLFxuXHRcdFx0XHRcdGF1dG9jb21wbGV0ZTogJ29mZidcblx0XHRcdFx0fSk7XG5cblx0XHRcdFx0Ly8gQ3JlYXRlIGFuIGlubmVyIGZpZWxkc2V0OyB0aGlzIG1pZ2h0IGJlIHVzZWZ1bCB0byBlYXNpbHkgZGlzYWJsZSB0aGUgd2hvbGUgZm9ybSBhdCBvbmNlIChhY3R1YWxseSB3ZSBkb24ndCB1c2UgaXQgYmVjYXVzZSBLZW5kbyB3aWRnZXRzIGFyZSBub3QgZGlzYWJsZWQgYXV0b21hdGljYWxseSlcblx0XHRcdFx0Zm9ybS5hcHBlbmQoXG5cdFx0XHRcdFx0JCgnPGZpZWxkc2V0PicsIHtcblx0XHRcdFx0XHRcdGNsYXNzOiAnJ1xuXHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0Ly8gQWRkIGZvcm0gdG8gdGFiIHBhbmVcblx0XHRcdFx0dGFiUGFuZS5wcmVwZW5kKGZvcm0pO1xuXG5cdFx0XHRcdC8vIGZvcm0ub24oXCJrZXlwcmVzc1wiLCBmdW5jdGlvbihldmVudCkge1xuXHRcdFx0XHQvLyBcdC8vIElmIHRoZSB1c2VyIHByZXNzZXMgdGhlIFwiRW50ZXJcIiBrZXkgb24gdGhlIGtleWJvYXJkXG5cdFx0XHRcdC8vIFx0aWYgKGV2ZW50LmtleSA9PT0gXCJFbnRlclwiKSB7XG5cdFx0XHRcdC8vIFx0XHQvLyBDYW5jZWwgdGhlIGRlZmF1bHQgYWN0aW9uLCBpZiBuZWVkZWRcblx0XHRcdFx0Ly8gXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdC8vIFx0XHRjb25zb2xlLmxvZyhcIkVOVEVSXCIpXG5cdFx0XHRcdC8vIFx0fVxuXHRcdFx0XHQvLyB9KTtcblx0XHRcdFx0Zm9ybS5zdWJtaXQoZnVuY3Rpb24oZXZ0KSB7XG5cdFx0XHRcdFx0Y29uc29sZS5sb2coXCJTVUJNSVRcIilcblx0XHRcdFx0XHRldnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEdldCBmaWVsZHNldCwgd2hpY2ggaXMgdGhlIGFjdHVhbCBmb3JtIGl0ZW1zIGNvbnRhaW5lclxuXHRcdFx0bGV0IGZpZWxkc2V0ID0gZm9ybS5maW5kKCdmaWVsZHNldCcpO1xuXG5cdFx0XHQvLyBCVUlMRCBJTlRFUkZBQ0UgOjogVEFCIFBBTkVTJyBGT1JNIElURU1TXG5cblx0XHRcdC8vIENoZWNrIGlmIGZvcm0gaXRlbSBhbHJlYWR5IGV4aXN0cyBpbiBmaWVsZHNldDsgaWYgeWVzLCBqdXN0IHVwZGF0ZSBpdHMgZGF0YVxuXHRcdFx0bGV0IGZvcm1JdGVtID0gZmllbGRzZXQuZmluZChgI2Zvcm0taXRlbS0keyQuZXNjYXBlU2VsZWN0b3IoY29uZmlnUGFyYW0ubmFtZSl9YCk7XG5cblx0XHRcdGlmIChmb3JtSXRlbS5sZW5ndGggPT0gMClcblx0XHRcdHtcblx0XHRcdFx0aGFzTmV3Rm9ybUl0ZW0gPSB0cnVlO1xuXG5cdFx0XHRcdGZvcm1JdGVtID0gQ29uZmlnRm9ybUl0ZW1GYWN0b3J5LmNyZWF0ZShjb25maWdQYXJhbSwgIWRpc2FibGVFZGl0KTtcblxuXHRcdFx0XHQvLyBBZGQgc2VwYXJhdG9yIGJlZm9yZVxuXHRcdFx0XHRpZiAoY29uZmlnUGFyYW0uc2VwYXJhdG9yICE9IG51bGwgJiYgY29uZmlnUGFyYW0uc2VwYXJhdG9yLnBvcyA9PSAnYmVmb3JlJylcblx0XHRcdFx0XHRmaWVsZHNldC5hcHBlbmQodGhpcy5fYnVpbGRTZXBhcmF0b3IoY29uZmlnUGFyYW0uc2VwYXJhdG9yKSk7XG5cblx0XHRcdFx0Ly8gQWRkIGZvcm0gaXRlbSB0byBmb3JtXG5cdFx0XHRcdGZpZWxkc2V0LmFwcGVuZChmb3JtSXRlbSk7XG5cblx0XHRcdFx0Ly8gQWRkIHNlcGFyYXRvciBhZnRlclxuXHRcdFx0XHRpZiAoY29uZmlnUGFyYW0uc2VwYXJhdG9yICE9IG51bGwgJiYgY29uZmlnUGFyYW0uc2VwYXJhdG9yLnBvcyA9PSAnYWZ0ZXInKVxuXHRcdFx0XHRcdGZpZWxkc2V0LmFwcGVuZCh0aGlzLl9idWlsZFNlcGFyYXRvcihjb25maWdQYXJhbS5zZXBhcmF0b3IpKTtcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdFx0Zm9ybUl0ZW1bMF0uZGF0YSA9IGNvbmZpZ1BhcmFtO1xuXHRcdH1cblxuXHRcdC8vIEFkZCBsaXN0ZW5lciB0byBzaG93IGhlbHAgdG9vbHRpcHNcblx0XHRsZXQgYWxsVGFiUGFuZXMgPSAkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZWApO1xuXHRcdGFsbFRhYlBhbmVzLmtlbmRvVG9vbHRpcCh7XG5cdFx0XHRmaWx0ZXI6ICdpW3RpdGxlXS5oZWxwJyxcblx0XHRcdHBvc2l0aW9uOiAncmlnaHQnLFxuXHRcdFx0d2lkdGg6ICcyNTBweCcsXG5cdFx0XHRjb250ZW50OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdHJldHVybiBgPGRpdiBjbGFzcz1cImhlbHAtdG9vbHRpcFwiPiR7ZS50YXJnZXQuZGF0YSgndGl0bGUnKX08L2Rpdj5gO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBrZW5kbyB2YWxpZGF0aW9uIG9uIGZvcm1zJyBtYWluIGNvbnRhaW5lclxuXHRcdHRoaXMuX3ZhbGlkYXRvciA9ICQoYCMke21haW5Db250YWluZXJJZH1gKS5rZW5kb1ZhbGlkYXRvcih7XG5cdFx0XHR2YWxpZGF0ZU9uQmx1cjogdHJ1ZSxcblx0XHRcdHJ1bGVzOiB7XG5cdFx0XHRcdC8vIEFkZCBydWxlIHRvIHZhbGlkYXRlIEFPSSBmb3JtIGl0ZW1zXG5cdFx0XHRcdC8vIChzZWU6IGh0dHBzOi8vZGVtb3MudGVsZXJpay5jb20va2VuZG8tdWkvdmFsaWRhdG9yL2N1c3RvbS12YWxpZGF0aW9uKVxuXHRcdFx0XHRhb2k6IGZ1bmN0aW9uIChpbnB1dCkge1xuXHRcdFx0XHRcdGlmIChpbnB1dC5pcygnW2RhdGEtYW9pLW1zZ10nKSAmJiBpbnB1dC52YWwoKSAhPSAnJylcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRpZiAoaW5wdXQudmFsKCkgPT0gJzAsMCwwJylcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXHRcdFx0fVxuXHRcdH0pLmRhdGEoJ2tlbmRvVmFsaWRhdG9yJyk7XG5cdH1cblxuXHRkZXN0cm95SW50ZXJmYWNlKClcblx0e1xuXHRcdC8vIERlc3Ryb3kgYWxsIEtlbmRvIHdpZGdldHMgaW4gZm9ybXNcblx0XHRrZW5kby5kZXN0cm95KCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gZGl2LnRhYi1wYW5lID4gZm9ybWApKTtcblxuXHRcdC8vIFJlbW92ZSBhbGwgdGFic1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFic2ApLmVtcHR5KCk7XG5cblx0XHQvLyBSZW1vdmUgZHluYW1pYyB0YWIgcGFuZXMgKHRhYiBwYW5lcyBjcmVhdGVkIGJ5IEludGVyZmFjZSBCdWlsZGVyKVxuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gZGl2LnRhYi1wYW5lW2RhdGEtZHluYW1pYz1cInRydWVcIl1gKS5yZW1vdmUoKTtcblxuXHRcdC8vIFJlbW92ZSBmb3JtIGluc2lkZSBzdGF0aWMgdGFiIHBhbmVzIChwcmVkZWZpbmVkIHRhYiBwYW5lcyBpbiBodG1sKVxuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gZGl2LnRhYi1wYW5lID4gZm9ybWApLnJlbW92ZSgpO1xuXG5cdFx0Ly8gUmVtb3ZlIFwiYWN0aXZlXCIgY2xhc3MgZnJvbSBzdGF0aWMgdGFiIHBhbmVzIChvdGhlcndpc2UgdGhpcyBjbGFzcyBtZXNzZXMgd2l0aCB0aGUgdGFiIG5hdmlnYXRvciBmdW5jdGlvbmluZylcblx0XHQkKGAjJHt0aGlzLl9tYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZWApLnJlbW92ZUNsYXNzKCdhY3RpdmUnKTtcblx0fVxuXG5cdGRpc2FibGVJbnRlcmZhY2UoZGlzYWJsZSlcblx0e1xuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIGFsbCBjb25maWcgZm9ybSBpdGVtc1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gKltpZF49J2Zvcm0taXRlbS0nXWApLnByb3AoJ2VkaXRFbmFibGVkJywgIWRpc2FibGUpO1xuXHR9XG5cblx0X2J1aWxkU2VwYXJhdG9yKHNlcGFyYXRvcilcblx0e1xuXHRcdGlmIChzZXBhcmF0b3IudGV4dCA9PSBudWxsKVxuXHRcdFx0cmV0dXJuICQoYDxociBjbGFzcz1cImNvbmZpZy1mb3JtLXNlcGFyYXRvclwiPmApO1xuXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuICQoYDxsYWJlbCBjbGFzcz1cImNvbmZpZy1mb3JtLXNlcGFyYXRvci1sYWJlbCBtYi0zXCI+JHtzZXBhcmF0b3IudGV4dH08L2xhYmVsPmApO1xuXHR9XG5cblx0Z2V0Q2hhbmdlZERhdGEoKVxuXHR7XG5cdFx0bGV0IGNoYW5nZXMgPSBuZXcgU0ZTMlguU0ZTQXJyYXkoKTtcblxuXHRcdGZvciAodmFyIGNwIG9mIHRoaXMuX2NvbmZpZ1BhcmFtcylcblx0XHR7XG5cdFx0XHRpZiAoY3AuaXNNb2RpZmllZClcblx0XHRcdFx0Y2hhbmdlcy5hZGRTRlNPYmplY3QoY3AudG9TZnNPYmplY3QoKSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNoYW5nZXM7XG5cdH1cblxuXHRyZXNldElzTW9kaWZpZWQoKVxuXHR7XG5cdFx0Zm9yIChsZXQgY3Agb2YgdGhpcy5fY29uZmlnUGFyYW1zKVxuXHRcdHtcblx0XHRcdGlmIChjcC5pc01vZGlmaWVkKVxuXHRcdFx0XHRjcC5yZXNldElzTW9kaWZpZWQoKTtcblx0XHR9XG5cdH1cblxuXHRjaGVja0lzVmFsaWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvci52YWxpZGF0ZSgpO1xuXHR9XG5cblx0cmVzZXRWYWxpZGF0aW9uKClcblx0e1xuXHRcdHRoaXMuX3ZhbGlkYXRvci5oaWRlTWVzc2FnZXMoKTtcblxuXHRcdC8vIFRoZSBtZXRob2QgYWJvdmUgZG9lc24ndCByZW1vdmUgdGhlIGstaW52YWxpZCBjbGFzc2VzIGFuZCBhcmlhLWludmFsaWQ9XCJ0cnVlXCIgYXR0cmlidXRlcyBmcm9tIGlucHV0c1xuXHRcdC8vIExldCdzIGRvIGl0IG1hbnVhbGx5XG5cdFx0JChgIyR7dGhpcy5fbWFpbkNvbnRhaW5lcklkfSAuay1pbnZhbGlkYCkucmVtb3ZlQ2xhc3MoJ2staW52YWxpZCcpO1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gW2FyaWEtaW52YWxpZD1cInRydWVcIl1gKS5yZW1vdmVBdHRyKCdhcmlhLWludmFsaWQnKTtcblx0fVxuXG5cdGdldENvbmZpZ0Zvcm1JdGVtKGNvbmZpZ1BhcmFtTmFtZSlcblx0e1xuXHRcdGxldCBmb3JtSXRlbSA9ICQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH1gKS5maW5kKGAjZm9ybS1pdGVtLSR7JC5lc2NhcGVTZWxlY3Rvcihjb25maWdQYXJhbU5hbWUpfWApO1xuXG5cdFx0aWYgKGZvcm1JdGVtLmxlbmd0aCA+IDApXG5cdFx0XHRyZXR1cm4gZm9ybUl0ZW1bMF07XG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHRhY3RpdmF0ZUZpcnN0VGFiUGFuZWwoKVxuXHR7XG5cdFx0bGV0IGNvbmZpZ1BhcmFtID0gdGhpcy5fY29uZmlnUGFyYW1zWzBdO1xuXHRcdGNvbnN0IHRhYlBhbmVJZCA9IHRoaXMuVEFCX1BBTkVfUFJFRklYICsgY29uZmlnUGFyYW0uY2F0ZWdvcnlJZDtcblx0XHRsZXQgdGFiUGFuZSA9ICQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gIyR7dGFiUGFuZUlkfWApO1xuXHRcdHRhYlBhbmUuYWRkQ2xhc3MoJ3Nob3cgYWN0aXZlJyk7XG5cdH1cbn1cbiIsImV4cG9ydCBjbGFzcyBDb25maWd1cmF0aW9uUGFyYW1ldGVyXG57XG5cdHN0YXRpYyBmcm9tU2ZzT2JqZWN0KGVsZW1lbnQpXG5cdHtcblx0XHRsZXQgY3AgPSBuZXcgQ29uZmlndXJhdGlvblBhcmFtZXRlcigpO1xuXG5cdFx0Ly8gUGFyc2UgY29tbW9uIGRhdGFcblx0XHRjcC5uYW1lID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ25hbWUnKTtcblx0XHRjcC5sYWJlbCA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCdsYWJlbCcpO1xuXHRcdGNwLmNhdGVnb3J5ID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ2NhdGVnb3J5Jyk7XG5cdFx0Y3AuaW1tZWRpYXRlID0gKGVsZW1lbnQuY29udGFpbnNLZXkoJ2ltbWVkaWF0ZScpID8gZWxlbWVudC5nZXRCb29sKCdpbW1lZGlhdGUnKSA6IGZhbHNlKTtcblx0XHRjcC50b29sdGlwID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ3Rvb2x0aXAnKTtcblx0XHRjcC50eXBlID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ3R5cGUnKTtcblx0XHRjcC52YWx1ZSA9IGVsZW1lbnQuZ2V0KCd2YWx1ZScpO1xuXHRcdGNwLnZhbGlkYXRvciA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCd2YWxpZGF0b3InKTtcblx0XHRjcC5lZGl0YWJsZSA9IChlbGVtZW50LmNvbnRhaW5zS2V5KCdlZGl0JykgPyBlbGVtZW50LmdldEJvb2woJ2VkaXQnKSA6IHRydWUpO1xuXHRcdGNwLnRyaWdnZXIgPSAoZWxlbWVudC5jb250YWluc0tleSgndHJpZ2dlcicpID8gZWxlbWVudC5nZXRCb29sKCd0cmlnZ2VyJykgOiBmYWxzZSk7XG5cdFx0Y3AudHJpZ2dlckRhdGEgPSBlbGVtZW50LmdldFNGU0FycmF5KCd0cmlnZ2VyRGF0YScpO1xuXHRcdGNwLmNsaWVudE9ubHkgPSAoZWxlbWVudC5jb250YWluc0tleSgnY2xpZW50T25seScpID8gZWxlbWVudC5nZXRCb29sKCdjbGllbnRPbmx5JykgOiBmYWxzZSk7XG5cdFx0Y3AuZGF0YVByb3ZpZGVyID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ2RhdGFQcm92aWRlcicpO1xuXG5cdFx0Ly8gUGFyc2UgY29tcG9uZW50IHNwZWNpZmljIGF0dHJpYnV0ZXNcblx0XHRsZXQgdG1wQXR0cmlidXRlcyA9IGVsZW1lbnQuZ2V0U0ZTT2JqZWN0KCdhdHRyaWJ1dGVzJyk7XG5cdFx0aWYgKHRtcEF0dHJpYnV0ZXMgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRsZXQgYXR0cmlidXRlcyA9IHt9O1xuXG5cdFx0XHRsZXQga2V5cyA9IHRtcEF0dHJpYnV0ZXMuZ2V0S2V5c0FycmF5KCk7XG5cdFx0XHRmb3IgKGxldCBrZXkgb2Yga2V5cylcblx0XHRcdFx0YXR0cmlidXRlc1trZXldID0gdG1wQXR0cmlidXRlcy5nZXQoa2V5KTtcblxuXHRcdFx0Y3AuYXR0cmlidXRlcyA9IGF0dHJpYnV0ZXM7XG5cdFx0fVxuXG5cdFx0Ly8gUGFyc2Ugc2VwYXJhdG9yIHNldHRpbmdzXG5cdFx0bGV0IHRtcFNlcGFyYXRvciA9IGVsZW1lbnQuZ2V0U0ZTT2JqZWN0KCdzZXBhcmF0b3InKTtcblx0XHRpZiAodG1wU2VwYXJhdG9yICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0bGV0IHNlcGFyYXRvciA9IHt9O1xuXG5cdFx0XHRsZXQga2V5czEgPSB0bXBTZXBhcmF0b3IuZ2V0S2V5c0FycmF5KCk7XG5cdFx0XHRmb3IgKGxldCBrZXkxIG9mIGtleXMxKVxuXHRcdFx0XHRzZXBhcmF0b3Jba2V5MV0gPSB0bXBTZXBhcmF0b3IuZ2V0KGtleTEpO1xuXG5cdFx0XHRjcC5zZXBhcmF0b3IgPSBzZXBhcmF0b3I7XG5cdFx0fVxuXG5cdFx0Ly8gUGFyc2UgZGVmYXVsdCBsaXN0IGl0ZW1cblx0XHRsZXQgdG1wRGVmYXVsdExpc3RJdGVtID0gZWxlbWVudC5nZXRTRlNBcnJheSgnZGVmYXVsdExpc3RJdGVtJyk7XG5cdFx0aWYgKHRtcERlZmF1bHRMaXN0SXRlbSAhPSBudWxsICYmIHRtcERlZmF1bHRMaXN0SXRlbS5zaXplKCkgPiAwKVxuXHRcdHtcblx0XHRcdGxldCBkZWZhdWx0TGlzdEl0ZW0gPSBbXTtcblxuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0bXBEZWZhdWx0TGlzdEl0ZW0uc2l6ZSgpOyBpKyspXG5cdFx0XHRcdGRlZmF1bHRMaXN0SXRlbS5wdXNoKENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIuZnJvbVNmc09iamVjdCh0bXBEZWZhdWx0TGlzdEl0ZW0uZ2V0U0ZTT2JqZWN0KGkpKSk7XG5cblx0XHRcdGNwLmRlZmF1bHRMaXN0SXRlbSA9IGRlZmF1bHRMaXN0SXRlbTtcblxuXHRcdFx0Ly8gUGFyc2UgbGlzdCB2YWx1ZXNcblx0XHRcdGxldCBsaXN0VmFsdWVzID0gW107XG5cblx0XHRcdGxldCB0bXBMaXN0VmFsdWVzID0gZWxlbWVudC5nZXRTRlNBcnJheSgnbGlzdFZhbHVlcycpO1xuXHRcdFx0aWYgKHRtcExpc3RWYWx1ZXMgIT0gbnVsbCAmJiB0bXBMaXN0VmFsdWVzLnNpemUoKSA+IDApXG5cdFx0XHR7XG5cdFx0XHRcdGZvciAobGV0IHYgPSAwOyB2IDwgdG1wTGlzdFZhbHVlcy5zaXplKCk7IHYrKylcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGxldCBsaXN0VmFsdWVPYmogPSB0bXBMaXN0VmFsdWVzLmdldFNGU09iamVjdCh2KTtcblx0XHRcdFx0XHRsZXQgb2JqID0ge307XG5cblx0XHRcdFx0XHRsZXQga2V5czIgPSBsaXN0VmFsdWVPYmouZ2V0S2V5c0FycmF5KCk7XG5cdFx0XHRcdFx0Zm9yIChsZXQga2V5MiBvZiBrZXlzMilcblx0XHRcdFx0XHRcdG9ialtrZXkyXSA9IGxpc3RWYWx1ZU9iai5nZXQoa2V5Mik7XG5cblx0XHRcdFx0XHRsaXN0VmFsdWVzLnB1c2gob2JqKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRjcC5saXN0VmFsdWVzID0gbGlzdFZhbHVlcztcblxuXHRcdFx0Ly8gSWYgd2UgaGF2ZSBhIGxpc3QsIG9uIHRoZSBzZXJ2ZXItc2lkZSBpdGVtcyBjb3VsZCBiZSByZXByZXNlbnRlZCBieSBhIGNsYXNzXG5cdFx0XHRjcC5jbGF6eiA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCdjbGF6eicpO1xuXG5cdFx0XHQvLyBBdm9pZCBsaXN0IHRvIGJlIGVtcHRpZWRcblx0XHRcdGNwLmRlbnlFbXB0eSA9IChlbGVtZW50LmNvbnRhaW5zS2V5KCdkZW55RW1wdHknKSA/IGVsZW1lbnQuZ2V0Qm9vbCgnZGVueUVtcHR5JykgOiBmYWxzZSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNwO1xuXHR9XG5cblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdFx0LyogQ09OU1RBTlRTICovXG5cdFx0dGhpcy5ERUZBVUxUX0NBVEVHT1JZX05BTUUgPSAnR2VuZXJhbCc7XG5cdFx0dGhpcy5ERUZBVUxUX0NBVEVHT1JZX0lEID0gJ2dlbmVyYWwnO1xuXG5cdFx0LyogUFVCTElDIFZBUlMgKi9cblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXHRcdHRoaXMubGFiZWwgPSAnJztcblx0XHR0aGlzLnRvb2x0aXAgPSAnJztcblx0XHR0aGlzLnR5cGUgPSBudWxsO1xuXHRcdHRoaXMudHJpZ2dlciA9IGZhbHNlO1xuXHRcdHRoaXMudHJpZ2dlckRhdGEgPSBudWxsO1xuXHRcdHRoaXMuY2xpZW50T25seSA9IGZhbHNlO1xuXHRcdHRoaXMuZWRpdGFibGUgPSB0cnVlO1xuXHRcdHRoaXMuYXR0cmlidXRlcyA9IG51bGw7XG5cdFx0dGhpcy5kYXRhUHJvdmlkZXIgPSBudWxsO1xuXG5cdFx0dGhpcy5zZXBhcmF0b3IgPSBudWxsO1x0XHRcdC8vIFBhcmFtZXRlciB1c2VkIHRvIGNyZWF0ZSBhIHNlcGFyYXRvciBiZWZvcmUgb3IgYWZ0ZXIgdGhlIGNvbmZpZyBwYXJhbWV0ZXJcblx0XHR0aGlzLmRlZmF1bHRMaXN0SXRlbSA9IG51bGw7XHQvLyBMaXN0IG9mIHN1Yi1Db25maWd1cmF0aW9uUGFyYW1ldGVycywgZWFjaCBjb250YWluaW5nIHRoZSBkZWZhdWx0IHZhbHVlc1xuXHRcdHRoaXMuY2xhenogPSBudWxsO1x0XHRcdFx0Ly8gTmFtZSBvZiB0aGUgY2xhc3MgcmVwcmVzZW50aW5nIHRoZSBsaXN0IGl0ZW0gKG5vdCB1c2VkIGluIGNhc2Ugb2YgcHJpbWl0ZXZlIGRhdGEgdHlwZXMpXG5cdFx0dGhpcy5kZW55RW1wdHkgPSBmYWxzZTtcdFx0XHQvLyBEaXNhbGxvdyB0byBlbXB0eSBhIGxpc3QgKERhdGFHcmlkIGNvbmZpZyBwYXJhbWV0ZXIgdHlwZSBvbmx5KVxuXG5cdFx0dGhpcy5pbW1lZGlhdGUgPSBmYWxzZTtcdFx0XHQvLyBTaG93cyBpY29uIGluZGljYXRpbmcgdGhhdCBzZXR0aW5nIHdpbGwgYmUgYXBwbGllZCBpbW1lZGlhdGVseSBvbiBzdWJtaXQsIHdpdGhvdXQgdGhlIG5lZWQgZm9yIGEgc2VydmVyIHJlc3RhcnRcblxuXHRcdC8qIFBSSVZBVEUgVkFSUyAqL1xuXG5cdFx0dGhpcy5fY2F0ZWdvcnkgPSB0aGlzLkRFRkFVTFRfQ0FURUdPUllfTkFNRTtcblx0XHR0aGlzLl9jYXRlZ29yeUlkID0gdGhpcy5ERUZBVUxUX0NBVEVHT1JZX0lEO1xuXHRcdHRoaXMuX3ZhbHVlID0gbnVsbDtcblx0XHR0aGlzLl9pbml0aWFsVmFsdWUgPSBudWxsO1x0XHQvLyBTYXZlIHRoZSBpbml0aWFsIHZhbHVlIG9mIHRoZSBjb25maWd1cmF0aW9uIHBhcmFtZXRlciwgdG8gY2hlY2sgaWYgdGhlIHZhbHVlIHdhcyBtb2RpZmllZFxuXHRcdHRoaXMuX3ZhbGlkYXRvciA9IG51bGw7XG5cblx0XHR0aGlzLl9saXN0SXRlbXMgPSBbXTtcdFx0XHQvLyBBcnJheSBvZiBhcnJheXMgb2YgQ29uZmlndXJhdGlvblBhcmFtZXRlcnNcblx0XHR0aGlzLl9saXN0SXRlbXNDaGFuZ2VkID0gZmFsc2U7XHQvLyBGbGFnIHRvIGJlIHNldCBpbiBjYXNlIGEgbGlzdCBpdGVtIGlzIGFkZGVkIG9yIHJlbW92ZWRcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIEdFVFRFUlMgLyBTRVRURVJTXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0c2V0IGNhdGVnb3J5KHZhbClcblx0e1xuXHRcdGlmICh2YWwpXG5cdFx0e1xuXHRcdFx0dGhpcy5fY2F0ZWdvcnkgPSB2YWw7XG5cdFx0XHR0aGlzLl9zZXRJZEZyb21DYXRlZ29yeU5hbWUodGhpcy5fY2F0ZWdvcnkpO1xuXHRcdH1cblx0fVxuXG5cdGdldCBjYXRlZ29yeSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fY2F0ZWdvcnk7XG5cdH1cblxuXHRzZXQgdmFsdWUodmFsKVxuXHR7XG5cdFx0aWYgKHRoaXMuX3ZhbHVlICE9IHZhbClcblx0XHR7XG5cdFx0XHQvLyBJZiB2YWx1ZSBpcyBudWxsLCB0aGVuIHdlIGFyZSBzZXR0aW5nIHRoaXMgZm9yIHRoZSBmaXJzdCB0aW1lIGFuZFxuXHRcdFx0Ly8gd2Ugd2FudCB0byBzYXZlIHRoZSBpbml0aWFsIHZhbHVlLCB0byBjaGVjayBsYXRlciBpZiBpdCBoYXMgYmVlbiBtb2RpZmllZFxuXHRcdFx0aWYgKHRoaXMuX3ZhbHVlID09IG51bGwpXG5cdFx0XHRcdHRoaXMuX2luaXRpYWxWYWx1ZSA9IHZhbDtcblxuXHRcdFx0dGhpcy5fdmFsdWUgPSB2YWw7XG5cdFx0fVxuXHR9XG5cblx0Z2V0IHZhbHVlKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl92YWx1ZTtcblx0fVxuXG5cdHNldCB2YWxpZGF0b3IodmFsKVxuXHR7XG5cdFx0aWYgKHZhbClcblx0XHRcdHRoaXMuX3ZhbGlkYXRvciA9IHZhbDtcblx0fVxuXG5cdGdldCB2YWxpZGF0b3IoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvcjtcblx0fVxuXG5cdC8qKlxuXHQgKiBBbiBhcnJheSBvZiBvYmplY3RzOyBlYWNoIG9iamVjdCBjb250YWlucyB0aGUgbmFtZS12YWx1ZSBwYWlycyB1c2VkIHRvXG5cdCAqIHBvcHVsYXRlIHRoZSBsaXN0IG9mIHN1Yi1jb25maWd1cmF0aW9uIHBhcmFtZXRlcnMgYXJyYXlzLCBiYXNlZCBvbiBkZWZhdWx0TGlzdEl0ZW0uXG5cdCAqL1xuXHRzZXQgbGlzdFZhbHVlcyhhcnIpXG5cdHtcblx0XHR0aGlzLl9zZXRTdWJDb25maWd1cmF0aW9uUGFyYW1zKGFycik7XG5cdH1cblxuXHRnZXQgbGlzdFZhbHVlcygpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fZ2V0U3ViQ29uZmlndXJhdGlvblBhcmFtc1ZhbHVlcygpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gR0VUVEVSUyBPTkxZXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0Z2V0IGlzTW9kaWZpZWQoKVxuXHR7XG5cdFx0bGV0IF9pc01vZGlmaWVkID0gZmFsc2U7XG5cblx0XHQvLyBJZiB0aGUgcGFyYW1ldGVyIGlzIHVzZWQgb24gdGhlIGNsaWVudCBvbmx5IChmb3IgZXhhbXBsZSBpbiBhIGN1c3RvbSB0cmlnZ2VyKVxuXHRcdC8vIHRoZW4gd2UgbmV2ZXIgaGF2ZSB0byBjb25zaWRlciBpdCBhcyBtb2RpZmllZCwgdG8gcHJldmVudCBpdCBiZWluZyBzZW50IHRvIHRoZSBzZXJ2ZXJcblx0XHRpZiAoIXRoaXMuY2xpZW50T25seSlcblx0XHR7XG5cdFx0XHRpZiAodGhpcy5fdmFsdWUgIT0gdGhpcy5faW5pdGlhbFZhbHVlIHx8IHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQpXG5cdFx0XHRcdF9pc01vZGlmaWVkID0gdHJ1ZTtcblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0Ly8gQ2hlY2sgc3ViIHBhcmFtZXRlcnNcblx0XHRcdFx0b3V0ZXJMb29wOiBmb3IgKGxldCBsaXN0SXRlbSBvZiB0aGlzLl9saXN0SXRlbXMpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmb3IgKGxldCBzdWJDUCBvZiBsaXN0SXRlbSlcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRpZiAoc3ViQ1AuaXNNb2RpZmllZClcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0X2lzTW9kaWZpZWQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRicmVhayBvdXRlckxvb3A7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIF9pc01vZGlmaWVkO1xuXHR9XG5cblx0Z2V0IGNhdGVnb3J5SWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2NhdGVnb3J5SWQ7XG5cdH1cblxuXHRnZXQgbGlzdEl0ZW1zKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9saXN0SXRlbXM7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBQVUJMSUMgTUVUSE9EU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdC8qKlxuXHQgKiBSZXR1cm4gYSBjbG9uZSBvZiB0aGlzIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIuXG5cdCAqL1xuXHRjbG9uZShjbG9uZVZhbHVlID0gZmFsc2UpXG5cdHtcblx0XHRsZXQgY3AgPSBuZXcgQ29uZmlndXJhdGlvblBhcmFtZXRlcigpO1xuXHRcdGNwLm5hbWUgPSB0aGlzLm5hbWU7XG5cdFx0Y3AubGFiZWwgPSB0aGlzLmxhYmVsO1xuXHRcdGNwLmNhdGVnb3J5ID0gdGhpcy5jYXRlZ29yeTtcblx0XHRjcC50b29sdGlwID0gdGhpcy50b29sdGlwO1xuXHRcdGNwLnR5cGUgPSB0aGlzLnR5cGU7XG5cdFx0Y3AudmFsaWRhdG9yID0gdGhpcy52YWxpZGF0b3I7XG5cdFx0Y3AudHJpZ2dlciA9IHRoaXMudHJpZ2dlcjtcblx0XHRjcC50cmlnZ2VyRGF0YSA9ICh0aGlzLnRyaWdnZXJEYXRhICE9IG51bGwgPyBTRlMyWC5TRlNBcnJheS5uZXdGcm9tQmluYXJ5RGF0YSh0aGlzLnRyaWdnZXJEYXRhLnRvQmluYXJ5KCkpIDogbnVsbCk7XG5cdFx0Y3AuY2xpZW50T25seSA9IHRoaXMuY2xpZW50T25seTtcblx0XHRjcC5kYXRhUHJvdmlkZXIgPSB0aGlzLmRhdGFQcm92aWRlcjtcblxuXHRcdGlmIChjbG9uZVZhbHVlKVxuXHRcdFx0Y3AudmFsdWUgPSB0aGlzLnZhbHVlO1xuXG5cdFx0aWYgKHRoaXMuYXR0cmlidXRlcyAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGNwLmF0dHJpYnV0ZXMgPSBuZXcgT2JqZWN0KCk7XG5cdFx0XHRmb3IgKGxldCBzMSBpbiB0aGlzLmF0dHJpYnV0ZXMpXG5cdFx0XHRcdGNwLmF0dHJpYnV0ZXNbczFdID0gdGhpcy5hdHRyaWJ1dGVzW3MxXTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5zZXBhcmF0b3IgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRjcC5zZXBhcmF0b3IgPSBuZXcgT2JqZWN0KClcblx0XHRcdGZvciAobGV0IHMyIGluIHRoaXMuc2VwYXJhdG9yKVxuXHRcdFx0XHRjcC5zZXBhcmF0b3JbczJdID0gdGhpcy5zZXBhcmF0b3JbczJdO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLmRlZmF1bHRMaXN0SXRlbSAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGxldCBjbG9uZWREZWZhdWx0TGlzdEl0ZW1zID0gW107XG5cblx0XHRcdGZvciAobGV0IHN1YkNQIG9mIHRoaXMuZGVmYXVsdExpc3RJdGVtKVxuXHRcdFx0XHRjbG9uZWREZWZhdWx0TGlzdEl0ZW1zLnB1c2goc3ViQ1AuY2xvbmUoY2xvbmVWYWx1ZSkpO1xuXG5cdFx0XHRjcC5kZWZhdWx0TGlzdEl0ZW0gPSBjbG9uZWREZWZhdWx0TGlzdEl0ZW1zO1xuXHRcdH1cblxuXHRcdGNwLmxpc3RWYWx1ZXMgPSB0aGlzLmxpc3RWYWx1ZXM7IC8vIE5vIG5lZWQgdG8gY2xvbmUgdGhpcywgYXMgdGhlIGxpc3RWYWx1ZXMgc2V0dGVyIGFscmVhZHkgZG9lcyBpdFxuXHRcdGNwLmNsYXp6ID0gdGhpcy5jbGF6ejtcblx0XHRjcC5kZW55RW1wdHkgPSB0aGlzLmRlbnlFbXB0eTtcblx0XHRjcC5pbW1lZGlhdGUgPSB0aGlzLmltbWVkaWF0ZTtcblxuXHRcdHJldHVybiBjcDtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXNldCBpbml0aWFsIHZhbHVlIGJ5IGNvcHlpbmcgdGhlIGN1cnJlbnQgdmFsdWUuXG5cdCAqL1xuXHRyZXNldElzTW9kaWZpZWQoKVxuXHR7XG5cdFx0dGhpcy5faW5pdGlhbFZhbHVlID0gdGhpcy5fdmFsdWU7XG5cblx0XHQvLyBSZXNldCBzdWItcGFyYW1ldGVyc1xuXHRcdGlmICh0aGlzLl9saXN0SXRlbXMgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRmb3IgKGxldCBsaXN0SXRlbSBvZiB0aGlzLl9saXN0SXRlbXMpXG5cdFx0XHR7XG5cdFx0XHRcdGZvciAobGV0IHN1YkNQIG9mIGxpc3RJdGVtKVxuXHRcdFx0XHRcdHN1YkNQLnJlc2V0SXNNb2RpZmllZCgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQgPSBmYWxzZTtcblx0fVxuXG5cdGFkZExpc3RJdGVtKG5ld0xpc3RJdGVtKVxuXHR7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zLnB1c2gobmV3TGlzdEl0ZW0pO1xuXHRcdHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQgPSB0cnVlO1xuXHR9XG5cblx0dXBkYXRlTGlzdEl0ZW0obGlzdEl0ZW0sIGl0ZW1JbmRleClcblx0e1xuXHRcdHRoaXMuX2xpc3RJdGVtc1tpdGVtSW5kZXhdID0gbGlzdEl0ZW07XG5cdFx0dGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZCA9IHRydWU7XG5cdH1cblxuXHRyZW1vdmVMaXN0SXRlbShpdGVtSW5kZXgpXG5cdHtcblx0XHR0aGlzLl9saXN0SXRlbXMuc3BsaWNlKGl0ZW1JbmRleCwgMSk7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZCA9IHRydWU7XG5cdH1cblxuXHR0b1Nmc09iamVjdCgpXG5cdHtcblx0XHRsZXQgb2JqID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXG5cdFx0Ly8gU2V0IGNoYW5nZWQgc2V0dGluZyBuYW1lXG5cdFx0b2JqLnB1dFV0ZlN0cmluZygnbmFtZScsIHRoaXMubmFtZSk7XG5cblx0XHQvLyBTZXQgY2hhbmdlZCBzZXR0aW5nIGNsYXNzLCBpZiBhbnlcblx0XHRpZiAodGhpcy5jbGF6eiAhPSBudWxsKVxuXHRcdFx0b2JqLnB1dFV0ZlN0cmluZygnY2xhenonLCB0aGlzLmNsYXp6KTtcblxuXHRcdGlmICh0aGlzLnZhbHVlICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IGNoYW5nZWQgc2V0dGluZyB2YWx1ZVxuXHRcdFx0aWYgKHR5cGVvZiB0aGlzLnZhbHVlID09PSAnYm9vbGVhbicpXG5cdFx0XHRcdG9iai5wdXRCb29sKCd2YWx1ZScsIHRoaXMudmFsdWUpO1xuXHRcdFx0ZWxzZSBpZiAodHlwZW9mIHRoaXMudmFsdWUgPT09ICdudW1iZXInKVxuXHRcdFx0XHRvYmoucHV0SW50KCd2YWx1ZScsIHRoaXMudmFsdWUpO1xuXHRcdFx0ZWxzZVxuXHRcdFx0XHRvYmoucHV0VGV4dCgndmFsdWUnLCB0aGlzLnZhbHVlKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdC8vIFNldCBjaGFuZ2VkIHNldHRpbmcgbGlzdCBvZiB2YWx1ZXNcblxuXHRcdFx0bGV0IGxpc3RJdGVtcyA9IG5ldyBTRlMyWC5TRlNBcnJheSgpO1xuXG5cdFx0XHRmb3IgKGxldCBhIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHRcdHtcblx0XHRcdFx0aWYgKGEubGVuZ3RoID09IDEpIC8vIFdlIGhhdmUganVzdCBvbmUgc3ViIGNvbmZpZyBwYXJhbTsgbm8gbmVlZCB0byBwYXJzZSBpdCBjb21wbGl0ZWx5XG5cdFx0XHRcdHtcblx0XHRcdFx0XHQvLyBTaW1wbGUgbGlzdFxuXHRcdFx0XHRcdGxldCB0ZW1wT2JqID0gYVswXS50b1Nmc09iamVjdCgpO1xuXHRcdFx0XHRcdGxldCB3YSA9IHRlbXBPYmouZ2V0V3JhcHBlZEl0ZW0oJ3ZhbHVlJyk7XG5cdFx0XHRcdFx0bGlzdEl0ZW1zLmFkZCh3YS52YWx1ZSwgd2EudHlwZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0Ly8gQ29tcGxleCBsaXN0XG5cblx0XHRcdFx0XHRsZXQgdmFsdWVzID0gbmV3IFNGUzJYLlNGU0FycmF5KCk7XG5cblx0XHRcdFx0XHRmb3IgKGxldCBzdWJDcCBvZiBhKVxuXHRcdFx0XHRcdFx0dmFsdWVzLmFkZFNGU09iamVjdChzdWJDcC50b1Nmc09iamVjdCgpKTtcblxuXHRcdFx0XHRcdGxpc3RJdGVtcy5hZGRTRlNBcnJheSh2YWx1ZXMpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdG9iai5wdXRTRlNBcnJheSgndmFsdWUnLCBsaXN0SXRlbXMpO1xuXHRcdH1cblxuXHRcdHJldHVybiBvYmo7XG5cdH1cblxuXHQvKipcblx0ICogUmV0dXJuIGEgZGVzY3JpcHRpb24gb2YgdGhlIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIgaW5zdGFuY2UuXG5cdCAqL1xuXHR0b1N0cmluZygpXG5cdHtcblx0XHRsZXQgcyA9IGBgO1xuXHRcdHMgKz0gYENvbmZpZ3VyYXRpb24gcGFyYW1ldGVyOiAke3RoaXMubmFtZX1cXG5gO1xuXHRcdHMgKz0gYFxcdHR5cGU6ICR7dGhpcy50eXBlfVxcbmA7XG5cdFx0cyArPSBgXFx0bGFiZWw6ICR7dGhpcy5sYWJlbH1cXG5gO1xuXHRcdHMgKz0gYFxcdGNhdGVnb3J5IG5hbWU6ICR7dGhpcy5jYXRlZ29yeX1cXG5gO1xuXHRcdHMgKz0gYFxcdGNhdGVnb3J5IGlkOiAke3RoaXMuY2F0ZWdvcnlJZH1cXG5gO1xuXHRcdHMgKz0gYFxcdGltbWVkaWF0ZTogJHt0aGlzLmltbWVkaWF0ZX1cXG5gO1xuXHRcdHMgKz0gYFxcdHRvb2x0aXA6ICR7dGhpcy50b29sdGlwfVxcbmA7XG5cdFx0cyArPSBgXFx0dmFsdWU6ICR7dGhpcy52YWx1ZX1cXG5gO1xuXHRcdHMgKz0gYFxcdHRyaWdnZXI6ICR7dGhpcy50cmlnZ2VyfVxcbmA7XG5cdFx0cyArPSBgXFx0dHJpZ2dlciBkYXRhOiAke3RoaXMudHJpZ2dlckRhdGF9XFxuYDtcblx0XHRzICs9IGBcXHRjbGllbnQgb25seTogJHt0aGlzLmNsaWVudE9ubHl9XFxuYDtcblx0XHRzICs9IGBcXHR2YWxpZGF0b3I6ICR7dGhpcy52YWxpZGF0b3J9XFxuYDtcblx0XHRzICs9IGBcXHRpcyBtb2RpZmllZDogJHt0aGlzLmlzTW9kaWZpZWR9XFxuYDtcblxuXHRcdGlmICh0aGlzLmF0dHJpYnV0ZXMgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRzICs9IGBcXHRjb21wb25lbnQgYXR0cmlidXRlczpcXG5gO1xuXG5cdFx0XHRmb3IgKGxldCBzMSBpbiB0aGlzLmF0dHJpYnV0ZXMpXG5cdFx0XHRcdHMgKz0gYFxcdFxcdCR7czF9IC0tPiAke3RoaXMuYXR0cmlidXRlc1tzMV19XFxuYDtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5kYXRhUHJvdmlkZXIgIT0gbnVsbClcblx0XHRcdHMgKz0gYFxcdGRhdGEgcHJvdmlkZXI6ICR7dGhpcy5kYXRhUHJvdmlkZXJ9XFxuYDtcblxuXHRcdGlmICh0aGlzLnNlcGFyYXRvciAhPSBudWxsKVxuXHRcdHtcblx0XHRcdHMgKz0gYFxcdHNlcGFyYXRvcjpcXG5gO1xuXG5cdFx0XHRmb3IgKGxldCBzMiBpbiB0aGlzLnNlcGFyYXRvcilcblx0XHRcdFx0cyArPSBgXFx0XFx0JHtzMn0gLS0+ICR7dGhpcy5zZXBhcmF0b3JbczJdfVxcbmA7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX2xpc3RJdGVtcyAhPSBudWxsICYmIHRoaXMuX2xpc3RJdGVtcy5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdHMgKz0gYFxcdCMgbGlzdCBpdGVtczogJHt0aGlzLl9saXN0SXRlbXMubGVuZ3RofVxcbmA7XG5cblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fbGlzdEl0ZW1zLmxlbmd0aDsgaSsrKVxuXHRcdFx0e1xuXHRcdFx0XHRzICs9IGBcXHRsaXN0IGl0ZW0gJHtpfSBzdWItcGFyYW1ldGVyczpcXG5gO1xuXHRcdFx0XHRmb3IgKGxldCBlID0gMDsgZSA8IHRoaXMuX2xpc3RJdGVtc1tpXS5sZW5ndGg7IGUrKylcblx0XHRcdFx0XHRzICs9IGBcXHRcXHQke3RoaXMuX2xpc3RJdGVtc1tpXVtlXS50b0NvbXBhY3RTdHJpbmcoKX1cXG5gO1xuXHRcdFx0fVxuXG5cdFx0XHRzICs9IGBcXHRjbGFzcyBuYW1lOiAke3RoaXMuY2xhenp9XFxuYDtcblx0XHRcdHMgKz0gYFxcdGRlbnkgZW1wdHkgbGlzdDogJHt0aGlzLmRlbnlFbXB0eX1cXG5gO1xuXHRcdH1cblxuXHRcdHJldHVybiBzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybiBhIGNvbXBhY3QgZGVzY3JpcHRpb24gb2YgdGhlIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIgaW5zdGFuY2UuXG5cdCAqL1xuXHR0b0NvbXBhY3RTdHJpbmcoKVxuXHR7XG5cdFx0cmV0dXJuIGBDb25maWd1cmF0aW9uIHBhcmFtZXRlciAnJHt0aGlzLm5hbWV9JzogJHt0aGlzLnZhbHVlfSAke3RoaXMuaXNNb2RpZmllZCA/ICdbWF0nIDogJ1sgXSd9YDtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgTUVUSE9EU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdC8qKlxuXHQgKiBSZXRyaWV2ZSB0aGUgY2F0ZWdvcnkgaWQgZm9ybSB0aGUgY2F0ZWdvcnkgbmFtZS5cblx0ICogU3BhY2VzIGFuZCBpbnZhbGlkIGNoYXJhY3RlcnMgYXJlIHJlbW92ZWQ7IHdvcmRzIGFyZSBzZXBhcmF0ZWQgdXNpbmcgY2FwaXRhbHMuXG5cdCAqL1xuXHRfc2V0SWRGcm9tQ2F0ZWdvcnlOYW1lKGNhdGVnb3J5TmFtZSlcblx0e1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSBjYXRlZ29yeU5hbWU7XG5cblx0XHQvLyBTdHJpcCBpbnZhbGlkIGNoYXJhY3RlcnNcblx0XHR2YXIgcGF0dGVybiA9IC9bXjAtOWEtekEtWl0vZztcblx0XHR0aGlzLl9jYXRlZ29yeUlkID0gdGhpcy5fY2F0ZWdvcnlJZC5yZXBsYWNlKHBhdHRlcm4sICcgJyk7XG5cblx0XHQvLyBDYXBpdGFsaXplIHdvcmRzXG5cdFx0dmFyIHdvcmRzID0gdGhpcy5fY2F0ZWdvcnlJZC5zcGxpdCgnICcpO1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSAnJztcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgd29yZHMubGVuZ3RoOyBpKyspXG5cdFx0e1xuXHRcdFx0bGV0IHdvcmQgPSB3b3Jkc1tpXTtcblx0XHRcdGlmICh3b3JkLmxlbmd0aCA+IDApXG5cdFx0XHRcdHRoaXMuX2NhdGVnb3J5SWQgKz0gKGkgPiAwID8gd29yZC5zdWJzdHIoMCwxKS50b1VwcGVyQ2FzZSgpIDogd29yZC5zdWJzdHIoMCwxKS50b0xvd2VyQ2FzZSgpKSArICh3b3JkLmxlbmd0aCA+IDEgPyB3b3JkLnN1YnN0cigxKSA6IFwiXCIpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLl9jYXRlZ29yeUlkLmxlbmd0aCA9PSAwKVxuXHRcdFx0dGhpcy5fY2F0ZWdvcnlJZCA9IHRoaXMuREVGQVVMVF9DQVRFR09SWV9JRDtcblx0fVxuXG5cdF9zZXRTdWJDb25maWd1cmF0aW9uUGFyYW1zKF9saXN0VmFsdWVzKVxuXHR7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zID0gW107XG5cblx0XHRmb3IgKGxldCBvYmogb2YgX2xpc3RWYWx1ZXMpXG5cdFx0e1xuXHRcdFx0bGV0IGxpc3RJdGVtID0gW107XG5cblx0XHRcdGZvciAobGV0IGRlZmF1bHRDUCBvZiB0aGlzLmRlZmF1bHRMaXN0SXRlbSlcblx0XHRcdHtcblx0XHRcdFx0bGV0IHN1YkNQID0gZGVmYXVsdENQLmNsb25lKGZhbHNlKTtcblx0XHRcdFx0c3ViQ1AudmFsdWUgPSBvYmpbc3ViQ1AubmFtZV07XG5cblx0XHRcdFx0bGlzdEl0ZW0ucHVzaChzdWJDUCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xpc3RJdGVtcy5wdXNoKGxpc3RJdGVtKTtcblx0XHR9XG5cdH1cblxuXHRfZ2V0U3ViQ29uZmlndXJhdGlvblBhcmFtc1ZhbHVlcygpXG5cdHtcblx0XHRsZXQgX2xpc3RWYWx1ZXMgPSBbXTtcblxuXHRcdGZvciAobGV0IGxpc3RJdGVtIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHR7XG5cdFx0XHRsZXQgb2JqID0ge307XG5cblx0XHRcdGZvciAobGV0IHN1YkNQIG9mIGxpc3RJdGVtKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoc3ViQ1AudmFsdWUgIT0gbnVsbClcblx0XHRcdFx0XHRvYmpbc3ViQ1AubmFtZV0gPSBzdWJDUC52YWx1ZTtcblx0XHRcdH1cblxuXHRcdFx0X2xpc3RWYWx1ZXMucHVzaChvYmopO1xuXHRcdH1cblxuXHRcdHJldHVybiBfbGlzdFZhbHVlcztcblx0fVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDNUdBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDeEhBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQ3pMQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDblBBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQ2xYQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUMzQkE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUMvR0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDekZBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDN0VBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDL0VBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQzdKQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDaERBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDMVJBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QSIsInNvdXJjZVJvb3QiOiIifQ==