rubyfox-server 2.17.3.2 → 2.19.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -263
  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-13~module-16~module-17~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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtMTN+bW9kdWxlLTE2fm1vZHVsZS0xN35tb2R1bGUtNC5idW5kbGUuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctY2hlY2stYm94LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kcm9wLWRvd24tbGlzdC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctZHVhbC1saXN0LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1mb3JtLWl0ZW0uanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWdyaWQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWxhYmVsLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1udW1lcmljLXN0ZXBwZXIuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXRleHQtaW5wdXQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXZlY3Rvci0zZC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci93aWRnZXRzL2xpc3QtaXRlbS1lZGl0b3IuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvd2lkZ2V0cy92ZWN0b3ItM2QtaW5wdXQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvdXRpbHMvdWlidWlsZGVyL2NvbmZpZy1mb3JtLWl0ZW0tZmFjdG9yeS5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy91dGlscy91aWJ1aWxkZXIvY29uZmlnLWludGVyZmFjZS1idWlsZGVyLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL3V0aWxzL3VpYnVpbGRlci9jb25maWd1cmF0aW9uLXBhcmFtZXRlci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnQ2hlY2tCb3ggZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0dHlwZTogJ2NoZWNrYm94Jyxcblx0XHRcdFx0Y2xhc3M6ICcnLFxuXHRcdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRuYW1lOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdCdkYXRhLXJvbGUnOiAnc3dpdGNoJyxcblx0XHRcdH07XG5cblx0XHRcdC8vIFNldCB3aWRnZXQgYXR0cmlidXRlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuICAgX2luaXRpYWxpemUoKVxuICAge1xuXHQgICBpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0ICAge1xuXHRcdCAgIC8vIEluaXRpYWxpemUga2VuZG8gd2lkZ2V0XG5cdFx0ICAga2VuZG8uaW5pdCh0aGlzLl93aWRnZXRIdG1sKTtcblxuXHRcdCAgIC8vIFNhdmUgcmVmLiB0byB3aWRnZXRcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldCA9IHRoaXMuX3dpZGdldEh0bWwuZGF0YSgna2VuZG9Td2l0Y2gnKTtcblxuXHRcdCAgIC8vIEVuYWJsZSB2YWx1ZSBjb21taXQgYmluZGluZ1xuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0LmJpbmQoJ2NoYW5nZScsICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSk7XG5cdCAgIH1cblxuXHQgICAvLyBQcm9jZWVkIHdpdGggaW5pdGlhbGl6YXRpb25cblx0ICAgc3VwZXIuX2luaXRpYWxpemUoKTtcbiAgIH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCB0aGUgbGFiZWwgdGV4dCBpcyBzZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQudmFsdWUodGhpcy5fZGF0YS52YWx1ZSk7XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbC52YWx1ZSA9IHRoaXMuX2RhdGEudmFsdWU7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LmVuYWJsZSh0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9vblZhbHVlSW5wdXQoZSlcblx0e1xuXHRcdC8vIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB0byBuZXcgdmFsdWVcblx0XHR0aGlzLl9kYXRhLnZhbHVlID0gdGhpcy5faW5uZXJXaWRnZXQudmFsdWUoKTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1jaGVjay1ib3gnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLWNoZWNrLWJveCcsIENvbmZpZ0NoZWNrQm94KTtcbiIsImltcG9ydCB7Q29uZmlnRm9ybUl0ZW19IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbSc7XG5pbXBvcnQge0NvbmZpZ0xhYmVsfSBmcm9tICcuL2NvbmZpZy1sYWJlbCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdEcm9wRG93bkxpc3QgZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0Y2xhc3M6ICdmb3JtLWNvbnRyb2wnLFxuXHRcdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRuYW1lOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdCdkYXRhLXJvbGUnOiAnZHJvcGRvd25saXN0Jyxcblx0XHRcdH07XG5cblx0XHRcdC8vIFNldCB3aWRnZXQgYXR0cmlidXRlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfaW5pdGlhbGl6ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHdpZGdldFxuXHRcdFx0a2VuZG8uaW5pdCh0aGlzLl93aWRnZXRIdG1sKTtcblxuXHRcdFx0Ly8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQgPSB0aGlzLl93aWRnZXRIdG1sLmRhdGEoJ2tlbmRvRHJvcERvd25MaXN0Jyk7XG5cblx0XHRcdC8vIFNldCBsaXN0IGl0ZW1zXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC5zZXREYXRhU291cmNlKHRoaXMuX2dldERhdGFTb3VyY2UodGhpcy5fZGF0YS5kYXRhUHJvdmlkZXIpKVxuXG5cdFx0XHQvLyBFbmFibGUgdmFsdWUgY29tbWl0IGJpbmRpbmdcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYmluZCgnY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0XHR9XG5cblx0XHQvLyBQcm9jZWVkIHdpdGggaW5pdGlhbGl6YXRpb25cblx0XHRzdXBlci5faW5pdGlhbGl6ZSgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LnZhbHVlKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC53cmFwcGVyLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0X2dldERhdGFTb3VyY2UoZHBTdHJpbmcpXG5cdHtcblx0XHRpZiAoZHBTdHJpbmcpXG5cdFx0XHRyZXR1cm4gZHBTdHJpbmcuc3BsaXQoJywnKTtcblxuXHRcdC8vIEluIGNhc2UgdGhlIGRhdGFwcm92aWRlciBpcyBlbXB0eSwgYWRkIGF0IGxlYXN0IHRoZSBjdXJyZW50IHZhbHVlXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIFt0aGlzLl9kYXRhLnZhbHVlXTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kcm9wLWRvd24tbGlzdCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZHJvcC1kb3duLWxpc3QnLCBDb25maWdEcm9wRG93bkxpc3QpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0R1YWxMaXN0IGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlci5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGRpdj4nKTtcblxuXHRcdGNvbnN0IGF2YWlsYWJsZUlkID0gdGhpcy5fZ2V0SWQodGhpcy5fZGF0YS5uYW1lLCAnYXZhaWxhYmxlJyk7XG5cdFx0Y29uc3Qgc2VsZWN0ZWRJZCA9IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyk7XG5cblx0XHQvLyBDcmVhdGUgaGVhZGVyIGZvciBsYWJlbHNcblx0XHRsZXQgaGVhZGVyID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICdmb3JtLWxhYmVsLWNvbnRhaW5lciBkdWFsLWxpc3QtbGFiZWxzJ30pO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+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==